@spunto/build 0.20.0 → 0.20.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spunto/build",
3
- "version": "0.20.0",
3
+ "version": "0.20.2",
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",
@@ -7,8 +7,8 @@
7
7
  * **Measured, not remembered.** Each catalog is what the SDK pinned by its feature
8
8
  * (`./features.ts`) answers, and it changes when that pin moves:
9
9
  *
10
- * - Claude: `query().supportedModels()` of `@anthropic-ai/claude-agent-sdk` 0.3.310, with a
11
- * subscription token, on 2026-10-26. Each model comes back with `supportedEffortLevels`;
10
+ * - Claude: `query().supportedModels()` of `@anthropic-ai/claude-agent-sdk` 0.3.310, on
11
+ * 2026-10-26. Each model comes back with `supportedEffortLevels`;
12
12
  * - Codex: `codex debug models` of `@openai/codex` 0.164.0 — the catalog bundled in the binary,
13
13
  * offline, on 2026-10-26 — the `visibility: "list"` models, with their
14
14
  * `supported_reasoning_levels` and `default_reasoning_level`.
@@ -15,8 +15,9 @@
15
15
  // (`./catalogs.ts`): `{"effort":"high"}`
16
16
  // exit 0 once the input is closed and the last turn is over, 1 when the session could not run
17
17
  //
18
- // Credentials are not this file's business: `CLAUDE_CODE_OAUTH_TOKEN` or `ANTHROPIC_API_KEY`, set
19
- // as secrets, reach the SDK's binary through the environment like they reached the CLI before.
18
+ // Credentials are not this file's business: whatever the member set as secrets (an
19
+ // `ANTHROPIC_API_KEY`) reaches the SDK's binary through the environment, untouched — this runner
20
+ // reads no credential itself.
20
21
 
21
22
  import { createInterface } from "node:readline"
22
23
 
@@ -117,16 +117,19 @@ export function startScript(p: StartCommandScript): string {
117
117
  * The state of a command and the tail of both streams. `exit_code` is written last by the wrapper,
118
118
  * so its presence is the completion signal — the pid alone would call a command finished the
119
119
  * instant its shell is replaced by an exec'd child.
120
- * Prints `FOUND`, `EXIT` (`-` while running), `ALIVE`, `SIZEOUT`, `SIZEERR`, `OUT`, `ERR` (base64).
120
+ * Prints `FOUND`, `ALIVE`, `EXIT` (`-` while running), `SIZEOUT`, `SIZEERR`, `OUT`, `ERR` (base64).
121
121
  */
122
122
  export function pollScript(commandId: string, maxOutputBytes = DEFAULT_POLL_OUTPUT_BYTES): string {
123
123
  const dir = dirOf(commandId)
124
124
  return [
125
125
  `if [ ! -d ${dir} ]; then echo "FOUND:0"; exit 0; fi`,
126
126
  `echo "FOUND:1"`,
127
- `if [ -f ${dir}/exit_code ]; then echo "EXIT:$(cat ${dir}/exit_code)"; else echo "EXIT:-"; fi`,
127
+ // The pid before `exit_code`: the wrapper writes its code before exiting, so a dead wrapper
128
+ // with no code read *after* it is one that died without writing it (`commandDied`). `ALIVE:-`
129
+ // is a command still being started, its pid not written yet.
128
130
  `pid=$(cat ${dir}/pid 2>/dev/null || echo "")`,
129
- `if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then echo "ALIVE:1"; else echo "ALIVE:0"; fi`,
131
+ `if [ -z "$pid" ]; then echo "ALIVE:-"; elif kill -0 "$pid" 2>/dev/null; then echo "ALIVE:1"; else echo "ALIVE:0"; fi`,
132
+ `if [ -f ${dir}/exit_code ]; then echo "EXIT:$(cat ${dir}/exit_code)"; else echo "EXIT:-"; fi`,
130
133
  `echo "SIZEOUT:$(wc -c < ${dir}/stdout.log 2>/dev/null || echo 0)"`,
131
134
  `echo "SIZEERR:$(wc -c < ${dir}/stderr.log 2>/dev/null || echo 0)"`,
132
135
  `echo "OUT:$(tail -c ${maxOutputBytes} ${dir}/stdout.log 2>/dev/null | base64 | tr -d '\\n')"`,
@@ -203,3 +206,9 @@ export function commandExitCode(fields: Map<string, string>): number | null {
203
206
 
204
207
  /** A wrapper still alive with an exit code already written is finishing up: done, not running. */
205
208
  export const commandRunning = (fields: Map<string, string>) => commandExitCode(fields) === null && fields.get("ALIVE") === "1"
209
+
210
+ /**
211
+ * A poll of a wrapper that is gone without writing `exit_code`: the box rebooted, or the process was
212
+ * SIGKILLed (OOM). Nothing will ever write the code, so read as "still running" it stays so forever.
213
+ */
214
+ export const commandDied = (fields: Map<string, string>) => commandExitCode(fields) === null && fields.get("ALIVE") === "0"