@spunto/build 0.21.1 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -166,8 +166,34 @@ JSON columns at them with `$type<…>()`, instead of a generator having to impor
166
166
  `SetupStatus` is what a shell script writes into a container and a control plane reads back minutes
167
167
  later: changing it is a migration, not an edit.
168
168
 
169
+ ### `@spunto/build/agent-contract` — the Spunto agent contract
170
+
171
+ What an agent app's runner reads on stdin (`user`, `interrupt`, `title`) and prints on stdout:
172
+ **our** vocabulary, one JSON object per line, each event with the harness message it was read from
173
+ as `source`. The runner normalises; the platform has one strict reader for every app:
174
+
175
+ ```ts
176
+ import { readContractLine, runConformance, agentContractSchema } from "@spunto/build/agent-contract"
177
+
178
+ readContractLine('{"type":"message","role":"assistant","text":"done"}') // → [{ type, payload, source }]
179
+ // closed schemas: an unknown field or type is kept as `raw`, with the reason — never half-read
180
+
181
+ const results = await runConformance(start) // start: ({ resume }) => a process you spawned
182
+ ```
183
+
184
+ The JSON Schema is shipped as `@spunto/build/agent-contract/schema.json`, generated from the very
185
+ table the reader validates with. The conformance suite drives a runner like the platform does and
186
+ checks every line and the order of events (simple turn, tool, interrupt, resume, limit, title,
187
+ files). `@spunto/build/agent-contract/fake-agent.mjs` is a whole runner in 46 lines with no SDK
188
+ that passes it. The Claude and Codex runners (`./agent-runners`) carry their adapters next to them
189
+ and are meant to be **bundled** (esbuild, `platform: node`, `format: esm`) before being run.
190
+
169
191
  ### `@spunto/build/agent-stream` — reading an agent session as it happens
170
192
 
193
+ Since the contract (`agent-v1`), what is left here is the writing side of a session and the
194
+ **legacy dialects** — the CLI's `claude-stream`, the runners' former `claude-runner` /
195
+ `codex-runner` — for sessions that began on them.
196
+
171
197
  One adapter per harness dialect, one vocabulary out. A CLI's JSON output is an output format, not
172
198
  an API; adapters normalise into a small set of event types so stored history doesn't date the first
173
199
  time a vendor reshuffles a field.
@@ -175,6 +201,12 @@ time a vendor reshuffles a field.
175
201
  Here for the reason that inverts the rest of the package: **nothing has forked this yet.** Putting
176
202
  it in the shared package now costs nothing and means the second product never writes its own.
177
203
 
204
+ Tokens of a message still being written (Claude's `stream_event` lines, from
205
+ `includePartialMessages`) are **not** events: `parseStreamLine` reads them as nothing, and
206
+ `foldDraft(protocol, lines, previous)` folds them into the one transient text block in flight —
207
+ closed by the finished message, never stored. Where the draft lives between two reads is the
208
+ caller's business.
209
+
178
210
  ### `@spunto/build/terminal` — the half of a persistent terminal that is a string
179
211
 
180
212
  A worker's terminal is an exec attached to a session that outlives it, so closing a browser tab
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spunto/build",
3
- "version": "0.21.1",
3
+ "version": "0.23.0",
4
4
  "description": "Spunto's shared Build engine — the devcontainer image protocol and VS Code extension registry clients, with no database, no HTTP framework and no UI.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -63,6 +63,12 @@
63
63
  "types": "./src/agent-stream/index.ts",
64
64
  "import": "./src/agent-stream/index.ts"
65
65
  },
66
+ "./agent-contract": {
67
+ "types": "./src/agent-contract/index.ts",
68
+ "import": "./src/agent-contract/index.ts"
69
+ },
70
+ "./agent-contract/schema.json": "./src/agent-contract/agent-contract.v1.schema.json",
71
+ "./agent-contract/fake-agent.mjs": "./src/agent-contract/examples/fake-agent.mjs",
66
72
  "./agent-protocol": {
67
73
  "types": "./src/agent-protocol/index.ts",
68
74
  "import": "./src/agent-protocol/index.ts"
@@ -104,7 +110,8 @@
104
110
  "typescript": "^5",
105
111
  "vitest": "^4.1.10",
106
112
  "ws": "^8.22.0",
107
- "zod": "^4.6.5"
113
+ "zod": "^4.6.5",
114
+ "esbuild": "^0.25.12"
108
115
  },
109
116
  "peerDependencies": {
110
117
  "zod": "^4"