surshar / claude-code
Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.
Built by Anthropic · github.com/anthropics
| 1 | import type { EngineInterface, On } from 'claude-code' |
| 2 | |
| 3 | import Context from './context' |
| 4 | import Gate from './gate' |
| 5 | import IsAnalyticsOff from './is-analytics-off' |
| 6 | import type { Sender } from './sender' |
| 7 | import { telemetryOf } from './telemetry-of' |
| 8 | |
| 9 | /** |
| 10 | * Registers the plugin's hooks: its engine.create step adds `$.telemetry` |
| 11 | * over the nouns beneath; session.start and session.end feed and flush it. |
| 12 | * |
| 13 | * `log` and `mark` queue a row for a built-in caller and refuse any other; |
| 14 | * a gate that throws refuses too, a refusal from beneath stays as it is. A |
| 15 | * batch goes out on a timer, when full, and when the session ends. |
| 16 | * |
| 17 | * @param on the engine's registrar |
| 18 | */ |
| 19 | export function register(on: On) { |
| 20 | let sender: Sender | undefined |
| 21 | let isInteractive: boolean | undefined |
| 22 | |
| 23 | on('telemetry.*', (_$, e, next) => Gate.served(e, next)).catch( |
| 24 | (_$, e, next) => Gate.caught(e, next), |
| 25 | ) |
| 26 | |
| 27 | on('session.start', (_$, e, next) => { |
| 28 | isInteractive = e.isInteractive |
| 29 | |
| 30 | return next(e) |
| 31 | }) |
| 32 | |
| 33 | on('session.end', async (_$, e, next) => { |
| 34 | await sender?.flush() |
| 35 | |
| 36 | return next(e) |
| 37 | }) |
| 38 | |
| 39 | on('engine.create', async (_$, e, next) => { |
| 40 | const beneath = await next(e) |
| 41 | |
| 42 | sender = telemetryOf({ |
| 43 | authorize: () => beneath.session.authorize(), |
| 44 | id: () => beneath.session.id(), |
| 45 | model: () => beneath.session.model(), |
| 46 | isInteractive: async () => |
| 47 | isInteractive ?? |
| 48 | (await beneath.session.surfaces()).includes('terminal'), |
| 49 | environment: async () => ({ |
| 50 | userType: await beneath.env.get('USER_TYPE'), |
| 51 | nodeEnv: await beneath.env.get('NODE_ENV'), |
| 52 | disableTelemetry: await beneath.env.get('DISABLE_TELEMETRY'), |
| 53 | disableNonessentialTraffic: await beneath.env.get( |
| 54 | 'CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC', |
| 55 | ), |
| 56 | doNotTrack: await beneath.env.get('DO_NOT_TRACK'), |
| 57 | customOauthUrl: await beneath.env.get('CLAUDE_CODE_CUSTOM_OAUTH_URL'), |
| 58 | useGateway: await beneath.env.get('CLAUDE_CODE_USE_GATEWAY'), |
| 59 | providerManagedByHost: await beneath.env.get( |
| 60 | 'CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST', |
| 61 | ), |
| 62 | useBedrock: await beneath.env.get('CLAUDE_CODE_USE_BEDROCK'), |
| 63 | useVertex: await beneath.env.get('CLAUDE_CODE_USE_VERTEX'), |
| 64 | useFoundry: await beneath.env.get('CLAUDE_CODE_USE_FOUNDRY'), |
| 65 | useAnthropicAws: await beneath.env.get('CLAUDE_CODE_USE_ANTHROPIC_AWS'), |
| 66 | useAnthropicGoogleCloud: await beneath.env.get( |
| 67 | 'CLAUDE_CODE_USE_ANTHROPIC_GOOGLE_CLOUD', |
| 68 | ), |
| 69 | useMantle: await beneath.env.get('CLAUDE_CODE_USE_MANTLE'), |
| 70 | }), |
| 71 | policy: () => beneath.settings.read({ source: 'policy' }), |
| 72 | facts: async () => ({ |
| 73 | entrypoint: await beneath.env.get('CLAUDE_CODE_ENTRYPOINT'), |
| 74 | agentSdkVersion: await beneath.env.get('CLAUDE_AGENT_SDK_VERSION'), |
| 75 | hostPlatform: await beneath.env.get('CLAUDE_CODE_HOST_PLATFORM'), |
| 76 | os: await beneath.env.get('OS'), |
| 77 | processorArchitecture: await beneath.env.get('PROCESSOR_ARCHITECTURE'), |
| 78 | shellPath: |
| 79 | (await beneath.env.get('SHELL')) ?? |
| 80 | (await beneath.env.get('COMSPEC')), |
| 81 | ci: await beneath.env.get('CI'), |
| 82 | claubbit: await beneath.env.get('CLAUBBIT'), |
| 83 | githubActions: await beneath.env.get('GITHUB_ACTIONS'), |
| 84 | claudeCodeAction: await beneath.env.get('CLAUDE_CODE_ACTION'), |
| 85 | claudeCodeRemote: await beneath.env.get('CLAUDE_CODE_REMOTE'), |
| 86 | remoteEnvironmentType: await beneath.env.get( |
| 87 | 'CLAUDE_CODE_REMOTE_ENVIRONMENT_TYPE', |
| 88 | ), |
| 89 | containerId: await beneath.env.get('CLAUDE_CODE_CONTAINER_ID'), |
| 90 | remoteSessionId: await beneath.env.get('CLAUDE_CODE_REMOTE_SESSION_ID'), |
| 91 | tags: await beneath.env.get('CLAUDE_CODE_TAGS'), |
| 92 | hasSessionAccessToken: IsAnalyticsOff.isEnvSet( |
| 93 | await beneath.env.get('CLAUDE_CODE_SESSION_ACCESS_TOKEN'), |
| 94 | ), |
| 95 | hasSessionIngressTokenFile: IsAnalyticsOff.isEnvSet( |
| 96 | await beneath.env.get('CLAUDE_SESSION_INGRESS_TOKEN_FILE'), |
| 97 | ), |
| 98 | hasWebsocketAuthFileDescriptor: IsAnalyticsOff.isEnvSet( |
| 99 | await beneath.env.get('CLAUDE_CODE_WEBSOCKET_AUTH_FILE_DESCRIPTOR'), |
| 100 | ), |
| 101 | githubEventName: await beneath.env.get('GITHUB_EVENT_NAME'), |
| 102 | runnerEnvironment: await beneath.env.get('RUNNER_ENVIRONMENT'), |
| 103 | runnerOs: await beneath.env.get('RUNNER_OS'), |
| 104 | githubActionPath: await beneath.env.get('GITHUB_ACTION_PATH'), |
| 105 | githubActorId: await beneath.env.get('GITHUB_ACTOR_ID'), |
| 106 | githubRepositoryId: await beneath.env.get('GITHUB_REPOSITORY_ID'), |
| 107 | githubRepositoryOwnerId: await beneath.env.get( |
| 108 | 'GITHUB_REPOSITORY_OWNER_ID', |
| 109 | ), |
| 110 | sweBenchRunId: await beneath.env.get('SWE_BENCH_RUN_ID'), |
| 111 | sweBenchInstanceId: await beneath.env.get('SWE_BENCH_INSTANCE_ID'), |
| 112 | sweBenchTaskId: await beneath.env.get('SWE_BENCH_TASK_ID'), |
| 113 | hasP4Port: IsAnalyticsOff.isEnvSet(await beneath.env.get('P4PORT')), |
| 114 | wslDistroName: await beneath.env.get('WSL_DISTRO_NAME'), |
| 115 | hasCursorTraceId: IsAnalyticsOff.isEnvSet( |
| 116 | await beneath.env.get('CURSOR_TRACE_ID'), |
| 117 | ), |
| 118 | vscodeGitAskpassMain: await beneath.env.get('VSCODE_GIT_ASKPASS_MAIN'), |
| 119 | bundleIdentifier: await beneath.env.get('__CFBundleIdentifier'), |
| 120 | hasVisualStudioVersion: IsAnalyticsOff.isEnvSet( |
| 121 | await beneath.env.get('VisualStudioVersion'), |
| 122 | ), |
| 123 | terminalEmulator: await beneath.env.get('TERMINAL_EMULATOR'), |
| 124 | term: await beneath.env.get('TERM'), |
| 125 | termProgram: await beneath.env.get('TERM_PROGRAM'), |
| 126 | hasTmux: IsAnalyticsOff.isEnvSet(await beneath.env.get('TMUX')), |
| 127 | hasSty: IsAnalyticsOff.isEnvSet(await beneath.env.get('STY')), |
| 128 | hasKonsoleVersion: IsAnalyticsOff.isEnvSet( |
| 129 | await beneath.env.get('KONSOLE_VERSION'), |
| 130 | ), |
| 131 | hasGnomeTerminalService: IsAnalyticsOff.isEnvSet( |
| 132 | await beneath.env.get('GNOME_TERMINAL_SERVICE'), |
| 133 | ), |
| 134 | hasXtermVersion: IsAnalyticsOff.isEnvSet( |
| 135 | await beneath.env.get('XTERM_VERSION'), |
| 136 | ), |
| 137 | hasVteVersion: IsAnalyticsOff.isEnvSet( |
| 138 | await beneath.env.get('VTE_VERSION'), |
| 139 | ), |
| 140 | hasTerminatorUuid: IsAnalyticsOff.isEnvSet( |
| 141 | await beneath.env.get('TERMINATOR_UUID'), |
| 142 | ), |
| 143 | hasKittyWindowId: IsAnalyticsOff.isEnvSet( |
| 144 | await beneath.env.get('KITTY_WINDOW_ID'), |
| 145 | ), |
| 146 | hasAlacrittyLog: IsAnalyticsOff.isEnvSet( |
| 147 | await beneath.env.get('ALACRITTY_LOG'), |
| 148 | ), |
| 149 | hasTilixId: IsAnalyticsOff.isEnvSet(await beneath.env.get('TILIX_ID')), |
| 150 | hasWtSession: IsAnalyticsOff.isEnvSet( |
| 151 | await beneath.env.get('WT_SESSION'), |
| 152 | ), |
| 153 | hasSessionName: IsAnalyticsOff.isEnvSet( |
| 154 | await beneath.env.get('SESSIONNAME'), |
| 155 | ), |
| 156 | msystem: await beneath.env.get('MSYSTEM'), |
| 157 | hasConEmuAnsi: IsAnalyticsOff.isEnvSet( |
| 158 | await beneath.env.get('ConEmuANSI'), |
| 159 | ), |
| 160 | hasConEmuPid: IsAnalyticsOff.isEnvSet( |
| 161 | await beneath.env.get('ConEmuPID'), |
| 162 | ), |
| 163 | hasConEmuTask: IsAnalyticsOff.isEnvSet( |
| 164 | await beneath.env.get('ConEmuTask'), |
| 165 | ), |
| 166 | hasSshConnection: IsAnalyticsOff.isEnvSet( |
| 167 | await beneath.env.get('SSH_CONNECTION'), |
| 168 | ), |
| 169 | hasSshClient: IsAnalyticsOff.isEnvSet( |
| 170 | await beneath.env.get('SSH_CLIENT'), |
| 171 | ), |
| 172 | hasSshTty: IsAnalyticsOff.isEnvSet(await beneath.env.get('SSH_TTY')), |
| 173 | }), |
| 174 | deployment: async () => [ |
| 175 | [ |
| 176 | 'codespaces', |
| 177 | IsAnalyticsOff.isEnvTruthy(await beneath.env.get('CODESPACES')), |
| 178 | ], |
| 179 | [ |
| 180 | 'gitpod', |
| 181 | IsAnalyticsOff.isEnvSet(await beneath.env.get('GITPOD_WORKSPACE_ID')), |
| 182 | ], |
| 183 | ['coder', IsAnalyticsOff.isEnvTruthy(await beneath.env.get('CODER'))], |
| 184 | [ |
| 185 | 'coder', |
| 186 | IsAnalyticsOff.isEnvSet( |
| 187 | await beneath.env.get('CODER_WORKSPACE_NAME'), |
| 188 | ), |
| 189 | ], |
| 190 | ['devpod', IsAnalyticsOff.isEnvTruthy(await beneath.env.get('DEVPOD'))], |
| 191 | [ |
| 192 | 'devpod', |
| 193 | IsAnalyticsOff.isEnvSet( |
| 194 | await beneath.env.get('DEVPOD_WORKSPACE_UID'), |
| 195 | ), |
| 196 | ], |
| 197 | [ |
| 198 | 'daytona', |
| 199 | IsAnalyticsOff.isEnvSet(await beneath.env.get('DAYTONA_WS_ID')), |
| 200 | ], |
| 201 | [ |
| 202 | 'gcp-cloud-workstations', |
| 203 | IsAnalyticsOff.isEnvTruthy( |
| 204 | await beneath.env.get('GOOGLE_CLOUD_WORKSTATIONS'), |
| 205 | ), |
| 206 | ], |
| 207 | [ |
| 208 | 'aws-cloud9', |
| 209 | IsAnalyticsOff.isEnvSet(await beneath.env.get('C9_PID')), |
| 210 | ], |
| 211 | [ |
| 212 | 'aws-cloud9', |
| 213 | IsAnalyticsOff.isEnvSet(await beneath.env.get('C9_USER')), |
| 214 | ], |
| 215 | ['replit', IsAnalyticsOff.isEnvSet(await beneath.env.get('REPL_ID'))], |
| 216 | ['replit', IsAnalyticsOff.isEnvSet(await beneath.env.get('REPL_SLUG'))], |
| 217 | [ |
| 218 | 'glitch', |
| 219 | IsAnalyticsOff.isEnvSet(await beneath.env.get('PROJECT_DOMAIN')), |
| 220 | ], |
| 221 | ['vercel', IsAnalyticsOff.isEnvTruthy(await beneath.env.get('VERCEL'))], |
| 222 | [ |
| 223 | 'railway', |
| 224 | IsAnalyticsOff.isEnvSet( |
| 225 | await beneath.env.get('RAILWAY_ENVIRONMENT_NAME'), |
| 226 | ), |
| 227 | ], |
| 228 | [ |
| 229 | 'railway', |
| 230 | IsAnalyticsOff.isEnvSet( |
| 231 | await beneath.env.get('RAILWAY_SERVICE_NAME'), |
| 232 | ), |
| 233 | ], |
| 234 | ['render', IsAnalyticsOff.isEnvTruthy(await beneath.env.get('RENDER'))], |
| 235 | [ |
| 236 | 'netlify', |
| 237 | IsAnalyticsOff.isEnvTruthy(await beneath.env.get('NETLIFY')), |
| 238 | ], |
| 239 | ['heroku', IsAnalyticsOff.isEnvSet(await beneath.env.get('DYNO'))], |
| 240 | [ |
| 241 | 'fly.io', |
| 242 | IsAnalyticsOff.isEnvSet(await beneath.env.get('FLY_APP_NAME')), |
| 243 | ], |
| 244 | [ |
| 245 | 'fly.io', |
| 246 | IsAnalyticsOff.isEnvSet(await beneath.env.get('FLY_MACHINE_ID')), |
| 247 | ], |
| 248 | [ |
| 249 | 'cloudflare-pages', |
| 250 | IsAnalyticsOff.isEnvTruthy(await beneath.env.get('CF_PAGES')), |
| 251 | ], |
| 252 | [ |
| 253 | 'deno-deploy', |
| 254 | IsAnalyticsOff.isEnvSet(await beneath.env.get('DENO_DEPLOYMENT_ID')), |
| 255 | ], |
| 256 | [ |
| 257 | 'aws-lambda', |
| 258 | IsAnalyticsOff.isEnvSet( |
| 259 | await beneath.env.get('AWS_LAMBDA_FUNCTION_NAME'), |
| 260 | ), |
| 261 | ], |
| 262 | [ |
| 263 | 'aws-fargate', |
| 264 | (await beneath.env.get('AWS_EXECUTION_ENV')) === 'AWS_ECS_FARGATE', |
| 265 | ], |
| 266 | [ |
| 267 | 'aws-ecs', |
| 268 | (await beneath.env.get('AWS_EXECUTION_ENV')) === 'AWS_ECS_EC2', |
| 269 | ], |
| 270 | [ |
| 271 | 'gcp-cloud-run', |
| 272 | IsAnalyticsOff.isEnvSet(await beneath.env.get('K_SERVICE')), |
| 273 | ], |
| 274 | [ |
| 275 | 'gcp', |
| 276 | IsAnalyticsOff.isEnvSet( |
| 277 | await beneath.env.get('GOOGLE_CLOUD_PROJECT'), |
| 278 | ), |
| 279 | ], |
| 280 | [ |
| 281 | 'azure-app-service', |
| 282 | IsAnalyticsOff.isEnvSet(await beneath.env.get('WEBSITE_SITE_NAME')), |
| 283 | ], |
| 284 | [ |
| 285 | 'azure-app-service', |
| 286 | IsAnalyticsOff.isEnvSet(await beneath.env.get('WEBSITE_SKU')), |
| 287 | ], |
| 288 | [ |
| 289 | 'azure-functions', |
| 290 | IsAnalyticsOff.isEnvSet( |
| 291 | await beneath.env.get('AZURE_FUNCTIONS_ENVIRONMENT'), |
| 292 | ), |
| 293 | ], |
| 294 | [ |
| 295 | 'digitalocean-app-platform', |
| 296 | IsAnalyticsOff.isEnvSet(await beneath.env.get('APP_URL')) && |
| 297 | String(await beneath.env.get('APP_URL')).includes( |
| 298 | 'ondigitalocean.app', |
| 299 | ), |
| 300 | ], |
| 301 | [ |
| 302 | 'huggingface-spaces', |
| 303 | IsAnalyticsOff.isEnvSet( |
| 304 | await beneath.env.get('SPACE_CREATOR_USER_ID'), |
| 305 | ), |
| 306 | ], |
| 307 | [ |
| 308 | 'github-actions', |
| 309 | IsAnalyticsOff.isEnvTruthy(await beneath.env.get('GITHUB_ACTIONS')), |
| 310 | ], |
| 311 | [ |
| 312 | 'gitlab-ci', |
| 313 | IsAnalyticsOff.isEnvTruthy(await beneath.env.get('GITLAB_CI')), |
| 314 | ], |
| 315 | [ |
| 316 | 'circleci', |
| 317 | IsAnalyticsOff.isEnvSet(await beneath.env.get('CIRCLECI')), |
| 318 | ], |
| 319 | [ |
| 320 | 'buildkite', |
| 321 | IsAnalyticsOff.isEnvSet(await beneath.env.get('BUILDKITE')), |
| 322 | ], |
| 323 | ['ci', IsAnalyticsOff.isEnvTruthy(await beneath.env.get('CI'))], |
| 324 | [ |
| 325 | 'kubernetes', |
| 326 | IsAnalyticsOff.isEnvSet( |
| 327 | await beneath.env.get('KUBERNETES_SERVICE_HOST'), |
| 328 | ), |
| 329 | ], |
| 330 | ], |
| 331 | configLocation: async () => ({ |
| 332 | configDir: await beneath.env.get('CLAUDE_CONFIG_DIR'), |
| 333 | home: await beneath.env.get('HOME'), |
| 334 | userProfile: await beneath.env.get('USERPROFILE'), |
| 335 | }), |
| 336 | cwd: () => beneath.session.cwd(), |
| 337 | repo: () => beneath.session.repo(), |
| 338 | read: path => beneath.fs.read(path), |
| 339 | list: path => beneath.fs.list(path), |
| 340 | exists: path => beneath.fs.exists(path), |
| 341 | run: argv => |
| 342 | beneath.process.run(argv, { timeoutMs: Context.PROBE_TIMEOUT_MS }), |
| 343 | fetch: (url, init) => beneath.http.fetch(url, init), |
| 344 | after: (ms, fn) => beneath.clock.after(ms, fn), |
| 345 | sleep: ms => beneath.clock.sleep(ms), |
| 346 | debug: text => beneath.ui.log(text, { to: 'debug' }), |
| 347 | }) |
| 348 | |
| 349 | const telemetry: EngineInterface['telemetry'] = sender.telemetry |
| 350 | |
| 351 | return { ...beneath, telemetry } |
| 352 | }) |
| 353 | } |