@slowcook-ai/cli 0.3.0 → 0.4.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 CHANGED
@@ -8,7 +8,45 @@ CLI for the slowcook brewing harness. Installs the `slowcook` binary.
8
8
  npm i -D @slowcook-ai/cli
9
9
  ```
10
10
 
11
- ## Commands (v0.3)
11
+ ## Commands (v0.4)
12
+
13
+ ### `slowcook refine` (first agent)
14
+
15
+ Drives a GitHub issue through a clarifying-question loop until a frozen spec is emitted as a draft PR. Enforces the issue-level ratchet: new issues must not silently duplicate or contradict earlier decisions.
16
+
17
+ ```bash
18
+ npx slowcook refine --issue <number> [options]
19
+ ```
20
+
21
+ **Required environment:**
22
+
23
+ - `ANTHROPIC_API_KEY` — for the refinement and relationship-analysis LLM calls
24
+ - `GITHUB_TOKEN` — with `contents: write`, `issues: write`, `pull-requests: write`
25
+
26
+ **Options:**
27
+
28
+ | Flag | Default | Description |
29
+ |---|---|---|
30
+ | `--issue <number>` | required | GitHub issue number |
31
+ | `--cwd <path>` | `.` | Repo working directory |
32
+ | `--owner <login>` | parsed from git remote | Repo owner |
33
+ | `--repo <name>` | parsed from git remote | Repo name |
34
+ | `--base <branch>` | `main` | Base branch for the draft spec PR |
35
+ | `--refine-model <id>` | `claude-opus-4-7` | Model for the refinement loop |
36
+ | `--relationship-model <id>` | `claude-sonnet-4-5` | Model for relationship analysis |
37
+
38
+ **Behaviour per invocation:**
39
+
40
+ 1. Reads the issue (body + labels + comments) and all currently-active specs.
41
+ 2. Runs a relationship analysis: `new_or_independent | overlap | contradiction`.
42
+ 3. Acts on the verdict:
43
+ - **overlap** — posts a comment naming the overlapping spec ids, applies `blocked-overlap` label, exits.
44
+ - **contradiction** without `change-of-mind` label — posts a blocker comment, applies `blocked-contradiction` label, exits.
45
+ - **contradiction** with `change-of-mind` label — proceeds; the spec's `supersedes` field is populated.
46
+ - **new / independent** — proceeds to the refinement loop.
47
+ 4. Runs one round of refinement: either posts clarifying questions (and exits; next invocation picks up on the next PM comment) OR emits the spec YAML, writes `specs/story-N.yaml` and updates `specs/_index.yaml`, commits + pushes a branch, opens a draft PR, applies `spec-ready` label.
48
+
49
+ Re-run on every new PM comment in the issue (via a GitHub Actions workflow triggered by `issue_comment` + `issues` events).
12
50
 
13
51
  ### `slowcook init`
14
52
 
package/dist/cli.js CHANGED
@@ -2,7 +2,8 @@
2
2
  import { guard } from "./commands/guard.js";
3
3
  import { manifest } from "./commands/manifest.js";
4
4
  import { init } from "./commands/init/index.js";
5
- const VERSION = "0.3.0";
5
+ import { refine } from "./commands/refine/index.js";
6
+ const VERSION = "0.4.0";
6
7
  const USAGE = `
7
8
  slowcook — TDD-first agentic development harness
8
9
 
@@ -11,6 +12,7 @@ Usage:
11
12
  slowcook guard --base <ref> --head <ref> [--override] [--config <path>]
12
13
  slowcook manifest record [--stack-config <path>] [--manifest <path>] [--story <id>]
13
14
  slowcook manifest verify [--stack-config <path>] [--manifest <path>] [--story <id>]
15
+ slowcook refine --issue <number> [--cwd <path>] [--owner <login>] [--repo <name>]
14
16
  slowcook version
15
17
  slowcook help
16
18
 
@@ -18,9 +20,10 @@ Commands available in ${VERSION}:
18
20
  init Scaffold slowcook configuration in a consumer project.
19
21
  guard Check for frozen-path violations between two git refs.
