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.
- package/CHANGELOG.md +168 -0
- package/README.md +114 -6
- package/dist/src/kernel/classifier.d.ts +18 -12
- package/dist/src/kernel/classifier.d.ts.map +1 -1
- package/dist/src/kernel/classifier.js +55 -32
- package/dist/src/kernel/classifier.js.map +1 -1
- package/dist/src/kernel/command-classifier.d.ts +71 -35
- package/dist/src/kernel/command-classifier.d.ts.map +1 -1
- package/dist/src/kernel/command-classifier.js +79 -37
- package/dist/src/kernel/command-classifier.js.map +1 -1
- package/dist/src/kernel/execution-replay.d.ts.map +1 -1
- package/dist/src/kernel/execution-replay.js +90 -44
- package/dist/src/kernel/execution-replay.js.map +1 -1
- package/dist/src/kernel/inline-js-classifier.d.ts +126 -0
- package/dist/src/kernel/inline-js-classifier.d.ts.map +1 -0
- package/dist/src/kernel/inline-js-classifier.js +275 -0
- package/dist/src/kernel/inline-js-classifier.js.map +1 -0
- package/dist/src/kernel/types.d.ts +2 -2
- package/dist/src/kernel/types.d.ts.map +1 -1
- package/dist/src/shell/cli/main.d.ts +49 -25
- package/dist/src/shell/cli/main.d.ts.map +1 -1
- package/dist/src/shell/cli/main.js +208 -370
- package/dist/src/shell/cli/main.js.map +1 -1
- package/dist/src/shell/cli/use-steady.js +189 -8
- package/dist/src/shell/cli/use-steady.js.map +1 -1
- package/dist/src/shell/cli/workflow-inspect-target-tree.d.ts +121 -0
- package/dist/src/shell/cli/workflow-inspect-target-tree.d.ts.map +1 -0
- package/dist/src/shell/cli/workflow-inspect-target-tree.js +256 -0
- package/dist/src/shell/cli/workflow-inspect-target-tree.js.map +1 -0
- package/dist/src/shell/cli/workflow-inspect-task-to-ir.d.ts +67 -0
- package/dist/src/shell/cli/workflow-inspect-task-to-ir.d.ts.map +1 -0
- package/dist/src/shell/cli/workflow-inspect-task-to-ir.js +192 -0
- package/dist/src/shell/cli/workflow-inspect-task-to-ir.js.map +1 -0
- package/dist/src/shell/cli/workflow-inspect.d.ts +142 -0
- package/dist/src/shell/cli/workflow-inspect.d.ts.map +1 -0
- package/dist/src/shell/cli/workflow-inspect.js +381 -0
- package/dist/src/shell/cli/workflow-inspect.js.map +1 -0
- package/dist/src/shell/cli/workflow-resume-info.d.ts +93 -0
- package/dist/src/shell/cli/workflow-resume-info.d.ts.map +1 -0
- package/dist/src/shell/cli/workflow-resume-info.js +185 -0
- package/dist/src/shell/cli/workflow-resume-info.js.map +1 -0
- package/dist/src/shell/cli/workflow-spec-loader.d.ts +69 -0
- package/dist/src/shell/cli/workflow-spec-loader.d.ts.map +1 -0
- package/dist/src/shell/cli/workflow-spec-loader.js +268 -0
- package/dist/src/shell/cli/workflow-spec-loader.js.map +1 -0
- package/dist/src/workflow/resume-token-builder.d.ts +54 -0
- package/dist/src/workflow/resume-token-builder.d.ts.map +1 -0
- package/dist/src/workflow/resume-token-builder.js +71 -0
- package/dist/src/workflow/resume-token-builder.js.map +1 -0
- package/dist/src/workflow/resume-token-io.d.ts +99 -0
- package/dist/src/workflow/resume-token-io.d.ts.map +1 -0
- package/dist/src/workflow/resume-token-io.js +198 -0
- package/dist/src/workflow/resume-token-io.js.map +1 -0
- package/dist/src/workflow/resume-token-types.d.ts +131 -0
- package/dist/src/workflow/resume-token-types.d.ts.map +1 -0
- package/dist/src/workflow/resume-token-types.js +36 -0
- package/dist/src/workflow/resume-token-types.js.map +1 -0
- package/dist/src/workflow/resume-token-validator.d.ts +48 -0
- package/dist/src/workflow/resume-token-validator.d.ts.map +1 -0
- package/dist/src/workflow/resume-token-validator.js +161 -0
- package/dist/src/workflow/resume-token-validator.js.map +1 -0
- package/dist/src/workflow/resume-verifier-types.d.ts +104 -0
- package/dist/src/workflow/resume-verifier-types.d.ts.map +1 -0
- package/dist/src/workflow/resume-verifier-types.js +19 -0
- package/dist/src/workflow/resume-verifier-types.js.map +1 -0
- package/dist/src/workflow/resume-verifier.d.ts +75 -0
- package/dist/src/workflow/resume-verifier.d.ts.map +1 -0
- package/dist/src/workflow/resume-verifier.js +335 -0
- package/dist/src/workflow/resume-verifier.js.map +1 -0
- 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
|
|
1
|
+
# UseSteady
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
|
2
|
+
* Kernel v1 / K4 + K5 + K6 -- replay classifier.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
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
|
|
20
|
-
* (echo <args> / true /
|
|
21
|
-
*
|
|
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
|
|
26
|
-
* (env-dependent or non-deterministic shape;
|
|
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
|
|
30
|
+
* (would require LLM intake -- out of K4)
|
|
29
31
|
*
|
|
30
|
-
*
|
|
31
|
-
* - run_command
|
|
32
|
-
*
|
|
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
|
|
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
|
|
2
|
+
* Kernel v1 / K4 + K5 + K6 -- replay classifier.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
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
|
|
20
|
-
* (echo <args> / true /
|
|
21
|
-
*
|
|
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
|
|
26
|
-
* (env-dependent or non-deterministic shape;
|
|
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
|
|
30
|
+
* (would require LLM intake -- out of K4)
|
|
29
31
|
*
|
|
30
|
-
*
|
|
31
|
-
* - run_command
|
|
32
|
-
*
|
|
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
|
|
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
|
-
//
|
|
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
|
|
133
|
+
* Classifies a non-replayable task's refusal reason for K5 + K6 surface
|
|
134
|
+
* reporting.
|
|
125
135
|
*
|
|
126
|
-
* The
|
|
127
|
-
* "this command shape is outside the deterministic universe":
|
|
136
|
+
* The three reasons separate three distinct refusal-shape buckets:
|
|
128
137
|
*
|
|
129
|
-
* - "
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
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
|
-
* - "
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
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":"AAAA
|
|
1
|
+
{"version":3,"file":"classifier.js","sourceRoot":"","sources":["../../../src/kernel/classifier.ts"],"names":[],"mappings":"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"}
|