feat: single-source cross-app wire contracts in @boocode/contracts (v2.7.13)

Move all hand-synced cross-app wire contracts into one built workspace
package, @boocode/contracts, consumed by server/web/coder/coder-web via
workspace:* + a per-subpath exports map. The ws-frames and provider-config
Zod schemas are schema-first (z.infer); MessageMetadata, ErrorReason,
AgentSessionConfig, the provider snapshot types, and WorktreeRiskReport are
each single-sourced. Deletes the byte-identical copies and their parity
tests, fixes a live AgentSessionConfig drift (coder dead copy removed,
unified to the web required/nullable shape), removes the dead pending_change
WS arms in the fallback SPA, and inverts the build order (contracts builds
first) across root build, Dockerfile, and the coder deploy docs. Reverses
the shared-package decision declined in v2.5.12.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-02 21:00:00 +00:00
parent 2a05d2f9fe
commit 649ce71eff
55 changed files with 804 additions and 1108 deletions

View File

@@ -140,7 +140,7 @@ No matter which backend runs, the turn streams the same way. Each backend emits
| `apps/coder/.env.host` | Production env (DATABASE_URL, LLAMA_SWAP_URL, CODER_PROVIDERS_PATH, CLAUDE_SDK_BACKEND, …) |
| `data/coder-providers.json` | Live runtime provider overrides (gitignored); template is `data/coder-providers.example.json` |
**Build & deploy.** `apps/coder` imports the server's compiled `dist/` (`createInferenceRunner`, `createBroker`, `ALL_TOOLS`), so **`apps/server` must build first**: `pnpm -C apps/server build && pnpm -C apps/coder build && sudo systemctl restart boocoder`. The server's `package.json` `exports` map needs both `types` and `default` conditions per subpath (and `declaration: true` in its tsconfig) or NodeNext can't find the `.d.ts` and tsc fails "Cannot find module" here. Agent dispatch spawns binaries **directly**`spawn(fullBinaryPath, argsArray, { cwd })` using `install_path` — never `spawn('sh', ['-c', ...])`, which fails under systemd.
**Build & deploy.** `apps/coder` imports from both `@boocode/contracts` and the server's compiled `dist/` (`createInferenceRunner`, `createBroker`, `ALL_TOOLS`), so **`packages/contracts` and `apps/server` must build first**: `pnpm -C packages/contracts build && pnpm -C apps/server build && pnpm -C apps/coder build && sudo systemctl restart boocoder`. The server's `package.json` `exports` map needs both `types` and `default` conditions per subpath (and `declaration: true` in its tsconfig) or NodeNext can't find the `.d.ts` and tsc fails "Cannot find module" here. Agent dispatch spawns binaries **directly**`spawn(fullBinaryPath, argsArray, { cwd })` using `install_path` — never `spawn('sh', ['-c', ...])`, which fails under systemd.
## Configuration
@@ -267,7 +267,7 @@ interface AgentBackend {
`AcpToolSnapshot` (`apps/coder/src/services/acp-tool-snapshot.ts`) is the accumulating shape for a tool call — `{ toolCallId, title, kind?, status?, rawInput?, rawOutput? }` — merged incrementally and rendered via `snapshotToWireToolCall`.
The provider picker is driven by `ProviderSnapshotEntry` / `AgentCommand` in `apps/coder/src/services/provider-types.ts`, which must stay byte-identical to the web copy in `apps/web/src/api/types.ts` (see Testing).
The provider picker is driven by `ProviderSnapshotEntry` / `AgentCommand` single-sourced in `@boocode/contracts` (`packages/contracts/src/provider-snapshot.ts`). `apps/coder/src/services/provider-types.ts` re-exports them; the web imports them directly. There is no hand-synced copy to keep in sync.
### Constants
@@ -332,7 +332,7 @@ The picker is built by a four-stage pipeline: `provider-config.ts` (never-throws
- `services/backends/__tests__/turn-guard.test.ts` — abort orphan-terminal suppression
- `services/backends/__tests__/lifecycle-decisions.test.ts` — idle/LRU/restart eviction
- `services/__tests__/acp-event-map.test.ts` / `acp-tool-snapshot.test.ts` — ACP normalization + snapshot merge
- `services/__tests__/provider-types-parity.test.ts`text-identity parity between `provider-types.ts` and the web `api/types.ts` copy (compile-time cross-import is blocked by TS6307 on web's composite tsconfig)
- `services/__tests__/provider-types-parity.test.ts`**deleted**: provider snapshot types are now single-sourced in `@boocode/contracts/provider-snapshot`; parity is enforced by the single definition
- `services/__tests__/write_guard.test.ts` (+ `_fuzz`) — path escape + secret-file blocking
### Adding a new backend