package.jsonpins the root development runner and its V8 coverage provider to 5.0.1 so the hoisted runner can load coverage..gitignoreexcludes the.vitest/artifact directory.package-lock.jsonandbun.lockresolve Vitest and V8 coverage 5.0.1 across every workspace, including evals.package.jsonoverrides vitest-evals 0.17.0's Vitest peer edge to 5.0.1.bun.lockretains configuration version 0 and the existing hoisted install layout.
- PTY and codemode invoke the hoisted runner without declaring it. A root pin makes their shared runner version explicit under both npm and Bun.
- vitest-evals 0.17.0 declares Vitest
>=4 <5. Its npm peer override makes the single-major installation explicit; runtime tests and TypeScript checks verify compatibility instead of preserving a split runner graph. - Bun hoists the harness beside the root runner even when a lock entry requests workspace nesting. Keeping every runner on 5.0.1 avoids mixed TaskMeta types without changing the native workflows' root dependency paths.
- Package managers select test runners and resolve peer dependencies before extensions load.
- The root development dependencies and generated dependency locks.
package.json: the rootdevscript isnode scripts/run-workspaces.mjs --parallel --workspace packages/ai --workspace packages/coding-agent dev; theconcurrentlydevDependency is removed andshell-quote1.10.0 is declared as a root devDependency — three repository scripts import it directly but it only reachednode_modulesasconcurrently's transitive dependency (its version was already pinned by the root override).package-lock.json/bun.lockare regenerated the repository way (bun.lockstaysconfigVersion: 0).
concurrentlywas the last root script that bypassed the package-manager-agnostic runner from #1447;npm run dev,bun run devandpnpm run devnow all start both lanes through the same driver, with prefixed output and one Ctrl-C reaching every lane (senpi#1895).
- Root scripts and the dependency closure are resolved by the package manager before any extension loads.
- The root
scripts.devline and the root devDependency block, on every upstream tooling bump.
package.json: the rootoverridesblock movesfast-urito 3.1.8,brace-expansionto 5.0.12 and@anthropic-ai/sdkto 0.127.0, and gainsexpress-rate-limit8.7.0,hono4.13.8,ip-address10.7.2,qs6.16.0 and a nested@earendil-works/gondolin>undici6.28.1.@types/nodemoves to 26.6.2,@biomejs/biometo 2.5.14 andtsxto 4.23.13.biome.json: the$schemaURL follows the Biome pin to 2.5.14.packages/telemetry/package.json:@types/nodemoves to 26.6.2.
- Every advisory
npm auditandbun auditcould reach came in through a transitive edge the fork does not declare:fast-uriandajv, and the@modelcontextprotocol/sdksubtree that carrieshono,qsandexpress-rate-limit>ip-address.scripts/regenerate-bun-lock-isolated.mjsseeds its island with the committedbun.lock, so re-resolving only the npm lock left Bun on the vulnerable copies; declaring the versions as overrides moves both lockfiles together without drifting the 56 unrelated transitives a from-scratch Bun resolution touched. tsxstops at 4.23.13 because 4.23.14 and 4.23.15 were both published 2026-09-20, inside the.npmrcmin-release-age=2window npm enforces.
- Dependency resolution and formatter configuration are read by the package manager and the toolchain before any extension is loaded.
- LOW: the
overridesblock and the devDependency versions, on every upstream manifest bump.
.devcontainer/devcontainer.jsonexposes an optional B.AI secret alongside the other provider keys.pi-test.sh,pi-test.ps1,test.sh, andpackages/coding-agent/scripts/qa-app-server/lib/env.mjsscrubBAI_API_KEYfrom hermetic test processes.
- The native B.AI provider should work consistently in local checkouts and dev containers without storing credentials in tracked files.
- Development environment bootstrapping and container secret declarations run before Senpi or its extensions.
- LOW: the provider-key arrays in the setup script and devcontainer secret block.
package.json: the rootcheckscript now runsbiome check --error-on-warnings .(read-only) instead ofbiome check --write --error-on-warnings ., so format drift fails the script rather than being silently repaired. A newcheck:fixscript keeps the autofix form (biome check --write --error-on-warnings . && npm run check) for local use..husky/pre-commit: runsnpm run check:fix, preserving the hook's existing autofix-then-verify behavior now thatcheckno longer writes..github/workflows/releasability.yml: drops the hand-inlined read-only biome step plus its verbatim copy of the remaining check sub-scripts and callsnpm run checkdirectly; that workaround existed only becausecheckautofixed, and its copy had already drifted from the real chain (missingcheck:entry-graphsandcheck:claude-sdk-platform-lock).
- #1443: the CI
Static checksjob runsnpm run check, whose leadingbiome check --writereformats offending files inside the runner and exits 0. The rewrite is discarded when the runner exits, so a formatting regression could never fail CI while drift accumulated on main. RootAGENTS.mdalso requires the local check and CI to stay in sync; with autofix in the shared script they disagreed by construction.
- The root
package.jsonscript chain, the Husky hook, and the workflow step are build-time and repository-policy gates that execute before any Senpi runtime loads; no runtime extension participates in them.
- LOW: the
checkscript string in rootpackage.jsonand the adjacentcheck:fixentry. - LOW: the check invocation line in
.husky/pre-commit.
claude-sdk-oauth re-login refreshes the slot; stored pool blocks bind to credential revisions (2026-09-17)
packages/coding-agent/src/core/extensions/builtin/anthropic-subscription/accounts.ts: newupsertAccount()— a same-name slot is replaced in place (fresh token material, block stamps cleared,displayNamepreserved); unknown names still append.packages/coding-agent/src/core/extensions/builtin/anthropic-subscription/oauth-login.ts: a re-login now targets an existing slot instead of mintingaccount-N+1— a lone slot or the pool's oneauth_error-blocked slot is refreshed in place; anything else stays append-only unless the user types an existing name, so a blank or headless re-login never overwrites the newest working slot in a multi-account pool. The Anthropic import is now a move: accepting it removes the grant from theanthropicprovider so two stores never refresh one single-use token.packages/coding-agent/src/core/extensions/builtin/anthropic-subscription/index.ts: wiresremoveAnthropicCredentialthrough the locked auth.json backend.packages/coding-agent/src/core/extensions/builtin/anthropic-subscription/{affinity,guidance,stream-guidance}.ts:AllAccountsBlockedErrorcarries the dominant block reason and the all-blocked guidance names an authentication failure explicitly, so the outer credential-pool classifier maps it toauth_errorinstead of laundering it into a rate-limit cooldown via the generic "(rate limit or auth errors)" wording.packages/coding-agent/src/core/credential-pool/{state-store,rotation-stream}.tsandpackages/coding-agent/src/core/credential-accounts.ts: stored-lane sidecar health is bound to a credential revision (HMAC over the installation key and slot material, never raw material) — the stored-lane twin of the env revision rule — so a re-login or token refresh retires the block the old material earned. Legacy rows without a revision are retired on first read.- Tests: new
test/claude-sdk-oauth-login-refresh.test.ts(refresh matrix, import move, dominant reason) andtest/credential-pool-stored-revision.test.ts(legacy/foreign/current revision, revision stamping);test/credential-error-taxonomy.test.tsgains the guidance→classifier composition cases;test/credential-accounts.test.tsandtest/model-runtime-credential-rotation.test.tsfixtures now stamp the matching revision for blocks that must apply.
- omo#7084 (two fresh field reports on 2026.9.16-3):
/login claude-sdk-oauthnever refreshed the existing slot — it appendedaccount-N+1or threw on a duplicate name — whileauth_errorblocks were permanent by design ("until login refreshes the slot"), so the documented recovery could never fire and the pool dead-ended at "blocked until re-login". The import path also copied the Anthropic grant into a second store, guaranteeing a laterinvalid_grant. - omo#8383: the lane's generic all-blocked wording let the outer classifier string-match "rate limit" and stamp a cooldown for what was a 401 revocation, and the stored lane's sidecar had no credential-replacement signal at all, so blocks outlived the credential that earned them.
- The slot store, the OAuth login flow, the failover block policy, and the credential-pool sidecar are engine internals; the recovery contract spans the lane's auth.json stamps and the generic pool's sidecar, which no extension surface reaches.
packages/coding-agent/src/core/extensions/builtin/anthropic-subscription/oauth-login.ts(login naming and the import branch).packages/coding-agent/src/core/credential-pool/rotation-stream.ts(stored-lane listing andpersistBlock).
tsconfig.jsonincludesscripts/qa/**/*.tsso roottsc --noEmittype-checks the qa runners.package.json:npm run checkalso runstsc --noEmit -p scripts/tsconfig.jsonafter the root program.
scripts/qa/*.tssat outside every tsconfig, so implicit-any import errors there never failed CI.
- Root
tsconfig.jsoninclude globs and thepackage.jsoncheckscript are compile-time gates; no runtime extension can add files totsc.
- LOW: the
includearray in roottsconfig.jsonand thecheckscript string in rootpackage.json.
package.json:npm run checkrunscheck:entry-graphsaftercheck:ts-imports, matching the original 5507d76ee gate.scripts/check-entry-graphs.mjsprints each entry's file count on success so a green run still reports the harness/session size.packages/agent/src/harness/messages.ts: session no longer value-imports the AI barrel; seepackages/agent/src/changes.md.
- The session subpath is a cost contract (budget 25, no
packages/ai/src/index.ts). The script existed but was not incheck, so the barrel regression stayed red until someone ran it by hand.
- Root
package.jsonscripts and the source import graph are build-time inputs; no runtime extension can restore either.
- LOW: the
checkscript string in rootpackage.json.
packages/chord/package.jsonreturns to upstream's own0.85.1version instead of the fork CalVer stamp, so the bundled workspace keeps@earendil-works/chord's published release identity.
- chord is bundled into the senpi tarball but the fork does not publish it. CalVer-stamping it made the packaged manifests declare
@earendil-works/chord@^<CalVer>, which no registry version answers, sobun add @code-yeongyu/senpifailed (issue #1632). Keeping chord on upstream's0.85.1— which exists on the registry and is byte-for-byte our bundled copy apart from packaging metadata — makes every declared edge resolvable while the bundled copy shadows it at runtime.
packages/chord/package.jsonis static manifest data consumed by the package manager and the release/publish pipeline, never reachable from the runtime extension system.
- The
versionfield inpackages/chord/package.json.
pi-test.shandpi-test.ps1addVENICE_API_KEYto the provider credentials cleared before the suite runs, alongside the existingCEREBRAS_API_KEY/XAI_API_KEYentries.test.shandpackages/coding-agent/scripts/qa-app-server/lib/env.mjsgained the same entry.
- Venice is now a built-in provider, and several suites key opt-in live behavior off the mere presence of a provider API key. Leaving
VENICE_API_KEYin the inherited environment would let a developer's real credential change test behavior or reach the network.
- These are the shell entry points that build the test environment before any senpi process starts.
- LOW: the
unset/credential-name lists inpi-test.shandpi-test.ps1when upstream adds providers.
package.json:test,clean,eval,dev,dev:tsc,generate:models,generate:model-catalog,hydrate:model-data, andcheck:model-datadelegate into workspaces throughnode scripts/run-workspaces.mjs [--if-present] [--workspace <path>] <script>instead ofnpm run --workspaces --if-present <script>,npm --workspace=<name> run,npm --prefix <dir> run, orcd <dir> && npm runlanes inside concurrently.devkeeps only thepackages/aiandpackages/coding-agentlanes, the two workspaces that define adevscript.version:*keepnpm version --workspaces(npm's version bookkeeping, not a script delegation);refresh-lock,publish*, andrelease*are untouched.
- Under bun the old shapes worked only where bun happened to rewrite
npm runtobun run, and bun's--workspacesfans out in parallel while npm runs sequentially;--prefix,--workspace=, andcd <dir> && npm runnever reach bun or pnpm and always execute real npm, against thescripts/AGENTS.mdrule of not hardcoding the child package manager. The runner executes every workspace script with the manager that launched the root script, sequentially and in path order, with one PASS / SKIP / FAIL summary, sobun run test,npm run test, andpnpm run testbehave identically. Thepackages/agentandpackages/tuidev lanes pointed at scripts that do not exist.
- Root manifest scripts run before any Senpi runtime starts; the package manager is the only surface above them.
- LOW: the nine script lines in the root
package.jsonscriptsblock. Upstream still spells these in npm's dialect; keep the runner form on sync.
package.json:version:patch,version:minorandversion:majorappendbun install --lockfile-onlyafternpm install --package-lock-only --ignore-scripts.package.json:refresh-lockdoes the same, so the manual lockfile-refresh path and the release path agree.
bun install --frozen-lockfilebroke on main twice in one day: releasev2026.9.4-2(a79aa2080) rewrotepackage-lock.jsonwhilebun.lockkept 2026.9.3 workspace versions, andd052dbb6badded the@anthropic-ai/sdkoverride without regenerating it (fixed as a one-off in #1364).- Both incidents share one cause: every script that refreshes a lockfile refreshes only the npm one, and CI installs with
npm ci, so the drift recurs at each bump with nothing observing it. #1364 cleared the symptom; this closes the source.
- These are the repo's own release and lockfile-maintenance scripts; nothing outside
package.jsondecides which lockfiles a version bump rewrites.
package.jsonscripts— theversion:*andrefresh-locklines.
package.jsonpins@anthropic-ai/sdkat 0.123.0 (was 0.120.0), the version the 2026-09-03 upstream sync of badlogic/pi-mono v0.84.4 resolved against..npmrcaddsmin-release-age-exclude[]=@anthropic-ai/sdknext to the existing excludes, with an in-file note to remove it after 2026-09-05.
- The fork's
min-release-age=2supply-chain gate refuses packages younger than two days, so the freshly published 0.123.0 pin would fail installs until 2026-09-05. The exclude is time-boxed by its removal note instead of weakening the policy for every package.
- Root manifest pins and npm install policy execute before any package code, let alone an extension, runs.
- LOW: the
package.jsonroot dependency overrides block and the.npmrcexclude list on future upstream syncs and release bumps.
package.json: the three root scripts that fan out to workspaces stop passing workspace flags after the script name.testandcleanmove the flags before the script name (npm run --workspaces --if-present <script>), andevalmoves its flag beforerun(npm --workspace=@code-yeongyu/senpi-evals run eval --). npm behavior is unchanged in all three cases.scripts/root-workspace-scripts.test.mjs(new): parses the root manifest and fails a root script for either recursion-prone shape — a workspace flag after the script name, or a singular--workspaceon annpm runcall (which bun ignores, re-entering the root script). Both shipped shapes are covered; a mutation check confirms revertingevaltonpm run --workspace=<name> evalfails the guard.
- Bun rewrites
npm run <name>tobun run <name>inside script text, and bun appends flags placed after the script name to the script itself instead of parsing them.npm run test --workspaces --if-presenttherefore re-invoked the ROOT script with an ever-growing flag suffix (bun run test --workspaces --if-present --workspaces --if-present ...) and spun forever instead of running the workspace suites — it never failed, so it read as a slow suite.cleanandevalhad the same defect. Verified in a throwaway fixture: the flag-before form fans out under both npm and bun, while the singular--workspace=<name>form still recurses under bun (bun does not recognize it), which is whyevalneeds the flag beforerunso nonpm runsubstring remains to rewrite.
- These are root package manifest scripts consumed by the release gate (
scripts/release.mjs,scripts/local-release.mjsrunCI=1 npm test) and by contributors directly; no extension surface exists above the package manager.
- LOW: the
test,clean, andevallines in the rootpackage.jsonscripts block.
Shared socket clients now register rendered_components through additive set_client_info capabilities. Factory-rendered component records are filtered per connection, including capability-aware snapshot replay. Capabilities remain connection-wide across sessions and are cleared only on socket release; explicit close removes only the closing width. Shared bindings retain factories while disposing live renderers and footer providers when no capable connection remains, recreating them for later capable joiners.
Root tracker for repository-level divergence from upstream badlogic/pi-mono.
Owns every audited production path whose nearest tracker is the repository root.
biome.jsondrops the!!**/.codegraphignore entry.
- The omo product removed its CodeGraph integration, so nothing writes a
.codegraphdirectory anymore. An ignore entry for a directory that is never created is dead configuration that implies the integration still exists. - The matching
EXCLUDED_ROOT_PATHSchange inpackages/coding-agent/src/beta/omo-local-update-fingerprint.tsis recorded inpackages/coding-agent/src/changes.md, that path's nearest ancestor tracker.
- The biome ignore list is fork-owned: it is an omo-specific surface that upstream
badlogic/pi-monodoes not carry.
- LOW:
biome.jsonignore list ordering during upstream syncs.
package.jsonbumps the pinned@anthropic-ai/sdkfrom0.91.1to0.120.0so the pin satisfies@anthropic-ai/claude-agent-sdk@0.3.241's>=0.93.0peer range.
- Every bun install printed
warn: incorrect peer dependency "@anthropic-ai/sdk@0.91.1"; the SDK floor moved to 0.93.0 when the agent SDK gained its credentials subsystem.
- The root pin set is fork-owned dependency policy; upstream does not pin these packages together.
- LOW:
package.jsonroot dependency pins during upstream syncs.
biome.jsonkeeps the fork lint surface: schema2.5.10,preset: "recommended"syntax, and the**/api/cursor-agent/genand**/.codegraphexclusions.packages/agent/package.jsonkeeps the senpi calver (2026.8.24),tscbuild (upstream usestsgo), and the fork dependency set (diff9,typebox1.3.18, calver workspace ranges).packages/session-backends/sqlite-node/package.jsonkeeps the fork package name@earendil-works/pi-storage-sqlite-node,tscbuild, and vitest4.1.11.packages/telemetry/package.jsonkeeps calver,@types/node26, vitest4.1.11, andprivate: true.packages/tui/package.jsonkeeps calver,tscbuild, the--import tsx+ multiplexer-env test loader, node>=24,marked18.0.10, and thebench:frame-costscript.
These are fork-owned product surfaces (senpi branding, provider wire behavior, fork runtime features) that upstream does not carry; the sync must re-assert them on top of upstream's tree.
The divergence lives in core wiring, package identity, or build plumbing that executes before any extension loads, so no extension hook can express it.
- Version/name/scripts blocks of every listed
package.jsonon each upstream release bump;biome.jsonwhenever upstream migrates Biome versions.
vitest.base.ts: added a resolve alias mapping@earendil-works/pi-ai/auth/*topackages/ai/src/auth/*.tsso vitest resolves the newauth/pool/slotssubpath to source during tests.
- Workspace tests import
@earendil-works/pi-ai/auth/pool/slots; without a source alias vitest resolves to the builtdist, which does not exist for the new module, breaking test runs.
- Test runner aliasing is repository-level tooling configuration.
- LOW: single additive alias line in
vitest.base.ts.
package.json:@biomejs/biome2.5.9 -> 2.5.10.packages/agent/package.json:typebox1.3.16 -> 1.3.18.packages/ai/package.json:typebox1.3.16 -> 1.3.18.packages/coding-agent/package.json:typebox1.3.16 -> 1.3.18.packages/protocol/package.json:typebox1.3.16 -> 1.3.18.packages/senpi-codemode/package.json:typebox1.3.16 -> 1.3.18.packages/{ai,coding-agent}/package.json:@aws-sdk/client-bedrock-runtime3.1115.0 -> 3.1116.0.packages/coding-agent/package.json:@anthropic-ai/claude-agent-sdk0.3.238 -> 0.3.241.- Root and generated release locks were regenerated from those exact pins.
- These are the repository-audited patch-level or same-line upgrades available for the 2026.8.24 release. TypeBox must remain single-instanced across the shared protocol/runtime packages, and the Bedrock pin must remain identical in
aiandcoding-agent. The Claude Agent SDK update also requires regenerating its platform lock and the published/install dependency closures. @anthropic-ai/sdkremains at 0.91.1 because the minimum peer-compatible 0.93.0 still introduces browser-breaking credential-chain imports, while 0.120.0 is likewise unsafe. Deliberate breaking holds remain unchanged foropenai6.26.0 andsignal-exit3.0.7.
- Dependency resolution, exact pins, generated release locks, and platform-package selection happen before the runtime and extension system load.
- HIGH: root and coding-agent dependency blocks and generated lock artifacts.
- MEDIUM: the shared TypeBox pins across five package manifests.
package.json: root devDependencies bumpedesbuild0.28.1 -> 0.28.2 andtsx4.23.1 -> 4.23.12; declaredconcurrently10.0.5 (the rootdevscript invoked it while it was undeclared and absent from the lock); dropped the unused@anthropic-ai/sandbox-runtimeandjitidevDependencies and the unusedget-east-asian-widthdependency. Overrides bumped@hono/node-server2.0.10 -> 2.1.1,postcss8.5.18 -> 8.5.26,brace-expansion5.0.8 -> 5.0.9,esbuild0.28.1 -> 0.28.2,rimraf6.1.2 -> 6.1.3 (including the nestedgaxios.rimrafpin),shell-quote1.9.0 -> 1.10.0,vite8.0.16 -> 8.2.2, andws8.21.1 -> 8.21.3, whilefast-uristays on 3.x andprotobufjson 7.x and@anthropic-ai/sdkstays pinned at 0.91.1..npmrc: rewrote themin-release-ageexemption list as package-name patterns (@hono/node-server,@anthropic-ai/claude-agent-sdk,@aws-sdk/*,@google/genai,@smithy/*,typebox,vite) so the freshly published target versions resolve under the repository's two-day supply-chain window.packages/agent/package.json,packages/protocol/package.json:typeboxmoved to 1.3.16 (from 1.3.8 and from the inconsistent 1.3.7).packages/telemetry/package.json:@types/node24.12.4 -> 26.2.0, matching the rest of the repository.packages/tui/package.json:marked18.0.7 -> 18.0.10.crates/senpi-pty/Cargo.toml,crates/senpi-pty/package.json, and the workspaceCargo.tomlpins:libc=0.2.174 -> =0.2.189,napi=3.10.3 -> =3.12.1,napi-derive=3.5.9 -> =3.6.3,napi-build=2.3.2 -> =2.4.1,@napi-rs/cli3.7.2 -> 3.8.6.scripts/rolldown-platform-lock.test.mjs: the asserted Rolldown binding version tracks 1.0.3 -> 1.2.4, which is whatvite8.2.2 resolves.
- These pins had drifted behind their current releases while the repository enforces exact pins through
npm run check:pinned-deps, so refreshing them in one pass keeps every workspace on one resolved version and keeps the sharedtypeboxidentity single-instanced. The removals delete manifest entries with zero source references, and declaringconcurrentlymakes the root manifest truthful about whatnpm run devactually needs.@anthropic-ai/sdkis deliberately held at 0.91.1 because 0.120.0 adds credential-chain modules whosenode:fsandnode:pathimports break the browser-bundle invariant enforced byscripts/check-browser-smoke.mjs. The.npmrcrewrite fixes an exemption list that could never match: npm compares these patterns against the package name only, so the previousname@versionstring was inert.
- Dependency resolution, override pinning, the supply-chain age gate, and Cargo pin selection are all performed by the package managers before any runtime exists, so no extension can influence which versions get installed or locked.
- HIGH: the
overridesanddevDependenciesblocks inpackage.json, which upstream edits on nearly every release. - MEDIUM: the per-package
typebox/@types/nodepins and the workspaceCargo.tomldependency table. - LOW:
.npmrcand the Rolldown binding version constant.
Canonical backfill seeded from the pre-backfill audit report under
local-ignore/qa-evidence/20260817-changes-md-audit/pre-backfill-audit.json
(upstream pin badlogic/pi-mono v0.84.2, 914cf1472e715297caa30db4b9535d534a9eb718).
Every remaining audited production path with no nearer tracker than the root:
.npmrc: addsmin-release-age-exclude=@hono/node-server@2.0.10on top of the upstream min-release-age supply-chain policy.biome.json: biome schema2.3.5->2.5.5,recommended: truemigrated topreset: "recommended", and extended ignore sets for generated and tool-owned trees (!**/api/cursor-agent/gen,!!**/.codegraph).package.json: monorepo renamedpi-monorepo->senpi-monorepo,packages/ptyjoined the workspace, chained-cdbuild scripts replaced byscripts/build-all.mjswithbuild:npm/build:bun/build:pnpmentry points, rootcheckswappedtsgo --noEmitfortsc --noEmitand addedcheck:claude-sdk-platform-lockplus script-based browser smoke, and fork-onlyverify:pmsorchestration was added.pnpm-workspace.yaml: mirrors the root npm workspace's nestedpackages/session-backends/*glob so the pnpm parity build installs and links the sqlite session backend's workspace dependencies beforescripts/build-all.mjsbuilds it.tsconfig.base.json:target/libraised fromES2022toES2024.tsconfig.json: reformatted to the fork's biome multi-line layout; workspace path mappings are semantically unchanged.vitest.base.ts: added the workspace source alias mapping@earendil-works/pi-ai/utils/*topackages/ai/src/utils/*so shared test configs resolve utils from source.packages/agent/package.json: private CalVer2026.8.16,tsgo->tscbuild/typecheck, fork dependency pins (@earendil-works/pi-ai/pi-telemetry^2026.8.16,diff9.0.0,ignore7.0.6).packages/client/package.json: CalVer2026.8.16,tsgo->tsc,@earendil-works/pi-protocolpinned exactly to2026.8.16.packages/client/src/unix.ts: typed the socketdatacallback chunk asBuffer.packages/protocol/package.json: CalVer2026.8.16,tsgo->tsc.packages/session-backends/sqlite-node/package.json: renamed@earendil-works/pi-session-backend-sqlite-node->@earendil-works/pi-storage-sqlite-node, made private and independently versioned at0.83.0,tsgo->tsc, and keeps its runtimepi-agent-core/pi-aidependencies on lockstep semver ranges so npm, Bun, and pnpm all link the live workspace packages.packages/session-backends/sqlite-node/src/sqlite/repo.ts: optional-chaining refactor of the message-target guard.packages/telemetry/package.json: private CalVer2026.8.16.packages/telemetry/src/index.ts: type-layout reformat under the fork's biome/TypeScript settings; no contract change.packages/tui/package.json: private CalVer2026.8.16,tsgo->tsc, tests run undertsxwithtest/setup-multiplexer-env.mjs, addedbench:frame-cost, Node engine>=24.0.0, pinned bumps (marked18.0.7)..pi/extensions/prompt-url-widget.ts: deleted; relocated into global builtins (see the focused section below)..pi/extensions/tps.ts: deleted; relocated into global builtins (see the focused section below).
- Senpi is a fork with its own identity, CalVer release trains, and an npm/bun/pnpm install
matrix; root manifests, compiler settings, and lint configuration carry that policy, so they
intentionally diverge from the upstream npm-only
0.xlayout. - Non-published support packages (
agent,telemetry,tui, sqlite storage backend) are private and lockstep-versioned or independently pinned per AGENTS dependency policy, which shows up as manifest-level divergence with no deeper tracker of its own. - The two deleted
.pi/extensions/*files were repository-local development extensions that the fork promoted into shipped product behavior; the deletion itself is the audited divergence and is recorded here because.pi/has no tracker of its own.
- Every path in this section is repository, build, toolchain, or non-coding-agent package metadata that executes before any Senpi session, extension loader, or runtime exists. Extensions load inside a coding-agent session and cannot rename a monorepo, retarget compilers, reshape git hooks, reversion packages, or alter dependency policy.
- HIGH: root
package.jsonscripts/workspaces andpackages/*/package.jsonversion blocks on every upstream sync; upstream0.xbumps must be reconciled into CalVer deliberately. - MEDIUM:
biome.json,tsconfig.base.json,tsconfig.json, andvitest.base.tswhenever upstream bumps toolchain majors or adds workspaces. - MEDIUM:
.pi/extensions/prompt-url-widget.tsand.pi/extensions/tps.ts— upstream still owns these files, so syncs will propose edits to deleted paths; resolve to the deletion and re-port any upstream improvement into the builtin copies.
- Deleted
.pi/extensions/prompt-url-widget.tsand.pi/extensions/tps.ts, which the upstream pin still ships as repository-local dev extensions. - Relocated their functionality into always-on global builtins at
packages/coding-agent/src/core/extensions/builtin/prompt-url-widget.tsandpackages/coding-agent/src/core/extensions/builtin/tps.ts, registered with the other fork builtins and covered bypackages/coding-agent/src/core/extensions/builtin/changes.md. - Subsequent fork releases hardened the TPS builtin (monotonic timing in
7f6097bf3, cache-hit notice inc7874fda3) with regression coverage inpackages/coding-agent/test/suite/tps-extension.test.ts. - Context: sibling
.pi/extensions/import-repro.tsand.pi/extensions/redraws.tsmoved the same way and are rename-tracked under the builtin tracker, so they do not appear in the canonical audit list above.
- Repository-local
.pi/extensionsonly load for sessions started inside this clone and require per-repo wiring. Senpi ships the URL prompt widget and tokens-per-second notice as product affordances for every user and session, versioned, registered, and tested together with the coding agent instead of living in an unaudied dot-directory.
- Remaining a repo-local extension is exactly what this change removed: an extension cannot distribute itself to other clones or sessions. Promoting the behavior into the builtin set is the mechanism; there is no extension-side equivalent of "ship enabled-by-default for all users".
- Upstream-side edits to the deleted
.pi/extensions/prompt-url-widget.tsand.pi/extensions/tps.tson every sync (resolve to deletion, re-port improvements). - Builtin registration and widget internals under
packages/coding-agent/src/core/extensions/builtin/if upstream reworks extension loading or adds overlapping notices.
pnpm-workspace.yamlnow includespackages/session-backends/*, matching the root npm workspace and the package set explicitly built byscripts/build-all.mjs.packages/session-backends/sqlite-node/package.jsondeclares its shippedpi-agent-core/pi-aiimports as lockstep runtime dependencies instead of packedfile:dev dependencies.scripts/sync-versions.jskeeps the backend's own0.83.0version independent while synchronizing those lockstep dependency ranges during Senpi releases.
- The release pre-commit gate verifies npm, Bun, and pnpm. Pnpm previously excluded the
nested backend from its workspace and then, once included, packed its
file:dependencies before their declarations were built. The ordered build therefore reached the backend with unresolvedpi-agent-core/pi-aitypes even though npm and Bun passed.
- This is package-manager workspace topology and release-version synchronization. Runtime extensions load only after packages install and build, so they cannot repair missing workspace membership, dependency links, or manifest pins.
- Upstream changes to the SQLite backend's dependency placement or independent-version policy.
- Future workspace additions under nested
packages/*/*paths, which must remain aligned across root npm workspaces,pnpm-workspace.yaml, andscripts/build-all.mjs.
package.json: the root manifest stays the fork'ssenpi-monorepo(Node >= 24,packages/ptyworkspace,build/clean/testrouted throughscripts/build-all.mjsandscripts/run-workspaces.mjs, the forkcheckchain withcheck:claude-sdk-platform-lockandtsc --noEmit,refresh-lock,preinstallbin stubs, Bun/pnpmtrustedDependencies/onlyBuiltDependencies, and the held overrides such asprotobufjs 7.6.5,@anthropic-ai/sdk 0.123.0,esbuild 0.28.2); upstream'scheck:runtime-deps/check:entry-graphs/check:package-installscripts exist but are not wired intocheck.packages/chord/package.json: differs from the pin only by version fields: the fork CalVer2026.9.12instead of0.85.1,vitest 4.1.11instead of4.1.9so the held pin stays single-instanced, andprivate: truebecause chord is bundled into the senpi tarball rather than published.packages/chord/src/types.ts: the same declarations as upstream; the only difference is biome 2.5.10 formatting of the nested conditional types (JsonRepresentation,InvalidJsonPart,InvalidRemoteMember), which the fork's--error-on-warningscheck rewrites.packages/telemetry/package.json: version fields only: CalVer2026.9.12,@types/node 26.2.0,vitest 4.1.11,private: true.tsconfig.json: keeps the fork path map (@code-yeongyu/senpi,@code-yeongyu/senpi/hooks,@code-yeongyu/senpi-server,@earendil-works/pi-pty,@earendil-works/pi-agent-core/session/testing) unioned with upstream's Chord root and subpath entries; the file is expanded one-entry-per-line by the fork formatter.vitest.base.ts: unions upstream'saiUtilsalias with the forkaiAuthPoolalias (@earendil-works/pi-ai/auth/*->packages/ai/src/auth/*) beside the Chord aliases upstream added.
- The fork ships under its own package names, CalVer lockstep, Node 24 floor, mixed npm/Bun/pnpm build orchestration and held dependency pins; the root manifest, TypeScript path map and vitest aliases are where those choices are declared, so the sync cannot take upstream's versions of them verbatim.
- Workspace manifests, compiler path maps and test-runner aliases are build-time inputs read before any runtime code loads; no extension hook can rename packages, change the engine floor or register a module alias.
- HIGH: root
package.jsonscripts,devDependencies,overridesandengineswhenever upstream bumps tooling or adds acheck:*step. - MEDIUM:
tsconfig.jsonpathswhen upstream adds a workspace or subpath export;vitest.base.tsalias list for the same reason. - LOW:
packages/chord/package.jsonandpackages/telemetry/package.jsonversion lines on every upstream release;packages/chord/src/types.tsre-wraps whenever upstream edits those conditional types.