@slowcook-ai/cli 0.16.0-alpha.3 → 0.17.0-alpha.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 +10 -0
- package/dist/cli.js +49 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/brew/agent.d.ts +25 -1
- package/dist/commands/brew/agent.d.ts.map +1 -1
- package/dist/commands/brew/agent.js +123 -20
- package/dist/commands/brew/agent.js.map +1 -1
- package/dist/commands/brew/halt.d.ts +1 -1
- package/dist/commands/brew/halt.d.ts.map +1 -1
- package/dist/commands/brew/halt.js +13 -0
- package/dist/commands/brew/halt.js.map +1 -1
- package/dist/commands/check/index.d.ts +14 -0
- package/dist/commands/check/index.d.ts.map +1 -0
- package/dist/commands/check/index.js +75 -0
- package/dist/commands/check/index.js.map +1 -0
- package/dist/commands/check/mock-isolation.d.ts +52 -0
- package/dist/commands/check/mock-isolation.d.ts.map +1 -0
- package/dist/commands/check/mock-isolation.js +186 -0
- package/dist/commands/check/mock-isolation.js.map +1 -0
- package/dist/commands/init/mock.d.ts.map +1 -1
- package/dist/commands/init/mock.js +47 -13
- package/dist/commands/init/mock.js.map +1 -1
- package/dist/commands/on-mockup-approved/index.d.ts +25 -0
- package/dist/commands/on-mockup-approved/index.d.ts.map +1 -0
- package/dist/commands/on-mockup-approved/index.js +359 -0
- package/dist/commands/on-mockup-approved/index.js.map +1 -0
- package/dist/commands/plate/classify.d.ts +65 -0
- package/dist/commands/plate/classify.d.ts.map +1 -0
- package/dist/commands/plate/classify.js +194 -0
- package/dist/commands/plate/classify.js.map +1 -0
- package/dist/commands/plate/index.d.ts.map +1 -1
- package/dist/commands/plate/index.js +259 -34
- package/dist/commands/plate/index.js.map +1 -1
- package/dist/commands/port/index.d.ts +30 -0
- package/dist/commands/port/index.d.ts.map +1 -0
- package/dist/commands/port/index.js +237 -0
- package/dist/commands/port/index.js.map +1 -0
- package/dist/commands/port/transform.d.ts +68 -0
- package/dist/commands/port/transform.d.ts.map +1 -0
- package/dist/commands/port/transform.js +122 -0
- package/dist/commands/port/transform.js.map +1 -0
- package/dist/commands/preview/config.d.ts +73 -0
- package/dist/commands/preview/config.d.ts.map +1 -0
- package/dist/commands/preview/config.js +200 -0
- package/dist/commands/preview/config.js.map +1 -0
- package/dist/commands/preview/deploy.d.ts +35 -0
- package/dist/commands/preview/deploy.d.ts.map +1 -0
- package/dist/commands/preview/deploy.js +247 -0
- package/dist/commands/preview/deploy.js.map +1 -0
- package/dist/commands/preview/index.d.ts +9 -0
- package/dist/commands/preview/index.d.ts.map +1 -0
- package/dist/commands/preview/index.js +67 -0
- package/dist/commands/preview/index.js.map +1 -0
- package/dist/commands/preview/ssh.d.ts +49 -0
- package/dist/commands/preview/ssh.d.ts.map +1 -0
- package/dist/commands/preview/ssh.js +99 -0
- package/dist/commands/preview/ssh.js.map +1 -0
- package/dist/commands/preview/teardown.d.ts +25 -0
- package/dist/commands/preview/teardown.d.ts.map +1 -0
- package/dist/commands/preview/teardown.js +164 -0
- package/dist/commands/preview/teardown.js.map +1 -0
- package/dist/commands/recon/index.d.ts +60 -0
- package/dist/commands/recon/index.d.ts.map +1 -0
- package/dist/commands/recon/index.js +278 -0
- package/dist/commands/recon/index.js.map +1 -0
- package/dist/commands/refine/context.d.ts +12 -0
- package/dist/commands/refine/context.d.ts.map +1 -1
- package/dist/commands/refine/context.js +72 -0
- package/dist/commands/refine/context.js.map +1 -1
- package/dist/commands/refine/history-index.d.ts +84 -0
- package/dist/commands/refine/history-index.d.ts.map +1 -0
- package/dist/commands/refine/history-index.js +289 -0
- package/dist/commands/refine/history-index.js.map +1 -0
- package/dist/commands/refine/index.d.ts.map +1 -1
- package/dist/commands/refine/index.js +28 -0
- package/dist/commands/refine/index.js.map +1 -1
- package/dist/commands/run-mock/index.d.ts +34 -0
- package/dist/commands/run-mock/index.d.ts.map +1 -0
- package/dist/commands/run-mock/index.js +308 -0
- package/dist/commands/run-mock/index.js.map +1 -0
- package/dist/commands/vibe/emit.d.ts +6 -0
- package/dist/commands/vibe/emit.d.ts.map +1 -1
- package/dist/commands/vibe/emit.js +12 -0
- package/dist/commands/vibe/emit.js.map +1 -1
- package/dist/commands/vibe/index.d.ts.map +1 -1
- package/dist/commands/vibe/index.js +180 -47
- package/dist/commands/vibe/index.js.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -2,12 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
CLI for the slowcook brewing harness. Installs the `slowcook` binary.
|
|
4
4
|
|
|
5
|
+
> ⚠️ **Active development — expect breaking changes.** Slowcook is pre-1.0 and the architecture itself is iterating in public. The 0.15 line was scrapped mid-cut and replaced by today's 0.16 mock-app architecture. CLI commands, file layouts, prompt contracts, and the package surface can and will change between alpha versions.
|
|
6
|
+
>
|
|
7
|
+
> If you're adopting slowcook today: pin exact versions in your consumer (`.brewing/slowcook-cli-version`), read each release entry in [the changelog](https://github.com/aminazar/slowcook/blob/main/CHANGELOG.md) before bumping, and treat it as a partnership — feedback from real consumers is what drives the next cut.
|
|
8
|
+
|
|
5
9
|
## Install
|
|
6
10
|
|
|
7
11
|
```bash
|
|
12
|
+
# Stable line (0.13.x today; story-flow + bug-flow + chef orchestrator)
|
|
8
13
|
npm i -D @slowcook-ai/cli
|
|
14
|
+
|
|
15
|
+
# 0.16 alpha track (singular mock app + element-anchored review)
|
|
16
|
+
npm i -D @slowcook-ai/cli@alpha @slowcook-ai/mock-runtime@latest
|
|
9
17
|
```
|
|
10
18
|
|
|
19
|
+
The `latest` tag points at the most recent stable cut; the `alpha` tag points at the in-progress 0.16 architecture. The two are NOT installable together — pick one per consumer.
|
|
20
|
+
|
|
11
21
|
## Commands (v0.4)
|
|
12
22
|
|
|
13
23
|
### `slowcook refine` (first agent)
|
package/dist/cli.js
CHANGED
|
@@ -9,6 +9,7 @@ import { refine } from "./commands/refine/index.js";
|
|
|
9
9
|
import { onSpecMerged } from "./commands/on-spec-merged/index.js";
|
|
10
10
|
import { onTestsMerged } from "./commands/on-tests-merged/index.js";
|
|
11
11
|
import { onBrewMerged } from "./commands/on-brew-merged/index.js";
|
|
12
|
+
import { onMockupApproved } from "./commands/on-mockup-approved/index.js";
|
|
12
13
|
import { testgen } from "./commands/testgen/index.js";
|
|
13
14
|
import { investigate } from "./commands/investigate/index.js";
|
|
14
15
|
import { recipeRegression } from "./commands/recipe-regression/index.js";
|
|
@@ -20,6 +21,11 @@ import { map } from "./commands/map/index.js";
|
|
|
20
21
|
import { extract } from "./commands/extract/index.js";
|
|
21
22
|
import { vibe } from "./commands/vibe/index.js";
|
|
22
23
|
import { plate } from "./commands/plate/index.js";
|
|
24
|
+
import { port } from "./commands/port/index.js";
|
|
25
|
+
import { preview } from "./commands/preview/index.js";
|
|
26
|
+
import { check } from "./commands/check/index.js";
|
|
27
|
+
import { recon } from "./commands/recon/index.js";
|
|
28
|
+
import { runMock } from "./commands/run-mock/index.js";
|
|
23
29
|
import { dispatch } from "./commands/dispatch/index.js";
|
|
24
30
|
import { fixtures } from "./commands/fixtures/index.js";
|
|
25
31
|
// Read VERSION from package.json at runtime so the CLI's self-reported
|
|
@@ -57,6 +63,10 @@ Usage:
|
|
|
57
63
|
slowcook extract [--schema] [--tokens] [--cwd <path>]
|
|
58
64
|
slowcook vibe --spec <id> [--cwd <path>] [--owner <login>] [--repo <name>] [--dry-run]
|
|
59
65
|
slowcook plate --pr <number> [--cwd <path>] [--owner <login>] [--repo <name>] [--review-comment-id <id>]
|
|
66
|
+
slowcook port --story <id> [--cwd <path>] [--dry-run] [--force]
|
|
67
|
+
slowcook preview (deploy|teardown) --pr <number> [--ssh-key <path>] [--cwd <path>]
|
|
68
|
+
slowcook check mock-isolation [--cwd <path>]
|
|
69
|
+
slowcook run-mock <story-id> [--no-poll] [--poll-seconds <n>] [--branch <ref>]
|
|
60
70
|
slowcook dispatch <step> [inputs...]
|
|
61
71
|
slowcook fixtures check [--max-age-days <n>] [--story <id>]
|
|
62
72
|
slowcook version
|
|
@@ -80,6 +90,10 @@ Commands available in ${VERSION}:
|
|
|
80
90
|
extract Brownfield extracts (schema.mmd, tokens.md) for refine/investigate context. Fast, no node_modules.
|
|
81
91
|
vibe (0.15-α.1) Design-first mockup generator. Reads spec + brownfield + code-map; emits runnable React mockup to slowcook/mockup/story-N PR.
|
|
82
92
|
plate (0.15-α.3) Mockup amendment agent. Triggered by /plate PR comments on slowcook-mockup PRs; force-pushes amendments.
|
|
93
|
+
port (0.16-α.8) Deterministic mock/ → src/ copy. Walks mock/src/, applies useScenarioFixture → useDataDomain rewrite, prepends provenance header. Pre-brew CI step.
|
|
94
|
+
preview (0.16-α.5) SSH preview deploy. \`deploy --pr N\`: build + run the mock app on the consumer's box; post URL to PR. \`teardown --pr N\`: stop + remove.
|
|
95
|
+
check (0.16-α.13) Static structural checks. \`check mock-isolation\` verifies every import in mock/ stays inside mock/ (catches vibe-prompt slippage that breaks the mock-vs-prod separation rule).
|
|
96
|
+
run-mock (0.16-α.17) One-command mock launch + auto-pull. \`run-mock <story>\`: checkout mockup branch, npm install in mock/, run next dev with overlay env vars, poll origin every 15s + git pull --ff-only on plate amendments.
|
|
83
97
|
dispatch Trigger a slowcook GitHub Actions workflow remotely (brew / testgen / refine).
|
|
84
98
|
|
|
85
99
|
Coming in later versions:
|
|
@@ -112,6 +126,12 @@ async function main() {
|
|
|
112
126
|
case "on-brew-merged":
|
|
113
127
|
await onBrewMerged(args.slice(1));
|
|
114
128
|
return;
|
|
129
|
+
case "on-mockup-approved":
|
|
130
|
+
// 0.16.0-α.23 — fires from the slowcook-mockup-approved.yml
|
|
131
|
+
// workflow on label-add. Posts a cost-rollup audit comment on
|
|
132
|
+
// the source issue (looked up via spec.source_issue).
|
|
133
|
+
await onMockupApproved(args.slice(1));
|
|
134
|
+
return;
|
|
115
135
|
case "testgen":
|
|
116
136
|
case "recipe":
|
|
117
137
|
// 0.13.0-alpha.1 — `recipe` is the canonical name (kitchen
|
|
@@ -174,6 +194,35 @@ async function main() {
|
|
|
174
194
|
// amends mockup files; force-pushes the same branch.
|
|
175
195
|
await plate(args.slice(1), VERSION);
|
|
176
196
|
return;
|
|
197
|
+
case "port":
|
|
198
|
+
// 0.16.0-α.8 — deterministic copy of mock/src/* → src/*.
|
|
199
|
+
// No LLM; same input → same output; auditable diff. Runs as a
|
|
200
|
+
// CI step before brew so brew's allowed-paths can shrink.
|
|
201
|
+
await port(args.slice(1), VERSION);
|
|
202
|
+
return;
|
|
203
|
+
case "preview":
|
|
204
|
+
// 0.16.0-α.5 — SSH preview deploy. Reads .brewing/preview.yaml,
|
|
205
|
+
// builds the consumer's mock app on their box, runs the docker
|
|
206
|
+
// container, posts the URL to the PR. teardown undoes it.
|
|
207
|
+
await preview(args.slice(1), VERSION);
|
|
208
|
+
return;
|
|
209
|
+
case "check":
|
|
210
|
+
// 0.16.0-α.13 — static structural checks. mock-isolation
|
|
211
|
+
// verifies vibe + plate keep mock/ self-contained.
|
|
212
|
+
await check(args.slice(1), VERSION);
|
|
213
|
+
return;
|
|
214
|
+
case "recon":
|
|
215
|
+
// 0.17.6 — pre-brew structural divergence check. Runs after
|
|
216
|
+
// both mockup PR + tests PR are merged; catches residual
|
|
217
|
+
// vibe ⇄ testgen divergence before brew burns tokens.
|
|
218
|
+
await recon(args.slice(1), VERSION);
|
|
219
|
+
return;
|
|
220
|
+
case "run-mock":
|
|
221
|
+
// 0.16.0-α.17 — one-command mock launch + auto-pull on plate
|
|
222
|
+
// amendments. Wraps git fetch/checkout + npm install + next dev
|
|
223
|
+
// + a 15s poll loop that pulls when origin moves.
|
|
224
|
+
await runMock(args.slice(1), VERSION);
|
|
225
|
+
return;
|
|
177
226
|
case "dispatch":
|
|
178
227
|
await dispatch(args.slice(1));
|
|
179
228
|
return;
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AACzE,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAExD,uEAAuE;AACvE,2EAA2E;AAC3E,yEAAyE;AACzE,uEAAuE;AACvE,yBAAyB;AACzB,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;AAC9D,MAAM,OAAO,GAAW,CAAC,GAAG,EAAE;IAC5B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;QAC9D,OAAO,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,eAAe,CAAC;IACzB,CAAC;AACH,CAAC,CAAC,EAAE,CAAC;AAEL,MAAM,KAAK,GAAG
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
2
|
import type { ForgeAdapter, Spec } from "@slowcook-ai/core";
|
|
3
3
|
import { type StackConfig } from "@slowcook-ai/stack-ts";
|
|
4
|
-
import { type HaltReport } from "./halt.js";
|
|
4
|
+
import { type HaltReason, type HaltReport } from "./halt.js";
|
|
5
5
|
/** ------------------------- Context + options ------------------------- */
|
|
6
6
|
export interface BrewContext {
|
|
7
7
|
repoRoot: string;
|
|
@@ -98,8 +98,32 @@ export declare function findHandler(repoRoot: string, method: string, path: stri
|
|
|
98
98
|
* look inside a function body, it uses `read_file` normally.
|
|
99
99
|
*/
|
|
100
100
|
export declare function outlineFile(pathHint: string, source: string): string;
|
|
101
|
+
/**
|
|
102
|
+
* 0.16.0-α.30 — halt-envelope parser.
|
|
103
|
+
*
|
|
104
|
+
* The plate-mode prompt instructs the agent to halt by emitting an
|
|
105
|
+
* XML envelope in its text output:
|
|
106
|
+
*
|
|
107
|
+
* <halt class="MOCKUP_DESIGN_CONFLICT">
|
|
108
|
+
* <test>tests/integration/story-N-ui.test.tsx > "owner sees Pin"</test>
|
|
109
|
+
* <conflict>The test asserts X but the mock renders Y.</conflict>
|
|
110
|
+
* <recommendation>PM should /plate or /refine.</recommendation>
|
|
111
|
+
* </halt>
|
|
112
|
+
*
|
|
113
|
+
* Without this parser, brew never recognises its own agent's halt
|
|
114
|
+
* envelopes. The agent's perfect classification gets converted to a
|
|
115
|
+
* generic AGENT_STALLED_NO_EDITS halt because brew only counts tool
|
|
116
|
+
* calls. Returns null when no envelope is found OR when the class
|
|
117
|
+
* isn't in the recognised whitelist (defensive against typos).
|
|
118
|
+
*/
|
|
119
|
+
type HaltEnvelope = {
|
|
120
|
+
class: HaltReason;
|
|
121
|
+
summary: string;
|
|
122
|
+
};
|
|
123
|
+
export declare function parseHaltEnvelope(rationale: string): HaltEnvelope | null;
|
|
101
124
|
/** ------------------------- Entry helpers ------------------------- */
|
|
102
125
|
export declare function readFrozenPaths(repoRoot: string): FrozenPaths;
|
|
103
126
|
export declare function readStackConfig(repoRoot: string): StackConfig;
|
|
104
127
|
export declare function loadSpec(repoRoot: string, storyId: string): Spec;
|
|
128
|
+
export {};
|
|
105
129
|
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/commands/brew/agent.ts"],"names":[],"mappings":"AAaA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAKL,KAAK,WAAW,EAIjB,MAAM,uBAAuB,CAAC;AAkB/B,OAAO,
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/commands/brew/agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -125,15 +125,29 @@ export async function runBrew(ctx) {
|
|
|
125
125
|
: new Set();
|
|
126
126
|
appendRunLog(ctx, `BASELINE_FULL total=${fullBaseline.tests.length} green=${fullBaselineGreen.size} red=${fullBaseline.tests.length - fullBaselineGreen.size}`);
|
|
127
127
|
if (!baseline.ran) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
128
|
+
// 0.16.0-α.28 — partial-degradation: if SOME suites produced tests
|
|
129
|
+
// (e.g. backend vitest passed) but others failed (e.g. playwright
|
|
130
|
+
// acceptance crashed because Next webServer couldn't boot without
|
|
131
|
+
// .env.acceptance), proceed with what we got + log the degradation
|
|
132
|
+
// instead of halting TEST_RUNNER_BROKEN. Halt only when nothing ran.
|
|
133
|
+
if (baseline.tests.length === 0) {
|
|
134
|
+
return haltFor(ctx, {
|
|
135
|
+
reason: "TEST_RUNNER_BROKEN",
|
|
136
|
+
iterations: 0,
|
|
137
|
+
checkpoints: 0,
|
|
138
|
+
greenCount: 0,
|
|
139
|
+
totalCount: expectedTestIds.size,
|
|
140
|
+
spendUsd: 0,
|
|
141
|
+
summary: `Test runner failed to produce usable output on the baseline run. Error: ${baseline.error ?? "(unknown)"}. Fix the runner before brewing.`,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
const failedSuiteNames = baseline.suites
|
|
145
|
+
.filter((s) => s.exit_code !== 0)
|
|
146
|
+
.map((s) => s.suite)
|
|
147
|
+
.join(", ") || "(unknown)";
|
|
148
|
+
console.log(`⚠ baseline DEGRADED — suite(s) "${failedSuiteNames}" couldn't boot; proceeding with ${baseline.tests.length} test(s) from suite(s) that did run.`);
|
|
149
|
+
console.log(` degradation reason: ${(baseline.error ?? "").slice(0, 300)}`);
|
|
150
|
+
appendRunLog(ctx, `BASELINE_DEGRADED failed_suites=${failedSuiteNames} surviving_tests=${baseline.tests.length} reason="${(baseline.error ?? "").slice(0, 200).replace(/"/g, "'")}"`);
|
|
137
151
|
}
|
|
138
152
|
// Fix 1 (0.7.14): keep a lookup of failure messages per test id so
|
|
139
153
|
// each iteration's turn prompt can include the target test's failure
|
|
@@ -313,6 +327,28 @@ export async function runBrew(ctx) {
|
|
|
313
327
|
// successful turn — only the spend-delta on the NEXT iter's
|
|
314
328
|
// START line reveals tokens were burned.
|
|
315
329
|
appendRunLog(ctx, `ITER ${iteration} NO-EDITS (agent made no tool calls this turn) spend_delta=$${turnResult.spendDelta.toFixed(2)} consecutive_no_edits=${consecutiveNoEdits} stagnation=${stagnation}/${STAGNATION_CAP}`);
|
|
330
|
+
// 0.16.0-α.30: halt-envelope parser. The plate-mode prompt tells
|
|
331
|
+
// the agent to halt by emitting `<halt class="X">...</halt>` in
|
|
332
|
+
// its text. Without this parser, brew never reads its own agent's
|
|
333
|
+
// halt envelopes and falls through to AGENT_STALLED_NO_EDITS — the
|
|
334
|
+
// agent's perfect MOCKUP_DESIGN_CONFLICT classification gets
|
|
335
|
+
// converted to a generic stall (rewo PR #147 brew run 25278580747:
|
|
336
|
+
// agent emitted MOCKUP_DESIGN_CONFLICT envelope, brew reported
|
|
337
|
+
// AGENT_STALLED_NO_EDITS, $0.91 wasted on the misclassification).
|
|
338
|
+
const haltEnvelope = parseHaltEnvelope(turnResult.rationale);
|
|
339
|
+
if (haltEnvelope) {
|
|
340
|
+
appendRunLog(ctx, `ITER ${iteration} ${haltEnvelope.class} — agent emitted halt envelope in rationale`);
|
|
341
|
+
return haltFor(ctx, {
|
|
342
|
+
reason: haltEnvelope.class,
|
|
343
|
+
iterations: iteration,
|
|
344
|
+
checkpoints: iterationLogs.filter((l) => l.outcome === "checkpoint").length,
|
|
345
|
+
greenCount: greenSet.size,
|
|
346
|
+
totalCount: expectedTestIds.size,
|
|
347
|
+
spendUsd,
|
|
348
|
+
iterationLogs,
|
|
349
|
+
summary: haltEnvelope.summary,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
316
352
|
// Fix 3 (0.7.14): voluntary-halt escape hatch. If the agent's
|
|
317
353
|
// rationale ends with "Considering halting voluntarily" the model
|
|
318
354
|
// has self-reported that it can't make progress — halt immediately
|
|
@@ -381,14 +417,54 @@ export async function runBrew(ctx) {
|
|
|
381
417
|
appendRunLog(ctx, `ITER ${iteration} REJECT frozen-path ${frozenHit} (also touched ${diff.changedPaths.length - 1} other file(s)) spend_delta=$${turnResult.spendDelta.toFixed(2)}`);
|
|
382
418
|
continue;
|
|
383
419
|
}
|
|
384
|
-
// 0.
|
|
385
|
-
//
|
|
386
|
-
//
|
|
387
|
-
//
|
|
420
|
+
// 0.16.0-α.29 — plate-mode contract refinement.
|
|
421
|
+
//
|
|
422
|
+
// Old contract ("don't touch the UI") was too rigid — the
|
|
423
|
+
// data-wiring IS in the component (handlers POST, hooks fetch,
|
|
424
|
+
// forms submit). Forbidding all UI edits forced brew to find
|
|
425
|
+
// nonexistent escape hatches and stalled (rewo PR #147 brew run
|
|
426
|
+
// 25278045422 — AGENT_STALLED_NO_EDITS at $1.82, agent correctly
|
|
427
|
+
// diagnosed it needed to wire POST /api/pins but the click handler
|
|
428
|
+
// lives in the ported component).
|
|
429
|
+
//
|
|
430
|
+
// New contract: "preserve UI shape, swap mock data for real data."
|
|
431
|
+
//
|
|
432
|
+
// - Port-marked files (@slowcook-port-from) are the ONLY UI-tree
|
|
433
|
+
// files brew is allowed to write — to wire real data + handlers
|
|
434
|
+
// into the shape that vibe defined. Brew should preserve JSX
|
|
435
|
+
// structure, props signature, className, layout. Tier-2
|
|
436
|
+
// acceptance + visual regression are the backstop for shape
|
|
437
|
+
// drift.
|
|
438
|
+
//
|
|
439
|
+
// - .mock.ts files: still rejected (those are pre-port mock
|
|
440
|
+
// fixtures with no behavior to wire).
|
|
441
|
+
//
|
|
442
|
+
// - src/components/* and src/*.tsx WITHOUT the port marker:
|
|
443
|
+
// consumer's hand-written prod UI. Off-limits in plate mode
|
|
444
|
+
// (brew shouldn't touch UI it didn't get from vibe).
|
|
388
445
|
const platePathHit = ctx.mode === "plate"
|
|
389
|
-
? diff.changedPaths.find((p) =>
|
|
390
|
-
|
|
391
|
-
|
|
446
|
+
? diff.changedPaths.find((p) => {
|
|
447
|
+
if (/\.mock\.ts$/.test(p))
|
|
448
|
+
return true;
|
|
449
|
+
// Marker check first — port-owned files are ALLOWED writes
|
|
450
|
+
// under the new contract. Reading the working-tree version
|
|
451
|
+
// because the agent's edit IS the working tree.
|
|
452
|
+
try {
|
|
453
|
+
const fullPath = join(ctx.repoRoot, p);
|
|
454
|
+
if (existsSync(fullPath)) {
|
|
455
|
+
const head = readFileSync(fullPath, "utf8").slice(0, 2048);
|
|
456
|
+
if (head.includes("@slowcook-port-from"))
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
catch { /* ignore — fall through to path checks */ }
|
|
461
|
+
// Hand-written UI (no marker) stays frozen.
|
|
462
|
+
if (/^src\/components\//.test(p))
|
|
463
|
+
return true;
|
|
464
|
+
if (/^src\/.*\.tsx$/.test(p))
|
|
465
|
+
return true;
|
|
466
|
+
return false;
|
|
467
|
+
})
|
|
392
468
|
: null;
|
|
393
469
|
if (platePathHit) {
|
|
394
470
|
revertToSnapshot(ctx, snapshot);
|
|
@@ -396,7 +472,7 @@ export async function runBrew(ctx) {
|
|
|
396
472
|
iteration,
|
|
397
473
|
target_test_id: currentTarget,
|
|
398
474
|
outcome: "rejected-frozen-path",
|
|
399
|
-
note: `plate-mode protects UI: ${platePathHit}.
|
|
475
|
+
note: `plate-mode protects hand-written UI: ${platePathHit}. Brew can only wire data into port-marked files (@slowcook-port-from) or write to src/lib/data + src/app/api + supabase/migrations.`,
|
|
400
476
|
files_touched: diff.changedPaths,
|
|
401
477
|
lines_added: diff.linesAdded,
|
|
402
478
|
lines_removed: diff.linesRemoved,
|
|
@@ -406,11 +482,11 @@ export async function runBrew(ctx) {
|
|
|
406
482
|
priorAttempts.push({
|
|
407
483
|
iteration,
|
|
408
484
|
outcome: "reverted-no-progress",
|
|
409
|
-
note: `rejected: plate-mode wrote to
|
|
485
|
+
note: `rejected: plate-mode wrote to hand-written UI path ${platePathHit} (no @slowcook-port-from marker). If the test target requires editing this exact file, the vibe/recipe pair is mismatched — halt with MOCKUP_DESIGN_CONFLICT.`,
|
|
410
486
|
files_touched: diff.changedPaths,
|
|
411
487
|
});
|
|
412
488
|
stagnation += 1;
|
|
413
|
-
appendRunLog(ctx, `ITER ${iteration} REJECT plate-
|
|
489
|
+
appendRunLog(ctx, `ITER ${iteration} REJECT plate-handwritten-ui ${platePathHit} spend_delta=$${turnResult.spendDelta.toFixed(2)}`);
|
|
414
490
|
continue;
|
|
415
491
|
}
|
|
416
492
|
const scopeHit = diff.changedPaths.find((p) => !isAllowedPath(p, ctx.allowedPaths) &&
|
|
@@ -467,7 +543,10 @@ export async function runBrew(ctx) {
|
|
|
467
543
|
// story's manifest files (0.11.16+) for fast feedback. Full
|
|
468
544
|
// suite runs at brew completion as the correctness gate.
|
|
469
545
|
const result = runTestSuite(ctx, storyTestFiles);
|
|
470
|
-
if (!result.ran) {
|
|
546
|
+
if (!result.ran && result.tests.length === 0) {
|
|
547
|
+
// 0.16.0-α.28 — only halt when zero tests came back. Same
|
|
548
|
+
// degrade-on-partial policy as the baseline run: if SOME suite
|
|
549
|
+
// produced tests, proceed with what we got.
|
|
471
550
|
revertToSnapshot(ctx, snapshot);
|
|
472
551
|
iterationLogs.push({
|
|
473
552
|
iteration,
|
|
@@ -1702,6 +1781,30 @@ async function haltFor(ctx, args) {
|
|
|
1702
1781
|
}
|
|
1703
1782
|
return { kind: "halted", report };
|
|
1704
1783
|
}
|
|
1784
|
+
const RECOGNISED_HALT_CLASSES = new Set([
|
|
1785
|
+
"MOCKUP_DESIGN_CONFLICT",
|
|
1786
|
+
"SPEC_AMBIGUITY_DETECTED",
|
|
1787
|
+
"TEST_RUNNER_BROKEN",
|
|
1788
|
+
"AGENT_SELF_REPORTED_STUCK",
|
|
1789
|
+
]);
|
|
1790
|
+
export function parseHaltEnvelope(rationale) {
|
|
1791
|
+
if (!rationale)
|
|
1792
|
+
return null;
|
|
1793
|
+
const m = rationale.match(/<halt\s+class\s*=\s*["']([A-Z_]+)["']\s*>([\s\S]*?)<\/halt>/);
|
|
1794
|
+
if (!m || !m[1] || !m[2])
|
|
1795
|
+
return null;
|
|
1796
|
+
const cls = m[1];
|
|
1797
|
+
if (!RECOGNISED_HALT_CLASSES.has(cls))
|
|
1798
|
+
return null;
|
|
1799
|
+
const inner = m[2];
|
|
1800
|
+
// Prefer <conflict>; fall back to all text inside the envelope.
|
|
1801
|
+
const conflictMatch = inner.match(/<conflict>([\s\S]*?)<\/conflict>/);
|
|
1802
|
+
const raw = conflictMatch && conflictMatch[1]
|
|
1803
|
+
? conflictMatch[1]
|
|
1804
|
+
: inner.replace(/<[^>]+>/g, " ");
|
|
1805
|
+
const summary = raw.replace(/\s+/g, " ").trim().slice(0, 800);
|
|
1806
|
+
return { class: cls, summary };
|
|
1807
|
+
}
|
|
1705
1808
|
function generateDiagnosis(iterationLogs, greenSet, expected) {
|
|
1706
1809
|
const storyGreen = [...greenSet].filter((t) => expected.has(t)).length;
|
|
1707
1810
|
if (iterationLogs.length === 0) {
|