Repository navigation
ref(toolkit-core): Start the shared API client with errors and response reading - #1732
Merged
Merged
Conversation
Lint bans node:* imports and Node globals in toolkit-core, and a second typecheck runs it against the DOM library with no Node types. The cache codec keeps node:zlib; its types move to body.ts so the policy and stores stay portable.
validateResponse takes any Standard Schema validator, so the MCP keeps Zod and the CLI keeps valibot. toolkit-core depends only on the interface's types, and lint now bans zod and valibot imports in shared modules.
Nothing loads mcp-core's CJS output. The package is private, "type": "module", and all 29 exports point at .js with no "require" condition, so require() would resolve to the ESM files anyway. Its consumers are workspace-only: mcp-server bundles it as a devDependency through those .js exports, mcp-cloudflare bundles it with Vite, and mcp-test-client and mcp-server-evals are private and ESM. No source in the repo requires it or reads its .cjs files. Dropping the CJS build also avoids the rolldown "canonical name not found" panic hit by the CJS pass once the API errors move to toolkit-core. mcp-server's own CJS+ESM output is unchanged.
Generated by the ts-morph codemod move-shared-errors.mjs (script in the PR description), run from a scratch directory with ts-morph@28.0.0 installed: node move-shared-errors.mjs <repo-root> oxfmt <added and modified files> It moves mcp-core's api-client/errors.ts, api-path.ts, and api-path.test.ts into toolkit-core/src/api-client/, moves UserInputError and ConfigurationError into the shared errors module (mcp-core/src/errors.ts re-exports them), and rewrites every importer.
The codemod moved api-path.test.ts into toolkit-core, but its second block reads mcp-core's client.ts source to check every request path uses apiPath. That block moves back to mcp-core until client.ts moves too.
readErrorResponse reads a failed response once: its text, parsed JSON, the server's string `detail`, whether it is an HTML page, and the rate-limit wait. Each host maps that to its own errors. readJsonResponse is the MCP's Content-Type-checked JSON parse, moved here for both.
Generated by the ts-morph codemod use-shared-json-response.mjs (script in the PR description), run from a scratch directory with ts-morph@28.0.0 installed: node use-shared-json-response.mjs <repo-root> oxfmt packages/mcp-core/src/api-client/client.ts It rewrites the 18 `this.parseJsonResponse(...)` calls in SentryApiService to toolkit-core's readJsonResponse, deletes the private method, and imports the shared one.
SentryApiService.request reads a failed response with toolkit-core's readErrorResponse and maps it to ApiError subclasses as before: the same messages, details, retryAfterMs, and warnings. The Zod ApiErrorSchema it used for the `detail` check is gone. Two small changes: if the error body cannot be read, the caller now gets an ApiError for the status instead of the stream error, and the "no string detail" warning's validationErrorMessage is a fixed string instead of Zod's message.
throwRawApiError takes the body, parsed JSON, and `detail` from toolkit-core's readErrorResponse instead of parsing them itself. The detail it puts on ApiError is unchanged: the server's string detail, the JSON body for statuses other than 401 and 403, the text for non-JSON bodies, and the status text when the body cannot be read.
The toolkit-core README covers the api-client modules and their portability guard, api-patterns.md says where ApiError and error reading live now, and the error-handling doc and logging skill point at the moved errors module.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
BYK
approved these changes
Oct 29, 2026
BYK
enabled auto-merge (squash)
October 29, 2026 19:43
This was referenced Oct 29, 2026
sentry-junior Bot
added a commit
that referenced
this pull request
Oct 29, 2026
… 8.3 and 8.4 Co-Authored-By: BYK <burak.kaya@sentry.io>
BYK
added a commit
that referenced
this pull request
Oct 29, 2026
… api-client (#1736) Moves pagination, the response-cache policy, retry, and transport under `toolkit-core/src/api-client/`, the layout they will have inside `@sentry/api` (#1669, task 8.3). Every importer is rewritten. Nothing else changes. It's the second PR in the group 8 stack. #1732, the foundation, has merged, so this one targets `main`. ## What changes - **Moves.** Only the relative imports inside the moved files change: - `pagination.ts` → `api-client/pagination.ts` - `api-retry.ts` → `api-client/retry.ts` - `api-transport.ts` → `api-client/transport.ts` - `response-cache/{body,index,invalidation,keys,memory-store,policy,store,tiers}.ts` → `api-client/response-cache/` - Their tests move with them. - **Stays put:** `response-cache/codec.ts`. It's the `node:zlib` codec, host storage that won't move into `@sentry/api`. It's still excluded from the browser typecheck, and the `./response-cache/codec` export doesn't change. - **Exports:** `./pagination`, `./api-retry`, `./api-transport`, and `./response-cache` are replaced by the existing `./api-client/*` wildcard plus one `./api-client/response-cache` entry for the directory index. `@sentry/toolkit-core` is `private`, and every consumer is in this workspace and rewritten here. - **Importers.** The codemod rewrites 11 import specifiers across the CLI (including `script/generate-api-schema.ts`), `mcp-core/src/api-client/client.ts`, and toolkit-core. - **Docs:** `api-patterns.md`, the toolkit-core README, and code comments name the new subpaths. ## Behavior changes None. This PR does not touch `packages/mcp-server`, `packages/cli/src/lib/mcp.ts`, or the evals stdio entry. The `@sentry/mcp-server` retirement PR owns those. ## Commits 1. `85fae9151` Move the modules and rewrite importers (**generated**, `move-transport-layer.mjs`) 2. `85df504be` Point comments and docs at the new paths (hand) ## Verification - The generated commit reproduces exactly: check out `origin/main` (`9409280c1`), run the command below, then oxfmt on the changed files. The tree matches `85fae9151`. - `pnpm run tsc` (including toolkit-core's browser typecheck), `pnpm run lint`, and `node scripts/check-doc-links.mjs` pass. - Tests: toolkit-core 306 passed; mcp-core 1881 passed, 6 skipped; mcp-cloudflare 443 passed; mcp-server 87 passed; CLI `test/lib test/commands test/script` 11895 passed, 46 skipped, **6 failed**. - The 6 CLI failures are sandbox-only, and they fail the same way without this change. The sandbox runs with `CAP_DAC_OVERRIDE`, so these permission tests can't make a file unreadable: `completions` (EACCES, EPERM), `dsn/code-scanner` (unreadable file), `init/tools/file-changes` (I/O failure), `telemetry` (read-only DB), and `upgrade` (`acquireLock` permission error). CI runs them normally. ## Codemod The script isn't in the tree. To re-run it, check out the parent of the generated commit and run it from a scratch directory with `ts-morph@28.0.0` installed. Then run oxfmt on the added, modified, and renamed package files. <details> <summary><code>move-transport-layer.mjs</code> (commit 85fae91)</summary> ```sh node move-transport-layer.mjs <repo-root> git add -A -- packages oxfmt $(git diff --cached --name-only --diff-filter=AMR) ``` ```js // Codemod: move toolkit-core's pagination, response-cache policy, api-retry, // and api-transport modules under src/api-client/, and rewrite every // importer and the package's exports. The node:zlib cache codec stays at // src/response-cache/codec.ts as a host-side module. // // Usage: node move-transport-layer.mjs <toolkit-repo-root> // (run from a directory where `ts-morph@28.0.0` is installed) import { readFileSync, writeFileSync } from "node:fs"; import path from "node:path"; import { Node, Project } from "ts-morph"; const root = path.resolve(process.argv[2] ?? "."); const coreDir = path.join(root, "packages/toolkit-core"); const coreSrc = path.join(coreDir, "src"); // Old path -> new path, relative to toolkit-core/src. const MOVES = new Map([ ["pagination.ts", "api-client/pagination.ts"], ["pagination.test.ts", "api-client/pagination.test.ts"], ["api-retry.ts", "api-client/retry.ts"], ["api-retry.test.ts", "api-client/retry.test.ts"], ["api-transport.ts", "api-client/transport.ts"], ["api-transport.test.ts", "api-client/transport.test.ts"], ]); const CACHE_FILES = [ "body.ts", "index.ts", "invalidation.ts", "invalidation.test.ts", "keys.ts", "keys.test.ts", "memory-store.ts", "memory-store.test.ts", "policy.ts", "policy.test.ts", "policy.property.test.ts", "store.ts", "tiers.ts", "tiers.test.ts", ]; for (const file of CACHE_FILES) { MOVES.set(`response-cache/${file}`, `api-client/response-cache/${file}`); } // Package subpath -> new subpath. `response-cache/codec` does not move. const SPECIFIERS = new Map([ ["@sentry/toolkit-core/api-retry", "@sentry/toolkit-core/api-client/retry"], [ "@sentry/toolkit-core/api-transport", "@sentry/toolkit-core/api-client/transport", ], [ "@sentry/toolkit-core/pagination", "@sentry/toolkit-core/api-client/pagination", ], [ "@sentry/toolkit-core/response-cache", "@sentry/toolkit-core/api-client/response-cache", ], ]); // 1. Move the files inside toolkit-core. ts-morph rewrites relative imports // in and to them; then give every rewritten specifier the `.js` suffix // the package uses. const core = new Project({ tsConfigFilePath: path.join(coreDir, "tsconfig.json"), }); const moved = new Set(); for (const [from, to] of MOVES) { const sourceFile = core.getSourceFileOrThrow(path.join(coreSrc, from)); sourceFile.move(path.join(coreSrc, to)); moved.add(sourceFile.getFilePath()); } for (const sourceFile of core.getSourceFiles()) { const importer = sourceFile.getFilePath(); for (const declaration of [ ...sourceFile.getImportDeclarations(), ...sourceFile.getExportDeclarations(), ]) { const target = declaration.getModuleSpecifierSourceFile(); if (!target || !declaration.getModuleSpecifierValue()?.startsWith(".")) { continue; } const targetPath = target.getFilePath(); if (!moved.has(importer) && !moved.has(targetPath)) continue; let specifier = path.relative( path.dirname(importer), targetPath.replace(/\.ts$/, ""), ); if (!specifier.startsWith(".")) specifier = `./${specifier}`; declaration.setModuleSpecifier(`${specifier}.js`); } } await core.save(); // 2. Rewrite package specifiers everywhere else, including dynamic imports // and vi.mock() calls: any string literal equal to an old subpath. const others = new Project({ skipAddingFilesFromTsConfig: true }); others.addSourceFilesAtPaths([ path.join(root, "{packages,apps}/*/{src,test,script,scripts}/**/*.{ts,tsx,mts}"), `!${path.join(root, "**/node_modules/**")}`, `!${path.join(root, "**/dist/**")}`, `!${path.join(coreDir, "**")}`, ]); let rewritten = 0; for (const sourceFile of others.getSourceFiles()) { let changed = false; sourceFile.forEachDescendant((node) => { if (!Node.isStringLiteral(node)) return; const next = SPECIFIERS.get(node.getLiteralValue()); if (next) { node.setLiteralValue(next); changed = true; rewritten += 1; } }); if (changed) await sourceFile.save(); } // 3. Point the package exports at the new paths. The `./api-client/*` // wildcard covers pagination, retry, and transport; the cache needs its // index. const manifestPath = path.join(coreDir, "package.json"); const manifest = JSON.parse(readFileSync(manifestPath, "utf8")); const exports = {}; for (const [key, value] of Object.entries(manifest.exports)) { if (["./api-retry", "./api-transport", "./pagination", "./response-cache"].includes(key)) { continue; } if (key === "./api-client/*") { exports["./api-client/response-cache"] = { types: "./src/api-client/response-cache/index.ts", default: "./src/api-client/response-cache/index.ts", }; } exports[key] = value; } manifest.exports = exports; writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); console.log(`moved ${moved.size} files, rewrote ${rewritten} specifiers`); ``` </details> <!-- junior-request-attribution:start --> via **BYK**. <!-- junior-request-attribution:end --> <!-- junior-session-footer:start --> <!-- junior-conversation-id:agent%3Aa6eddc0161cff61914454da9f74fcdf1 --> -- [View Junior Session in Sentry](https://sentry.sentry.io/explore/conversations/agent%3Aa6eddc0161cff61914454da9f74fcdf1/?project=4510944073809921) <!-- junior-session-footer:end --> --------- Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com> Co-authored-by: BYK <burak.kaya@sentry.io>
BYK
added a commit
that referenced
this pull request
Oct 29, 2026
…mar (#1730) Part of #1564. Dashboard commands parsed their positionals by hand inside `func`, and issue commands used their own grammar (#1729). This moves both onto the shared ID grammar (`grammar/id-arguments.pegjs`, #1714), parsed before `func` runs. Event view's issue checks (#1733, #1738) use the new issue kind too. **Shared grammar: kinds with names.** `IdKind.names` adds one idea to `id-arguments.pegjs`: a kind may name an item without its ID, and anything that is not, and may not be, an ID is a name. Kinds without names keep their grammar paths exactly as before. Kinds with names keep each line whole (no splitting at spaces), so `Top 10` stays one title and never becomes title `Top` + ID `10`. - `ID_KINDS.dashboard`: a numeric ID or a title, which may hold spaces and slashes (`Latency/p95`). `<org>/[<project>/]<digits>` reads as a path only when slugs come before the digits, so `Errors.v2/123` and `/123` are titles. After a target, the title takes the rest of the arguments (`my-org/ My Dashboard`). A bare first word names an org (`orgScoped`). - `ID_KINDS.issue`: an identifier (numeric ID, short ID, selector, issue URL) is one whole token (`wholeIds`). `src/lib/issue-identifier.ts` takes it apart with the #1729 grammar, which is unchanged. Text with spaces is a name, meaning a search. - `dashboard-arguments.pegjs` is gone. `dashboard list` keeps its thin `parseDashboardListArgs`, because a bare word there is a title filter (see #1711). **Bare first word: org or title?** For `dashboard view My Dashboard`, the parser makes no decision. It returns the structural reading (org `My`, title `Dashboard`) and the whole input as one title (`nameWithTarget`, surfaced as `orgOrTitle`). `resolveDashboardInput` decides after auth: - First it checks whether `My` is an org: the cached org list and region cache, then `GET /organizations/My/` only on a cache miss. - If the org exists, the title lookup in that org is final, even when it misses. - On a 404 or 403 it warns ``No org 'My'; treating "My Dashboard" as the dashboard title. Use my-org/ to name an org.`` and looks up "My Dashboard" in the auto-detected org. - If that misses too, one error names both readings (no org `My` to find `Dashboard` in, and no `My Dashboard` in `<detected-org>`) and hints at `<org>/ Dashboard` and at quoting. - A 5xx or network error from the org check propagates, with no fallback. - It never falls back for `my-org/ …` (explicit org), a numeric ref, or a URL. **Issue search text.** `issue view "login timeout"` resolves through `GET /organizations/{org}/issues/?query=…` in the detected org. One hit is the issue. Zero or several hits raise a `ResolutionError` that lists up to 5 candidates as runnable commands and points at `sentry issue list <org>/ --query '…'`. I checked the endpoint against getsentry/sentry (`organization_group_index.py`, `group_index/index.py`): `query` takes free text, an exact event ID or short ID gets a fast lookup, and an explicit query replaces the default `is:unresolved`. **Search hints.** Text where a trace, span, log, or replay ID belongs (`trace view login`) now fails with ``Not a trace ID: "login". To search, try `sentry trace list --query 'login'`.``. The hint comes from `validate()`, so commands that recover malformed IDs (`trace view`, `span view`, `log view`) recover first and use the hint only as their final error. Event IDs get no hint, because `event list` lists one issue's events. **event view.** `ID_KINDS.issue.distinctForm` (uppercase short ID or numeric) replaces `looksLikeIssueShortId` + `isAllDigits` and keeps #1738's order: `<org>/<short-id>`, then `<short-id>/<event-id>` (even an all-digit event ID), then `<org>/<numeric-id>`. I added a regression test for the all-digit event ID and one for that order. **Behavior changes:** - `dashboard view my-org My Dashboard` (unquoted title) looks up "My Dashboard". Before, it used `My` and dropped `Dashboard`. The same goes for `my-org/ My Dashboard` and `https://acme.sentry.io/ My Dashboard`. - `dashboard view My Dashboard`: when there is no org `My` (404/403), it falls back to the title "My Dashboard" in the detected org, with the warning above. If neither reading finds a dashboard, one error names both. Dashboard commands with one dashboard ref get this (`view`, `restore`, `revisions`, `widget edit/delete`, and `widget add` after it splits off its widget title). - A numeric ref first is the dashboard, as with every ID kind: `dashboard view 42 X`, `my-org/42 X`. Before, the first of two arguments was always the target. After a target, a numeric ID keeps the rest as extra (`my-org 123 extra` → ID 123, ignored `extra`) instead of joining them into a title. Arguments after the ID go through the shared rules: extra, reversed (`42 my-org/`), or the shared "reference different projects" error when they name another target. - A lone non-Sentry URL is no longer taken as a dashboard title. - `issue view "login timeout"` (text with spaces) searches instead of failing as a malformed identifier. Control characters and URLs are still rejected. - Trace/span/log/replay IDs that are plain text get a search hint instead of "Invalid trace ID". - Parse errors (no dashboard, an org URL without a dashboard, a dashboard URL passed to `list`, an invalid target slug) fail before the auth guard, as in the earlier commits on this branch. They print `Failed to parse "…" for <placeholder>: …` and exit 252. - `widget add/edit/delete`: an argument error comes before flag errors like "Specify --index or --title". `widget add`'s positional completes cached dashboards. `parseDashboardTarget` had no callers left and is removed. **Lint ratchet (#1739):** the dashboard entries are off both allow-lists, since these commands now parse before `func`. The issue entries (`issue/utils.ts`, `issue/merge.ts`, which need an array issue positional) stay. **Syncing:** this branch merges `main` (no rebase). 54ebfa2 and 7f52f19 merge #1729, #1732–#1734, #1736, #1738 and #1739. Verification: - `tsc`, `pnpm run lint` (oxlint, format, ast-grep) and `scripts/cli-lint-rules.test.mjs` (70/70) pass. - vitest on `test/lib`, `test/grammar` and the dashboard, issue, event, trace, span, log, replay and feedback command tests: 10,158 passed. The 6 failures are the sandbox-only permission tests (completions EACCES/EPERM, code-scanner, file-changes, telemetry readonly, upgrade lock), which also fail on `main`. The full CLI suite shows the same 6, plus e2e/eval files that need a build or credentials. - New tests: - The bare-org fallback: the org from cache and from the API (no fallback), org missing then fallback hit with the warning, a 403, org missing then fallback miss with the combined error, a 5xx (propagates, no fallback), `my-org/ My Dashboard`, and a numeric ref. - Issue search with 0, 1 and several hits. - Search hints, including `validate: false` deferral. - #1738's event view order. - Differential runs against this PR's previous parsers: - Issue arguments: 8,575 cases. 1,388 former errors are now searches (text with spaces), with 0 other differences. - Dashboard view: 32,552 cases over 0–3 arguments. Every difference is in one of the categories above: a numeric ID first (2,600), arguments after a dashboard URL that name another target (688), a numeric ID after a target with more words (475), and a lone non-Sentry URL (1). <!-- junior-request-attribution:start --> via **BYK**. <!-- junior-request-attribution:end --> <!-- junior-session-footer:start --> <!-- junior-conversation-id:agent%3A5a5e7e4543124325a44d731c08dd6089 --> -- [View Junior Session in Sentry](https://sentry.sentry.io/explore/conversations/agent%3A5a5e7e4543124325a44d731c08dd6089/?project=4510944073809921) <!-- junior-session-footer:end --> --------- Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com> Co-authored-by: BYK <burak.kaya@sentry.io>
sentry-junior Bot
added a commit
that referenced
this pull request
Oct 30, 2026
main moved response parsing into toolkit-core's readJsonResponse (#1732, #1737), which still throws a plain Error for an empty or non-JSON body. validateEvents is the only caller that lets a 400 reach that parser, so classify its non-JSON 400s there with createApiError. Successful non-JSON responses stay reportable.
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Starts the shared Sentry API client in
toolkit-core/src/api-client/(step 1 of #1669, task group 8). The MCP and the CLI both use it for errors, API paths, and response reading.It is the first of a stack of PRs by layer (see "Next" below).
What changes
Portability guard (8.1). Lint bans
node:*imports and Node globals such asBufferandprocessintoolkit-core. A second typecheck (tsconfig.browser.json) checks it against the DOM library with no Node types, andpnpm run tscruns both. Thenode:zlibcache codec is the one exception. Its types move toresponse-cache/body.ts, so the policy and store modules stay portable.Standard Schema validation.
validateResponsetakes any Standard Schema validator: Zod from the MCP, valibot from the CLI.toolkit-coredepends only on@standard-schema/spectypes. Lint banszodandvalibotimports in its source; they are dev dependencies for the tests only.Shared errors and
apiPath.ApiError, its status subclasses,createApiError,UserInputError,ConfigurationError, andapiPathmove frommcp-coreto@sentry/toolkit-core/api-client/*.mcp-core/src/errors.tsre-exports the two general errors, so its importers don't change.Shared response reading.
readErrorResponsereads a failed response once: its text, parsed JSON, stringdetail, whether it is an HTML page, and the rate-limit wait.readJsonResponseis the MCP's Content-Type-checked JSON parse.SentryApiServiceuses both.throwRawApiErrorusesreadErrorResponse.ApiErrorsubclasses, CLI exit-codedApiError).mcp-core builds ESM only. Once the errors moved, the CJS build hit a rolldown "canonical name not found" panic. Nothing loads that CJS output:
@sentry/mcp-coreisprivateand"type": "module"..js, with norequirecondition.mcp-serverbundles it as a devDependency through those.jsexports,mcp-cloudflarebundles it with Vite, andmcp-test-clientandmcp-server-evalsare private ESM packages..cjsfiles.@sentry/mcp-server's own CJS and ESM output is unchanged. I tried upgrading tsdown first, to 0.15.12, 0.18.4, 0.20.3, 0.22.14, and 0.23.4. Every version broke themcp-server-mocksbuild: 0.15.12 failed declaration output (members is not iterable), and 0.18.4 and later hit a rolldown JSON parse "recursion limit exceeded" onsrc/fixtures/trace.json. 0.18.4 and 0.20.3 also failed themcp-coreandmcp-serverbuilds. Bundling toolkit-core into the dist (noExternal) would have duplicated the error classes across dists and brokeninstanceofbetween packages.Docs. The
toolkit-coreREADME now has an "API client" section.api-patterns.md,error-handling.md, and the logging skill point at the new error module.Behavior changes
ApiErrorfor the status instead of the raw stream error.validationErrorMessageon the "Failed to parse validated API error response" warning is now a fixed string instead of Zod's message.ApiErrorSchemais deleted; nothing else used it.Messages, details,
retryAfterMs, and the CLI's error detail are otherwise unchanged.Next
This is the bottom of a stack of PRs by layer for the rest of #1669 group 8. Each one is based on the PR below it:
api-client/.@sentry/api, withSentryApiServiceswitched onto them.lib/api/wrappers switched onto the shared client.This PR does not touch
packages/mcp-server,packages/cli/src/lib/mcp.ts, or the evals stdio entry; the@sentry/mcp-serverretirement PR owns those.Commits
Each codemod run is a generated commit whose message gives the command, and each hand fix is a separate commit:
13053adabPortability guard (hand)f13df0d24Standard Schema validation (hand)bea21d648mcp-core ESM only (hand)0d083bdf3Move errors andapiPath(generated,move-shared-errors.mjs)4ddc54813Move theclient.tsrequest-path test back next toclient.ts(hand)143da6e39Shared response reading (hand)b776eb55bMCP JSON parsing on the shared reader (generated,use-shared-json-response.mjs)44976334dMCP error responses on the shared reader (hand)7027a482dCLI raw error responses on the shared reader (hand)bf0b248acDocs (hand)Codemods
The scripts are not in the tree. To re-run one, check out the parent of its generated commit, run the script from a scratch directory with
ts-morph@28.0.0installed, then run oxfmt on the changed files. The output should match the commit.move-shared-errors.mjs(commit 0d083bd)use-shared-json-response.mjs(commit b776eb5)Verification
At
bf0b248ac, rebased onmainafter #1722 merged:pnpm run tscpasses. It includes toolkit-core's browser-target typecheck and the CLI typecheck.pnpm run lintpasses (oxlint, oxfmt, ast-grep rules), and so doespnpm run docs:check.pnpm run testalso passed mcp-server (87), mcp-test-client (80), docs-mcp (49), local (322), and cli-docs.test/lib,test/commands): 11718 pass and 6 fail in 5 files (completions,dsn/code-scanner,init/tools/file-changes,telemetry,upgrade).CAP_DAC_OVERRIDE, so achmod 000file stays readable.via BYK.
--
View Junior Session in Sentry