Repository navigation
perf(cli): Give __complete its own light entry point - #1762
sentry-junior[bot] wants to merge 1 commit into
Conversation
Shell completion runs on every TAB press, but `sentry __complete` paid for most of the CLI before printing anything. The npm bin required the whole 7.6 MB `dist/index.cjs` (~340 ms per call), and the completion engine's static imports reached `@sentry/node` anyway: `db/auth.ts` and the cache modules imported telemetry, and `logger.ts` imported `createConsolaReporter`. Its eager graph was 659 modules. `src/bin.ts` and `dist/bin.cjs` now check for `__complete` first and call `runCompletion` in `lib/complete.ts` without loading `cli.ts`; the npm package ships it as a separate `dist/complete.cjs` (322 KB). The database modules get `withDbSpan` and `recordCacheHit` from `db/index.ts`, which requires telemetry lazily like the existing tracing proxy and skips it with telemetry off, and `initSentry` hands the logger its Sentry reporter. The eager graph is now 40 modules. Median on Node 24 (`issue list ""`): npm 356 -> 67 ms, SEA binary 145 -> 97 ms, bare node 26 ms. Completion output is unchanged. `test/script/cli-startup.test.ts` bundles `lib/complete.ts` and fails on any package outside an allowlist or more than 50 source modules, and the npm e2e test checks `__complete` never loads `index.cjs`. Co-Authored-By: BYK <burak.kaya@sentry.io>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f410427. Configure here.
| "-e", | ||
| `process.on("exit", () => process.stderr.write(JSON.stringify(Object.keys(require.cache)))); | ||
| process.argv.splice(1, 0, ${JSON.stringify(BUNDLE_BIN_PATH)}); | ||
| require(process.argv[1]);`, |
There was a problem hiding this comment.
E2E test misses completion entry
Medium Severity
The new e2e guard inserts the bin path in front of -e instead of replacing it, so process.argv[2] is -e rather than __complete. The wrapper therefore loads index.cjs and never takes the complete.cjs fast path, so the assertions on completion output and loaded modules cannot hold.
Reviewed by Cursor Bugbot for commit f410427. Configure here.
There was a problem hiding this comment.
Not a bug: Node leaves -e and its script out of process.argv, so with node -e <script> __complete … the array is [node, "__complete", …]. After the splice it is [node, bin.cjs, "__complete", …] and argv[2] is "__complete". I checked this locally on Node 24, and the test passes against a fresh pnpm run bundle. Its require.cache shows bin.cjs and complete.cjs only.
| if (process.argv[2] === "__complete") { | ||
| import("./lib/complete.js") | ||
| .then(({ runCompletion }) => runCompletion(process.argv.slice(3))) | ||
| .catch(() => { | ||
| // Completions should never crash — silently return no results | ||
| process.exitCode = 0; | ||
| }); |
There was a problem hiding this comment.
Disabling telemetry bypasses SQLite schema repair
When SENTRY_CLI_NO_TELEMETRY=1—including on every __complete run—getDatabase() returns raw SQLite instead of the proxy that repairs schema errors and handles readonly writes. A completion query against a stale schema can therefore fail and silently produce no suggestions; keep database resilience independent of telemetry loading.
Evidence
runCompletion()setsSENTRY_CLI_NO_TELEMETRYto"1";lazyTelemetry()then returnsundefined, andgetDatabase()falls back torawDb.createTracedDatabase()andcreateTracedStatement()are the only wrappers that calltryRepairAndRetry()for schema errors and handle readonly write errors.schema.tsdocuments repair for missing tables and columns.getCachedOrganizations()queries columns includingcredential_identity; if one is missing, the raw query fails, andhandleComplete()catches the failure and returns no completions rather than repairing and retrying.
Identified by Warden · code-review · NDZ-CMD
There was a problem hiding this comment.
Not changing this in this PR: the behavior is unchanged from main, so the PR does not introduce it.
- On
main,runCompletion()insrc/cli.tsalready setsgetEnv().SENTRY_CLI_NO_TELEMETRY = "1"before it importscomplete.js. - On
main,getDatabase()already setsdb = rawDbwhenSENTRY_CLI_NO_TELEMETRY === "1", so__completehas always skipped thecreateTracedDatabase()repair proxy. Any user who setsSENTRY_CLI_NO_TELEMETRY=1skips it too. - This PR only moves that branch into
lazyTelemetry(). The result is the same:lazyTelemetry()?.createTracedDatabase(rawDb) ?? rawDb. - Stale schemas are still fixed when the database opens:
getDatabase()runsinitSchema()andrunMigrations()onrawDb, andrunMigrations()callsrepairSchema()for databases from a newer CLI. Only the retry-on-query step is skipped. If completion fails, it returns no suggestions and does not crash.
Moving the repair and readonly handling out of telemetry.ts, so it works without telemetry, is a reasonable follow-up. It changes behavior for every no-telemetry run, though, so it belongs in its own PR, not this performance refactor.


Shell completion runs
sentry __completeon every TAB press, and since #1760 also for every flag name in bash and fish. Each call was paying for most of the CLI before it printed anything. This addresses the review thread on #1751 (complete.ts).Where the time went
dist/index.cjsjust to reach the completion branch incli.ts.@sentry/node, even with telemetry off.db/auth.tsanddb/user.tsimportedwithDbSpanfromtelemetry.ts, the cache modules importedrecordCacheHit, andlogger.tsimportedcreateConsolaReporter. That graph was 659 modules: Sentry SDK, OpenTelemetry, and the API client. The completers themselves cost under 10 ms.What changed
src/bin.tsanddist/bin.cjscheck for__completefirst. They callrunCompletioninsrc/lib/complete.tswithout loadingcli.ts. The npm package ships that path as a separatedist/complete.cjs(322 KB). The SEA binary takes it as a lazily evaluated chunk of its single bundle.withDbSpanandrecordCacheHitfromdb/index.ts. Like the existing tracing proxy there, these require telemetry lazily and skip it when telemetry is off, whichrunCompletionsets.initSentrynow passes the Sentry reporter toattachSentryReporter, sologger.tsno longer imports the SDK.Numbers. Median of 20 runs on Node 24 (Linux x64), against a seeded config DB:
issue list ""issue list --init ./(directory)In dev (tsx), the same calls went from about 650 ms to about 315 ms; most of what's left is tsx's own startup.
Guard.
test/script/cli-startup.test.tsbundleslib/complete.tswithout its deferred imports. It fails on any package outsideCOMPLETION_PACKAGES, naming the importer, or when there are more than 50 source modules. It also now coversbin.ts. The npm e2e suite checks that__completeloadscomplete.cjsand neverindex.cjs. The "Shell completion" section ofAGENTS.mddescribes the rule.What's left.
consolais about 15 ms of the remaining npm time, and Stricli (througherrors.ts) about 3 ms. In the SEA binary, the rest is mostly the cost of loading the single 7.6 MB embedded script. Each of these would need a larger change (a lazy logger, a second SEA script), so they are left for follow-ups.via BYK.
--
View Session in Sentry