forge-cc 0.1.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/.forge.json +5 -0
- package/AGENTS.md +42 -0
- package/README.md +283 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +148 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/loader.d.ts +2 -0
- package/dist/config/loader.js +44 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +57 -0
- package/dist/config/schema.js +15 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/gates/index.d.ts +11 -0
- package/dist/gates/index.js +106 -0
- package/dist/gates/index.js.map +1 -0
- package/dist/gates/lint-gate.d.ts +2 -0
- package/dist/gates/lint-gate.js +66 -0
- package/dist/gates/lint-gate.js.map +1 -0
- package/dist/gates/prd-gate.d.ts +7 -0
- package/dist/gates/prd-gate.js +193 -0
- package/dist/gates/prd-gate.js.map +1 -0
- package/dist/gates/runtime-gate.d.ts +5 -0
- package/dist/gates/runtime-gate.js +99 -0
- package/dist/gates/runtime-gate.js.map +1 -0
- package/dist/gates/tests-gate.d.ts +2 -0
- package/dist/gates/tests-gate.js +116 -0
- package/dist/gates/tests-gate.js.map +1 -0
- package/dist/gates/types-gate.d.ts +2 -0
- package/dist/gates/types-gate.js +59 -0
- package/dist/gates/types-gate.js.map +1 -0
- package/dist/gates/visual-gate.d.ts +6 -0
- package/dist/gates/visual-gate.js +118 -0
- package/dist/gates/visual-gate.js.map +1 -0
- package/dist/go/auto-chain.d.ts +107 -0
- package/dist/go/auto-chain.js +303 -0
- package/dist/go/auto-chain.js.map +1 -0
- package/dist/go/executor.d.ts +130 -0
- package/dist/go/executor.js +409 -0
- package/dist/go/executor.js.map +1 -0
- package/dist/go/finalize.d.ts +58 -0
- package/dist/go/finalize.js +200 -0
- package/dist/go/finalize.js.map +1 -0
- package/dist/go/linear-sync.d.ts +75 -0
- package/dist/go/linear-sync.js +239 -0
- package/dist/go/linear-sync.js.map +1 -0
- package/dist/go/verify-loop.d.ts +47 -0
- package/dist/go/verify-loop.js +172 -0
- package/dist/go/verify-loop.js.map +1 -0
- package/dist/hooks/pre-commit.d.ts +5 -0
- package/dist/hooks/pre-commit.js +69 -0
- package/dist/hooks/pre-commit.js.map +1 -0
- package/dist/linear/client.d.ts +108 -0
- package/dist/linear/client.js +388 -0
- package/dist/linear/client.js.map +1 -0
- package/dist/linear/issues.d.ts +20 -0
- package/dist/linear/issues.js +39 -0
- package/dist/linear/issues.js.map +1 -0
- package/dist/linear/milestones.d.ts +11 -0
- package/dist/linear/milestones.js +32 -0
- package/dist/linear/milestones.js.map +1 -0
- package/dist/linear/projects.d.ts +16 -0
- package/dist/linear/projects.js +50 -0
- package/dist/linear/projects.js.map +1 -0
- package/dist/reporter/human.d.ts +2 -0
- package/dist/reporter/human.js +63 -0
- package/dist/reporter/human.js.map +1 -0
- package/dist/reporter/json.d.ts +2 -0
- package/dist/reporter/json.js +4 -0
- package/dist/reporter/json.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +109 -0
- package/dist/server.js.map +1 -0
- package/dist/spec/generator.d.ts +14 -0
- package/dist/spec/generator.js +206 -0
- package/dist/spec/generator.js.map +1 -0
- package/dist/spec/interview.d.ts +104 -0
- package/dist/spec/interview.js +342 -0
- package/dist/spec/interview.js.map +1 -0
- package/dist/spec/linear-sync.d.ts +48 -0
- package/dist/spec/linear-sync.js +125 -0
- package/dist/spec/linear-sync.js.map +1 -0
- package/dist/spec/scanner.d.ts +45 -0
- package/dist/spec/scanner.js +473 -0
- package/dist/spec/scanner.js.map +1 -0
- package/dist/spec/templates.d.ts +345 -0
- package/dist/spec/templates.js +86 -0
- package/dist/spec/templates.js.map +1 -0
- package/dist/state/reader.d.ts +29 -0
- package/dist/state/reader.js +116 -0
- package/dist/state/reader.js.map +1 -0
- package/dist/state/writer.d.ts +60 -0
- package/dist/state/writer.js +222 -0
- package/dist/state/writer.js.map +1 -0
- package/dist/types.d.ts +64 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/browser.d.ts +10 -0
- package/dist/utils/browser.js +89 -0
- package/dist/utils/browser.js.map +1 -0
- package/hooks/pre-commit-verify.js +103 -0
- package/package.json +68 -0
- package/skills/README.md +33 -0
- package/skills/forge-go.md +332 -0
- package/skills/forge-spec.md +251 -0
- package/skills/forge-triage.md +133 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
/** Regex to parse tsc error lines: src/foo.ts(10,5): error TS2322: ... */
|
|
3
|
+
const TSC_ERROR_RE = /^(.+?)\((\d+),\d+\):\s*(.+)$/;
|
|
4
|
+
export async function verifyTypes(projectDir) {
|
|
5
|
+
const start = Date.now();
|
|
6
|
+
const errors = [];
|
|
7
|
+
const warnings = [];
|
|
8
|
+
try {
|
|
9
|
+
execSync("npx tsc --noEmit", {
|
|
10
|
+
cwd: projectDir,
|
|
11
|
+
stdio: "pipe",
|
|
12
|
+
timeout: 120_000,
|
|
13
|
+
});
|
|
14
|
+
return {
|
|
15
|
+
gate: "types",
|
|
16
|
+
passed: true,
|
|
17
|
+
errors,
|
|
18
|
+
warnings,
|
|
19
|
+
duration_ms: Date.now() - start,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
const output = err instanceof Error && "stdout" in err
|
|
24
|
+
? String(err.stdout)
|
|
25
|
+
: "";
|
|
26
|
+
for (const line of output.split("\n")) {
|
|
27
|
+
const trimmed = line.trim();
|
|
28
|
+
if (!trimmed)
|
|
29
|
+
continue;
|
|
30
|
+
if (trimmed.toLowerCase().includes("warning")) {
|
|
31
|
+
warnings.push(trimmed);
|
|
32
|
+
}
|
|
33
|
+
else if (trimmed.includes("error TS")) {
|
|
34
|
+
const match = TSC_ERROR_RE.exec(trimmed);
|
|
35
|
+
if (match) {
|
|
36
|
+
errors.push({
|
|
37
|
+
file: match[1],
|
|
38
|
+
line: Number.parseInt(match[2], 10),
|
|
39
|
+
message: match[3],
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
errors.push({ message: trimmed });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (errors.length === 0) {
|
|
48
|
+
errors.push({ message: "tsc exited with non-zero status but no TS errors were parsed" });
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
gate: "types",
|
|
52
|
+
passed: false,
|
|
53
|
+
errors,
|
|
54
|
+
warnings,
|
|
55
|
+
duration_ms: Date.now() - start,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=types-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-gate.js","sourceRoot":"","sources":["../../src/gates/types-gate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,0EAA0E;AAC1E,MAAM,YAAY,GAAG,8BAA8B,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,UAAkB;IAClD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,MAAM,GAAgB,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,IAAI,CAAC;QACH,QAAQ,CAAC,kBAAkB,EAAE;YAC3B,GAAG,EAAE,UAAU;YACf,KAAK,EAAE,MAAM;YACb,OAAO,EAAE,OAAO;SACjB,CAAC,CAAC;QAEH,OAAO;YACL,IAAI,EAAE,OAAO;YACb,MAAM,EAAE,IAAI;YACZ,MAAM;YACN,QAAQ;YACR,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAChC,CAAC;IACJ,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,MAAM,GACV,GAAG,YAAY,KAAK,IAAI,QAAQ,IAAI,GAAG;YACrC,CAAC,CAAC,MAAM,CAAE,GAA0B,CAAC,MAAM,CAAC;YAC5C,CAAC,CAAC,EAAE,CAAC;QAET,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC9C,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACzB,CAAC;iBAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBACxC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACzC,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,CAAC,IAAI,CAAC;wBACV,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;wBACd,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;wBACnC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;qBAClB,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,8DAA8D,EAAE,CAAC,CAAC;QAC3F,CAAC;QAED,OAAO;YACL,IAAI,EAAE,OAAO;YACb,MAAM,EAAE,KAAK;YACb,MAAM;YACN,QAAQ;YACR,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAChC,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { getBrowser, startDevServer, stopDevServer, waitForServer, } from "../utils/browser.js";
|
|
2
|
+
import { mkdirSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
export async function verifyVisual(projectDir, pages, options) {
|
|
5
|
+
const start = Date.now();
|
|
6
|
+
const resolvedPages = pages.length > 0 ? pages : ["/"];
|
|
7
|
+
const port = options?.devServerPort ?? 3000;
|
|
8
|
+
const screenshotDir = options?.screenshotDir ?? join(projectDir, ".forge", "screenshots");
|
|
9
|
+
const consoleErrors = [];
|
|
10
|
+
const warnings = [];
|
|
11
|
+
const screenshots = [];
|
|
12
|
+
mkdirSync(screenshotDir, { recursive: true });
|
|
13
|
+
try {
|
|
14
|
+
// Start dev server
|
|
15
|
+
try {
|
|
16
|
+
await startDevServer(projectDir, options?.devServerCommand, port);
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
const message = err instanceof Error ? err.message : "Unknown dev server error";
|
|
20
|
+
return {
|
|
21
|
+
gate: "visual",
|
|
22
|
+
passed: false,
|
|
23
|
+
errors: [{ message: `Dev server failed to start: ${message}` }],
|
|
24
|
+
warnings,
|
|
25
|
+
duration_ms: Date.now() - start,
|
|
26
|
+
screenshots,
|
|
27
|
+
consoleErrors,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// Ensure server is reachable
|
|
31
|
+
const ready = await waitForServer(port);
|
|
32
|
+
if (!ready) {
|
|
33
|
+
return {
|
|
34
|
+
gate: "visual",
|
|
35
|
+
passed: false,
|
|
36
|
+
errors: [{ message: `Dev server not reachable on port ${port}` }],
|
|
37
|
+
warnings,
|
|
38
|
+
duration_ms: Date.now() - start,
|
|
39
|
+
screenshots,
|
|
40
|
+
consoleErrors,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// Launch browser and create context
|
|
44
|
+
const browser = await getBrowser();
|
|
45
|
+
const context = await browser.newContext();
|
|
46
|
+
try {
|
|
47
|
+
for (const pagePath of resolvedPages) {
|
|
48
|
+
const page = await context.newPage();
|
|
49
|
+
// Collect console errors
|
|
50
|
+
page.on("console", (msg) => {
|
|
51
|
+
if (msg.type() === "error") {
|
|
52
|
+
consoleErrors.push(msg.text());
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
page.on("pageerror", (err) => {
|
|
56
|
+
consoleErrors.push(err.message);
|
|
57
|
+
});
|
|
58
|
+
// Navigate to the page
|
|
59
|
+
try {
|
|
60
|
+
await page.goto(`http://localhost:${port}${pagePath}`, {
|
|
61
|
+
waitUntil: "networkidle",
|
|
62
|
+
timeout: 30_000,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
const message = err instanceof Error ? err.message : "Navigation failed";
|
|
67
|
+
consoleErrors.push(`Navigation error for ${pagePath}: ${message}`);
|
|
68
|
+
await page.close();
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
// Take screenshot
|
|
72
|
+
try {
|
|
73
|
+
const safeName = pagePath.replace(/\//g, "_").replace(/^_/, "") || "index";
|
|
74
|
+
const screenshotPath = join(screenshotDir, `${safeName}.png`);
|
|
75
|
+
await page.screenshot({ path: screenshotPath, fullPage: true });
|
|
76
|
+
screenshots.push({ page: pagePath, path: screenshotPath });
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
const message = err instanceof Error ? err.message : "Screenshot failed";
|
|
80
|
+
warnings.push(`Screenshot failed for ${pagePath}: ${message}`);
|
|
81
|
+
}
|
|
82
|
+
await page.close();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
await context.close();
|
|
87
|
+
}
|
|
88
|
+
// Convert console errors to GateError objects
|
|
89
|
+
const errors = consoleErrors.map((msg) => ({
|
|
90
|
+
message: msg,
|
|
91
|
+
}));
|
|
92
|
+
return {
|
|
93
|
+
gate: "visual",
|
|
94
|
+
passed: consoleErrors.length === 0,
|
|
95
|
+
errors,
|
|
96
|
+
warnings,
|
|
97
|
+
duration_ms: Date.now() - start,
|
|
98
|
+
screenshots,
|
|
99
|
+
consoleErrors,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
const message = err instanceof Error ? err.message : "Unknown error in verifyVisual";
|
|
104
|
+
return {
|
|
105
|
+
gate: "visual",
|
|
106
|
+
passed: false,
|
|
107
|
+
errors: [{ message }],
|
|
108
|
+
warnings,
|
|
109
|
+
duration_ms: Date.now() - start,
|
|
110
|
+
screenshots,
|
|
111
|
+
consoleErrors,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
await stopDevServer();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=visual-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visual-gate.js","sourceRoot":"","sources":["../../src/gates/visual-gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-Chain — Multi-Milestone Execution Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* After a milestone completes, spawns a fresh agent with clean context for the
|
|
5
|
+
* next milestone. Fresh agent reads CLAUDE.md + STATE.md + next milestone section
|
|
6
|
+
* only. Loops until all milestones done or a failure stops the chain.
|
|
7
|
+
*
|
|
8
|
+
* This module is the data/logic layer. It does NOT spawn agents — that is
|
|
9
|
+
* the skill file's job (via Claude Code's Task tool). Auto-chain prepares
|
|
10
|
+
* the context and tracks results across milestones.
|
|
11
|
+
*/
|
|
12
|
+
import type { MilestoneProgress } from "../state/reader.js";
|
|
13
|
+
import type { CommitResult } from "../state/writer.js";
|
|
14
|
+
import type { ForgeConfig } from "../types.js";
|
|
15
|
+
export interface AutoChainOptions {
|
|
16
|
+
projectDir: string;
|
|
17
|
+
prdPath: string;
|
|
18
|
+
config: ForgeConfig;
|
|
19
|
+
branch: string;
|
|
20
|
+
/** Project name (e.g., "forge-cc") */
|
|
21
|
+
project: string;
|
|
22
|
+
/** Relative PRD path for state docs */
|
|
23
|
+
activePrd: string;
|
|
24
|
+
/** Developer name for session memory */
|
|
25
|
+
developer: string;
|
|
26
|
+
/** If not provided, detect from STATE.md */
|
|
27
|
+
startMilestone?: number;
|
|
28
|
+
/** Called when a milestone begins execution */
|
|
29
|
+
onMilestoneStart?: (milestoneNumber: number, name: string) => void;
|
|
30
|
+
/** Called when a milestone finishes (success or failure) */
|
|
31
|
+
onMilestoneComplete?: (milestoneNumber: number, result: MilestoneResult) => void;
|
|
32
|
+
/** Called when the entire chain finishes */
|
|
33
|
+
onChainComplete?: (results: MilestoneResult[]) => void;
|
|
34
|
+
}
|
|
35
|
+
export interface MilestoneResult {
|
|
36
|
+
milestoneNumber: number;
|
|
37
|
+
milestoneName: string;
|
|
38
|
+
success: boolean;
|
|
39
|
+
commitSha?: string;
|
|
40
|
+
isLast: boolean;
|
|
41
|
+
/** Fresh-context prompt for spawning this milestone's agent */
|
|
42
|
+
freshPrompt: string;
|
|
43
|
+
errors: string[];
|
|
44
|
+
}
|
|
45
|
+
export interface AutoChainResult {
|
|
46
|
+
completed: MilestoneResult[];
|
|
47
|
+
/** true if the chain stopped due to a milestone failure */
|
|
48
|
+
stopped: boolean;
|
|
49
|
+
/** Milestone number where the chain stopped (on failure) */
|
|
50
|
+
stoppedAt?: number;
|
|
51
|
+
/** true if every milestone in the roadmap is complete */
|
|
52
|
+
allComplete: boolean;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Build the fresh-context prompt for a milestone agent (Ralph Loop pattern).
|
|
56
|
+
*
|
|
57
|
+
* Reads CLAUDE.md (abbreviated to Quick Context), STATE.md content, and the
|
|
58
|
+
* current milestone section from the PRD. The total is kept as small as
|
|
59
|
+
* possible (~200-300 lines) while giving the agent enough context to work.
|
|
60
|
+
*/
|
|
61
|
+
export declare function buildFreshSessionPrompt(projectDir: string, prdPath: string, milestoneNumber: number): Promise<string>;
|
|
62
|
+
/**
|
|
63
|
+
* Find the next pending milestone number from the roadmap.
|
|
64
|
+
*
|
|
65
|
+
* Scans ROADMAP.md for milestones whose status does NOT start with "Complete".
|
|
66
|
+
* Returns the lowest-numbered pending milestone, or null if all are done.
|
|
67
|
+
*/
|
|
68
|
+
export declare function findNextPendingMilestone(projectDir: string): Promise<MilestoneProgress | null>;
|
|
69
|
+
/**
|
|
70
|
+
* Auto-chain orchestrator: manages multi-milestone execution with context resets.
|
|
71
|
+
*
|
|
72
|
+
* For each pending milestone:
|
|
73
|
+
* 1. Determines the starting milestone (from options or STATE.md/ROADMAP.md)
|
|
74
|
+
* 2. Builds a fresh-context prompt for the milestone agent
|
|
75
|
+
* 3. Calls the milestone context builder for structured data
|
|
76
|
+
* 4. Returns results so the calling skill can spawn agents and drive execution
|
|
77
|
+
*
|
|
78
|
+
* The chain stops on the first milestone failure, or when all milestones
|
|
79
|
+
* are complete. The caller is responsible for actually executing each
|
|
80
|
+
* milestone (spawning agents, running waves) — this function provides the
|
|
81
|
+
* orchestration loop and context management.
|
|
82
|
+
*/
|
|
83
|
+
export declare function runAutoChain(options: AutoChainOptions): Promise<AutoChainResult>;
|
|
84
|
+
/**
|
|
85
|
+
* Called after a milestone's agent finishes execution.
|
|
86
|
+
*
|
|
87
|
+
* Handles:
|
|
88
|
+
* 1. Updating milestone progress in STATE.md and ROADMAP.md
|
|
89
|
+
* 2. Committing milestone work to git
|
|
90
|
+
* 3. Returning the commit SHA for the milestone result
|
|
91
|
+
*
|
|
92
|
+
* The caller should update the MilestoneResult with the returned commit info.
|
|
93
|
+
*/
|
|
94
|
+
export declare function completeMilestone(options: {
|
|
95
|
+
projectDir: string;
|
|
96
|
+
project: string;
|
|
97
|
+
milestoneNumber: number;
|
|
98
|
+
milestoneName: string;
|
|
99
|
+
branch: string;
|
|
100
|
+
activePrd: string;
|
|
101
|
+
developer: string;
|
|
102
|
+
filesToStage: string[];
|
|
103
|
+
push?: boolean;
|
|
104
|
+
}): Promise<{
|
|
105
|
+
commitResult: CommitResult;
|
|
106
|
+
isLast: boolean;
|
|
107
|
+
}>;
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-Chain — Multi-Milestone Execution Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* After a milestone completes, spawns a fresh agent with clean context for the
|
|
5
|
+
* next milestone. Fresh agent reads CLAUDE.md + STATE.md + next milestone section
|
|
6
|
+
* only. Loops until all milestones done or a failure stops the chain.
|
|
7
|
+
*
|
|
8
|
+
* This module is the data/logic layer. It does NOT spawn agents — that is
|
|
9
|
+
* the skill file's job (via Claude Code's Task tool). Auto-chain prepares
|
|
10
|
+
* the context and tracks results across milestones.
|
|
11
|
+
*/
|
|
12
|
+
import { readFile } from "node:fs/promises";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { readStateFile, readRoadmapProgress, readCurrentMilestone, } from "../state/reader.js";
|
|
15
|
+
import { isLastMilestone, updateMilestoneProgress, commitMilestoneWork, } from "../state/writer.js";
|
|
16
|
+
import { buildMilestoneContext } from "./executor.js";
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Helpers
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
async function safeRead(filePath) {
|
|
21
|
+
try {
|
|
22
|
+
return await readFile(filePath, "utf-8");
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return "";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Extract the "Quick Context" section from CLAUDE.md.
|
|
30
|
+
*
|
|
31
|
+
* Returns just the abbreviated context block (from "## Quick Context" to the
|
|
32
|
+
* next `##` heading or end of file). Falls back to the first 30 lines of
|
|
33
|
+
* the file if the section header isn't found.
|
|
34
|
+
*/
|
|
35
|
+
function extractQuickContext(claudeMd) {
|
|
36
|
+
if (!claudeMd)
|
|
37
|
+
return "";
|
|
38
|
+
const quickMatch = claudeMd.match(/##\s*Quick Context\s*\n([\s\S]*?)(?=\n##\s|$)/);
|
|
39
|
+
if (quickMatch) {
|
|
40
|
+
return `## Quick Context\n${quickMatch[1].trim()}`;
|
|
41
|
+
}
|
|
42
|
+
// Fallback: first 30 lines (enough context without bloating the prompt)
|
|
43
|
+
const lines = claudeMd.split("\n").slice(0, 30);
|
|
44
|
+
return lines.join("\n").trim();
|
|
45
|
+
}
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// buildFreshSessionPrompt
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
/**
|
|
50
|
+
* Build the fresh-context prompt for a milestone agent (Ralph Loop pattern).
|
|
51
|
+
*
|
|
52
|
+
* Reads CLAUDE.md (abbreviated to Quick Context), STATE.md content, and the
|
|
53
|
+
* current milestone section from the PRD. The total is kept as small as
|
|
54
|
+
* possible (~200-300 lines) while giving the agent enough context to work.
|
|
55
|
+
*/
|
|
56
|
+
export async function buildFreshSessionPrompt(projectDir, prdPath, milestoneNumber) {
|
|
57
|
+
const [claudeMd, stateInfo, milestoneSection] = await Promise.all([
|
|
58
|
+
safeRead(join(projectDir, "CLAUDE.md")),
|
|
59
|
+
readStateFile(projectDir),
|
|
60
|
+
readCurrentMilestone(prdPath, milestoneNumber),
|
|
61
|
+
]);
|
|
62
|
+
const lines = [];
|
|
63
|
+
// 1. Abbreviated CLAUDE.md
|
|
64
|
+
const quickContext = extractQuickContext(claudeMd);
|
|
65
|
+
if (quickContext) {
|
|
66
|
+
lines.push("# Project Context");
|
|
67
|
+
lines.push("");
|
|
68
|
+
lines.push(quickContext);
|
|
69
|
+
lines.push("");
|
|
70
|
+
}
|
|
71
|
+
// 2. STATE.md — current position
|
|
72
|
+
if (stateInfo) {
|
|
73
|
+
lines.push("# Current State");
|
|
74
|
+
lines.push("");
|
|
75
|
+
lines.push(stateInfo.raw.trim());
|
|
76
|
+
lines.push("");
|
|
77
|
+
}
|
|
78
|
+
// 3. Current milestone section from PRD
|
|
79
|
+
if (milestoneSection) {
|
|
80
|
+
lines.push("# Current Milestone");
|
|
81
|
+
lines.push("");
|
|
82
|
+
lines.push(milestoneSection.trim());
|
|
83
|
+
lines.push("");
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
lines.push(`# Current Milestone`);
|
|
87
|
+
lines.push("");
|
|
88
|
+
lines.push(`Milestone ${milestoneNumber} section not found in PRD at ${prdPath}.`);
|
|
89
|
+
lines.push("");
|
|
90
|
+
}
|
|
91
|
+
// 4. Session instructions (minimal)
|
|
92
|
+
lines.push("# Session Instructions");
|
|
93
|
+
lines.push("");
|
|
94
|
+
lines.push("You are executing the milestone described above. Follow the PRD precisely.");
|
|
95
|
+
lines.push("- Run `npx tsc --noEmit` after all changes to verify types.");
|
|
96
|
+
lines.push("- Stage only files you create/modify (never `git add .`).");
|
|
97
|
+
lines.push("- Do not commit — the orchestrator handles commits.");
|
|
98
|
+
lines.push("- On completion, update `.planning/STATE.md` and `.planning/ROADMAP.md`.");
|
|
99
|
+
lines.push("");
|
|
100
|
+
return lines.join("\n");
|
|
101
|
+
}
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// findNextPendingMilestone
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
/**
|
|
106
|
+
* Find the next pending milestone number from the roadmap.
|
|
107
|
+
*
|
|
108
|
+
* Scans ROADMAP.md for milestones whose status does NOT start with "Complete".
|
|
109
|
+
* Returns the lowest-numbered pending milestone, or null if all are done.
|
|
110
|
+
*/
|
|
111
|
+
export async function findNextPendingMilestone(projectDir) {
|
|
112
|
+
const roadmap = await readRoadmapProgress(projectDir);
|
|
113
|
+
if (!roadmap || roadmap.milestones.length === 0) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
// Sort by number ascending to get the lowest pending one
|
|
117
|
+
const sorted = [...roadmap.milestones].sort((a, b) => a.number - b.number);
|
|
118
|
+
for (const milestone of sorted) {
|
|
119
|
+
const statusLower = milestone.status.toLowerCase();
|
|
120
|
+
if (!statusLower.startsWith("complete") &&
|
|
121
|
+
!statusLower.startsWith("done")) {
|
|
122
|
+
return milestone;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return null; // All milestones are complete
|
|
126
|
+
}
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
// runAutoChain
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
/**
|
|
131
|
+
* Auto-chain orchestrator: manages multi-milestone execution with context resets.
|
|
132
|
+
*
|
|
133
|
+
* For each pending milestone:
|
|
134
|
+
* 1. Determines the starting milestone (from options or STATE.md/ROADMAP.md)
|
|
135
|
+
* 2. Builds a fresh-context prompt for the milestone agent
|
|
136
|
+
* 3. Calls the milestone context builder for structured data
|
|
137
|
+
* 4. Returns results so the calling skill can spawn agents and drive execution
|
|
138
|
+
*
|
|
139
|
+
* The chain stops on the first milestone failure, or when all milestones
|
|
140
|
+
* are complete. The caller is responsible for actually executing each
|
|
141
|
+
* milestone (spawning agents, running waves) — this function provides the
|
|
142
|
+
* orchestration loop and context management.
|
|
143
|
+
*/
|
|
144
|
+
export async function runAutoChain(options) {
|
|
145
|
+
const { projectDir, prdPath, config, branch, project, activePrd, developer, onMilestoneStart, onMilestoneComplete, onChainComplete, } = options;
|
|
146
|
+
const completed = [];
|
|
147
|
+
// Determine starting milestone
|
|
148
|
+
let currentMilestoneNumber;
|
|
149
|
+
if (options.startMilestone !== undefined) {
|
|
150
|
+
currentMilestoneNumber = options.startMilestone;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// Auto-detect from STATE.md and ROADMAP.md
|
|
154
|
+
const nextPending = await findNextPendingMilestone(projectDir);
|
|
155
|
+
if (!nextPending) {
|
|
156
|
+
// All milestones are already complete
|
|
157
|
+
const result = {
|
|
158
|
+
completed: [],
|
|
159
|
+
stopped: false,
|
|
160
|
+
allComplete: true,
|
|
161
|
+
};
|
|
162
|
+
onChainComplete?.([]);
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
currentMilestoneNumber = nextPending.number;
|
|
166
|
+
}
|
|
167
|
+
// Loop through milestones until we run out or hit a failure
|
|
168
|
+
while (true) {
|
|
169
|
+
// Build fresh-context prompt for this milestone
|
|
170
|
+
const freshPrompt = await buildFreshSessionPrompt(projectDir, prdPath, currentMilestoneNumber);
|
|
171
|
+
// Build structured context (validates milestone exists in PRD)
|
|
172
|
+
let context;
|
|
173
|
+
try {
|
|
174
|
+
context = await buildMilestoneContext({
|
|
175
|
+
projectDir,
|
|
176
|
+
prdPath,
|
|
177
|
+
milestoneNumber: currentMilestoneNumber,
|
|
178
|
+
config,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
// Milestone not found in PRD — chain cannot continue
|
|
183
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
184
|
+
const failResult = {
|
|
185
|
+
milestoneNumber: currentMilestoneNumber,
|
|
186
|
+
milestoneName: "Unknown",
|
|
187
|
+
success: false,
|
|
188
|
+
isLast: false,
|
|
189
|
+
freshPrompt,
|
|
190
|
+
errors: [errorMessage],
|
|
191
|
+
};
|
|
192
|
+
completed.push(failResult);
|
|
193
|
+
onMilestoneComplete?.(currentMilestoneNumber, failResult);
|
|
194
|
+
const chainResult = {
|
|
195
|
+
completed,
|
|
196
|
+
stopped: true,
|
|
197
|
+
stoppedAt: currentMilestoneNumber,
|
|
198
|
+
allComplete: false,
|
|
199
|
+
};
|
|
200
|
+
onChainComplete?.(completed);
|
|
201
|
+
return chainResult;
|
|
202
|
+
}
|
|
203
|
+
// Notify: milestone starting
|
|
204
|
+
onMilestoneStart?.(currentMilestoneNumber, context.milestoneName);
|
|
205
|
+
// Build the milestone result with the fresh prompt.
|
|
206
|
+
// The caller uses `freshPrompt` to spawn an agent, then calls
|
|
207
|
+
// `completeMilestone()` after the agent finishes.
|
|
208
|
+
const milestoneResult = {
|
|
209
|
+
milestoneNumber: currentMilestoneNumber,
|
|
210
|
+
milestoneName: context.milestoneName,
|
|
211
|
+
success: true, // Optimistic; caller updates via completeMilestone
|
|
212
|
+
isLast: await isLastMilestone(projectDir, currentMilestoneNumber),
|
|
213
|
+
freshPrompt,
|
|
214
|
+
errors: [],
|
|
215
|
+
};
|
|
216
|
+
completed.push(milestoneResult);
|
|
217
|
+
// Notify: milestone complete (caller will drive actual execution)
|
|
218
|
+
onMilestoneComplete?.(currentMilestoneNumber, milestoneResult);
|
|
219
|
+
// If this was the last milestone, we're done
|
|
220
|
+
if (milestoneResult.isLast) {
|
|
221
|
+
const chainResult = {
|
|
222
|
+
completed,
|
|
223
|
+
stopped: false,
|
|
224
|
+
allComplete: true,
|
|
225
|
+
};
|
|
226
|
+
onChainComplete?.(completed);
|
|
227
|
+
return chainResult;
|
|
228
|
+
}
|
|
229
|
+
// Find the next pending milestone
|
|
230
|
+
const nextPending = await findNextPendingMilestone(projectDir);
|
|
231
|
+
if (!nextPending) {
|
|
232
|
+
// All milestones are complete
|
|
233
|
+
const chainResult = {
|
|
234
|
+
completed,
|
|
235
|
+
stopped: false,
|
|
236
|
+
allComplete: true,
|
|
237
|
+
};
|
|
238
|
+
onChainComplete?.(completed);
|
|
239
|
+
return chainResult;
|
|
240
|
+
}
|
|
241
|
+
currentMilestoneNumber = nextPending.number;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// ---------------------------------------------------------------------------
|
|
245
|
+
// completeMilestone — post-execution bookkeeping
|
|
246
|
+
// ---------------------------------------------------------------------------
|
|
247
|
+
/**
|
|
248
|
+
* Called after a milestone's agent finishes execution.
|
|
249
|
+
*
|
|
250
|
+
* Handles:
|
|
251
|
+
* 1. Updating milestone progress in STATE.md and ROADMAP.md
|
|
252
|
+
* 2. Committing milestone work to git
|
|
253
|
+
* 3. Returning the commit SHA for the milestone result
|
|
254
|
+
*
|
|
255
|
+
* The caller should update the MilestoneResult with the returned commit info.
|
|
256
|
+
*/
|
|
257
|
+
export async function completeMilestone(options) {
|
|
258
|
+
const { projectDir, project, milestoneNumber, milestoneName, branch, activePrd, developer, filesToStage, push, } = options;
|
|
259
|
+
// Check if this is the last milestone
|
|
260
|
+
const last = await isLastMilestone(projectDir, milestoneNumber);
|
|
261
|
+
// Find next milestone for state docs
|
|
262
|
+
const roadmap = await readRoadmapProgress(projectDir);
|
|
263
|
+
const milestoneTable = roadmap?.milestones.map((m) => ({
|
|
264
|
+
number: m.number,
|
|
265
|
+
name: m.name,
|
|
266
|
+
status: m.number === milestoneNumber
|
|
267
|
+
? `Complete (${new Date().toISOString().slice(0, 10)})`
|
|
268
|
+
: m.status,
|
|
269
|
+
})) ?? [];
|
|
270
|
+
// Find the next milestone (if any)
|
|
271
|
+
const nextMilestone = last
|
|
272
|
+
? undefined
|
|
273
|
+
: roadmap?.milestones
|
|
274
|
+
.filter((m) => m.number > milestoneNumber &&
|
|
275
|
+
!m.status.toLowerCase().startsWith("complete"))
|
|
276
|
+
.sort((a, b) => a.number - b.number)[0];
|
|
277
|
+
const nextMilestoneInfo = nextMilestone
|
|
278
|
+
? { number: nextMilestone.number, name: nextMilestone.name }
|
|
279
|
+
: undefined;
|
|
280
|
+
// Update state docs (STATE.md, ROADMAP.md, session memory)
|
|
281
|
+
await updateMilestoneProgress({
|
|
282
|
+
projectDir,
|
|
283
|
+
project,
|
|
284
|
+
milestoneNumber,
|
|
285
|
+
milestoneName,
|
|
286
|
+
branch,
|
|
287
|
+
activePrd,
|
|
288
|
+
developer,
|
|
289
|
+
nextMilestone: nextMilestoneInfo,
|
|
290
|
+
milestoneTable,
|
|
291
|
+
});
|
|
292
|
+
// Commit milestone work
|
|
293
|
+
const commitResult = commitMilestoneWork({
|
|
294
|
+
projectDir,
|
|
295
|
+
milestoneNumber,
|
|
296
|
+
milestoneName,
|
|
297
|
+
filesToStage,
|
|
298
|
+
push,
|
|
299
|
+
branch,
|
|
300
|
+
});
|
|
301
|
+
return { commitResult, isLast: last };
|
|
302
|
+
}
|
|
303
|
+
//# sourceMappingURL=auto-chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-chain.js","sourceRoot":"","sources":["../../src/go/auto-chain.ts"],"names":[],"mappings":"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"}
|