@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 +32 -0
- package/package.json +9 -2
- package/src/agent-contract/agent-contract.v1.schema.json +672 -0
- package/src/agent-contract/conformance.ts +315 -0
- package/src/agent-contract/examples/fake-agent.mjs +46 -0
- package/src/agent-contract/index.ts +20 -0
- package/src/agent-contract/vocabulary.ts +313 -0
- package/src/agent-runners/catalogs.ts +7 -0
- package/src/agent-runners/claude/adapter.ts +330 -0
- package/src/agent-runners/claude.mjs +46 -17
- package/src/agent-runners/codex/adapter.ts +135 -0
- package/src/agent-runners/codex.mjs +15 -7
- package/src/agent-runners/index.ts +24 -15
- package/src/agent-stream/agent-stream.ts +45 -430
- package/src/agent-stream/draft.ts +156 -0
- package/src/agent-stream/index.ts +3 -0
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.
|
|
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"
|