@slowcook-ai/cli 0.5.2 → 0.6.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.
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Prompts + tool definitions for the brew agent loop.
3
+ *
4
+ * The agent's one job per turn: make the TARGET red test go green without
5
+ * regressing any currently-green test. Slowcook (not the agent) runs the test
6
+ * suite between turns and applies the ratchet. The agent's tools are limited
7
+ * to reading and writing files, plus one "justify-overflow" tool for when it
8
+ * needs to break the graduality cap.
9
+ */
10
+ export const BREW_SYSTEM = `You are the brewing implementer agent for slowcook — a rigorous TDD-first coding harness.
11
+
12
+ ## Your task per turn
13
+
14
+ You will be told one specific failing test (the **target**). Your job: make a code change that flips the target from red to green, WITHOUT breaking any currently-green test.
15
+
16
+ After your turn ends, slowcook runs the test suite and applies a mechanical ratchet:
17
+
18
+ - If any previously-green test now fails → your changes are **reverted entirely**.
19
+ - If the target went green (and no regressions) → your changes become a **checkpoint**.
20
+ - If nothing changed green/red → your changes are **reverted** (no progress = no commit).
21
+
22
+ This means: **you only keep changes that advance the green set.** Make real progress per turn, not exploratory edits.
23
+
24
+ ## Tools
25
+
26
+ - **read_file(path)** — read a file from the worktree. Use it before editing.
27
+ - **list_directory(path)** — see what's in a directory.
28
+ - **write_file(path, contents)** — create or fully replace a file. Prefer reading first + writing a complete updated file.
29
+ - **justify_diff_overflow({ reason_category, affected_scope, narrative, proposed_substories_if_split? })** — call ONLY if your intended change must exceed the graduality soft-cap (200 lines across ≤5 files). Explain why.
30
+
31
+ You do NOT run tests. Slowcook runs them after your turn and tells you the result in the next turn's prompt.
32
+
33
+ ## Constraints
34
+
35
+ - **One target per turn.** The prompt names ONE failing test. Work on that one. Incidental green flips on other tests are fine but not the goal.
36
+ - **Minimum diff.** Smallest change that flips the target. Don't refactor. Don't anticipate future tests.
37
+ - **Stay within \`allowed_paths\` from the spec.** If the spec says you may only touch \`src/app/api/reactions/\`, do not edit anything outside.
38
+ - **Never modify frozen paths.** \`tests/\`, \`.brewing/\`, \`vitest.config.*\`, \`package.json\` scripts — read them, never write them. Slowcook will mechanically reject any such diff.
39
+ - **Never use \`test.skip\` / \`.todo\` / \`.only\` / environment branches like \`if (NODE_ENV === 'test')\`.** Slowcook's static scan catches these and will reject the turn.
40
+
41
+ ## Output conventions
42
+
43
+ - Use tools to make changes. Do not paste code in your text reply — slowcook only applies changes that come through \`write_file\`.
44
+ - At the end of your turn, include a one-paragraph **rationale** explaining what you changed and why. Slowcook uses this for halt reports if brewing stalls.
45
+ - If you need more information (read files, list directories), use the read tools first, THEN edit. Don't guess at file contents.
46
+
47
+ ## Failure recovery guidance
48
+
49
+ - If you receive a prompt showing your previous turn was **reverted**, read the failure reason carefully. Typical causes:
50
+ 1. **Regression** — one of your edits broke a currently-green test. Look at which test; your change touched its dependency.
51
+ 2. **No progress** — your edits didn't change any test outcome. The code path you changed may not be exercised by the target test.
52
+ 3. **Frozen-path violation** — you edited a file you shouldn't have. Don't.
53
+ - On no-progress reverts, consider whether the target test is reachable from the code path you're editing, or whether it's testing a layer your code doesn't touch (e.g., the test calls \`fetch('http://localhost:3000')\` but no server is running).
54
+ `;
55
+ export const BREW_TOOLS = [
56
+ {
57
+ name: "read_file",
58
+ description: "Read a file from the worktree. Returns the file's current contents as a string. Throws if the file doesn't exist.",
59
+ input_schema: {
60
+ type: "object",
61
+ properties: {
62
+ path: { type: "string", description: "Repo-relative path (e.g., 'src/app/api/reactions/route.ts')" },
63
+ },
64
+ required: ["path"],
65
+ },
66
+ },
67
+ {
68
+ name: "list_directory",
69
+ description: "List entries in a directory. Returns an array of { name, type: 'file'|'dir' }. Useful for exploring code structure.",
70
+ input_schema: {
71
+ type: "object",
72
+ properties: {
73
+ path: { type: "string", description: "Repo-relative directory path (e.g., 'src/app/api/reactions/')" },
74
+ },
75
+ required: ["path"],
76
+ },
77
+ },
78
+ {
79
+ name: "write_file",
80
+ description: "Create or fully overwrite a file. Parent directories are created as needed. Returns the number of lines written.",
81
+ input_schema: {
82
+ type: "object",
83
+ properties: {
84
+ path: { type: "string", description: "Repo-relative path to write." },
85
+ contents: { type: "string", description: "Full file contents. This replaces whatever was there before." },
86
+ },
87
+ required: ["path", "contents"],
88
+ },
89
+ },
90
+ {
91
+ name: "justify_diff_overflow",
92
+ description: "Call ONLY when your proposed change must exceed the graduality soft-cap (200 lines / 5 files). Without this call, an oversized diff is rejected by slowcook.",
93
+ input_schema: {
94
+ type: "object",
95
+ properties: {
96
+ reason_category: {
97
+ type: "string",
98
+ enum: ["new_module", "protocol_change", "cross_cutting", "refactor_needed", "other"],
99
+ },
100
+ affected_scope: {
101
+ type: "array",
102
+ items: { type: "string" },
103
+ description: "Paths or directories affected by the overflow.",
104
+ },
105
+ narrative: {
106
+ type: "string",
107
+ description: "Concrete one-paragraph explanation of why the smaller diff isn't viable.",
108
+ },
109
+ proposed_substories_if_split: {
110
+ type: "array",
111
+ items: { type: "string" },
112
+ description: "If this story should be split, list the sub-stories here.",
113
+ },
114
+ },
115
+ required: ["reason_category", "affected_scope", "narrative"],
116
+ },
117
+ },
118
+ ];
119
+ /**
120
+ * Render a single-turn prompt for the agent. Keeps history short (we re-supply
121
+ * the same system prompt via prompt caching, then hand a fresh turn-state each
122
+ * iteration; agent doesn't carry over its own previous turns because slowcook
123
+ * may have reverted them).
124
+ */
125
+ export function turnPrompt(args) {
126
+ const sections = [];
127
+ sections.push(`## Brew iteration ${args.iteration} of ${args.max_iterations}`);
128
+ sections.push(`**Budget:** $${args.budget_spent_usd.toFixed(2)} spent of $${args.budget_cap_usd.toFixed(2)} cap.`);
129
+ sections.push("");
130
+ sections.push("### Target test (flip this one from red to green)");
131
+ sections.push("```");
132
+ sections.push(args.target_test_id);
133
+ sections.push(` (in ${args.target_test_file})`);
134
+ sections.push("```");
135
+ sections.push("");
136
+ sections.push("### Spec (the contract)");
137
+ sections.push("```yaml");
138
+ sections.push(args.spec_yaml.trim());
139
+ sections.push("```");
140
+ sections.push("");
141
+ if (args.allowed_paths.length > 0) {
142
+ sections.push("### Allowed paths for this story");
143
+ for (const p of args.allowed_paths)
144
+ sections.push(`- \`${p}\``);
145
+ sections.push("");
146
+ }
147
+ sections.push(`### Test state going into this turn: ${args.currently_green.length} green / ${args.currently_red.length} red`);
148
+ sections.push("");
149
+ if (args.currently_green.length > 0) {
150
+ sections.push("<details><summary>Currently green (keep them green!)</summary>");
151
+ sections.push("");
152
+ for (const t of args.currently_green.slice(0, 30))
153
+ sections.push(`- \`${t}\``);
154
+ if (args.currently_green.length > 30) {
155
+ sections.push(`- … (${args.currently_green.length - 30} more)`);
156
+ }
157
+ sections.push("</details>");
158
+ sections.push("");
159
+ }
160
+ if (args.previous_attempts && args.previous_attempts.length > 0) {
161
+ sections.push("### Your previous attempts on this target");
162
+ for (const a of args.previous_attempts.slice(-3)) {
163
+ sections.push(`- **iter ${a.iteration}: ${a.outcome}** — ${a.note}`);
164
+ if (a.files_touched.length > 0) {
165
+ sections.push(` files: ${a.files_touched.map((f) => `\`${f}\``).join(", ")}`);
166
+ }
167
+ }
168
+ sections.push("");
169
+ }
170
+ sections.push("### Your turn");
171
+ sections.push("Use the tools to inspect the code, then write the minimum change that flips the target test. End with a one-paragraph rationale of what you changed and why.");
172
+ return sections.join("\n");
173
+ }
174
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/commands/brew/prompts.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- export declare const CLI_VERSION_FOR_TEMPLATES = "0.5.2";
1
+ export declare const CLI_VERSION_FOR_TEMPLATES = "0.6.0";
2
2
  export interface TemplateParams {
3
3
  /** CODEOWNERS handle or team (e.g. "@aminazar" or "@acme/frontend"). */
4
4
  owner: string;
@@ -1,6 +1,6 @@
1
1
  // Static and parameterized file contents written by `slowcook init`.
2
2
  // Version is bumped in lockstep with the CLI package.
3
- export const CLI_VERSION_FOR_TEMPLATES = "0.5.2";
3
+ export const CLI_VERSION_FOR_TEMPLATES = "0.6.0";
4
4
  export const SLOWCOOK_CODEOWNERS_MARKER_BEGIN = "# --- slowcook:frozen-paths BEGIN ---";
5
5
  export const SLOWCOOK_CODEOWNERS_MARKER_END = "# --- slowcook:frozen-paths END ---";
6
6
  export function frozenPathsJson() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slowcook-ai/cli",
3
- "version": "0.5.2",
3
+ "version": "0.6.0",
4
4
  "description": "CLI for the slowcook brewing harness",
5
5
  "license": "MIT",
6
6
  "author": "aminazar",
@@ -37,9 +37,9 @@
37
37
  "@octokit/rest": "^21.0.2",
38
38
  "yaml": "^2.6.0",
39
39
  "zod": "^3.23.8",
40
- "@slowcook-ai/forge-github": "^0.5.0",
41
40
  "@slowcook-ai/core": "^0.5.0",
42
- "@slowcook-ai/stack-ts": "^0.5.0"
41
+ "@slowcook-ai/stack-ts": "^0.6.0",
42
+ "@slowcook-ai/forge-github": "^0.5.0"
43
43
  },
44
44
  "publishConfig": {
45
45
  "access": "public"