usesteady 0.1.0-alpha.63 → 0.1.0-alpha.64

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +168 -0
  2. package/README.md +114 -6
  3. package/dist/src/kernel/classifier.d.ts +18 -12
  4. package/dist/src/kernel/classifier.d.ts.map +1 -1
  5. package/dist/src/kernel/classifier.js +55 -32
  6. package/dist/src/kernel/classifier.js.map +1 -1
  7. package/dist/src/kernel/command-classifier.d.ts +71 -35
  8. package/dist/src/kernel/command-classifier.d.ts.map +1 -1
  9. package/dist/src/kernel/command-classifier.js +79 -37
  10. package/dist/src/kernel/command-classifier.js.map +1 -1
  11. package/dist/src/kernel/execution-replay.d.ts.map +1 -1
  12. package/dist/src/kernel/execution-replay.js +90 -44
  13. package/dist/src/kernel/execution-replay.js.map +1 -1
  14. package/dist/src/kernel/inline-js-classifier.d.ts +126 -0
  15. package/dist/src/kernel/inline-js-classifier.d.ts.map +1 -0
  16. package/dist/src/kernel/inline-js-classifier.js +275 -0
  17. package/dist/src/kernel/inline-js-classifier.js.map +1 -0
  18. package/dist/src/kernel/types.d.ts +2 -2
  19. package/dist/src/kernel/types.d.ts.map +1 -1
  20. package/dist/src/shell/cli/main.d.ts +49 -25
  21. package/dist/src/shell/cli/main.d.ts.map +1 -1
  22. package/dist/src/shell/cli/main.js +208 -370
  23. package/dist/src/shell/cli/main.js.map +1 -1
  24. package/dist/src/shell/cli/use-steady.js +189 -8
  25. package/dist/src/shell/cli/use-steady.js.map +1 -1
  26. package/dist/src/shell/cli/workflow-inspect-target-tree.d.ts +121 -0
  27. package/dist/src/shell/cli/workflow-inspect-target-tree.d.ts.map +1 -0
  28. package/dist/src/shell/cli/workflow-inspect-target-tree.js +256 -0
  29. package/dist/src/shell/cli/workflow-inspect-target-tree.js.map +1 -0
  30. package/dist/src/shell/cli/workflow-inspect-task-to-ir.d.ts +67 -0
  31. package/dist/src/shell/cli/workflow-inspect-task-to-ir.d.ts.map +1 -0
  32. package/dist/src/shell/cli/workflow-inspect-task-to-ir.js +192 -0
  33. package/dist/src/shell/cli/workflow-inspect-task-to-ir.js.map +1 -0
  34. package/dist/src/shell/cli/workflow-inspect.d.ts +142 -0
  35. package/dist/src/shell/cli/workflow-inspect.d.ts.map +1 -0
  36. package/dist/src/shell/cli/workflow-inspect.js +381 -0
  37. package/dist/src/shell/cli/workflow-inspect.js.map +1 -0
  38. package/dist/src/shell/cli/workflow-resume-info.d.ts +93 -0
  39. package/dist/src/shell/cli/workflow-resume-info.d.ts.map +1 -0
  40. package/dist/src/shell/cli/workflow-resume-info.js +185 -0
  41. package/dist/src/shell/cli/workflow-resume-info.js.map +1 -0
  42. package/dist/src/shell/cli/workflow-spec-loader.d.ts +69 -0
  43. package/dist/src/shell/cli/workflow-spec-loader.d.ts.map +1 -0
  44. package/dist/src/shell/cli/workflow-spec-loader.js +268 -0
  45. package/dist/src/shell/cli/workflow-spec-loader.js.map +1 -0
  46. package/dist/src/workflow/resume-token-builder.d.ts +54 -0
  47. package/dist/src/workflow/resume-token-builder.d.ts.map +1 -0
  48. package/dist/src/workflow/resume-token-builder.js +71 -0
  49. package/dist/src/workflow/resume-token-builder.js.map +1 -0
  50. package/dist/src/workflow/resume-token-io.d.ts +99 -0
  51. package/dist/src/workflow/resume-token-io.d.ts.map +1 -0
  52. package/dist/src/workflow/resume-token-io.js +198 -0
  53. package/dist/src/workflow/resume-token-io.js.map +1 -0
  54. package/dist/src/workflow/resume-token-types.d.ts +131 -0
  55. package/dist/src/workflow/resume-token-types.d.ts.map +1 -0
  56. package/dist/src/workflow/resume-token-types.js +36 -0
  57. package/dist/src/workflow/resume-token-types.js.map +1 -0
  58. package/dist/src/workflow/resume-token-validator.d.ts +48 -0
  59. package/dist/src/workflow/resume-token-validator.d.ts.map +1 -0
  60. package/dist/src/workflow/resume-token-validator.js +161 -0
  61. package/dist/src/workflow/resume-token-validator.js.map +1 -0
  62. package/dist/src/workflow/resume-verifier-types.d.ts +104 -0
  63. package/dist/src/workflow/resume-verifier-types.d.ts.map +1 -0
  64. package/dist/src/workflow/resume-verifier-types.js +19 -0
  65. package/dist/src/workflow/resume-verifier-types.js.map +1 -0
  66. package/dist/src/workflow/resume-verifier.d.ts +75 -0
  67. package/dist/src/workflow/resume-verifier.d.ts.map +1 -0
  68. package/dist/src/workflow/resume-verifier.js +335 -0
  69. package/dist/src/workflow/resume-verifier.js.map +1 -0
  70. package/package.json +11 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,173 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.0-alpha.64 - Governed kernel widening: workflow inspect, resume tokens, bounded node -e replay
