You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
***sentry local command uses getParsedEnvelope() for envelope item dispatch**: \`src/commands/local.ts\` receives raw Sentry envelopes via a Hono HTTP server, pushes them into a Spotlight \`MessageBuffer\<EventContainer>\`, then in the subscriber calls \`container.getParsedEnvelope()\` to get \`\[header, items\[]]\`. Each item's \`\[itemHeader, itemPayload]\` is dispatched: \`event\`/\`error\` types → \`formatErrorItem\`, \`transaction\` → \`formatTransactionItem\`, \`log\` → \`formatLogItem\` (returns multiple lines), all others fall back to a minimal \`timestamp • type\` line. Formatters are inline in \`local.ts\` and use the CLI's color helpers.
***Response cache hit invisibility — synthetic Response carries no marker**: Response cache hit invisibility — synthetic Response from \`getCachedResponse()\` in \`src/lib/response-cache.ts\` is indistinguishable from network. Solved via module-level \`lastCacheHitAgeMs\`: set on hit, cleared at top of \`authenticatedFetch()\` per-call (single-process CLI = race-free). \`src/lib/cache-hint.ts\` provides \`formatCacheHint()\` (\`"cached · 3m ago · use -f to refresh"\`) and \`appendCacheHint(existingHint)\` (joins with \` | \`). Wired in \`buildCommand\` (\`src/lib/command.ts\`): \`appendCacheHint(returned?.hint)\` runs only when generator returns a \`CommandReturn\` — bare \`return;\` paths (e.g. \`--web\`) skip the hint. Same chokepoint can host future cross-cutting hint decorators. Test-only \`\_setLastCacheHitAgeForTesting(ms)\` exposes state.
***Raw markdown output for non-interactive terminals, rendered for TTY**: Markdown-first output pipeline: custom renderer in \`src/lib/formatters/markdown.ts\` walks \`marked\` tokens to produce ANSI-styled output. Commands build CommonMark using helpers (\`mdKvTable()\`, \`mdRow()\`, \`colorTag()\`, \`escapeMarkdownCell()\`, \`safeCodeSpan()\`) and pass through \`renderMarkdown()\`. \`isPlainOutput()\` precedence: \`SENTRY\_PLAIN\_OUTPUT\` > \`NO\_COLOR\` > \`FORCE\_COLOR\` > \`!isTTY\`. \`--json\` always outputs JSON. Colors defined in \`COLORS\` object in \`colors.ts\`. Tests run non-TTY so assertions match raw CommonMark; use \`stripAnsi()\` helper for rendered-mode assertions.
***@spotlightjs/spotlight exports only two paths — no formatter/parser access**: The \`@spotlightjs/spotlight\` package's \`exports\` map exposes only \`.\` (main server) and \`./sdk\` (buffer API). Formatter registries (\`humanFormatters\`, \`applyFormatter\`) and parser helpers (\`isErrorEvent\`, type guards) live under \`dist/server/formatters/\` and \`dist/server/parser/\` but are not in \`exports\`. Bun's strict module resolution blocks deep \`dist/\` imports at runtime. Workaround: write inline formatters using the CLI's own color system (\`muted\`, \`bold\`, \`cyan\`, etc.) following the same pattern as Spotlight's human formatters.
***API tests must use useTestConfigDir to isolate disk response cache**: \*\*API tests must use useTestConfigDir to isolate disk response cache\*\*: Tests mocking \`globalThis.fetch\` MUST call \`useTestConfigDir()\` + \`setAuthToken()\`. \`authenticatedFetch\` checks a filesystem response cache (\`~/.sentry/cache/responses/\`) BEFORE calling fetch — without per-test dirs, test N's response is served to test N+1. TTL tiers in \`classifyUrl()\`: stable=5min, volatile=60s (issues/logs), immutable=24h (events/traces by ID). Also: \`@sentry/api\` SDK calls \`\_fetch(request)\` with no init — fall back to \`input.headers\` when \`init\` is undefined (prevents HTTP 415). SDK returns \`data={}\` for empty/204 responses — always guard with \`Array.isArray(data)\` before \`.map()\`. Use \`unwrapPaginatedResult\` (not \`unwrapResult\`) for Link header pagination.
***Biome noUselessUndefined also rejects () => {} empty arrow callbacks**: Biome lint traps: (1) \`noUselessUndefined\` rejects \`() => undefined\` AND \`noEmptyBlockStatements\` rejects \`() => {}\` — use top-level \`function noop(): void {}\`. (2) \`noExcessiveCognitiveComplexity\` caps at 15. (3) \`expect(() => fn()).toThrow(X)\` must be one line. (4) Plugin forbids raw \`metadata\` table queries — use \`getMetadata\`/\`setMetadata\`/\`clearMetadata\`. (5) Also enforced: \`useBlockStatements\`, \`noNestedTernary\`, \`useAtIndex\`, \`noStaticOnlyClass\`, \`useSimplifiedLogicExpression\`, \`noShadow\`. Namespace imports forbidden. (6) \`useYield\` fires on \`async \*func()\` with statements but not empty bodies — only add \`biome-ignore\` to generators with statements. \`lint:fix\` differs from CI \`lint\`: auto-fix hides \`noPrecisionLoss\` on >2^53 literals, \`noIncrementDecrement\`, import ordering. Always \`bun run lint\` before pushing.
***Bun --isolate coverage inflates LF count for files with verbose comments/JSDoc**: Bun --isolate coverage inflates LF count: under \`bun test --isolate --parallel\` (CI's \`test:unit\`), Bun's coverage instrumentation counts comments, blank lines, type annotations, and closing braces as 'executable'. E.g. \`zstd-transport.ts\` LF=165 locally → 210 under --isolate, dropping coverage 99%→78%. Workaround: trim verbose inline comments inside function bodies; move rationale to JSDoc above the function. Statement coverage stays 100% — 'missing' lines are non-executable.
***Bun /$bunfs/ virtual FS uses JS parser — embedded .tsx files fail on TS syntax**: \*\*Bun \`/$bunfs/\` virtual FS + Ink TUI sidecar embedding\*\*: Files embedded via \`with { type: "file" }\` run from \`/$bunfs/root/\` using a JS parser (not TypeScript) — raw \`.tsx\` crashes on \`import { type Foo }\`. Fix: pre-bundle \`.tsx\` → \`.js\` via esbuild before embedding (\`script/text-import-plugin.ts\`). \`/$bunfs/\` has no \`node\_modules\` — inline all deps; use \`createRequire\` banner for CJS deps. Only \`node:\*\` builtins external. Query strings in \`/$bunfs/\` paths cause ENOENT. Related: Ink TUI sidecar (\`ink-app.tsx\`) must be fully self-contained — main bundle must NOT import \`ink\`/\`react\` separately; call \`app.mountApp()\` from the sidecar only to avoid dual-React "Invalid hook call" errors.
***Bun 1.3.11 tty.ReadStream leaks libuv handle — process.stdin.unref is undefined**: Bun 1.3.11 macOS TTY bug: \`process.stdin\` via kqueue \`EVFILT\_READ\` fails to deliver keystrokes when fd 0 is inherited via \`exec bin \</dev/tty\` (curl|bash flow). Linux (epoll) works. Workaround: \`openSync('/dev/tty','r')\` + \`new tty.ReadStream(fd)\` routes through libuv threadpool. Lives in \`src/lib/init/stdin-reopen.ts\`, darwin-gated in \`wizard-runner.ts\` via \`using \_tty\`. Leaks libuv handle → safety net in \`init.ts\`: \`setTimeout(process.exit, 100).unref()\`. Skip under \`NODE\_ENV=test\`.
***MastraClient has no dispose API — use AbortController for cleanup**: MastraClient has no \`close()\`/\`dispose()\` API — cleanup via \`ClientOptions.abortSignal\` (constructor) or per-prompt \`signal\`. Without explicit abort, Bun's fetch dispatcher keep-alive sockets hold the event loop alive past natural exit. Pattern in \`src/lib/init/wizard-runner.ts\`: create \`AbortController\` per \`runWizard\`, pass \`abortSignal: controller.signal\` to \`new MastraClient(...)\`, abort via \`using \_ = { \[Symbol.dispose]: () => controller.abort() }\`. Custom \`fetch\` wrapper must preserve \`init.signal\` via spread. Tests capture \`ClientOptions\` via \`spyOn(MastraClient.prototype, 'getWorkflow').mockImplementation(function() { capturedOpts.push(this.options); ... })\`.
***Multi-region fan-out: distinguish all-403 from empty orgs with hasSuccessfulRegion flag**: In \`listOrganizationsUncached\` (\`src/lib/api/organizations.ts\`), \`Promise.allSettled\` collects multi-region results. Don't use \`flatResults.length === 0\` to detect all-regions-failed — a region returning 200 OK with zero orgs pushes nothing into \`flatResults\`. Track a \`hasSuccessfulRegion\` boolean on any \`"fulfilled"\` settlement. Only re-throw 403 \`ApiError\` when \`!hasSuccessfulRegion && lastScopeError\`.
1069
+
For long-term knowledge entries managed by [lore](https://github.com/BYK/loreai) (gotchas, patterns, decisions, architecture), see [`.lore.md`](.lore.md) in the project root.
- Replace `bun run src/bin.ts` with `tsx src/bin.ts` (add `tsx` devDependency)
61
+
- Replace `bun run script/*.ts` with `tsx script/*.ts`
62
+
- Replace `bunx` with `pnpm exec`
63
+
- Update GitHub Actions workflows to use pnpm + Node.js instead of Bun
64
+
- Update `Dockerfile` / build scripts if applicable
65
+
66
+
### Phase 5: Cleanup
67
+
68
+
- Remove `@types/bun` from devDependencies
69
+
- Remove `bun.lock` (replaced by `pnpm-lock.yaml`)
70
+
- Remove or update `script/node-polyfills.ts` (may become unnecessary)
71
+
- Update `AGENTS.md` Bun API reference table
72
+
- Remove Bun-specific `.cursor/rules/bun-cli.mdc` or update for Node.js
73
+
- Clean up any remaining `Bun.*` references in comments/docs
74
+
75
+
## Known Issues
76
+
77
+
-`test/lib/index.test.ts` — `sdk.run throws when auth is required but missing` fails under pnpm's strict `node_modules`. The mock fetch returns empty 200s which prevents the expected auth error from being thrown. Pre-existing test fragility, not caused by migration changes.
0 commit comments