forge-cc 0.1.4 → 0.1.6

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.
Files changed (52) hide show
  1. package/README.md +96 -10
  2. package/dist/cli.js +225 -7
  3. package/dist/cli.js.map +1 -1
  4. package/dist/go/auto-chain.d.ts +37 -5
  5. package/dist/go/auto-chain.js +220 -81
  6. package/dist/go/auto-chain.js.map +1 -1
  7. package/dist/go/executor.d.ts +2 -0
  8. package/dist/go/executor.js.map +1 -1
  9. package/dist/hooks/pre-commit.js +9 -3
  10. package/dist/hooks/pre-commit.js.map +1 -1
  11. package/dist/reporter/human.d.ts +5 -0
  12. package/dist/reporter/human.js +30 -0
  13. package/dist/reporter/human.js.map +1 -1
  14. package/dist/setup/templates.js +97 -122
  15. package/dist/setup/templates.js.map +1 -1
  16. package/dist/spec/generator.d.ts +20 -0
  17. package/dist/spec/generator.js +23 -2
  18. package/dist/spec/generator.js.map +1 -1
  19. package/dist/spec/interview.d.ts +20 -2
  20. package/dist/spec/interview.js +8 -0
  21. package/dist/spec/interview.js.map +1 -1
  22. package/dist/spec/scanner.d.ts +34 -0
  23. package/dist/spec/scanner.js +93 -0
  24. package/dist/spec/scanner.js.map +1 -1
  25. package/dist/spec/templates.d.ts +22 -0
  26. package/dist/spec/templates.js +8 -0
  27. package/dist/spec/templates.js.map +1 -1
  28. package/dist/utils/platform.d.ts +29 -0
  29. package/dist/utils/platform.js +90 -0
  30. package/dist/utils/platform.js.map +1 -0
  31. package/dist/worktree/identity.d.ts +9 -0
  32. package/dist/worktree/identity.js +32 -0
  33. package/dist/worktree/identity.js.map +1 -0
  34. package/dist/worktree/manager.d.ts +70 -0
  35. package/dist/worktree/manager.js +217 -0
  36. package/dist/worktree/manager.js.map +1 -0
  37. package/dist/worktree/parallel.d.ts +87 -0
  38. package/dist/worktree/parallel.js +328 -0
  39. package/dist/worktree/parallel.js.map +1 -0
  40. package/dist/worktree/session.d.ts +64 -0
  41. package/dist/worktree/session.js +193 -0
  42. package/dist/worktree/session.js.map +1 -0
  43. package/dist/worktree/state-merge.d.ts +43 -0
  44. package/dist/worktree/state-merge.js +162 -0
  45. package/dist/worktree/state-merge.js.map +1 -0
  46. package/hooks/pre-commit-verify.js +9 -3
  47. package/hooks/version-check.js +78 -78
  48. package/package.json +1 -1
  49. package/skills/forge-go.md +39 -0
  50. package/skills/forge-setup.md +183 -157
  51. package/skills/forge-spec.md +50 -12
  52. package/skills/forge-update.md +92 -72
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/worktree/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Parallel Scheduler — Milestone Dependency Analyzer & Execution Planner
3
+ *
4
+ * Parses `dependsOn` from PRD milestones, builds a DAG, determines which
5
+ * milestones can run simultaneously in parallel waves, and provides
6
+ * functions to query ready milestones given completed set.
7
+ *
8
+ * Backward compatible: milestones without `dependsOn` are treated as
9
+ * having no dependencies (roots).
10
+ */
11
+ export interface MilestoneDep {
12
+ number: number;
13
+ name: string;
14
+ dependsOn: number[];
15
+ }
16
+ export interface DAGNode {
17
+ milestone: MilestoneDep;
18
+ children: number[];
19
+ parents: number[];
20
+ depth: number;
21
+ }
22
+ export interface ExecutionWave {
23
+ waveNumber: number;
24
+ milestones: number[];
25
+ }
26
+ export interface SchedulerResult {
27
+ waves: ExecutionWave[];
28
+ totalMilestones: number;
29
+ maxParallelism: number;
30
+ isSequential: boolean;
31
+ }
32
+ /**
33
+ * Build a directed acyclic graph from milestone dependencies.
34
+ *
35
+ * Validates:
36
+ * - All referenced dependencies exist in the milestone set
37
+ * - No cycles exist in the dependency graph
38
+ *
39
+ * Throws descriptive errors on validation failure.
40
+ */
41
+ export declare function buildDAG(milestones: MilestoneDep[]): Map<number, DAGNode>;
42
+ /**
43
+ * Topological sort milestones into parallel execution waves.
44
+ *
45
+ * - Wave 1: all milestones with no dependencies (roots)
46
+ * - Wave 2: milestones whose dependencies are all in Wave 1
47
+ * - Wave N: milestones whose dependencies are all in waves < N
48
+ */
49
+ export declare function computeExecutionWaves(dag: Map<number, DAGNode>): SchedulerResult;
50
+ /**
51
+ * Parse a PRD markdown document to extract milestone definitions and
52
+ * their `dependsOn` fields.
53
+ *
54
+ * Looks for milestone headers like:
55
+ * ### Milestone 1: Name Here
56
+ * ### Milestone 2 — Name Here
57
+ *
58
+ * And within each milestone section, looks for:
59
+ * **dependsOn:** 1, 3
60
+ * dependsOn: [1, 3]
61
+ * **dependsOn:** [1]
62
+ *
63
+ * If no `dependsOn` field is found, treats the milestone as having no
64
+ * dependencies (backward compatible).
65
+ */
66
+ export declare function parseMilestoneDependencies(prdContent: string): MilestoneDep[];
67
+ /**
68
+ * Given execution waves and a set of completed milestone numbers,
69
+ * return which milestones are ready to start.
70
+ *
71
+ * A milestone is ready if:
72
+ * 1. It has not been completed yet
73
+ * 2. All of its dependencies (from the wave schedule) are in the completed set
74
+ *
75
+ * This requires the original DAG to check dependencies, so we accept
76
+ * the waves plus the DAG.
77
+ */
78
+ export declare function getReadyMilestones(dag: Map<number, DAGNode>, completed: Set<number>): number[];
79
+ /**
80
+ * Parse a PRD file and build the full execution schedule.
81
+ * Combines parseMilestoneDependencies + buildDAG + computeExecutionWaves.
82
+ *
83
+ * If the PRD has no `dependsOn` fields, all milestones will be in wave 1
84
+ * (all roots), which is backward compatible with sequential execution
85
+ * when the caller processes them in milestone-number order.
86
+ */
87
+ export declare function buildScheduleFromPRD(prdPath: string): Promise<SchedulerResult>;
@@ -0,0 +1,328 @@
1
+ /**
2
+ * Parallel Scheduler — Milestone Dependency Analyzer & Execution Planner
3
+ *
4
+ * Parses `dependsOn` from PRD milestones, builds a DAG, determines which
5
+ * milestones can run simultaneously in parallel waves, and provides
6
+ * functions to query ready milestones given completed set.
7
+ *
8
+ * Backward compatible: milestones without `dependsOn` are treated as
9
+ * having no dependencies (roots).
10
+ */
11
+ import { readFile } from "node:fs/promises";
12
+ // ---------------------------------------------------------------------------
13
+ // buildDAG
14
+ // ---------------------------------------------------------------------------
15
+ /**
16
+ * Build a directed acyclic graph from milestone dependencies.
17
+ *
18
+ * Validates:
19
+ * - All referenced dependencies exist in the milestone set
20
+ * - No cycles exist in the dependency graph
21
+ *
22
+ * Throws descriptive errors on validation failure.
23
+ */
24
+ export function buildDAG(milestones) {
25
+ const dag = new Map();
26
+ const milestoneNumbers = new Set(milestones.map((m) => m.number));
27
+ // Initialize all nodes
28
+ for (const milestone of milestones) {
29
+ dag.set(milestone.number, {
30
+ milestone,
31
+ children: [],
32
+ parents: [...milestone.dependsOn],
33
+ depth: -1, // computed later
34
+ });
35
+ }
36
+ // Validate dependencies exist and build children links
37
+ for (const milestone of milestones) {
38
+ for (const dep of milestone.dependsOn) {
39
+ if (!milestoneNumbers.has(dep)) {
40
+ throw new Error(`Milestone ${milestone.number} ("${milestone.name}") depends on milestone ${dep}, which does not exist`);
41
+ }
42
+ const parentNode = dag.get(dep);
43
+ parentNode.children.push(milestone.number);
44
+ }
45
+ }
46
+ // Detect cycles using DFS with coloring (white/gray/black)
47
+ detectCycles(dag);
48
+ // Compute depths via BFS from roots
49
+ computeDepths(dag);
50
+ return dag;
51
+ }
52
+ /**
53
+ * Detect cycles in the DAG using DFS with three-color marking.
54
+ * Throws an error with a descriptive message if a cycle is found.
55
+ */
56
+ function detectCycles(dag) {
57
+ const WHITE = 0; // unvisited
58
+ const GRAY = 1; // in current DFS path
59
+ const BLACK = 2; // fully processed
60
+ const color = new Map();
61
+ for (const num of dag.keys()) {
62
+ color.set(num, WHITE);
63
+ }
64
+ const path = [];
65
+ function dfs(nodeNum) {
66
+ color.set(nodeNum, GRAY);
67
+ path.push(nodeNum);
68
+ const node = dag.get(nodeNum);
69
+ for (const childNum of node.children) {
70
+ const childColor = color.get(childNum);
71
+ if (childColor === GRAY) {
72
+ // Found a cycle — extract the cycle path for the error message
73
+ const cycleStart = path.indexOf(childNum);
74
+ const cyclePath = path.slice(cycleStart);
75
+ cyclePath.push(childNum); // close the cycle
76
+ const cycleStr = cyclePath
77
+ .map((n) => {
78
+ const m = dag.get(n).milestone;
79
+ return `M${m.number}("${m.name}")`;
80
+ })
81
+ .join(" -> ");
82
+ throw new Error(`Dependency cycle detected: ${cycleStr}`);
83
+ }
84
+ if (childColor === WHITE) {
85
+ dfs(childNum);
86
+ }
87
+ }
88
+ color.set(nodeNum, BLACK);
89
+ path.pop();
90
+ }
91
+ for (const num of dag.keys()) {
92
+ if (color.get(num) === WHITE) {
93
+ dfs(num);
94
+ }
95
+ }
96
+ }
97
+ /**
98
+ * Compute depth for each node via BFS from roots (nodes with no parents).
99
+ * Depth = longest path from any root to this node.
100
+ */
101
+ function computeDepths(dag) {
102
+ // Find roots (no parents)
103
+ const roots = [];
104
+ for (const [num, node] of dag) {
105
+ if (node.parents.length === 0) {
106
+ roots.push(num);
107
+ }
108
+ }
109
+ // BFS-like traversal computing max depth
110
+ // Use Kahn's algorithm approach: process nodes whose all parents are resolved
111
+ const depth = new Map();
112
+ const inDegree = new Map();
113
+ for (const [num, node] of dag) {
114
+ inDegree.set(num, node.parents.length);
115
+ }
116
+ const queue = [];
117
+ for (const root of roots) {
118
+ depth.set(root, 0);
119
+ queue.push(root);
120
+ }
121
+ while (queue.length > 0) {
122
+ const current = queue.shift();
123
+ const currentDepth = depth.get(current);
124
+ const node = dag.get(current);
125
+ node.depth = currentDepth;
126
+ for (const childNum of node.children) {
127
+ const childDepth = depth.get(childNum);
128
+ // Set child depth to max of current paths
129
+ if (childDepth === undefined || currentDepth + 1 > childDepth) {
130
+ depth.set(childNum, currentDepth + 1);
131
+ }
132
+ // Decrement in-degree; enqueue when all parents processed
133
+ const remaining = inDegree.get(childNum) - 1;
134
+ inDegree.set(childNum, remaining);
135
+ if (remaining === 0) {
136
+ queue.push(childNum);
137
+ }
138
+ }
139
+ }
140
+ }
141
+ // ---------------------------------------------------------------------------
142
+ // computeExecutionWaves
143
+ // ---------------------------------------------------------------------------
144
+ /**
145
+ * Topological sort milestones into parallel execution waves.
146
+ *
147
+ * - Wave 1: all milestones with no dependencies (roots)
148
+ * - Wave 2: milestones whose dependencies are all in Wave 1
149
+ * - Wave N: milestones whose dependencies are all in waves < N
150
+ */
151
+ export function computeExecutionWaves(dag) {
152
+ if (dag.size === 0) {
153
+ return {
154
+ waves: [],
155
+ totalMilestones: 0,
156
+ maxParallelism: 0,
157
+ isSequential: true,
158
+ };
159
+ }
160
+ // Group milestones by depth — depth corresponds to wave number
161
+ const waveMap = new Map();
162
+ for (const [num, node] of dag) {
163
+ const d = node.depth;
164
+ if (!waveMap.has(d)) {
165
+ waveMap.set(d, []);
166
+ }
167
+ waveMap.get(d).push(num);
168
+ }
169
+ // Sort wave keys and build ExecutionWave array
170
+ const sortedDepths = [...waveMap.keys()].sort((a, b) => a - b);
171
+ const waves = sortedDepths.map((depth, index) => ({
172
+ waveNumber: index + 1,
173
+ milestones: waveMap.get(depth).sort((a, b) => a - b),
174
+ }));
175
+ const maxParallelism = Math.max(...waves.map((w) => w.milestones.length));
176
+ const isSequential = maxParallelism <= 1;
177
+ return {
178
+ waves,
179
+ totalMilestones: dag.size,
180
+ maxParallelism,
181
+ isSequential,
182
+ };
183
+ }
184
+ // ---------------------------------------------------------------------------
185
+ // parseMilestoneDependencies
186
+ // ---------------------------------------------------------------------------
187
+ /**
188
+ * Parse a PRD markdown document to extract milestone definitions and
189
+ * their `dependsOn` fields.
190
+ *
191
+ * Looks for milestone headers like:
192
+ * ### Milestone 1: Name Here
193
+ * ### Milestone 2 — Name Here
194
+ *
195
+ * And within each milestone section, looks for:
196
+ * **dependsOn:** 1, 3
197
+ * dependsOn: [1, 3]
198
+ * **dependsOn:** [1]
199
+ *
200
+ * If no `dependsOn` field is found, treats the milestone as having no
201
+ * dependencies (backward compatible).
202
+ */
203
+ export function parseMilestoneDependencies(prdContent) {
204
+ const milestones = [];
205
+ // Split PRD into milestone sections
206
+ // Match headers like: ### Milestone 1: Name or ### Milestone 1 — Name
207
+ const milestoneHeaderRe = /###\s*Milestone\s+(\d+)\s*[:\—–-]\s*(.+)/g;
208
+ const headers = [];
209
+ let headerMatch;
210
+ while ((headerMatch = milestoneHeaderRe.exec(prdContent)) !== null) {
211
+ headers.push({
212
+ number: parseInt(headerMatch[1], 10),
213
+ name: headerMatch[2].trim(),
214
+ index: headerMatch.index,
215
+ });
216
+ }
217
+ // Extract section content for each milestone
218
+ for (let i = 0; i < headers.length; i++) {
219
+ const header = headers[i];
220
+ const sectionStart = header.index;
221
+ const sectionEnd = i + 1 < headers.length ? headers[i + 1].index : prdContent.length;
222
+ const sectionContent = prdContent.slice(sectionStart, sectionEnd);
223
+ // Look for dependsOn field in the section
224
+ const dependsOn = parseDependsOnField(sectionContent);
225
+ milestones.push({
226
+ number: header.number,
227
+ name: header.name,
228
+ dependsOn,
229
+ });
230
+ }
231
+ return milestones;
232
+ }
233
+ /**
234
+ * Parse the dependsOn field from a milestone section.
235
+ * Supports formats:
236
+ * **dependsOn:** 1, 3
237
+ * dependsOn: [1, 3]
238
+ * **dependsOn:** [1]
239
+ * **dependsOn:** none
240
+ *
241
+ * Returns empty array if not found or explicitly "none".
242
+ */
243
+ function parseDependsOnField(sectionContent) {
244
+ // Match patterns like:
245
+ // **dependsOn:** 1, 3 (bold markdown: ** before key, :** after)
246
+ // dependsOn: [1, 3] (plain text)
247
+ // **dependsOn:** [1] (bold with brackets)
248
+ const dependsOnRe = /\*{0,2}dependsOn:\*{0,2}\s*(.+)/i;
249
+ const match = sectionContent.match(dependsOnRe);
250
+ if (!match) {
251
+ return [];
252
+ }
253
+ const value = match[1].trim();
254
+ // Handle "none" or empty
255
+ if (value.toLowerCase() === "none" ||
256
+ value === "[]" ||
257
+ value === "" ||
258
+ value === "-") {
259
+ return [];
260
+ }
261
+ // Strip brackets if present: [1, 3] -> 1, 3
262
+ const stripped = value.replace(/^\[/, "").replace(/\].*$/, "");
263
+ // Parse comma-separated numbers
264
+ const numbers = [];
265
+ for (const part of stripped.split(",")) {
266
+ const trimmed = part.trim();
267
+ const num = parseInt(trimmed, 10);
268
+ if (!isNaN(num)) {
269
+ numbers.push(num);
270
+ }
271
+ }
272
+ return numbers;
273
+ }
274
+ // ---------------------------------------------------------------------------
275
+ // getReadyMilestones
276
+ // ---------------------------------------------------------------------------
277
+ /**
278
+ * Given execution waves and a set of completed milestone numbers,
279
+ * return which milestones are ready to start.
280
+ *
281
+ * A milestone is ready if:
282
+ * 1. It has not been completed yet
283
+ * 2. All of its dependencies (from the wave schedule) are in the completed set
284
+ *
285
+ * This requires the original DAG to check dependencies, so we accept
286
+ * the waves plus the DAG.
287
+ */
288
+ export function getReadyMilestones(dag, completed) {
289
+ const ready = [];
290
+ for (const [num, node] of dag) {
291
+ // Skip already completed
292
+ if (completed.has(num)) {
293
+ continue;
294
+ }
295
+ // Check if all parents are completed
296
+ const allParentsCompleted = node.parents.every((p) => completed.has(p));
297
+ if (allParentsCompleted) {
298
+ ready.push(num);
299
+ }
300
+ }
301
+ return ready.sort((a, b) => a - b);
302
+ }
303
+ // ---------------------------------------------------------------------------
304
+ // buildScheduleFromPRD — convenience function
305
+ // ---------------------------------------------------------------------------
306
+ /**
307
+ * Parse a PRD file and build the full execution schedule.
308
+ * Combines parseMilestoneDependencies + buildDAG + computeExecutionWaves.
309
+ *
310
+ * If the PRD has no `dependsOn` fields, all milestones will be in wave 1
311
+ * (all roots), which is backward compatible with sequential execution
312
+ * when the caller processes them in milestone-number order.
313
+ */
314
+ export async function buildScheduleFromPRD(prdPath) {
315
+ const prdContent = await readFile(prdPath, "utf-8");
316
+ const milestones = parseMilestoneDependencies(prdContent);
317
+ if (milestones.length === 0) {
318
+ return {
319
+ waves: [],
320
+ totalMilestones: 0,
321
+ maxParallelism: 0,
322
+ isSequential: true,
323
+ };
324
+ }
325
+ const dag = buildDAG(milestones);
326
+ return computeExecutionWaves(dag);
327
+ }
328
+ //# sourceMappingURL=parallel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parallel.js","sourceRoot":"","sources":["../../src/worktree/parallel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import type { UserIdentity } from "./identity.js";
2
+ export interface Session {
3
+ id: string;
4
+ user: string;
5
+ email: string;
6
+ skill: "go" | "spec";
7
+ milestone?: string;
8
+ branch: string;
9
+ worktreePath: string;
10
+ startedAt: string;
11
+ pid: number;
12
+ status: "active" | "stale" | "completing";
13
+ }
14
+ export interface SessionRegistry {
15
+ sessions: Session[];
16
+ }
17
+ /**
18
+ * Get the path to the session registry file.
19
+ * Located at <repoRoot>/.forge/sessions.json
20
+ */
21
+ export declare function getRegistryPath(repoRoot: string): string;
22
+ /**
23
+ * Load the session registry. Returns empty registry if file doesn't exist.
24
+ */
25
+ export declare function loadRegistry(repoRoot: string): SessionRegistry;
26
+ /**
27
+ * Save the session registry atomically.
28
+ */
29
+ export declare function saveRegistry(repoRoot: string, registry: SessionRegistry): void;
30
+ /**
31
+ * Register a new session. Returns the created session.
32
+ * Uses file-based locking to prevent lost updates from concurrent writes.
33
+ */
34
+ export declare function registerSession(repoRoot: string, params: {
35
+ user: UserIdentity;
36
+ skill: "go" | "spec";
37
+ milestone?: string;
38
+ branch: string;
39
+ worktreePath: string;
40
+ }): Session;
41
+ /**
42
+ * Deregister (remove) a session by ID.
43
+ * Uses file-based locking to prevent lost updates.
44
+ */
45
+ export declare function deregisterSession(repoRoot: string, sessionId: string): void;
46
+ /**
47
+ * Update a session's status.
48
+ * Uses file-based locking to prevent lost updates.
49
+ */
50
+ export declare function updateSessionStatus(repoRoot: string, sessionId: string, status: Session["status"]): void;
51
+ /**
52
+ * Find and mark stale sessions.
53
+ * A session is stale if its PID is no longer running.
54
+ * Uses file-based locking to prevent lost updates.
55
+ */
56
+ export declare function detectStaleSessions(repoRoot: string): Session[];
57
+ /**
58
+ * Get all active sessions.
59
+ */
60
+ export declare function getActiveSessions(repoRoot: string): Session[];
61
+ /**
62
+ * Get a session by ID.
63
+ */
64
+ export declare function getSession(repoRoot: string, sessionId: string): Session | null;