@slowcook-ai/cli 0.19.0-alpha.8 โ 0.19.1
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/AGENTS.md +240 -0
- package/REPORTING.md +193 -0
- package/dist/cli.js +78 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/brand/index.d.ts +26 -0
- package/dist/commands/brand/index.d.ts.map +1 -0
- package/dist/commands/brand/index.js +257 -0
- package/dist/commands/brand/index.js.map +1 -0
- package/dist/commands/brew/agent.d.ts +7 -2
- package/dist/commands/brew/agent.d.ts.map +1 -1
- package/dist/commands/brew/agent.js +9 -0
- package/dist/commands/brew/agent.js.map +1 -1
- package/dist/commands/brew/halt.d.ts +26 -0
- package/dist/commands/brew/halt.d.ts.map +1 -1
- package/dist/commands/brew/halt.js.map +1 -1
- package/dist/commands/brew/index.d.ts.map +1 -1
- package/dist/commands/brew/index.js +142 -18
- package/dist/commands/brew/index.js.map +1 -1
- package/dist/commands/brew/pair-navigator.d.ts +119 -0
- package/dist/commands/brew/pair-navigator.d.ts.map +1 -0
- package/dist/commands/brew/pair-navigator.js +187 -0
- package/dist/commands/brew/pair-navigator.js.map +1 -0
- package/dist/commands/budget/index.d.ts +2 -0
- package/dist/commands/budget/index.d.ts.map +1 -0
- package/dist/commands/budget/index.js +252 -0
- package/dist/commands/budget/index.js.map +1 -0
- package/dist/commands/chef/drift-fix.d.ts +33 -4
- package/dist/commands/chef/drift-fix.d.ts.map +1 -1
- package/dist/commands/chef/drift-fix.js +417 -29
- package/dist/commands/chef/drift-fix.js.map +1 -1
- package/dist/commands/chef/index.js +13 -3
- package/dist/commands/chef/index.js.map +1 -1
- package/dist/commands/chef/orchestrate.d.ts +1 -1
- package/dist/commands/chef/orchestrate.d.ts.map +1 -1
- package/dist/commands/chef/orchestrate.js +32 -9
- package/dist/commands/chef/orchestrate.js.map +1 -1
- package/dist/commands/dev-env/config.d.ts +57 -0
- package/dist/commands/dev-env/config.d.ts.map +1 -0
- package/dist/commands/dev-env/config.js +96 -0
- package/dist/commands/dev-env/config.js.map +1 -0
- package/dist/commands/dev-env/index.d.ts +27 -0
- package/dist/commands/dev-env/index.d.ts.map +1 -0
- package/dist/commands/dev-env/index.js +226 -0
- package/dist/commands/dev-env/index.js.map +1 -0
- package/dist/commands/dev-env/init.d.ts +28 -0
- package/dist/commands/dev-env/init.d.ts.map +1 -0
- package/dist/commands/dev-env/init.js +135 -0
- package/dist/commands/dev-env/init.js.map +1 -0
- package/dist/commands/docs/index.d.ts +16 -0
- package/dist/commands/docs/index.d.ts.map +1 -0
- package/dist/commands/docs/index.js +127 -0
- package/dist/commands/docs/index.js.map +1 -0
- package/dist/commands/eval/index.d.ts +54 -0
- package/dist/commands/eval/index.d.ts.map +1 -0
- package/dist/commands/eval/index.js +294 -0
- package/dist/commands/eval/index.js.map +1 -0
- package/dist/commands/extract/index.d.ts.map +1 -1
- package/dist/commands/extract/index.js +23 -1
- package/dist/commands/extract/index.js.map +1 -1
- package/dist/commands/garnish/index.d.ts +56 -0
- package/dist/commands/garnish/index.d.ts.map +1 -0
- package/dist/commands/garnish/index.js +281 -0
- package/dist/commands/garnish/index.js.map +1 -0
- package/dist/commands/garnish/trailer.d.ts +79 -0
- package/dist/commands/garnish/trailer.d.ts.map +1 -0
- package/dist/commands/garnish/trailer.js +118 -0
- package/dist/commands/garnish/trailer.js.map +1 -0
- package/dist/commands/init/index.d.ts.map +1 -1
- package/dist/commands/init/index.js +33 -0
- package/dist/commands/init/index.js.map +1 -1
- package/dist/commands/init/mock-vite.d.ts +54 -0
- package/dist/commands/init/mock-vite.d.ts.map +1 -0
- package/dist/commands/init/mock-vite.js +613 -0
- package/dist/commands/init/mock-vite.js.map +1 -0
- package/dist/commands/init/mock.d.ts +6 -0
- package/dist/commands/init/mock.d.ts.map +1 -1
- package/dist/commands/init/mock.js +20 -4
- package/dist/commands/init/mock.js.map +1 -1
- package/dist/commands/init/plan.d.ts +26 -1
- package/dist/commands/init/plan.d.ts.map +1 -1
- package/dist/commands/init/plan.js +41 -3
- package/dist/commands/init/plan.js.map +1 -1
- package/dist/commands/init/templates.d.ts.map +1 -1
- package/dist/commands/init/templates.js +12 -4
- package/dist/commands/init/templates.js.map +1 -1
- package/dist/commands/knowledge-add.d.ts +52 -0
- package/dist/commands/knowledge-add.d.ts.map +1 -0
- package/dist/commands/knowledge-add.js +232 -0
- package/dist/commands/knowledge-add.js.map +1 -0
- package/dist/commands/map/emit-typeorm.d.ts +117 -0
- package/dist/commands/map/emit-typeorm.d.ts.map +1 -0
- package/dist/commands/map/emit-typeorm.js +341 -0
- package/dist/commands/map/emit-typeorm.js.map +1 -0
- package/dist/commands/map/index.d.ts +18 -0
- package/dist/commands/map/index.d.ts.map +1 -1
- package/dist/commands/map/index.js +28 -0
- package/dist/commands/map/index.js.map +1 -1
- package/dist/commands/plate/agent.d.ts +7 -0
- package/dist/commands/plate/agent.d.ts.map +1 -1
- package/dist/commands/plate/agent.js +1 -1
- package/dist/commands/plate/agent.js.map +1 -1
- package/dist/commands/plate/index.d.ts.map +1 -1
- package/dist/commands/plate/index.js +6 -0
- package/dist/commands/plate/index.js.map +1 -1
- package/dist/commands/recon/index.d.ts +16 -3
- package/dist/commands/recon/index.d.ts.map +1 -1
- package/dist/commands/recon/index.js +267 -16
- package/dist/commands/recon/index.js.map +1 -1
- package/dist/commands/recon/migration-gate.d.ts +59 -0
- package/dist/commands/recon/migration-gate.d.ts.map +1 -0
- package/dist/commands/recon/migration-gate.js +131 -0
- package/dist/commands/recon/migration-gate.js.map +1 -0
- package/dist/commands/recon/reuse.d.ts +32 -0
- package/dist/commands/recon/reuse.d.ts.map +1 -1
- package/dist/commands/recon/reuse.js +66 -0
- package/dist/commands/recon/reuse.js.map +1 -1
- package/dist/commands/recon/stale-stubs.d.ts +65 -0
- package/dist/commands/recon/stale-stubs.d.ts.map +1 -0
- package/dist/commands/recon/stale-stubs.js +84 -0
- package/dist/commands/recon/stale-stubs.js.map +1 -0
- package/dist/commands/refine/agent.d.ts +23 -0
- package/dist/commands/refine/agent.d.ts.map +1 -1
- package/dist/commands/refine/agent.js +245 -15
- package/dist/commands/refine/agent.js.map +1 -1
- package/dist/commands/refine/brownfield-answer.d.ts +81 -0
- package/dist/commands/refine/brownfield-answer.d.ts.map +1 -0
- package/dist/commands/refine/brownfield-answer.js +231 -0
- package/dist/commands/refine/brownfield-answer.js.map +1 -0
- package/dist/commands/refine/context.d.ts +27 -1
- package/dist/commands/refine/context.d.ts.map +1 -1
- package/dist/commands/refine/context.js +438 -6
- package/dist/commands/refine/context.js.map +1 -1
- package/dist/commands/refine/git-attention.d.ts +123 -0
- package/dist/commands/refine/git-attention.d.ts.map +1 -0
- package/dist/commands/refine/git-attention.js +378 -0
- package/dist/commands/refine/git-attention.js.map +1 -0
- package/dist/commands/refine/history-index.d.ts +66 -0
- package/dist/commands/refine/history-index.d.ts.map +1 -1
- package/dist/commands/refine/history-index.js +195 -8
- package/dist/commands/refine/history-index.js.map +1 -1
- package/dist/commands/refine/index.d.ts.map +1 -1
- package/dist/commands/refine/index.js +105 -18
- package/dist/commands/refine/index.js.map +1 -1
- package/dist/commands/refine/multifurcate.d.ts +129 -0
- package/dist/commands/refine/multifurcate.d.ts.map +1 -0
- package/dist/commands/refine/multifurcate.js +247 -0
- package/dist/commands/refine/multifurcate.js.map +1 -0
- package/dist/commands/refine/proposals-synth.d.ts +50 -1
- package/dist/commands/refine/proposals-synth.d.ts.map +1 -1
- package/dist/commands/refine/proposals-synth.js +199 -35
- package/dist/commands/refine/proposals-synth.js.map +1 -1
- package/dist/commands/refine/spec-yaml.d.ts +214 -1210
- package/dist/commands/refine/spec-yaml.d.ts.map +1 -1
- package/dist/commands/refine/spec-yaml.js +10 -0
- package/dist/commands/refine/spec-yaml.js.map +1 -1
- package/dist/commands/refresh-knowledge.d.ts +139 -0
- package/dist/commands/refresh-knowledge.d.ts.map +1 -0
- package/dist/commands/refresh-knowledge.js +1029 -0
- package/dist/commands/refresh-knowledge.js.map +1 -0
- package/dist/commands/run-mock/index.d.ts.map +1 -1
- package/dist/commands/run-mock/index.js +135 -22
- package/dist/commands/run-mock/index.js.map +1 -1
- package/dist/commands/testgen/agent.d.ts +13 -0
- package/dist/commands/testgen/agent.d.ts.map +1 -1
- package/dist/commands/testgen/agent.js +137 -11
- package/dist/commands/testgen/agent.js.map +1 -1
- package/dist/commands/upsert-agent-docs.d.ts +48 -0
- package/dist/commands/upsert-agent-docs.d.ts.map +1 -0
- package/dist/commands/upsert-agent-docs.js +298 -0
- package/dist/commands/upsert-agent-docs.js.map +1 -0
- package/dist/commands/vibe/agent.d.ts +7 -0
- package/dist/commands/vibe/agent.d.ts.map +1 -1
- package/dist/commands/vibe/agent.js +2 -2
- package/dist/commands/vibe/agent.js.map +1 -1
- package/dist/commands/vibe/index.d.ts.map +1 -1
- package/dist/commands/vibe/index.js +7 -1
- package/dist/commands/vibe/index.js.map +1 -1
- package/dist/cost-store.d.ts +52 -0
- package/dist/cost-store.d.ts.map +1 -0
- package/dist/cost-store.js +108 -0
- package/dist/cost-store.js.map +1 -0
- package/dist/lib/budget.d.ts +73 -0
- package/dist/lib/budget.d.ts.map +1 -0
- package/dist/lib/budget.js +225 -0
- package/dist/lib/budget.js.map +1 -0
- package/dist/lib/mock-shape.d.ts +29 -0
- package/dist/lib/mock-shape.d.ts.map +1 -0
- package/dist/lib/mock-shape.js +77 -0
- package/dist/lib/mock-shape.js.map +1 -0
- package/dist/lib/read-only.d.ts +22 -0
- package/dist/lib/read-only.d.ts.map +1 -0
- package/dist/lib/read-only.js +34 -0
- package/dist/lib/read-only.js.map +1 -0
- package/package.json +17 -12
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @slowcook 0.19.0-ฮฑ.44 โ multifurcation pre-step.
|
|
3
|
+
*
|
|
4
|
+
* Some GitHub issues are not stories. They are programs of work disguised
|
|
5
|
+
* as tickets ("everything according to mock", "rewrite the patient app",
|
|
6
|
+
* "wire X to Y" where X and Y are whole subsystems). Forcing those
|
|
7
|
+
* through refine produces a fuzzy mega-spec that no downstream agent can
|
|
8
|
+
* reasonably implement.
|
|
9
|
+
*
|
|
10
|
+
* This module runs a cheap LLM pass BEFORE refine's relationship +
|
|
11
|
+
* refinement calls. It returns either:
|
|
12
|
+
*
|
|
13
|
+
* - { kind: "one", rationale } โ refine proceeds normally
|
|
14
|
+
* - { kind: "many", sub_issues, rationale } โ refine posts a
|
|
15
|
+
* PM-facing proposal listing the proposed sub-issues + halts; the
|
|
16
|
+
* PM decides whether to file the split. The original issue is
|
|
17
|
+
* marked `slowcook-multifurcation-proposed` so refine doesn't loop.
|
|
18
|
+
*
|
|
19
|
+
* Sub-issue titles + summaries are PM-style by contract (see prompt
|
|
20
|
+
* rules): intent-shaped, no file paths or pipeline names, โค 80 char
|
|
21
|
+
* titles, 1-3 sentence summaries. Quality of the proposal is the
|
|
22
|
+
* PM's call โ the comment template makes editing easy.
|
|
23
|
+
*/
|
|
24
|
+
import type { LlmClient, Spec } from "@slowcook-ai/core";
|
|
25
|
+
/**
|
|
26
|
+
* One existing spec the model needs to be aware of when proposing a
|
|
27
|
+
* split, so it can mark sub-issues that overlap with active scope
|
|
28
|
+
* INSTEAD of silently omitting them. The PM needs to see the full
|
|
29
|
+
* picture, not a hidden side-channel.
|
|
30
|
+
*
|
|
31
|
+
* Built from `listActiveSpecs(repoRoot)` โ a single line of Spec.
|
|
32
|
+
*/
|
|
33
|
+
export interface ActiveSpecDigest {
|
|
34
|
+
story_id: string;
|
|
35
|
+
title: string;
|
|
36
|
+
summary: string;
|
|
37
|
+
}
|
|
38
|
+
export interface MultifurcationSubIssue {
|
|
39
|
+
title: string;
|
|
40
|
+
summary: string;
|
|
41
|
+
/** Optional โ titles of OTHER sub-issues this one depends on landing first. */
|
|
42
|
+
depends_on?: string[];
|
|
43
|
+
/**
|
|
44
|
+
* cli ฮฑ.45 โ set when the proposed sub-issue's scope is already covered
|
|
45
|
+
* by an active spec. The PM still sees the sub-issue (so the parent
|
|
46
|
+
* issue's full scope is visible), but the comment renders an "Already
|
|
47
|
+
* covered by story-NNN" annotation and the PM can fold it into the
|
|
48
|
+
* existing story rather than opening a duplicate.
|
|
49
|
+
*/
|
|
50
|
+
existing_spec_id?: string;
|
|
51
|
+
}
|
|
52
|
+
export type MultifurcationVerdict = {
|
|
53
|
+
kind: "one";
|
|
54
|
+
rationale: string;
|
|
55
|
+
} | {
|
|
56
|
+
kind: "many";
|
|
57
|
+
rationale: string;
|
|
58
|
+
sub_issues: MultifurcationSubIssue[];
|
|
59
|
+
};
|
|
60
|
+
export interface MultifurcationInputs {
|
|
61
|
+
issueTitle: string;
|
|
62
|
+
issueBody: string;
|
|
63
|
+
/**
|
|
64
|
+
* cli ฮฑ.45 โ list of currently active specs in this repo. The
|
|
65
|
+
* multifurcation prompt uses them to annotate sub-issues that
|
|
66
|
+
* overlap with existing scope (story_id is the PM-visible
|
|
67
|
+
* reference; title + summary give the model enough context to
|
|
68
|
+
* decide whether overlap is real).
|
|
69
|
+
*
|
|
70
|
+
* Empty array is fine โ model just won't tag anything.
|
|
71
|
+
*/
|
|
72
|
+
activeSpecs?: ActiveSpecDigest[];
|
|
73
|
+
}
|
|
74
|
+
export interface MultifurcationResult {
|
|
75
|
+
verdict: MultifurcationVerdict;
|
|
76
|
+
costUsd: number;
|
|
77
|
+
usage: {
|
|
78
|
+
inputTokens: number;
|
|
79
|
+
outputTokens: number;
|
|
80
|
+
cacheReadTokens: number;
|
|
81
|
+
cacheCreateTokens: number;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export declare function assessMultifurcation(inputs: MultifurcationInputs, opts: {
|
|
85
|
+
llm: LlmClient;
|
|
86
|
+
model: string;
|
|
87
|
+
}): Promise<MultifurcationResult>;
|
|
88
|
+
/**
|
|
89
|
+
* Compose the user-side message. Exported for tests so the snapshot can
|
|
90
|
+
* assert active-specs context lands where the model expects it.
|
|
91
|
+
*/
|
|
92
|
+
export declare function buildMultifurcationUserMessage(inputs: MultifurcationInputs): string;
|
|
93
|
+
/**
|
|
94
|
+
* Compact a Spec list down to the digest shape the multifurcation
|
|
95
|
+
* prompt consumes. Summary is the first ~150 chars of the first
|
|
96
|
+
* acceptance scenario (the most spec-like prose); falls back to a
|
|
97
|
+
* non_goal or empty string.
|
|
98
|
+
*/
|
|
99
|
+
export declare function digestActiveSpecs(specs: Spec[]): ActiveSpecDigest[];
|
|
100
|
+
/**
|
|
101
|
+
* Parse the JSON verdict. Tolerant of leading/trailing prose (some
|
|
102
|
+
* models still wrap JSON in fences despite the prompt). Defaults to
|
|
103
|
+
* `{ kind: "one", rationale: "(parser fallback โ model output unparseable)" }`
|
|
104
|
+
* so that an LLM hiccup never blocks refine.
|
|
105
|
+
*/
|
|
106
|
+
export declare function parseMultifurcationJson(text: string): MultifurcationVerdict;
|
|
107
|
+
/**
|
|
108
|
+
* PM-facing comment body listing the proposed sub-issues. The template
|
|
109
|
+
* mirrors the refine "questions-first" layout โ proposal up top, agent's
|
|
110
|
+
* rationale folded into a <details> block, action prompts at the bottom.
|
|
111
|
+
*
|
|
112
|
+
* The HTML comment `<!-- slowcook:multifurcation -->` is a sentinel
|
|
113
|
+
* future refine runs grep for to skip re-proposing on the same issue.
|
|
114
|
+
*/
|
|
115
|
+
export declare function multifurcationCommentBody(proposal: {
|
|
116
|
+
rationale: string;
|
|
117
|
+
sub_issues: MultifurcationSubIssue[];
|
|
118
|
+
}, opts: {
|
|
119
|
+
issueTitle: string;
|
|
120
|
+
}): string;
|
|
121
|
+
/**
|
|
122
|
+
* Detect whether a multifurcation proposal has already been posted on
|
|
123
|
+
* an issue's comment thread. Used by the agent to skip re-running the
|
|
124
|
+
* LLM pass when the PM is still deciding.
|
|
125
|
+
*/
|
|
126
|
+
export declare function hasExistingMultifurcationComment(comments: Array<{
|
|
127
|
+
body: string;
|
|
128
|
+
}>): boolean;
|
|
129
|
+
//# sourceMappingURL=multifurcate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multifurcate.d.ts","sourceRoot":"","sources":["../../../src/commands/refine/multifurcate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAGzD;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,sBAAsB,EAAE,CAAA;CAAE,CAAC;AAE9E,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,qBAAqB,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE;QACL,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,eAAe,EAAE,MAAM,CAAC;QACxB,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,oBAAoB,EAC5B,IAAI,EAAE;IAAE,GAAG,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACtC,OAAO,CAAC,oBAAoB,CAAC,CAe/B;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAwBnF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,gBAAgB,EAAE,CAQnE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,qBAAqB,CA2E3E;AAyBD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,sBAAsB,EAAE,CAAA;CAAE,EACrE,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAC3B,MAAM,CAkDR;AAMD;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAChC,OAAO,CAET"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @slowcook 0.19.0-ฮฑ.44 โ multifurcation pre-step.
|
|
3
|
+
*
|
|
4
|
+
* Some GitHub issues are not stories. They are programs of work disguised
|
|
5
|
+
* as tickets ("everything according to mock", "rewrite the patient app",
|
|
6
|
+
* "wire X to Y" where X and Y are whole subsystems). Forcing those
|
|
7
|
+
* through refine produces a fuzzy mega-spec that no downstream agent can
|
|
8
|
+
* reasonably implement.
|
|
9
|
+
*
|
|
10
|
+
* This module runs a cheap LLM pass BEFORE refine's relationship +
|
|
11
|
+
* refinement calls. It returns either:
|
|
12
|
+
*
|
|
13
|
+
* - { kind: "one", rationale } โ refine proceeds normally
|
|
14
|
+
* - { kind: "many", sub_issues, rationale } โ refine posts a
|
|
15
|
+
* PM-facing proposal listing the proposed sub-issues + halts; the
|
|
16
|
+
* PM decides whether to file the split. The original issue is
|
|
17
|
+
* marked `slowcook-multifurcation-proposed` so refine doesn't loop.
|
|
18
|
+
*
|
|
19
|
+
* Sub-issue titles + summaries are PM-style by contract (see prompt
|
|
20
|
+
* rules): intent-shaped, no file paths or pipeline names, โค 80 char
|
|
21
|
+
* titles, 1-3 sentence summaries. Quality of the proposal is the
|
|
22
|
+
* PM's call โ the comment template makes editing easy.
|
|
23
|
+
*/
|
|
24
|
+
import { MULTIFURCATION_SYSTEM } from "@slowcook-ai/llm-anthropic";
|
|
25
|
+
export async function assessMultifurcation(inputs, opts) {
|
|
26
|
+
const userMessage = buildMultifurcationUserMessage(inputs);
|
|
27
|
+
const response = await opts.llm.complete({
|
|
28
|
+
system: MULTIFURCATION_SYSTEM,
|
|
29
|
+
cacheSystem: false,
|
|
30
|
+
model: opts.model,
|
|
31
|
+
messages: [{ role: "user", content: userMessage }],
|
|
32
|
+
maxTokens: 2048,
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
verdict: parseMultifurcationJson(response.text),
|
|
36
|
+
costUsd: response.costUsd,
|
|
37
|
+
usage: response.usage,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Compose the user-side message. Exported for tests so the snapshot can
|
|
42
|
+
* assert active-specs context lands where the model expects it.
|
|
43
|
+
*/
|
|
44
|
+
export function buildMultifurcationUserMessage(inputs) {
|
|
45
|
+
const sections = [];
|
|
46
|
+
sections.push("## Issue under review");
|
|
47
|
+
sections.push(`### Title\n${inputs.issueTitle}`);
|
|
48
|
+
sections.push(`### Body\n${inputs.issueBody || "(empty body)"}`);
|
|
49
|
+
const specs = inputs.activeSpecs ?? [];
|
|
50
|
+
if (specs.length > 0) {
|
|
51
|
+
sections.push("## Active specs in this repo");
|
|
52
|
+
sections.push("If any proposed sub-issue's scope is ALREADY covered by one of these, " +
|
|
53
|
+
"set `existing_spec_id` to that story_id in the sub-issue object. " +
|
|
54
|
+
"Still include the sub-issue in the proposal โ the PM needs the full picture, " +
|
|
55
|
+
"the annotation tells them this slice is already on the ratchet. " +
|
|
56
|
+
"Do NOT silently omit overlapping sub-issues.");
|
|
57
|
+
for (const s of specs) {
|
|
58
|
+
const summary = s.summary && s.summary.length > 0 ? ` โ ${s.summary}` : "";
|
|
59
|
+
sections.push(`- **story-${s.story_id}** "${s.title}"${summary}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
sections.push("Return the JSON verdict per the system prompt.");
|
|
63
|
+
return sections.join("\n\n");
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Compact a Spec list down to the digest shape the multifurcation
|
|
67
|
+
* prompt consumes. Summary is the first ~150 chars of the first
|
|
68
|
+
* acceptance scenario (the most spec-like prose); falls back to a
|
|
69
|
+
* non_goal or empty string.
|
|
70
|
+
*/
|
|
71
|
+
export function digestActiveSpecs(specs) {
|
|
72
|
+
return specs.map((s) => {
|
|
73
|
+
const firstScenario = s.acceptance_scenarios[0] ?? "";
|
|
74
|
+
const firstInvariant = s.invariants[0] ?? "";
|
|
75
|
+
const raw = firstScenario || firstInvariant || s.non_goals[0] || "";
|
|
76
|
+
const summary = raw.replace(/\s+/g, " ").trim().slice(0, 150);
|
|
77
|
+
return { story_id: s.story_id, title: s.title, summary };
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Parse the JSON verdict. Tolerant of leading/trailing prose (some
|
|
82
|
+
* models still wrap JSON in fences despite the prompt). Defaults to
|
|
83
|
+
* `{ kind: "one", rationale: "(parser fallback โ model output unparseable)" }`
|
|
84
|
+
* so that an LLM hiccup never blocks refine.
|
|
85
|
+
*/
|
|
86
|
+
export function parseMultifurcationJson(text) {
|
|
87
|
+
const json = extractJsonBlob(text);
|
|
88
|
+
if (!json) {
|
|
89
|
+
return {
|
|
90
|
+
kind: "one",
|
|
91
|
+
rationale: "(parser fallback โ model output unparseable, treating as single story)",
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
let raw;
|
|
95
|
+
try {
|
|
96
|
+
raw = JSON.parse(json);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return {
|
|
100
|
+
kind: "one",
|
|
101
|
+
rationale: "(parser fallback โ JSON parse failed)",
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
if (!raw || typeof raw !== "object") {
|
|
105
|
+
return { kind: "one", rationale: "(parser fallback โ non-object verdict)" };
|
|
106
|
+
}
|
|
107
|
+
const o = raw;
|
|
108
|
+
const verdict = typeof o.verdict === "string" ? o.verdict.toLowerCase() : "";
|
|
109
|
+
const rationale = typeof o.rationale === "string" ? o.rationale.trim() : "";
|
|
110
|
+
if (verdict === "one") {
|
|
111
|
+
return { kind: "one", rationale: rationale || "(no rationale provided)" };
|
|
112
|
+
}
|
|
113
|
+
if (verdict === "many") {
|
|
114
|
+
const subRaw = Array.isArray(o.sub_issues) ? o.sub_issues : [];
|
|
115
|
+
const sub_issues = [];
|
|
116
|
+
for (const entry of subRaw) {
|
|
117
|
+
if (!entry || typeof entry !== "object")
|
|
118
|
+
continue;
|
|
119
|
+
const e = entry;
|
|
120
|
+
const title = typeof e.title === "string" ? e.title.trim() : "";
|
|
121
|
+
const summary = typeof e.summary === "string" ? e.summary.trim() : "";
|
|
122
|
+
if (!title || !summary)
|
|
123
|
+
continue;
|
|
124
|
+
const depRaw = Array.isArray(e.depends_on) ? e.depends_on : [];
|
|
125
|
+
const depends_on = depRaw
|
|
126
|
+
.filter((d) => typeof d === "string" && d.trim().length > 0)
|
|
127
|
+
.map((d) => d.trim());
|
|
128
|
+
const item = { title, summary };
|
|
129
|
+
if (depends_on.length > 0)
|
|
130
|
+
item.depends_on = depends_on;
|
|
131
|
+
// cli ฮฑ.45 โ overlap annotation. Accept variants the model may
|
|
132
|
+
// emit (existing_spec_id, story_id, covered_by_story) and
|
|
133
|
+
// normalize to plain digit-suffix form ("002" not "story-002").
|
|
134
|
+
const rawId = (typeof e.existing_spec_id === "string" && e.existing_spec_id) ||
|
|
135
|
+
(typeof e.covered_by_story === "string" && e.covered_by_story) ||
|
|
136
|
+
(typeof e.story_id === "string" && e.story_id) ||
|
|
137
|
+
"";
|
|
138
|
+
const normalised = rawId.trim().replace(/^story-/i, "");
|
|
139
|
+
if (normalised.length > 0)
|
|
140
|
+
item.existing_spec_id = normalised;
|
|
141
|
+
sub_issues.push(item);
|
|
142
|
+
}
|
|
143
|
+
// Guardrail: if the model said "many" but failed to produce โฅ2 valid
|
|
144
|
+
// sub-issues, fall back to "one" rather than emit a broken proposal.
|
|
145
|
+
// Always tag the rationale so downstream logs reveal the downgrade.
|
|
146
|
+
if (sub_issues.length < 2) {
|
|
147
|
+
const prefix = "(parser fallback โ verdict was many but fewer than 2 valid sub-issues parsed)";
|
|
148
|
+
return {
|
|
149
|
+
kind: "one",
|
|
150
|
+
rationale: rationale ? `${prefix} ยท original rationale: ${rationale}` : prefix,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
kind: "many",
|
|
155
|
+
rationale: rationale || "(no rationale provided)",
|
|
156
|
+
sub_issues,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
kind: "one",
|
|
161
|
+
rationale: rationale || `(parser fallback โ unknown verdict "${verdict}")`,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Extract the first balanced { ... } JSON blob from raw model text.
|
|
166
|
+
* Strips common decorations: leading prose, ```json fences, trailing
|
|
167
|
+
* commentary. Returns null if no balanced object is found.
|
|
168
|
+
*/
|
|
169
|
+
function extractJsonBlob(text) {
|
|
170
|
+
const fenced = text.match(/```(?:json)?\s*(\{[\s\S]*?\})\s*```/);
|
|
171
|
+
if (fenced && fenced[1])
|
|
172
|
+
return fenced[1];
|
|
173
|
+
const start = text.indexOf("{");
|
|
174
|
+
if (start === -1)
|
|
175
|
+
return null;
|
|
176
|
+
let depth = 0;
|
|
177
|
+
for (let i = start; i < text.length; i++) {
|
|
178
|
+
const ch = text[i];
|
|
179
|
+
if (ch === "{")
|
|
180
|
+
depth++;
|
|
181
|
+
else if (ch === "}") {
|
|
182
|
+
depth--;
|
|
183
|
+
if (depth === 0)
|
|
184
|
+
return text.slice(start, i + 1);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* PM-facing comment body listing the proposed sub-issues. The template
|
|
191
|
+
* mirrors the refine "questions-first" layout โ proposal up top, agent's
|
|
192
|
+
* rationale folded into a <details> block, action prompts at the bottom.
|
|
193
|
+
*
|
|
194
|
+
* The HTML comment `<!-- slowcook:multifurcation -->` is a sentinel
|
|
195
|
+
* future refine runs grep for to skip re-proposing on the same issue.
|
|
196
|
+
*/
|
|
197
|
+
export function multifurcationCommentBody(proposal, opts) {
|
|
198
|
+
const lines = [];
|
|
199
|
+
lines.push("<!-- slowcook:multifurcation -->");
|
|
200
|
+
lines.push("### slowcook ยท refinement agent ๐ฒ");
|
|
201
|
+
lines.push("");
|
|
202
|
+
lines.push(`This issue looks like **more than one story** to me. Before I produce a spec, please confirm the split below โ refine ships one PR per story, and a single mega-spec usually misses the things that matter at each user-facing slice.`);
|
|
203
|
+
lines.push("");
|
|
204
|
+
const overlapCount = proposal.sub_issues.filter((s) => s.existing_spec_id).length;
|
|
205
|
+
lines.push(`#### Proposed sub-issues (${proposal.sub_issues.length}${overlapCount > 0 ? `, ${overlapCount} overlap existing specs` : ""})`);
|
|
206
|
+
lines.push("");
|
|
207
|
+
for (let i = 0; i < proposal.sub_issues.length; i++) {
|
|
208
|
+
const s = proposal.sub_issues[i];
|
|
209
|
+
const overlapBadge = s.existing_spec_id
|
|
210
|
+
? ` _(already covered by story-${escapeMd(s.existing_spec_id)})_`
|
|
211
|
+
: "";
|
|
212
|
+
lines.push(`**${i + 1}. ${escapeMd(s.title)}**${overlapBadge}`);
|
|
213
|
+
lines.push("");
|
|
214
|
+
lines.push(escapeMd(s.summary));
|
|
215
|
+
if (s.depends_on && s.depends_on.length > 0) {
|
|
216
|
+
lines.push("");
|
|
217
|
+
lines.push(`_Depends on: ${s.depends_on.map((d) => `"${d}"`).join(", ")}_`);
|
|
218
|
+
}
|
|
219
|
+
lines.push("");
|
|
220
|
+
}
|
|
221
|
+
lines.push("<details><summary>Why I think this should split</summary>");
|
|
222
|
+
lines.push("");
|
|
223
|
+
lines.push(proposal.rationale);
|
|
224
|
+
lines.push("");
|
|
225
|
+
lines.push("</details>");
|
|
226
|
+
lines.push("");
|
|
227
|
+
lines.push("#### What to do");
|
|
228
|
+
lines.push("");
|
|
229
|
+
lines.push("- ๐ **Looks right** โ file each sub-issue that DOESN'T have an _already covered by_ tag. For tagged ones, decide per row whether to fold them into the existing story (comment on that story) or skip. Then close this one or remove `needs-refinement` from it.");
|
|
230
|
+
lines.push("- โ๏ธ **Needs tweaking** โ reply with the edited list (edit titles, drop or add entries, change overlap calls). Remove the `slowcook-multifurcation-proposed` label and I'll re-propose.");
|
|
231
|
+
lines.push("- ๐ **Keep as one** โ reply \"keep as one\" and remove both labels (`slowcook-multifurcation-proposed` and `needs-refinement`, then re-add `needs-refinement`). I'll proceed with a single spec.");
|
|
232
|
+
lines.push("");
|
|
233
|
+
lines.push(`_For context, the original title was: **${escapeMd(opts.issueTitle)}**_`);
|
|
234
|
+
return lines.join("\n");
|
|
235
|
+
}
|
|
236
|
+
function escapeMd(s) {
|
|
237
|
+
return s.replace(/</g, "<").replace(/>/g, ">");
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Detect whether a multifurcation proposal has already been posted on
|
|
241
|
+
* an issue's comment thread. Used by the agent to skip re-running the
|
|
242
|
+
* LLM pass when the PM is still deciding.
|
|
243
|
+
*/
|
|
244
|
+
export function hasExistingMultifurcationComment(comments) {
|
|
245
|
+
return comments.some((c) => c.body.includes("<!-- slowcook:multifurcation -->"));
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=multifurcate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multifurcate.js","sourceRoot":"","sources":["../../../src/commands/refine/multifurcate.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import type { Spec, SpecProposals } from "@slowcook-ai/core";
|
|
2
|
+
/**
|
|
3
|
+
* 0.19.0-ฮฑ.30 (sc#63) โ load the consumer's existing column-set by
|
|
4
|
+
* scanning migration files. Returns Map<table, Set<column>> indexed
|
|
5
|
+
* by lower-case names. Used by deriveSchema to distinguish columns
|
|
6
|
+
* that already exist (skip) from those that need an ALTER TABLE.
|
|
7
|
+
*
|
|
8
|
+
* Returns null if no migrations found (greenfield / first slowcook
|
|
9
|
+
* story); deriveSchema falls back to its existing CREATE TABLE flow.
|
|
10
|
+
*/
|
|
11
|
+
export declare function loadExistingColumns(repoRoot: string): Map<string, Set<string>> | null;
|
|
2
12
|
/**
|
|
3
13
|
* Deterministic post-processor that derives proposals from the spec
|
|
4
14
|
* body when the LLM inlined decisions into `invariants` / `api_contract`
|
|
@@ -32,5 +42,44 @@ import type { Spec, SpecProposals } from "@slowcook-ai/core";
|
|
|
32
42
|
* hard-signal backstop: when the LLM doesn't elevate to a structured
|
|
33
43
|
* block, the synth derives one from prose + brownfield extracts.
|
|
34
44
|
*/
|
|
35
|
-
export declare function synthesizeProposalsFromSpec(spec: Spec
|
|
45
|
+
export declare function synthesizeProposalsFromSpec(spec: Spec, opts?: {
|
|
46
|
+
repoRoot?: string;
|
|
47
|
+
}): SpecProposals;
|
|
48
|
+
/**
|
|
49
|
+
* Map a URL path to a candidate Next.js App Router file location.
|
|
50
|
+
* Uses the `(main)` route group by default (authenticated app pages).
|
|
51
|
+
* Consumer can edit post-emit if their layout differs.
|
|
52
|
+
*/
|
|
53
|
+
/**
|
|
54
|
+
* 0.19.0-ฮฑ.29 (sc#64) โ app-shape detection for multi-app monorepos.
|
|
55
|
+
*
|
|
56
|
+
* - `single-flat` โ `src/app/<path>/page.tsx` (no route group)
|
|
57
|
+
* - `single-grouped` โ `src/app/(main)/<path>/page.tsx` (rewo convention)
|
|
58
|
+
* - `multi-app` โ `apps/<app>/src/app/<path>/page.tsx` (delgoosh)
|
|
59
|
+
*
|
|
60
|
+
* Detection walks the consumer's filesystem:
|
|
61
|
+
* - If `apps/<name>/src/app/` exists for two or more apps โ multi-app.
|
|
62
|
+
* - Else if `src/app/(main)/` exists โ single-grouped.
|
|
63
|
+
* - Else default to single-flat.
|
|
64
|
+
*
|
|
65
|
+
* When no repoRoot is provided (older callers / tests that pass spec
|
|
66
|
+
* only), defaults to `single-grouped` for backward compat with rewo.
|
|
67
|
+
*
|
|
68
|
+
* In multi-app mode, route โ app assignment heuristic:
|
|
69
|
+
* - Path's first segment matches an app name โ that app owns it
|
|
70
|
+
* (e.g., /patient/dashboard โ apps/patient/src/app/dashboard/page.tsx,
|
|
71
|
+
* the /patient prefix gets STRIPPED since it's already in the app dir)
|
|
72
|
+
* - Path matches no app โ first app gets it (caller can edit)
|
|
73
|
+
*/
|
|
74
|
+
export type AppShape = {
|
|
75
|
+
kind: "single-flat";
|
|
76
|
+
prefix: string;
|
|
77
|
+
} | {
|
|
78
|
+
kind: "single-grouped";
|
|
79
|
+
prefix: string;
|
|
80
|
+
} | {
|
|
81
|
+
kind: "multi-app";
|
|
82
|
+
apps: string[];
|
|
83
|
+
};
|
|
84
|
+
export declare function detectAppShape(repoRoot: string): AppShape;
|
|
36
85
|
//# sourceMappingURL=proposals-synth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proposals-synth.d.ts","sourceRoot":"","sources":["../../../src/commands/refine/proposals-synth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"proposals-synth.d.ts","sourceRoot":"","sources":["../../../src/commands/refine/proposals-synth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAG7D;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,GACf,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAajC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,IAAI,EACV,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,aAAa,CAkCf;AA0UD;;;;GAIG;AACH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,QAAQ,GAChB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAE1C,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CA8BzD"}
|