20
22
  manifest Record or verify the set of discoverable tests.
23
+ refine Drive a GitHub issue toward a frozen spec (refinement agent).
21
24
 
22
25
  Coming in later versions:
23
- refine, testgen, brew, review, dashboard
26
+ testgen, brew, review, dashboard
24
27
 
25
28
  Docs: https://github.com/aminazar/slowcook
26
29
  `;
@@ -37,6 +40,9 @@ async function main() {
37
40
  case "manifest":
38
41
  await manifest(args.slice(1));
39
42
  return;
43
+ case "refine":
44
+ await refine(args.slice(1), VERSION);
45
+ return;
40
46
  case "version":
41
47
  case "--version":
42
48
  case "-v":
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAEhD,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,MAAM,KAAK,GAAG;;;;;;;;;;;wBAWU,OAAO;;;;;;;;;CAS9B,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAExB,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,MAAM;YACT,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YACnC,OAAO;QACT,KAAK,OAAO;YACV,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3B,OAAO;QACT,KAAK,UAAU;YACb,MAAM,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9B,OAAO;QACT,KAAK,SAAS,CAAC;QACf,KAAK,WAAW,CAAC;QACjB,KAAK,IAAI;YACP,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,EAAE,CAAC,CAAC;YACnC,OAAO;QACT,KAAK,SAAS,CAAC;QACf,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,IAAI;YACP,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACnB,OAAO;QACT;YACE,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,KAAK,KAAK,EAAE,CAAC,CAAC;YACvD,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW;IACjC,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,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;AAEpD,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,MAAM,KAAK,GAAG;;;;;;;;;;;;wBAYU,OAAO;;;;;;;;;;CAU9B,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAExB,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,MAAM;YACT,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YACnC,OAAO;QACT,KAAK,OAAO;YACV,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3B,OAAO;QACT,KAAK,UAAU;YACb,MAAM,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9B,OAAO;QACT,KAAK,QAAQ;YACX,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YACrC,OAAO;QACT,KAAK,SAAS,CAAC;QACf,KAAK,WAAW,CAAC;QACjB,KAAK,IAAI;YACP,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,EAAE,CAAC,CAAC;YACnC,OAAO;QACT,KAAK,SAAS,CAAC;QACf,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,IAAI;YACP,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACnB,OAAO;QACT;YACE,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,KAAK,KAAK,EAAE,CAAC,CAAC;YACvD,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW;IACjC,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,62 @@
1
+ import type { LlmClient } from "./llm.js";
2
+ import type { ForgeAdapter, Spec } from "@slowcook-ai/core";
3
+ export declare const LABEL_CHANGE_OF_MIND = "change-of-mind";
4
+ export declare const LABEL_BLOCKED_CONTRADICTION = "blocked-contradiction";
5
+ export declare const LABEL_BLOCKED_OVERLAP = "blocked-overlap";
6
+ export declare const LABEL_SPEC_READY = "spec-ready";
7
+ export declare const LABEL_NEEDS_REFINEMENT = "needs-refinement";
8
+ export interface RefineContext {
9
+ issueNumber: number;
10
+ repoRoot: string;
11
+ forge: ForgeAdapter;
12
+ llm: LlmClient;
13
+ /** Model id for refinement (heavy reasoning). */
14
+ refineModel: string;
15
+ /** Model id for relationship analysis (cheaper). */
16
+ relationshipModel: string;
17
+ /** slowcook CLI version string for the spec's refined_by field. */
18
+ cliVersion: string;
19
+ /** Base branch for PRs (default: "main"). */
20
+ baseBranch: string;
21
+ /** Current UTC time (injectable for tests). */
22
+ now: Date;
23
+ }
24
+ export type RefineOutcome = {
25
+ kind: "questions-posted";
26
+ commentId: number;
27
+ } | {
28
+ kind: "spec-emitted";
29
+ specPath: string;
30
+ prUrl: string;
31
+ prNumber: number;
32
+ } | {
33
+ kind: "overlap-flagged";
34
+ conflicting_ids: string[];
35
+ } | {
36
+ kind: "contradiction-blocked";
37
+ conflicting_ids: string[];
38
+ } | {
39
+ kind: "change-of-mind-accepted";
40
+ supersedes: string[];
41
+ } | {
42
+ kind: "noop";
43
+ reason: string;
44
+ };
45
+ export declare function runRefinement(ctx: RefineContext): Promise<RefineOutcome>;
46
+ interface ParseContext {
47
+ storyId: string;
48
+ issueNumber: number;
49
+ createdAt: string;
50
+ cliVersion: string;
51
+ supersedes: string[];
52
+ }
53
+ export type AgentOutput = {
54
+ kind: "questions";
55
+ markdown: string;
56
+ } | {
57
+ kind: "spec";
58
+ spec: Spec;
59
+ };
60
+ export declare function parseAgentOutput(raw: string, ctx: ParseContext): AgentOutput;
61
+ export {};
62
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/commands/refine/agent.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,UAAU,CAAC;AACtD,OAAO,KAAK,EACV,YAAY,EAGZ,IAAI,EAEL,MAAM,mBAAmB,CAAC;AAsB3B,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AACrD,eAAO,MAAM,2BAA2B,0BAA0B,CAAC;AACnE,eAAO,MAAM,qBAAqB,oBAAoB,CAAC;AACvD,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAC7C,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,YAAY,CAAC;IACpB,GAAG,EAAE,SAAS,CAAC;IACf,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,+CAA+C;IAC/C,GAAG,EAAE,IAAI,CAAC;CACX;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC3E;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,eAAe,EAAE,MAAM,EAAE,CAAA;CAAE,GACtD;IAAE,IAAI,EAAE,uBAAuB,CAAC;IAAC,eAAe,EAAE,MAAM,EAAE,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,yBAAyB,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAKrC,wBAAsB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAgH9E;AA2CD,UAAU,YAAY;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC;AA+BjC,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,YAAY,GAChB,WAAW,CA6Cb"}
@@ -0,0 +1,209 @@
1
+ import YAML from "yaml";
2
+ import { z } from "zod";
3
+ import { REFINEMENT_ANALYST_SYSTEM, SPEC_CHECKLIST_MD, draftPrTitle, draftPrBody, } from "./prompts.js";
4
+ import { readIndex, writeIndex, writeSpec, listActiveSpecs, nextStoryId, entryFromSpec, } from "./spec-yaml.js";
5
+ import { analyzeRelationship, contradictionCommentBody, overlapCommentBody, } from "./relationship.js";
6
+ import { applySupersede } from "@slowcook-ai/core";
7
+ export const LABEL_CHANGE_OF_MIND = "change-of-mind";
8
+ export const LABEL_BLOCKED_CONTRADICTION = "blocked-contradiction";
9
+ export const LABEL_BLOCKED_OVERLAP = "blocked-overlap";
10
+ export const LABEL_SPEC_READY = "spec-ready";
11
+ export const LABEL_NEEDS_REFINEMENT = "needs-refinement";
12
+ /** Schema for the <sentinel> block the agent uses when it emits a spec. */
13
+ const SpecEmissionFenceStart = "---";
14
+ export async function runRefinement(ctx) {
15
+ const issue = await ctx.forge.getIssue(ctx.issueNumber);
16
+ if (issue.state === "closed") {
17
+ return { kind: "noop", reason: "issue is closed" };
18
+ }
19
+ if (!issue.labels.includes(LABEL_NEEDS_REFINEMENT)) {
20
+ return { kind: "noop", reason: `issue is not labeled ${LABEL_NEEDS_REFINEMENT}` };
21
+ }
22
+ // Step 1: relationship analysis
23
+ const existingSpecs = listActiveSpecs(ctx.repoRoot);
24
+ const verdict = await analyzeRelationship({ issueTitle: issue.title, issueBody: issue.body, activeSpecs: existingSpecs }, { llm: ctx.llm, model: ctx.relationshipModel });
25
+ const hasChangeOfMind = issue.labels.includes(LABEL_CHANGE_OF_MIND);
26
+ if (verdict.kind === "overlap") {
27
+ const comment = await ctx.forge.createIssueComment(ctx.issueNumber, overlapCommentBody(verdict));
28
+ await ctx.forge.addIssueLabels(ctx.issueNumber, [LABEL_BLOCKED_OVERLAP]);
29
+ return { kind: "overlap-flagged", conflicting_ids: verdict.conflicting_ids };
30
+ }
31
+ if (verdict.kind === "contradiction") {
32
+ if (!hasChangeOfMind) {
33
+ await ctx.forge.createIssueComment(ctx.issueNumber, contradictionCommentBody(verdict, false));
34
+ await ctx.forge.addIssueLabels(ctx.issueNumber, [LABEL_BLOCKED_CONTRADICTION]);
35
+ return { kind: "contradiction-blocked", conflicting_ids: verdict.conflicting_ids };
36
+ }
37
+ // Authorized change-of-mind: post an acknowledgment and proceed
38
+ await ctx.forge.createIssueComment(ctx.issueNumber, contradictionCommentBody(verdict, true));
39
+ }
40
+ const supersedes = verdict.kind === "contradiction" && hasChangeOfMind ? verdict.conflicting_ids : [];
41
+ // Step 2: refinement loop (single round — ask or emit based on full history)
42
+ const comments = await ctx.forge.listIssueComments(ctx.issueNumber);
43
+ const chat = buildChatHistory(issue, comments, supersedes);
44
+ const storyId = nextStoryId(ctx.repoRoot);
45
+ const agentResponse = await ctx.llm.complete({
46
+ system: REFINEMENT_ANALYST_SYSTEM(SPEC_CHECKLIST_MD),
47
+ cacheSystem: true,
48
+ model: ctx.refineModel,
49
+ messages: chat,
50
+ maxTokens: 4096,
51
+ temperature: 0.2,
52
+ });
53
+ const parsed = parseAgentOutput(agentResponse, {
54
+ storyId,
55
+ issueNumber: ctx.issueNumber,
56
+ createdAt: ctx.now.toISOString(),
57
+ cliVersion: ctx.cliVersion,
58
+ supersedes,
59
+ });
60
+ if (parsed.kind === "questions") {
61
+ const comment = await ctx.forge.createIssueComment(ctx.issueNumber, parsed.markdown);
62
+ return { kind: "questions-posted", commentId: comment.id };
63
+ }
64
+ // Spec emitted → write, update index, open draft PR
65
+ const spec = parsed.spec;
66
+ const specPath = writeSpec(ctx.repoRoot, spec);
67
+ const index = readIndex(ctx.repoRoot);
68
+ const updatedIndex = applySupersede(index, { id: spec.story_id, entry: entryFromSpec(spec) }, supersedes);
69
+ writeIndex(ctx.repoRoot, updatedIndex);
70
+ const branch = `slowcook/spec/story-${spec.story_id}`;
71
+ await ctx.forge.git.createBranch(branch);
72
+ await ctx.forge.git.stage(specPath);
73
+ await ctx.forge.git.stage(`specs/_index.yaml`);
74
+ await ctx.forge.git.commit(`slowcook: spec story-${spec.story_id} — ${spec.title}\n\nRefined from #${ctx.issueNumber}.`);
75
+ await ctx.forge.git.push(branch);
76
+ const pr = await ctx.forge.createPullRequest({
77
+ title: draftPrTitle(spec.story_id, spec.title),
78
+ body: draftPrBody({
79
+ storyId: spec.story_id,
80
+ issueNumber: ctx.issueNumber,
81
+ supersedes,
82
+ }),
83
+ head: branch,
84
+ base: ctx.baseBranch,
85
+ draft: true,
86
+ labels: ["slowcook-spec"],
87
+ });
88
+ await ctx.forge.addIssueLabels(ctx.issueNumber, [LABEL_SPEC_READY]);
89
+ await ctx.forge.removeIssueLabel(ctx.issueNumber, LABEL_NEEDS_REFINEMENT);
90
+ return { kind: "spec-emitted", specPath, prUrl: pr.url, prNumber: pr.number };
91
+ }
92
+ // ----- helpers -----
93
+ function buildChatHistory(issue, comments, supersedes) {
94
+ // First message: the issue body + metadata.
95
+ const issueBlock = `# Issue #${issue.number}: ${issue.title}
96
+
97
+ ${issue.body}`;
98
+ const messages = [{ role: "user", content: issueBlock }];
99
+ // Interleave prior comments: bot comments become assistant turns, PM comments become user turns.
100
+ // Skip the issue-level "overlap/contradiction" analysis acknowledgments by matching their headers.
101
+ for (const c of comments) {
102
+ const skip = c.body.startsWith("### slowcook · overlap detected") ||
103
+ c.body.startsWith("### slowcook · contradiction") ||
104
+ c.body.startsWith("### slowcook · change-of-mind authorized");
105
+ if (skip)
106
+ continue;
107
+ messages.push({
108
+ role: c.is_bot ? "assistant" : "user",
109
+ content: c.body,
110
+ });
111
+ }
112
+ if (supersedes.length > 0) {
113
+ messages.push({
114
+ role: "user",
115
+ content: `(slowcook system note: this spec is authorized to supersede ${supersedes
116
+ .map((id) => `story-${id}`)
117
+ .join(", ")}. Set the \`supersedes\` field accordingly.)`,
118
+ });
119
+ }
120
+ return messages;
121
+ }
122
+ const EmittedSpecSchema = z.object({
123
+ story_id: z.string().optional(),
124
+ title: z.string(),
125
+ status: z.string().optional(),
126
+ created_at: z.string().optional(),
127
+ supersedes: z.array(z.string()).optional(),
128
+ superseded_by: z.unknown().optional(),
129
+ token_budget_usd: z.number().optional(),
130
+ estimate: z.enum(["small", "medium", "large"]).optional(),
131
+ source_issue: z.string().optional(),
132
+ refined_by: z.string().optional(),
133
+ actors: z.array(z.object({ name: z.string(), notes: z.string().optional() })),
134
+ preconditions: z.array(z.string()),
135
+ invariants: z.array(z.string()),
136
+ api_contract: z.array(z.unknown()).optional(),
137
+ ui_behavior: z.record(z.string(), z.string()).optional(),
138
+ acceptance_scenarios: z.array(z.string()),
139
+ non_goals: z.array(z.string()),
140
+ related_specs: z
141
+ .array(z.object({
142
+ id: z.string(),
143
+ relationship: z.enum(["overlap", "related", "superseded"]),
144
+ note: z.string().optional(),
145
+ }))
146
+ .optional(),
147
+ });
148
+ export function parseAgentOutput(raw, ctx) {
149
+ const trimmed = raw.trim();
150
+ // Heuristic: spec starts with `---` or is wrapped in a ```yaml block.
151
+ const yamlBlock = extractYamlBlock(trimmed);
152
+ if (yamlBlock) {
153
+ const doc = YAML.parse(yamlBlock);
154
+ const parsed = EmittedSpecSchema.safeParse(doc);
155
+ if (!parsed.success) {
156
+ throw new Error(`Agent emitted a YAML-shaped response but it failed validation:\n${parsed.error.issues
157
+ .map((i) => ` ${i.path.join(".") || "(root)"}: ${i.message}`)
158
+ .join("\n")}\n\nRaw YAML:\n${yamlBlock.slice(0, 500)}`);
159
+ }
160
+ const d = parsed.data;
161
+ const spec = {
162
+ $schema: "./spec.schema.json",
163
+ story_id: ctx.storyId,
164
+ title: d.title,
165
+ status: "active",
166
+ created_at: ctx.createdAt,
167
+ supersedes: ctx.supersedes,
168
+ superseded_by: null,
169
+ token_budget_usd: d.token_budget_usd,
170
+ estimate: d.estimate,
171
+ source_issue: `#${ctx.issueNumber}`,
172
+ refined_by: `slowcook-refine@${ctx.cliVersion}`,
173
+ actors: d.actors,
174
+ preconditions: d.preconditions,
175
+ invariants: d.invariants,
176
+ api_contract: d.api_contract,
177
+ ui_behavior: d.ui_behavior,
178
+ acceptance_scenarios: d.acceptance_scenarios,
179
+ non_goals: d.non_goals,
180
+ related_specs: d.related_specs,
181
+ };
182
+ return { kind: "spec", spec };
183
+ }
184
+ // Otherwise: treat as a question round (markdown).
185
+ if (trimmed.length === 0) {
186
+ throw new Error("Agent returned an empty response; expected questions or a spec.");
187
+ }
188
+ return { kind: "questions", markdown: trimmed };
189
+ }
190
+ function extractYamlBlock(s) {
191
+ // ```yaml ... ``` fenced
192
+ const fence = s.match(/```yaml\s*([\s\S]*?)```/);
193
+ if (fence && fence[1])
194
+ return fence[1].trim();
195
+ // Bare YAML starting with --- (document separator)
196
+ if (s.startsWith("---")) {
197
+ return s;
198
+ }
199
+ // Content that's just YAML without front-matter fence — detect heuristically.
200
+ // If it contains typical spec keys AND doesn't look like markdown, treat as YAML.
201
+ const looksLikeYaml = /(^|\n)title:\s/i.test(s) &&
202
+ /(^|\n)actors:\s*/i.test(s) &&
203
+ /(^|\n)acceptance_scenarios:\s*/i.test(s);
204
+ if (looksLikeYaml && !s.includes("```") && !s.includes("### ")) {
205
+ return s;
206
+ }
207
+ return null;
208
+ }
209
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../src/commands/refine/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function refine(argv: string[], cliVersion: string): Promise<void>;
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/refine/index.ts"],"names":[],"mappings":"AAgHA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmF9E"}
@@ -0,0 +1,177 @@
1
+ import { execSync } from "node:child_process";
2
+ import { GitHubAdapter } from "@slowcook-ai/forge-github";
3
+ import { AnthropicClient } from "./llm.js";
4
+ import { runRefinement } from "./agent.js";
5
+ function parseArgs(argv) {
6
+ const args = {
7
+ issueNumber: 0,
8
+ repoRoot: process.cwd(),
9
+ baseBranch: "main",
10
+ refineModel: "claude-opus-4-7",
11
+ relationshipModel: "claude-sonnet-4-5",
12
+ };
13
+ for (let i = 0; i < argv.length; i++) {
14
+ const arg = argv[i];
15
+ const next = argv[i + 1];
16
+ if (arg === "--issue" && next) {
17
+ args.issueNumber = parseInt(next, 10);
18
+ i++;
19
+ }
20
+ else if (arg === "--cwd" && next) {
21
+ args.repoRoot = next;
22
+ i++;
23
+ }
24
+ else if (arg === "--owner" && next) {
25
+ args.owner = next;
26
+ i++;
27
+ }
28
+ else if (arg === "--repo" && next) {
29
+ args.repo = next;
30
+ i++;
31
+ }
32
+ else if (arg === "--base" && next) {
33
+ args.baseBranch = next;
34
+ i++;
35
+ }
36
+ else if (arg === "--refine-model" && next) {
37
+ args.refineModel = next;
38
+ i++;
39
+ }
40
+ else if (arg === "--relationship-model" && next) {
41
+ args.relationshipModel = next;
42
+ i++;
43
+ }
44
+ else if (arg === "--help" || arg === "-h") {
45
+ printHelp();
46
+ process.exit(0);
47
+ }
48
+ }
49
+ if (!args.issueNumber || isNaN(args.issueNumber)) {
50
+ console.error("Missing required --issue <number>");
51
+ printHelp();
52
+ process.exit(64);
53
+ }
54
+ return args;
55
+ }
56
+ function printHelp() {
57
+ console.log(`
58
+ slowcook refine — drive a GitHub issue toward a frozen spec
59
+
60
+ Each invocation is one round:
61
+ - Analyzes the issue's relationship to existing active specs.
62
+ - If overlap or contradiction (without 'change-of-mind' label): posts a
63
+ comment explaining how to proceed and exits.
64
+ - If no blocker: either asks clarifying questions (as a comment) or emits
65
+ the final spec + opens a draft PR.
66
+
67
+ Re-run on every new PM comment (typically via a GitHub Actions workflow
68
+ triggered by issue_comment events).
69
+
70
+ Usage:
71
+ slowcook refine --issue <number> [options]
72
+
73
+ Options:
74
+ --issue <number> Issue to refine (required)
75
+ --cwd <path> Repo working directory (default: current dir)
76
+ --owner <login> Repo owner (default: parsed from 'git remote get-url origin')
77
+ --repo <name> Repo name (default: parsed from 'git remote get-url origin')
78
+ --base <branch> Base branch for the spec PR (default: main)
79
+ --refine-model <id> Model for the refinement loop (default: claude-opus-4-7)
80
+ --relationship-model <id> Model for relationship analysis (default: claude-sonnet-4-5)
81
+ --help, -h Show this help
82
+
83
+ Environment:
84
+ ANTHROPIC_API_KEY (required) Anthropic API key
85
+ GITHUB_TOKEN (required) GitHub token with issues:write, contents:write, pull-requests:write
86
+
87
+ Exit codes:
88
+ 0 outcome was reached (questions posted, spec emitted, or noop)
89
+ 2 script error (bad args, missing env, network failure)
90
+ `);
91
+ }
92
+ function detectOwnerRepo(cwd) {
93
+ try {
94
+ const url = execSync("git remote get-url origin", {
95
+ cwd,
96
+ encoding: "utf8",
97
+ stdio: ["ignore", "pipe", "ignore"],
98
+ }).trim();
99
+ const m = url.match(/github\.com[:/]([^/]+)\/([^/.]+)(?:\.git)?$/);
100
+ if (m && m[1] && m[2])
101
+ return { owner: m[1], repo: m[2] };
102
+ }
103
+ catch {
104
+ // not a git repo / no origin — fine
105
+ }
106
+ return null;
107
+ }
108
+ export async function refine(argv, cliVersion) {
109
+ const args = parseArgs(argv);
110
+ const anthropicKey = process.env["ANTHROPIC_API_KEY"];
111
+ if (!anthropicKey) {
112
+ console.error("ANTHROPIC_API_KEY environment variable is not set.");
113
+ process.exit(2);
114
+ }
115
+ const githubToken = process.env["GITHUB_TOKEN"];
116
+ if (!githubToken) {
117
+ console.error("GITHUB_TOKEN environment variable is not set.");
118
+ process.exit(2);
119
+ }
120
+ let owner = args.owner;
121
+ let repo = args.repo;
122
+ if (!owner || !repo) {
123
+ const detected = detectOwnerRepo(args.repoRoot);
124
+ if (!detected) {
125
+ console.error("Could not detect owner/repo from git remote. Pass --owner and --repo explicitly.");
126
+ process.exit(2);
127
+ }
128
+ owner = owner ?? detected.owner;
129
+ repo = repo ?? detected.repo;
130
+ }
131
+ const forge = new GitHubAdapter({ owner, repo, token: githubToken });
132
+ const llm = new AnthropicClient(anthropicKey);
133
+ const ctx = {
134
+ issueNumber: args.issueNumber,
135
+ repoRoot: args.repoRoot,
136
+ forge,
137
+ llm,
138
+ refineModel: args.refineModel,
139
+ relationshipModel: args.relationshipModel,
140
+ cliVersion,
141
+ baseBranch: args.baseBranch,
142
+ now: new Date(),
143
+ };
144
+ console.log(`slowcook refine · issue #${args.issueNumber} on ${owner}/${repo} (refine model: ${args.refineModel})`);
145
+ try {
146
+ const outcome = await runRefinement(ctx);
147
+ switch (outcome.kind) {
148
+ case "questions-posted":
149
+ console.log(`Posted clarifying questions (comment ${outcome.commentId}). Awaiting PM reply.`);
150
+ break;
151
+ case "spec-emitted":
152
+ console.log(`Spec written: ${outcome.specPath}`);
153
+ console.log(`Draft PR: ${outcome.prUrl}`);
154
+ break;
155
+ case "overlap-flagged":
156
+ console.log(`Overlap with ${outcome.conflicting_ids.join(", ")}. Awaiting PM resolution.`);
157
+ break;
158
+ case "contradiction-blocked":
159
+ console.log(`Contradiction with ${outcome.conflicting_ids.join(", ")}. Blocked until 'change-of-mind' label applied.`);
160
+ break;
161
+ case "change-of-mind-accepted":
162
+ console.log(`Change-of-mind accepted; will supersede ${outcome.supersedes.join(", ")}.`);
163
+ break;
164
+ case "noop":
165
+ console.log(`Noop: ${outcome.reason}.`);
166
+ break;
167
+ }
168
+ }
169
+ catch (e) {
170
+ console.error(`Refinement failed: ${e.message}`);
171
+ if (process.env["SLOWCOOK_DEBUG"]) {
172
+ console.error(e);
173
+ }
174
+ process.exit(2);
175
+ }
176
+ }
177
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/refine/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Minimal LLM interface the refinement agent uses. Isolated so we can inject
3
+ * a fake in tests without touching the network.
4
+ */
5
+ export interface LlmClient {
6
+ complete(args: LlmRequest): Promise<string>;
7
+ }
8
+ export interface LlmMessage {
9
+ role: "user" | "assistant";
10
+ content: string;
11
+ }
12
+ export interface LlmRequest {
13
+ system: string;
14
+ /** System content will be cached if `cacheSystem` is true. */
15
+ cacheSystem?: boolean;
16
+ messages: LlmMessage[];
17
+ /** Model id to use (e.g., "claude-opus-4-7"). */
18
+ model: string;
19
+ maxTokens?: number;
20
+ temperature?: number;
21
+ }
22
+ export declare class AnthropicClient implements LlmClient {
23
+ private readonly client;
24
+ constructor(apiKey: string);
25
+ complete(args: LlmRequest): Promise<string>;
26
+ }
27
+ //# sourceMappingURL=llm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../../src/commands/refine/llm.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,eAAgB,YAAW,SAAS;IAC/C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;gBAEvB,MAAM,EAAE,MAAM;IAIpB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;CA4BlD"}
@@ -0,0 +1,33 @@
1
+ import Anthropic from "@anthropic-ai/sdk";
2
+ export class AnthropicClient {
3
+ client;
4
+ constructor(apiKey) {
5
+ this.client = new Anthropic({ apiKey });
6
+ }
7
+ async complete(args) {
8
+ const systemContent = args.cacheSystem
9
+ ? [
10
+ {
11
+ type: "text",
12
+ text: args.system,
13
+ cache_control: { type: "ephemeral" },
14
+ },
15
+ ]
16
+ : args.system;
17
+ const response = await this.client.messages.create({
18
+ model: args.model,
19
+ max_tokens: args.maxTokens ?? 4096,
20
+ temperature: args.temperature ?? 0.2,
21
+ system: systemContent,
22
+ messages: args.messages.map((m) => ({
23
+ role: m.role,
24
+ content: m.content,
25
+ })),
26
+ });
27
+ const first = response.content[0];
28
+ if (first && first.type === "text")
29
+ return first.text;
30
+ throw new Error(`Expected a text response from Claude, got: ${JSON.stringify(response.content).slice(0, 200)}`);
31
+ }
32
+ }
33
+ //# sourceMappingURL=llm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm.js","sourceRoot":"","sources":["../../../src/commands/refine/llm.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AA0B1C,MAAM,OAAO,eAAe;IACT,MAAM,CAAY;IAEnC,YAAY,MAAc;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,IAAgB;QAC7B,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW;YACpC,CAAC,CAAC;gBACE;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,MAAM;oBACjB,aAAa,EAAE,EAAE,IAAI,EAAE,WAAoB,EAAE;iBAC9C;aACF;YACH,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;QAEhB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YACjD,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,UAAU,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI;YAClC,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,GAAG;YACpC,MAAM,EAAE,aAAsB;YAC9B,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAClC,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,OAAO,EAAE,CAAC,CAAC,OAAO;aACnB,CAAC,CAAC;SACJ,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAClC,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC;QACtD,MAAM,IAAI,KAAK,CACb,8CAA8C,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAC/F,CAAC;IACJ,CAAC;CACF"}