4
+
5
+ ### Summary
6
+
7
+ This release widens the governed kernel layer along three independent
8
+ axes -- workflow inspect, resume tokens, and bounded `node -e` inline JS
9
+ replay -- without changing any public-wire contract. The published CLI
10
+ shape, JSON adapter schema, capability advertisement, and rejection
11
+ diagnostics are byte-identical to alpha.63 for every input the prior
12
+ release accepted. Operators upgrading from alpha.63 see new surfaces
13
+ appear; nothing previously working changes shape.
14
+
15
+ The kernel work is the headline. K6 closes the bounded-`node -e`
16
+ replayability question that K1-K5 deferred: a tightly constrained
17
+ subset of `node -e "<BODY>"` invocations are now deterministically
18
+ replayable under `usesteady replay --execute`. Everything outside that
19
+ closed structural predicate continues to refuse, with the refusal
20
+ reason refined for diagnosability. K5 echo byte-for-byte preservation
21
+ is restored after a transient byte-layer regression introduced during
22
+ K6 implementation.
23
+
24
+ ### What changed (user-visible)
25
+
26
+ **1. Kernel -- K6: bounded `node -e` deterministic replay.**
27
+
28
+ A new closed structural predicate admits `node -e "<BODY>"` invocations
29
+ for replay-under-execution when `<BODY>` is one of five `console.log`
30
+ atom forms (single-quoted string, signed integer literal, boolean
31
+ literal, `null` literal; the double-quoted string form is admissible by
32
+ the inline-JS predicate but unreachable via the v1.0 wire-level quoting
33
+ of the outer command). Two-gate defense in depth: a token denylist
34
+ (`require`, `process`, `fs`, `eval`, `Date`, `Math.random`, ...) and a
35
+ syntax denylist (backticks, `${`, `//`, `/*`, optional chaining,
36
+ dynamic property access) both run before the closed allow-list. The
37
+ K6 prefix probe runs before the K5 denylist so the leading `node -e "`
38
+ shape is not collaterally refused by K5's shell-metacharacter screen.
39
+ Full design contract: `docs/KERNEL_RUN_COMMAND_K6_DESIGN.md` v1.0.
40
+
41
+ **2. Kernel -- new refusal reason `non_deterministic_inline_js`.**
42
+
43
+ `ExecutionReplayVerdict.refused.reason` and `ClassifierResult.reason`
44
+ gain the value `"non_deterministic_inline_js"`. Emitted when a command
45
+ matches the K6 `node -e "<BODY>"` prefix shape but its body fails the
46
+ inline-JS predicate (denied token, denied syntax fragment, or unmatched
47
+ allow-list atom). Out-of-scope `node` invocations that do not match
48
+ the K6 prefix shape (`node -p`, `node script.js`, etc.) continue to
49
+ refuse with the existing K5-era reason `"non_deterministic_command"`.
50
+ All `switch` sites on these discriminated unions are exhaustively
51
+ updated; TypeScript exhaustiveness guarantees no default fallthrough
52
+ hides a missing branch.
53
+
54
+ **3. Kernel -- K6 execution is host-shell-free (`shell: false`).**
55
+
56
+ K6 inline-JS replay invokes `spawnSync('node', ['-e', body], { shell:
57
+ false, cwd: <K4-sandbox>, ... })`. The `shell: false` flag is the K6
58
+ hermeticity invariant: the body string is never reparsed by an
59
+ intermediate host shell, so no platform-specific quoting, glob, or
60
+ metacharacter expansion can mutate observable behavior between
61
+ artifact capture and replay. Execution still binds to the K4 sandbox
62
+ `cwd`; no `KernelResult` widening for stdout, stderr, or exit code.
63
+
64
+ **4. Kernel -- K5 echo byte-for-byte spawn preservation restored.**
65
+
66
+ The K6 implementation transiently widened the K5 `echo` executor to
67
+ spawn the trimmed form of the command instead of the raw command
68
+ bytes from the spec. Observable behavior was identical across every
69
+ supported host shell (all strip surrounding whitespace before
70
+ parsing), but the strict byte-for-byte K5 contract from alpha.59 was
71
+ technically violated. Alpha.64 restores the original byte-preservation
72
+ behavior and pins it with a regression-guard test for whitespace-
73
+ padded `echo` invocations.
74
+
75
+ **5. New CLI surface -- `usesteady workflow inspect <spec>` (P7-min).**
76
+
77
+ A read-only structural-inspection surface for `WorkflowSpec` files.
78
+ Renders the per-task target tree and IR mapping for a spec without
79
+ executing, persisting state, or producing a `KernelArtifact`. Useful
80
+ for validating spec shape before commit, for triaging
81
+ `run <spec.json>` failures, and for review-time spec audits. The
82
+ surface is purely additive: not invoked by any existing flow, never
83
+ mutates filesystem state, and never advertises beyond its own help
84
+ text.
85
+
86
+ **6. New CLI surface -- P2-min resume tokens.**
87
+
88
+ A new resume-token builder, validator, and verifier provide
89
+ survivability for long-running workflows without hidden continuation
90
+ state. Operators can capture a workflow's mid-run state into an
91
+ explicit resume token, inspect it via `usesteady workflow
92
+ resume-info <token>`, and feed it back to resume execution. No
93
+ existing `--prompt` / `run <spec.json>` invocation changes shape; the
94
+ resume surface is opt-in and additive.
95
+
96
+ **7. Public-surface productization: survivability wedge.**
97
+
98
+ `README.md`, the marketing landing surface, and the npm description
99
+ field are aligned to the survivability + governed-replay wedge.
100
+ Em-dash and arrow glyphs replaced with ASCII per encoding governance
101
+ (no public-facing file regresses ASCII-cleanliness). Deterministic
102
+ demo recording assets shipped under `docs/demo/` and
103
+ `marketing/public/demo/`: one hero `multistep-refactor` demo plus a
104
+ four-part survivability sequence (kill-mid-run, diverged-fs,
105
+ non-idempotent, resume-info), each as `.cast`, `.svg`, `.preview.svg`,
106
+ and `.session.txt` so all rendering paths are reproducible. Public
107
+ demo links repointed to anonymous-reachable URLs (P0 marketing fix).
108
+
109
+ **8. No public-wire breaks.**
110
+
111
+ `KernelResult` shape, the `--json` op schema, `usesteady capabilities`
112
+ output (text and JSON), and rejection-message structure are
113
+ byte-identical to alpha.63 for every input the prior release
114
+ accepted. No CLI flag has been retired or renamed. No JSON adapter
115
+ field has been retired or renamed. The K6 widening expands which
116
+ commands `replay --execute` admits without changing the response
117
+ shape for either the admit path (verdict `match` / `mismatch`) or the
118
+ refuse path (verdict `refused` -- the `reason` enum now carries one
119
+ additional value `non_deterministic_inline_js`, but all prior values
120
+ remain emitted unchanged).
121
+
122
+ ### Files added / changed (release-relevant)
123
+
124
+ - `src/kernel/inline-js-classifier.ts` -- NEW. Closed structural
125
+ predicate for K6 inline-JS bodies plus the command-shape prefix
126
+ probe and body extraction.
127
+ - `src/kernel/command-classifier.ts` -- K6 routing precedence + new
128
+ `InScopeCommand` discriminated union for the executor.
129
+ - `src/kernel/classifier.ts` -- K6 refusal-reason precedence.
130
+ - `src/kernel/execution-replay.ts` -- K6 `node -e` execution path
131
+ (`shell: false`) + K5 echo byte-preservation restoration.
132
+ - `src/kernel/types.ts` -- additive widening of
133
+ `ExecutionReplayVerdict.refused.reason` and `ClassifierResult.reason`.
134
+ - `src/shell/cli/use-steady.ts` -- help-text refresh for K6 shape;
135
+ workflow inspect + resume-info surfaces.
136
+ - `src/shell/cli/workflow-inspect*.ts`, `workflow-resume-info.ts`,
137
+ `workflow-spec-loader.ts` -- new workflow inspect and resume-info
138
+ surfaces (P7-min, P2-min).
139
+ - `src/workflow/resume-token-*.ts`, `resume-verifier*.ts` -- new
140
+ resume-token builder, validator, verifier.
141
+ - `tests/kernel/inline-js-classifier.test.ts` -- NEW. 90+ unit tests.
142
+ - `tests/kernel/{classifier, command-classifier, execution-replay}.test.ts`
143
+ -- additive K6 sections plus K5 byte-preservation regression guard.
144
+ - `tests/shell/workflow-inspect*.test.ts`,
145
+ `tests/shell/workflow-resume-*.test.ts`,
146
+ `tests/workflow/resume-*.test.ts` -- new workflow inspect and resume
147
+ test suites.
148
+ - `docs/KERNEL_RUN_COMMAND_K6_DESIGN.md` -- v1.0 design contract.
149
+ - `docs/product/k6-kickoff-report-v1.md`,
150
+ `p2-min-resume-token-design-v1.md`,
151
+ `p7-min-workflow-inspect-design-v1.md`,
152
+ `governed-workflow-primitives-investigation-v1.md`,
153
+ `workflow-survivability-pressure-report-v1.md`,
154
+ `public-launch-pack-v1.md`,
155
+ `messaging-compression-v1.md`,
156
+ `launch-thread-v1.md` -- design and product docs.
157
+ - `docs/demo/`, `marketing/public/demo/` -- deterministic demo
158
+ recording assets (hero + four-part survivability).
159
+ - `README.md`, `marketing/src/pages/Landing.tsx`, `package.json`
160
+ description -- survivability-wedge productization, ASCII encoding.
161
+
162
+ ### Out of scope for alpha.64
163
+
164
+ - No K7 work.
165
+ - No timeout policy on K6 execution.
166
+ - No multi-segment shell support.
167
+ - No `stdout` / `stderr` / `exitCode` persistence in `KernelResult`.
168
+ - No public-product surface changes beyond the additive workflow
169
+ inspect, resume-info, and demo / marketing routing.
170
+
3
171
  ## 0.1.0-alpha.63 - JSON adapter publication-truthfulness alignment
