forge-cc 1.0.2 → 2.0.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 +6 -5
- package/README.md +7 -7
- package/dist/cli.js +193 -131
- package/dist/cli.js.map +1 -1
- package/dist/codex-poll.d.ts +38 -0
- package/dist/codex-poll.js +70 -0
- package/dist/codex-poll.js.map +1 -0
- package/dist/config/schema.d.ts +0 -28
- package/dist/config/schema.js +0 -7
- package/dist/config/schema.js.map +1 -1
- package/dist/graph/index.d.ts +6 -0
- package/dist/graph/index.js +11 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/query.d.ts +52 -0
- package/dist/graph/query.js +319 -0
- package/dist/graph/query.js.map +1 -0
- package/dist/graph/reader.d.ts +13 -0
- package/dist/graph/reader.js +140 -0
- package/dist/graph/reader.js.map +1 -0
- package/dist/graph/schemas.d.ts +215 -0
- package/dist/graph/schemas.js +54 -0
- package/dist/graph/schemas.js.map +1 -0
- package/dist/graph/types.d.ts +109 -0
- package/dist/graph/types.js +2 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/graph/validator.d.ts +32 -0
- package/dist/graph/validator.js +253 -0
- package/dist/graph/validator.js.map +1 -0
- package/dist/graph/writer.d.ts +18 -0
- package/dist/graph/writer.js +159 -0
- package/dist/graph/writer.js.map +1 -0
- package/dist/linear/client.d.ts +94 -4
- package/dist/linear/client.js +203 -20
- package/dist/linear/client.js.map +1 -1
- package/dist/linear/sync.d.ts +11 -14
- package/dist/linear/sync.js +63 -83
- package/dist/linear/sync.js.map +1 -1
- package/dist/runner/loop.d.ts +1 -1
- package/dist/runner/loop.js +93 -100
- package/dist/runner/loop.js.map +1 -1
- package/dist/runner/prompt.d.ts +7 -9
- package/dist/runner/prompt.js +27 -30
- package/dist/runner/prompt.js.map +1 -1
- package/dist/setup.js +26 -3
- package/dist/setup.js.map +1 -1
- package/dist/types.d.ts +0 -23
- package/package.json +3 -5
- package/skills/README.md +35 -33
- package/skills/forge-build.md +344 -0
- package/skills/forge-capture.md +204 -0
- package/skills/forge-fix.md +207 -0
- package/skills/forge-plan.md +335 -0
- package/skills/forge-quick.md +154 -0
- package/skills/forge-setup.md +2 -2
- package/skills/ref/adversarial-review.md +117 -0
- package/skills/ref/graph-correction.md +88 -0
- package/skills/ref/requirement-sizing.md +146 -0
- package/dist/server.d.ts +0 -6
- package/dist/server.js +0 -51
- package/dist/server.js.map +0 -1
- package/dist/state/status.d.ts +0 -66
- package/dist/state/status.js +0 -96
- package/dist/state/status.js.map +0 -1
- package/skills/forge-go.md +0 -583
- package/skills/forge-spec.md +0 -367
- package/skills/forge-triage.md +0 -179
package/dist/linear/sync.js
CHANGED
|
@@ -1,102 +1,82 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
function emptySyncResult() {
|
|
2
|
+
return { issuesTransitioned: 0, issuesFailed: [], projectUpdated: false };
|
|
3
|
+
}
|
|
4
|
+
/** Resolve + update project status, mutating result in place. */
|
|
5
|
+
async function transitionProject(client, result, projectId, category, label) {
|
|
6
|
+
const statusId = await client.resolveProjectStatusByCategory(category);
|
|
7
|
+
console.log(`[forge] Updating project ${projectId} to "${label}"`);
|
|
8
|
+
const r = await client.updateProjectState(projectId, statusId);
|
|
9
|
+
if (r.success) {
|
|
10
|
+
result.projectUpdated = true;
|
|
9
11
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return;
|
|
12
|
+
else {
|
|
13
|
+
console.warn(`[forge] Failed to update project ${projectId}: ${r.error}`);
|
|
14
|
+
result.projectError = r.error;
|
|
14
15
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
}
|
|
17
|
+
/** Transition a single requirement's issue to "started" and project to "started". */
|
|
18
|
+
export async function syncRequirementStart(client, index, requirementId) {
|
|
19
|
+
const meta = index.requirements[requirementId];
|
|
20
|
+
const result = emptySyncResult();
|
|
21
|
+
if (!meta?.linearIssueId) {
|
|
22
|
+
console.warn(`[forge] No linearIssueId for requirement "${requirementId}" — skipping issue transition`);
|
|
20
23
|
}
|
|
21
24
|
else {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
const teamId = index.linear?.teamId;
|
|
26
|
+
if (!teamId) {
|
|
27
|
+
console.warn("[forge] No Linear teamId in graph index, skipping sync");
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
const issueStateId = await client.resolveIssueStateByCategory(teamId, "started", "In Progress");
|
|
31
|
+
console.log(`[forge] Transitioning requirement ${requirementId} to "In Progress"`);
|
|
32
|
+
const updateResult = await client.updateIssueState(meta.linearIssueId, issueStateId);
|
|
33
|
+
if (updateResult.success) {
|
|
34
|
+
result.issuesTransitioned = 1;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
console.warn(`[forge] Failed to update issue: ${updateResult.error}`);
|
|
38
|
+
result.issuesFailed = [meta.linearIssueId];
|
|
25
39
|
}
|
|
26
40
|
}
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
console.log(`[forge] Updating project ${projectId} to "${config.linearStates.inProgress}"`);
|
|
31
|
-
await client.updateProjectState(projectId, stateId);
|
|
41
|
+
// Also transition project to "In Progress" if not already
|
|
42
|
+
if (index.linear?.projectId) {
|
|
43
|
+
await transitionProject(client, result, index.linear.projectId, "started", "In Progress");
|
|
32
44
|
}
|
|
45
|
+
return result;
|
|
33
46
|
}
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
*/
|
|
38
|
-
export async function syncMilestoneComplete(client, config, status, milestone, isLast) {
|
|
39
|
-
const ms = status.milestones[milestone];
|
|
40
|
-
if (!ms) {
|
|
41
|
-
console.warn(`[forge] Milestone "${milestone}" not found in status file`);
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
const teamId = status.linearTeamId;
|
|
47
|
+
/** Transition all graph requirements' issues to "completed" and project to "completed". */
|
|
48
|
+
export async function syncGraphProjectDone(client, index) {
|
|
49
|
+
const teamId = index.linear?.teamId;
|
|
45
50
|
if (!teamId) {
|
|
46
|
-
console.warn("[forge] No
|
|
47
|
-
return;
|
|
51
|
+
console.warn("[forge] No Linear teamId in graph index, skipping sync");
|
|
52
|
+
return emptySyncResult();
|
|
48
53
|
}
|
|
49
|
-
const doneStateId = await client.
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
else {
|
|
56
|
-
console.log(`[forge] Transitioning ${issueIds.length} issue(s) to "${config.linearStates.done}"`);
|
|
57
|
-
for (const issueId of issueIds) {
|
|
58
|
-
await client.updateIssueState(issueId, doneStateId);
|
|
54
|
+
const doneStateId = await client.resolveIssueStateByCategory(teamId, "completed");
|
|
55
|
+
const result = emptySyncResult();
|
|
56
|
+
const allIssueIds = [];
|
|
57
|
+
for (const [id, meta] of Object.entries(index.requirements)) {
|
|
58
|
+
if (meta.linearIssueId) {
|
|
59
|
+
allIssueIds.push(meta.linearIssueId);
|
|
59
60
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (isLast) {
|
|
63
|
-
const projectId = status.linearProjectId;
|
|
64
|
-
if (projectId) {
|
|
65
|
-
const reviewStateId = await client.resolveStateId(teamId, config.linearStates.inReview);
|
|
66
|
-
console.log(`[forge] Updating project ${projectId} to "${config.linearStates.inReview}" (last milestone)`);
|
|
67
|
-
await client.updateProjectState(projectId, reviewStateId);
|
|
61
|
+
else {
|
|
62
|
+
console.warn(`[forge] No linearIssueId for requirement "${id}" — skipping`);
|
|
68
63
|
}
|
|
69
64
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if (!teamId) {
|
|
77
|
-
console.warn("[forge] No linearTeamId in status file, skipping sync");
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const doneStateId = await client.resolveStateId(teamId, config.linearStates.done);
|
|
81
|
-
// Transition all issues across all milestones to done
|
|
82
|
-
let totalIssues = 0;
|
|
83
|
-
for (const [name, ms] of Object.entries(status.milestones)) {
|
|
84
|
-
const issueIds = ms.linearIssueIds ?? [];
|
|
85
|
-
if (issueIds.length === 0) {
|
|
86
|
-
console.warn(`[forge] No linearIssueIds for milestone "${name}" — skipping issue transitions`);
|
|
87
|
-
continue;
|
|
65
|
+
if (allIssueIds.length > 0) {
|
|
66
|
+
console.log(`[forge] Transitioning ${allIssueIds.length} issue(s) to "Done"`);
|
|
67
|
+
const batchResult = await client.updateIssueBatch(allIssueIds, { stateId: doneStateId });
|
|
68
|
+
if (batchResult.success) {
|
|
69
|
+
result.issuesTransitioned = batchResult.data.updated;
|
|
70
|
+
result.issuesFailed = batchResult.data.failed;
|
|
88
71
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
72
|
+
else {
|
|
73
|
+
console.warn(`[forge] Batch update failed: ${batchResult.error}`);
|
|
74
|
+
result.issuesFailed = allIssueIds;
|
|
92
75
|
}
|
|
93
76
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const projectId = status.linearProjectId;
|
|
97
|
-
if (projectId) {
|
|
98
|
-
console.log(`[forge] Updating project ${projectId} to "${config.linearStates.done}"`);
|
|
99
|
-
await client.updateProjectState(projectId, doneStateId);
|
|
77
|
+
if (index.linear?.projectId) {
|
|
78
|
+
await transitionProject(client, result, index.linear.projectId, "completed", "Done");
|
|
100
79
|
}
|
|
80
|
+
return result;
|
|
101
81
|
}
|
|
102
82
|
//# sourceMappingURL=sync.js.map
|
package/dist/linear/sync.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/linear/sync.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/linear/sync.ts"],"names":[],"mappings":"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"}
|
package/dist/runner/loop.d.ts
CHANGED
package/dist/runner/loop.js
CHANGED
|
@@ -3,32 +3,19 @@ import { promisify } from "node:util";
|
|
|
3
3
|
import { basename, dirname, join, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { loadConfig } from "../config/loader.js";
|
|
6
|
-
import {
|
|
7
|
-
import { readMilestoneSection, buildPrompt } from "./prompt.js";
|
|
6
|
+
import { buildRequirementPrompt } from "./prompt.js";
|
|
8
7
|
import { createWorktree, mergeWorktree, removeWorktree, } from "../worktree/manager.js";
|
|
9
8
|
import { ForgeLinearClient } from "../linear/client.js";
|
|
10
|
-
import {
|
|
9
|
+
import { syncRequirementStart, syncGraphProjectDone, } from "../linear/sync.js";
|
|
10
|
+
import { loadIndex, loadOverview, loadRequirement, loadRequirements } from "../graph/reader.js";
|
|
11
|
+
import { updateRequirementStatus } from "../graph/writer.js";
|
|
12
|
+
import { findReady, isProjectComplete, buildRequirementContext, getTransitiveDeps } from "../graph/query.js";
|
|
11
13
|
const execFileAsync = promisify(execFile);
|
|
12
14
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
15
|
const cliPath = join(__dirname, "..", "cli.js");
|
|
14
16
|
function repoName(projectDir) {
|
|
15
17
|
return basename(resolve(projectDir));
|
|
16
18
|
}
|
|
17
|
-
function worktreePath(projectDir, slug, milestoneNumber) {
|
|
18
|
-
return resolve(projectDir, "..", ".forge-wt", repoName(projectDir), `${slug}-m${milestoneNumber}`);
|
|
19
|
-
}
|
|
20
|
-
function parseMilestoneNumber(key) {
|
|
21
|
-
const match = /(\d+)/.exec(key);
|
|
22
|
-
if (!match)
|
|
23
|
-
throw new Error(`Cannot parse milestone number from key: ${key}`);
|
|
24
|
-
return Number.parseInt(match[1], 10);
|
|
25
|
-
}
|
|
26
|
-
function parseMilestoneName(key) {
|
|
27
|
-
const colonIndex = key.indexOf(":");
|
|
28
|
-
if (colonIndex === -1)
|
|
29
|
-
return key;
|
|
30
|
-
return key.slice(colonIndex + 1).trim();
|
|
31
|
-
}
|
|
32
19
|
function spawnClaude(prompt, cwd) {
|
|
33
20
|
return new Promise((resolve, reject) => {
|
|
34
21
|
// Strip CLAUDECODE env var to allow spawning claude from within a Claude Code session
|
|
@@ -70,99 +57,105 @@ async function runVerifyInWorktree(wtPath) {
|
|
|
70
57
|
throw err;
|
|
71
58
|
}
|
|
72
59
|
}
|
|
73
|
-
export async function
|
|
60
|
+
export async function runGraphLoop(opts) {
|
|
74
61
|
const { slug, projectDir } = opts;
|
|
75
62
|
const config = await loadConfig(projectDir);
|
|
76
63
|
const maxIterations = config.maxIterations;
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
64
|
+
// Load the graph
|
|
65
|
+
let index = await loadIndex(projectDir, slug);
|
|
66
|
+
const baseBranch = index.branch;
|
|
67
|
+
while (!isProjectComplete(index)) {
|
|
68
|
+
const ready = findReady(index);
|
|
69
|
+
if (ready.length === 0) {
|
|
70
|
+
console.error("\n[forge] No ready requirements but project incomplete — possible deadlock");
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
// Execute requirements sequentially (parallel waves are a future enhancement)
|
|
74
|
+
for (const reqId of ready) {
|
|
75
|
+
console.log(`\n[forge] Starting requirement ${reqId}`);
|
|
76
|
+
// Mark in_progress
|
|
77
|
+
index = await updateRequirementStatus(projectDir, slug, reqId, "in_progress");
|
|
78
|
+
// Linear sync: start requirement
|
|
79
|
+
const apiKey = process.env.LINEAR_API_KEY;
|
|
80
|
+
if (apiKey && index.linear?.teamId) {
|
|
81
|
+
try {
|
|
82
|
+
const client = new ForgeLinearClient({ apiKey, teamId: index.linear.teamId });
|
|
83
|
+
await syncRequirementStart(client, index, reqId);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Linear sync is best-effort
|
|
87
|
+
}
|
|
98
88
|
}
|
|
99
|
-
|
|
100
|
-
|
|
89
|
+
// Load requirement content + overview + dependency context
|
|
90
|
+
const req = await loadRequirement(projectDir, slug, reqId);
|
|
91
|
+
if (!req) {
|
|
92
|
+
console.error(`[forge] Requirement file not found for ${reqId}`);
|
|
93
|
+
process.exit(1);
|
|
101
94
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
95
|
+
const overview = await loadOverview(projectDir, slug);
|
|
96
|
+
// Load ALL transitive deps, not just direct ones
|
|
97
|
+
const transitiveDeps = getTransitiveDeps(index, reqId).filter(id => id !== reqId);
|
|
98
|
+
const allReqs = await loadRequirements(projectDir, slug, transitiveDeps);
|
|
99
|
+
// Also add the target requirement to the map for buildRequirementContext
|
|
100
|
+
allReqs.set(reqId, req);
|
|
101
|
+
const depContext = buildRequirementContext(index, allReqs, reqId)
|
|
102
|
+
.filter(r => r.id !== reqId); // exclude self from deps
|
|
103
|
+
// Create worktree
|
|
104
|
+
const wtPath = resolve(projectDir, "..", ".forge-wt", repoName(projectDir), `${slug}-${reqId}`);
|
|
105
|
+
const wtBranch = `${baseBranch}/${reqId}`;
|
|
106
|
+
await createWorktree(wtPath, wtBranch, baseBranch, projectDir);
|
|
107
|
+
let passed = false;
|
|
108
|
+
let verifyErrors = null;
|
|
109
|
+
for (let iteration = 1; iteration <= maxIterations; iteration++) {
|
|
110
|
+
console.log(`\n[forge] Requirement ${reqId}, iteration ${iteration}/${maxIterations}`);
|
|
111
|
+
const prompt = buildRequirementPrompt({
|
|
112
|
+
requirement: req,
|
|
113
|
+
overview,
|
|
114
|
+
depContext,
|
|
115
|
+
verifyErrors,
|
|
116
|
+
});
|
|
117
|
+
await spawnClaude(prompt, wtPath);
|
|
118
|
+
try {
|
|
119
|
+
const result = await runVerifyInWorktree(wtPath);
|
|
120
|
+
if (result.result === "PASSED") {
|
|
121
|
+
passed = true;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
verifyErrors = result;
|
|
125
|
+
console.log(`[forge] Verify failed on iteration ${iteration}. Retrying...`);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
console.warn(`[forge] Verify execution error on iteration ${iteration}:`, err);
|
|
129
|
+
verifyErrors = null;
|
|
128
130
|
}
|
|
129
|
-
verifyErrors = result;
|
|
130
|
-
console.log(`[forge] Verify failed on iteration ${iteration}. Retrying...`);
|
|
131
131
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
132
|
+
if (!passed) {
|
|
133
|
+
console.error(`\n[forge] Requirement ${reqId} failed after ${maxIterations} iterations.`);
|
|
134
|
+
await removeWorktree(wtPath, projectDir);
|
|
135
|
+
process.exit(1);
|
|
136
136
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
// Merge back and clean up
|
|
138
|
+
console.log(`\n[forge] Requirement ${reqId} passed. Merging...`);
|
|
139
|
+
await mergeWorktree(wtBranch, baseBranch, projectDir);
|
|
140
140
|
await removeWorktree(wtPath, projectDir);
|
|
141
|
-
|
|
141
|
+
// Update status to complete
|
|
142
|
+
index = await updateRequirementStatus(projectDir, slug, reqId, "complete");
|
|
143
|
+
console.log(`[forge] Requirement ${reqId} complete.`);
|
|
142
144
|
}
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
await syncMilestoneComplete(client, config, status, milestoneKey, isLast);
|
|
156
|
-
}
|
|
157
|
-
catch {
|
|
158
|
-
// Linear sync is best-effort
|
|
159
|
-
}
|
|
145
|
+
// Reload index to recompute ready set
|
|
146
|
+
index = await loadIndex(projectDir, slug);
|
|
147
|
+
}
|
|
148
|
+
// Linear sync: mark project done (best-effort)
|
|
149
|
+
const apiKey = process.env.LINEAR_API_KEY;
|
|
150
|
+
if (apiKey && index.linear?.teamId) {
|
|
151
|
+
try {
|
|
152
|
+
const client = new ForgeLinearClient({ apiKey, teamId: index.linear.teamId });
|
|
153
|
+
await syncGraphProjectDone(client, index);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// Linear sync is best-effort
|
|
160
157
|
}
|
|
161
|
-
console.log(`[forge] Milestone ${milestoneNumber} complete.`);
|
|
162
|
-
// Refresh pending list for next iteration
|
|
163
|
-
const refreshed = await discoverStatuses(projectDir);
|
|
164
|
-
pending = findNextPending(refreshed.filter((s) => s.slug === slug));
|
|
165
158
|
}
|
|
166
|
-
console.log(`\n[forge] All
|
|
159
|
+
console.log(`\n[forge] All requirements for "${slug}" complete.`);
|
|
167
160
|
}
|
|
168
161
|
//# sourceMappingURL=loop.js.map
|
package/dist/runner/loop.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/runner/loop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,
|
|
1
|
+
{"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/runner/loop.ts"],"names":[],"mappings":"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"}
|
package/dist/runner/prompt.d.ts
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import type { PipelineResult } from "../types.js";
|
|
2
|
+
import type { Requirement } from "../graph/types.js";
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* the next `### Milestone` header or end of file.
|
|
4
|
+
* Build a prompt for the graph-based Ralph loop.
|
|
5
|
+
* Takes pre-loaded data — does NOT read disk.
|
|
6
6
|
*/
|
|
7
|
-
export declare function
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
milestoneNumber: number;
|
|
12
|
-
milestoneSection: string;
|
|
7
|
+
export declare function buildRequirementPrompt(opts: {
|
|
8
|
+
requirement: Requirement;
|
|
9
|
+
overview: string;
|
|
10
|
+
depContext: Requirement[];
|
|
13
11
|
verifyErrors?: PipelineResult | null;
|
|
14
12
|
}): string;
|
package/dist/runner/prompt.js
CHANGED
|
@@ -1,25 +1,3 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
/**
|
|
3
|
-
* Extract a milestone section from a PRD markdown file.
|
|
4
|
-
* Looks for `### Milestone {N}:` and returns everything up to
|
|
5
|
-
* the next `### Milestone` header or end of file.
|
|
6
|
-
*/
|
|
7
|
-
export async function readMilestoneSection(prdPath, milestoneNumber) {
|
|
8
|
-
const content = await readFile(prdPath, "utf-8");
|
|
9
|
-
const pattern = new RegExp(`^### Milestone ${milestoneNumber}\\b[^\n]*`, "m");
|
|
10
|
-
const match = pattern.exec(content);
|
|
11
|
-
if (!match) {
|
|
12
|
-
throw new Error(`Milestone ${milestoneNumber} not found in ${prdPath}`);
|
|
13
|
-
}
|
|
14
|
-
const startIndex = match.index;
|
|
15
|
-
// Find the next ### Milestone header after our match
|
|
16
|
-
const rest = content.slice(startIndex + match[0].length);
|
|
17
|
-
const nextHeader = /^### Milestone \d+/m.exec(rest);
|
|
18
|
-
const section = nextHeader
|
|
19
|
-
? content.slice(startIndex, startIndex + match[0].length + nextHeader.index)
|
|
20
|
-
: content.slice(startIndex);
|
|
21
|
-
return section.trimEnd();
|
|
22
|
-
}
|
|
23
1
|
/** Format PipelineResult errors into a human-readable string. */
|
|
24
2
|
function formatVerifyErrors(result) {
|
|
25
3
|
const lines = [`forge verify: ${result.result}`];
|
|
@@ -37,23 +15,42 @@ function formatVerifyErrors(result) {
|
|
|
37
15
|
}
|
|
38
16
|
return lines.join("\n");
|
|
39
17
|
}
|
|
40
|
-
/**
|
|
41
|
-
|
|
42
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Build a prompt for the graph-based Ralph loop.
|
|
20
|
+
* Takes pre-loaded data — does NOT read disk.
|
|
21
|
+
*/
|
|
22
|
+
export function buildRequirementPrompt(opts) {
|
|
23
|
+
const { requirement, overview, depContext, verifyErrors } = opts;
|
|
43
24
|
const currentState = verifyErrors && verifyErrors.result === "FAILED"
|
|
44
25
|
? formatVerifyErrors(verifyErrors)
|
|
45
26
|
: "First iteration — start from scratch";
|
|
46
|
-
|
|
27
|
+
const depsSection = depContext.length > 0
|
|
28
|
+
? `## Completed Dependencies\n\n${depContext.map((dep) => `### ${dep.id}: ${dep.title}\n${dep.body}`).join("\n\n")}\n\n`
|
|
29
|
+
: "";
|
|
30
|
+
const filesCreates = requirement.files.creates.join(", ") || "none";
|
|
31
|
+
const filesModifies = requirement.files.modifies.join(", ") || "none";
|
|
32
|
+
return `# Task: Complete Requirement ${requirement.id} — ${requirement.title}
|
|
33
|
+
|
|
34
|
+
## Project Overview
|
|
35
|
+
${overview}
|
|
36
|
+
|
|
37
|
+
${depsSection}## Your Requirement
|
|
38
|
+
${requirement.body}
|
|
39
|
+
|
|
40
|
+
### Acceptance Criteria
|
|
41
|
+
${requirement.acceptance.map((a) => `- ${a}`).join("\n")}
|
|
47
42
|
|
|
48
|
-
|
|
49
|
-
${
|
|
43
|
+
### File Scope
|
|
44
|
+
**Creates:** ${filesCreates}
|
|
45
|
+
**Modifies:** ${filesModifies}
|
|
50
46
|
|
|
51
|
-
## Current
|
|
47
|
+
## Current State
|
|
52
48
|
${currentState}
|
|
53
49
|
|
|
54
50
|
## Rules
|
|
55
51
|
- Run \`npx forge verify\` before finishing. All gates must pass.
|
|
56
52
|
- Commit your work before exiting.
|
|
57
|
-
- Do NOT create tests just to make gates pass. Fix real issues only
|
|
53
|
+
- Do NOT create tests just to make gates pass. Fix real issues only.
|
|
54
|
+
- Stay within the declared file scope when possible.`;
|
|
58
55
|
}
|
|
59
56
|
//# sourceMappingURL=prompt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/runner/prompt.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/runner/prompt.ts"],"names":[],"mappings":"AAGA,iEAAiE;AACjE,SAAS,kBAAkB,CAAC,MAAsB;IAChD,MAAM,KAAK,GAAa,CAAC,iBAAiB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3D,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,KAAK,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,WAAW,CAAC,CAAC;YAC5C,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC9B,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM;oBACpB,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,MAAM,EAAE;oBACzC,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;gBAC9B,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9C,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,MAAM,GAAG,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAKtC;IACC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAEjE,MAAM,YAAY,GAChB,YAAY,IAAI,YAAY,CAAC,MAAM,KAAK,QAAQ;QAC9C,CAAC,CAAC,kBAAkB,CAAC,YAAY,CAAC;QAClC,CAAC,CAAC,sCAAsC,CAAC;IAE7C,MAAM,WAAW,GACf,UAAU,CAAC,MAAM,GAAG,CAAC;QACnB,CAAC,CAAC,gCAAgC,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM;QACxH,CAAC,CAAC,EAAE,CAAC;IAET,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC;IACpE,MAAM,aAAa,GAAG,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC;IAEtE,OAAO,gCAAgC,WAAW,CAAC,EAAE,MAAM,WAAW,CAAC,KAAK;;;EAG5E,QAAQ;;EAER,WAAW;EACX,WAAW,CAAC,IAAI;;;EAGhB,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;eAGzC,YAAY;gBACX,aAAa;;;EAG3B,YAAY;;;;;;qDAMuC,CAAC;AACtD,CAAC"}
|