4
172
 
5
173
  ### Publication-truthfulness consolidation after alpha.62's #45 fix
package/README.md CHANGED
@@ -1,6 +1,88 @@
1
- # UseSteady - Review AI actions before they run
1
+ # UseSteady
2
2
 
3
- UseSteady shows you exactly what AI will do - before it executes anything.
3
+ **Inspect workflows before execution.**
4
+ **Survive interruption without hidden continuation.**
5
+
6
+ <p align="center">
7
+ <a href="docs/demo/hero/">
8
+ <img alt="Hero demo: AI proposes a 4-task refactor, operator inspects, run is killed mid-flight after task 2, operator verifies the resume token, then resumes - no inherited approvals, no hidden state." src="docs/demo/assets/hero/multistep-refactor.svg" width="900" />
9
+ </a>
10
+ </p>
11
+
12
+ <p align="center">
13
+ <em>One narrative, ~80 seconds, five beats: <strong>inspect</strong> -> approve -> run -> <strong>interrupt</strong> -> verify token -> <strong>resume</strong>. See the <a href="docs/demo/hero/">storyboard</a>.</em>
14
+ </p>
15
+
16
+ UseSteady is AI-assisted execution that is operationally trustworthy. You describe the workflow, UseSteady inspects it, you approve it, and only then does the work happen. When a long workflow gets interrupted - Ctrl+C, CI timeout, machine reboot - you resume from a visible token without inheriting approval authority and without hidden state.
17
+
18
+ ```bash
19
+ # 1. Inspect a workflow before running it. Read-only. Deterministic. No LLM.
20
+ npx usesteady workflow inspect spec.json
21
+
22
+ # 2. Run it. After each task, a resume token is written to
23
+ # <workspace>/.usesteady/resume-tokens/<runId>.json
24
+ npx usesteady run spec.json --yes
25
+
26
+ # 3. Resume after interruption. Per-task verification against current disk state.
27
+ # Approvals are NEVER inherited. Diverged state refuses.
28
+ npx usesteady run spec.json --yes --resume-from <token.json>
29
+
30
+ # 4. Inspect a resume token without running anything.
31
+ npx usesteady workflow resume-info <token.json> --spec spec.json
32
+ ```
33
+
34
+ See the [survivability demo suite](docs/demo/survivability/) for four canonical scenarios - each isolates one property in 30-60 seconds. The [hero demo](docs/demo/hero/) composes all four into one continuous flow.
35
+
36
+ ### Four survivability demos
37
+
38
+ Each tile prints the operational claim it proves directly into the terminal chrome - a 3-second-readable badge so you know what you are about to watch.
39
+
40
+ <table>
41
+ <tr>
42
+ <td align="center" width="50%">
43
+ <a href="docs/demo/survivability/01-kill-mid-run.md">
44
+ <img alt="Kill mid-run -> resume. Badge: Survives interruption." src="docs/demo/assets/survivability/01-kill-mid-run.preview.svg" width="100%" />
45
+ </a>
46
+ <br />
47
+ <strong>Kill mid-run -> resume</strong><br />
48
+ <em>Survives interruption</em>
49
+ </td>
50
+ <td align="center" width="50%">
51
+ <a href="docs/demo/survivability/02-diverged-fs.md">
52
+ <img alt="Diverged filesystem -> refusal. Badge: Resume refused." src="docs/demo/assets/survivability/02-diverged-fs.preview.svg" width="100%" />
53
+ </a>
54
+ <br />
55
+ <strong>Diverged filesystem -> refusal</strong><br />
56
+ <em>Resume refused</em>
57
+ </td>
58
+ </tr>
59
+ <tr>
60
+ <td align="center" width="50%">
61
+ <a href="docs/demo/survivability/03-non-idempotent.md">
62
+ <img alt="Non-idempotent task -> re-prompt. Badge: Operator approval required." src="docs/demo/assets/survivability/03-non-idempotent.preview.svg" width="100%" />
63
+ </a>
64
+ <br />
65
+ <strong>Non-idempotent task -> re-prompt</strong><br />
66
+ <em>Operator approval required</em>
67
+ </td>
68
+ <td align="center" width="50%">
69
+ <a href="docs/demo/survivability/04-resume-info.md">
70
+ <img alt="workflow resume-info inspection. Badge: Before execution." src="docs/demo/assets/survivability/04-resume-info.preview.svg" width="100%" />
71
+ </a>
72
+ <br />
73
+ <strong><code>workflow resume-info</code> inspection</strong><br />
74
+ <em>Before execution</em>
75
+ </td>
76
+ </tr>
77
+ </table>
78
+
79
+ Click any tile for the walkthrough. Each demo also ships as an animated SVG (in-repo, GitHub-renders) and an [asciinema v2 `.cast`](https://docs.asciinema.org/manual/asciicast/v2/) source - upload to asciinema.org for live playback or convert to MP4/GIF with `agg` / `asciicast2gif`.
80
+
81
+ ---
82
+
83
+ ## The smaller, interactive surface
84
+
85
+ UseSteady also has an interactive single-step mode for proposing and reviewing individual edits - useful before you graduate to multi-task workflows.
4
86
 
5
87
  ```bash
6
88
  # Interactive session
@@ -11,9 +93,6 @@ npx usesteady --prompt "replace 'Submit' with 'Send' in src/Button.tsx"
11
93
 
12
94
  # Piped stdin
13
95
  echo "rename old.ts to new.ts" | npx usesteady
14
-
15
- # CI / automation - zero prompts
16
- npx usesteady run spec.json --yes
17
96
  ```
18
97
 
19
98
  ---
@@ -137,8 +216,37 @@ Vague input -> Guidance -> You rewrite -> SYSTEM WILL
137
216
  - No silent execution
138
217
  - No vague summaries
139
218
  - No hidden changes
219
+ - No hidden continuation across interrupted runs
220
+ - No inherited approvals on resume
221
+
222
+ You see what changes, why it changes, and how risky it is - before anything runs. When a workflow is interrupted, you see the resume token (a plain JSON file in your workspace), and resume requires an explicit `--resume-from` invocation that re-verifies every "already-done" claim against current disk state.
223
+
224
+ ---
225
+
226
+ ## What UseSteady is NOT
227
+
228
+ - **Not an autonomous agent.** UseSteady does not run when you are not watching. It does not "figure things out" in the background. It has no daemon, no watcher, no retry loop.
229
+ - **Not a code-generation tool.** UseSteady doesn't write the workflow for you. You describe it (or generate it with whatever tool you like), then UseSteady inspects, approves, runs, and resumes it.
230
+ - **Not a replacement for AI coding assistants.** Use Cursor, Claude, Copilot for the proposal layer. UseSteady is the layer that decides what their proposals are allowed to do to your filesystem.
231
+ - **Not a managed service.** UseSteady runs locally. Your workflows execute on your machine. No telemetry, no cloud workspace, no remote state.
232
+ - **Not a workflow scheduler.** No cron, no triggers, no automatic invocation. The CLI runs when you run it.
233
+ - **Not "smart" about failures.** When a workflow is interrupted and the workspace has diverged from the resume token, UseSteady refuses to resume. It tells you exactly what changed. You decide what to do about it.
234
+
235
+ ---
236
+
237
+ ## How UseSteady differs from common alternatives
238
+
239
+ | | Autonomous coding agents | AI copilots / chat assistants | Workflow engines (Airflow, Temporal) | UseSteady |
240
+ |---|---|---|---|---|
241
+ | **Who decides what runs** | The agent | The IDE (after suggestion) | The scheduler | The operator, per step |
242
+ | **What "resume" means** | Restore hidden state, continue | n/a (single-prompt scope) | Resume from internal checkpoint | Re-verify visible token against disk; refuse on divergence |
243
+ | **Approval model** | Inherited or implied | Per-completion in IDE | Configuration-time only | Per-step at runtime, never inherited |
244
+ | **What you can inspect** | Logs, traces, agent reasoning | Diff in the IDE | DAG topology | The exact operations, the exact targets, the exact token bytes |
245
+ | **Where it runs** | Often cloud-managed | IDE host | Cluster | Your local machine |
246
+ | **What gets persisted** | Often hidden internal state | n/a | Engine-managed state stores | A visible JSON file in your workspace |
247
+ | **Failure mode** | Best-effort recovery | n/a (single shot) | DAG retry policy | Refuse on divergence; surface a typed reason |
140
248
 
141
- You see what changes, why it changes, and how risky it is - before anything runs.
249
+ UseSteady fits a different niche from any of these: long-horizon, multi-step, multi-operator AI-assisted changes whose **operational trust** is more important than autonomous sophistication.
142
250
 
143
251
  ---
144
252
 
@@ -1,7 +1,8 @@
1
1
  /**
2
- * Kernel v1 / K4 + K5 replay classifier.
2
+ * Kernel v1 / K4 + K5 + K6 -- replay classifier.
3
3
  *
4
- * ── Scope (PR-K4 design lock §3 D1, §5; K5 v1.0 §3 D1, §5.1) ─────────────────
4
+ * -- Scope (PR-K4 design section 3 D1, section 5; K5 v1.0 section 3 D1,
5
+ * section 5.1; K6 v1.0 section 3 D1) ------------------------------
5
6
  *
6
7
  * Pure pre-pass over `WorkflowSpec.tasks`. Decides whether an IR is
7
8
  * replayable end-to-end before any sandbox is created. Drives the per-IR
@@ -16,20 +17,25 @@
16
17
  * - operationType: "append_file" + targetFiles[0] + content
17
18
  * - operationType: "prepend_file" + targetFiles[0] + content
18
19
  * - structuredReplace: { oldValue, newValue, filePath }
19
- * - operationType: "run_command" + command matching K5 allow-list
20
- * (echo <args> / true / false; see
21
- * command-classifier.ts §5.1)
20
+ * - operationType: "run_command" + command matching the K5 + K6
21
+ * allow-list (echo <args> / true /
22
+ * false / node -e "<BODY>"; see
23
+ * command-classifier.ts)
22
24
  *
23
- * Explicitly NOT replayable in K4 + K5 v1.0:
25
+ * Explicitly NOT replayable in K4 + K5 + K6 v1.0:
24
26
  * - bare `{ input: "<NL>" }` (no operationType, no structuredReplace)
25
- * - operationType: "run_command" with a command outside the K5 allow-list
26
- * (env-dependent or non-deterministic shape; revisit in K6+)
27
+ * - operationType: "run_command" with a command outside the K5 + K6
28
+ * allow-list (env-dependent or non-deterministic shape; K7+ scope)
27
29
  * - any task with runtime "cursor" | "claude" but no FS op fields set
28
- * (would require LLM intake out of K4)
30
+ * (would require LLM intake -- out of K4)
29
31
  *
30
- * K5 reason discriminant (v1.0 §3 D5):
31
- * - run_command with out-of-scope shape reason: "non_deterministic_command"
32
- * - all other non_replayable refusals → reason: "non_deterministic_task"
32
+ * Reason discriminant (K5 v1.0 section 3 D5; K6 v1.0 section 10):
33
+ * - run_command + K6 prefix shape (`node -e "..."`) but BODY out of
34
+ * K6 scope -> reason: "non_deterministic_inline_js"
35
+ * - run_command, any other out-of-scope shape
36
+ * -> reason: "non_deterministic_command"
37
+ * - all other non_replayable refusals
38
+ * -> reason: "non_deterministic_task"
33
39
  *
34
40
  * The classifier returns the 1-based index of the first non-replayable task
35
41
  * (matches PR-2's `failed_at_step` convention) so the CLI surface and the
@@ -1 +1 @@
1
- {"version":3,"file":"classifier.d.ts","sourceRoot":"","sources":["../../../src/kernel/classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAU,sBAAsB,CAAC;AAE/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAyB,YAAY,CAAC;AAwBtE,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAU3D;AAID;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAoCpE;AAsCD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,YAAY,GAAG,gBAAgB,CASpE"}
1
+ {"version":3,"file":"classifier.d.ts","sourceRoot":"","sources":["../../../src/kernel/classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAU,sBAAsB,CAAC;AAG/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAyB,YAAY,CAAC;AAwBtE,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAU3D;AAID;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAsCpE;AAwDD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,YAAY,GAAG,gBAAgB,CASpE"}
@@ -1,7 +1,8 @@
1
1
  /**
2
- * Kernel v1 / K4 + K5 replay classifier.
2
+ * Kernel v1 / K4 + K5 + K6 -- replay classifier.
3
3
  *
4
- * ── Scope (PR-K4 design lock §3 D1, §5; K5 v1.0 §3 D1, §5.1) ─────────────────
4
+ * -- Scope (PR-K4 design section 3 D1, section 5; K5 v1.0 section 3 D1,
5
+ * section 5.1; K6 v1.0 section 3 D1) ------------------------------
5
6
  *
6
7
  * Pure pre-pass over `WorkflowSpec.tasks`. Decides whether an IR is
7
8
  * replayable end-to-end before any sandbox is created. Drives the per-IR
@@ -16,20 +17,25 @@
16
17
  * - operationType: "append_file" + targetFiles[0] + content
17
18
  * - operationType: "prepend_file" + targetFiles[0] + content
18
19
  * - structuredReplace: { oldValue, newValue, filePath }
19
- * - operationType: "run_command" + command matching K5 allow-list
20
- * (echo <args> / true / false; see
21
- * command-classifier.ts §5.1)
20
+ * - operationType: "run_command" + command matching the K5 + K6
21
+ * allow-list (echo <args> / true /
22
+ * false / node -e "<BODY>"; see
23
+ * command-classifier.ts)
22
24
  *
23
- * Explicitly NOT replayable in K4 + K5 v1.0:
25
+ * Explicitly NOT replayable in K4 + K5 + K6 v1.0:
24
26
  * - bare `{ input: "<NL>" }` (no operationType, no structuredReplace)
25
- * - operationType: "run_command" with a command outside the K5 allow-list
26
- * (env-dependent or non-deterministic shape; revisit in K6+)
27
+ * - operationType: "run_command" with a command outside the K5 + K6
28
+ * allow-list (env-dependent or non-deterministic shape; K7+ scope)
27
29
  * - any task with runtime "cursor" | "claude" but no FS op fields set
28
- * (would require LLM intake out of K4)
30
+ * (would require LLM intake -- out of K4)
29
31
  *
30
- * K5 reason discriminant (v1.0 §3 D5):
31
- * - run_command with out-of-scope shape reason: "non_deterministic_command"
32
- * - all other non_replayable refusals → reason: "non_deterministic_task"
32
+ * Reason discriminant (K5 v1.0 section 3 D5; K6 v1.0 section 10):
33
+ * - run_command + K6 prefix shape (`node -e "..."`) but BODY out of
34
+ * K6 scope -> reason: "non_deterministic_inline_js"
35
+ * - run_command, any other out-of-scope shape
36
+ * -> reason: "non_deterministic_command"
37
+ * - all other non_replayable refusals
38
+ * -> reason: "non_deterministic_task"
33
39
  *
34
40
  * The classifier returns the 1-based index of the first non-replayable task
35
41
  * (matches PR-2's `failed_at_step` convention) so the CLI surface and the
@@ -39,6 +45,7 @@
39
45
  */
40
46
  import { isAbsolute, posix } from "node:path";
41
47
  import { isReplayableCommandShape } from "./command-classifier.js";
48
+ import { isK6NodeECommandShape } from "./inline-js-classifier.js";
42
49
  // ─── Sandbox containment predicate (K4-I3 defense) ───────────────────────────
43
50
  //
44
51
  // The classifier MUST reject any task whose paths cannot be safely rooted
@@ -106,9 +113,11 @@ export function isReplayableTaskSpec(spec) {
106
113
  return spec.content !== undefined
107
114
  && isContainedRelativePath(target0);
108
115
  case "run_command":
109
- // K4 excluded all run_command tasks. K5 widens this to a structural
116
+ // K4 excluded all run_command tasks. K5 widened this to a structural
110
117
  // allow-list of three command shapes (echo <args> / true / false).
111
- // Out-of-scope commands STILL refuse see K5 design v1.0 §5.1.
118
+ // K6 widens it further to also admit `node -e "<BODY>"` where BODY
119
+ // satisfies the K6 closed inline-JS predicate. Out-of-scope commands
120
+ // STILL refuse -- see K6 design v1.0 sections 3 + 5.
112
121
  return typeof spec.command === "string"
113
122
  && isReplayableCommandShape(spec.command);
114
123
  default:
@@ -121,32 +130,46 @@ export function isReplayableTaskSpec(spec) {
121
130
  }
122
131
  // ─── IR-level classifier ─────────────────────────────────────────────────────
123
132
  /**
124
- * Classifies a non-replayable task's refusal reason for K5 surface reporting.
133
+ * Classifies a non-replayable task's refusal reason for K5 + K6 surface
134
+ * reporting.
125
135
  *
126
- * The two reasons separate "we never replay this task shape at all" from
127
- * "this command shape is outside the deterministic universe":
136
+ * The three reasons separate three distinct refusal-shape buckets:
128
137
  *
129
- * - "non_deterministic_command" : the task IS an `operationType:"run_command"`
130
- * AND its command string is NOT in the K5
131
- * allow-list (echo / true / false).
132
- * This is the precise K5 contribution.
138
+ * - "non_deterministic_inline_js" : K6. The task IS an
139
+ * `operationType:"run_command"` AND its
140
+ * command matches the K6 prefix shape
141
+ * `node -e "<BODY>"`, but BODY is NOT
142
+ * in the K6 closed inline-JS allow-list.
143
+ * This is the precise K6 contribution.
133
144
  *
134
- * - "non_deterministic_task" : every other non-replayable shape.
135
- * Catch-all for bare NL, path-escape,
136
- * unknown operationType, missing companion
137
- * fields, etc. Preserves the K4 surface
138
- * contract verbatim (so existing callers
139
- * that only checked the reason for legacy
140
- * bare-NL refusals continue to read the
141
- * expected literal).
145
+ * - "non_deterministic_command" : K5. The task IS an
146
+ * `operationType:"run_command"` AND its
147
+ * command string is NOT in the K5+K6
148
+ * allow-list AND it does NOT even match
149
+ * the K6 prefix shape. Catches every
150
+ * non-`node -e` out-of-scope command.
151
+ * Preserves the K5 surface contract.
152
+ *
153
+ * - "non_deterministic_task" : K4 catch-all. Every other
154
+ * non-replayable shape. Bare NL,
155
+ * path-escape, unknown operationType,
156
+ * missing companion fields, etc.
157
+ * Preserves the K4 surface contract
158
+ * verbatim.
142
159
  *
143
160
  * Private helper. Pure function.
144
161
  */
145
162
  function classifyRefusalReason(task) {
146
- // K5 distinction: only fires when the task IS run_command-shaped. A bare-NL
147
- // task that happens to contain the word "command" in `input` still gets the
148
- // default "non_deterministic_task" reason, preserving K4 surface contracts.
149
163
  if (task.operationType === "run_command") {
164
+ // K6 distinction: the command matches the K6 prefix shape
165
+ // (`node -e "<BODY>"`) but the body fell out of the K6 closed allow-list.
166
+ // We surface this as the K6-specific reason so observers can distinguish
167
+ // "this command shape is K6 but the body is out of scope" from "this
168
+ // command shape is not even K5/K6 in form" -- K6 design doc section 10.
169
+ if (typeof task.command === "string" && isK6NodeECommandShape(task.command)) {
170
+ return "non_deterministic_inline_js";
171
+ }
172
+ // Otherwise the run_command falls out of K5+K6 entirely. K5 reason.
150
173
  return "non_deterministic_command";
151
174
  }
152
175
  return "non_deterministic_task";
@@ -1 +1 @@
1
- {"version":3,"file":"classifier.js","sourceRoot":"","sources":["../../../src/kernel/classifier.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"classifier.js","sourceRoot":"","sources":["../../../src/kernel/classifier.ts"],"names":[],"mappings":"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"}