daedalus-cli 3.67.1 → 3.68.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.
Files changed (62) hide show
  1. package/AGENTS.md +2 -1
  2. package/CHANGELOG.md +7 -0
  3. package/README.md +2 -0
  4. package/dist/commands/agents.d.ts +2 -1
  5. package/dist/commands/agents.d.ts.map +1 -1
  6. package/dist/commands/agents.js +3 -1
  7. package/dist/commands/agents.js.map +1 -1
  8. package/dist/commands/index.js +1 -1
  9. package/dist/commands/index.js.map +1 -1
  10. package/dist/commands/marathon.d.ts +3 -0
  11. package/dist/commands/marathon.d.ts.map +1 -0
  12. package/dist/commands/marathon.js +96 -0
  13. package/dist/commands/marathon.js.map +1 -0
  14. package/dist/commands/marathon.test.d.ts +2 -0
  15. package/dist/commands/marathon.test.d.ts.map +1 -0
  16. package/dist/commands/marathon.test.js +85 -0
  17. package/dist/commands/marathon.test.js.map +1 -0
  18. package/dist/marathon/engine.d.ts +29 -0
  19. package/dist/marathon/engine.d.ts.map +1 -0
  20. package/dist/marathon/engine.js +212 -0
  21. package/dist/marathon/engine.js.map +1 -0
  22. package/dist/marathon/engine.test.d.ts +2 -0
  23. package/dist/marathon/engine.test.d.ts.map +1 -0
  24. package/dist/marathon/engine.test.js +80 -0
  25. package/dist/marathon/engine.test.js.map +1 -0
  26. package/dist/marathon/evaluator.d.ts +16 -0
  27. package/dist/marathon/evaluator.d.ts.map +1 -0
  28. package/dist/marathon/evaluator.js +153 -0
  29. package/dist/marathon/evaluator.js.map +1 -0
  30. package/dist/marathon/evaluator.test.d.ts +2 -0
  31. package/dist/marathon/evaluator.test.d.ts.map +1 -0
  32. package/dist/marathon/evaluator.test.js +86 -0
  33. package/dist/marathon/evaluator.test.js.map +1 -0
  34. package/dist/marathon/git-checkpoint.d.ts +11 -0
  35. package/dist/marathon/git-checkpoint.d.ts.map +1 -0
  36. package/dist/marathon/git-checkpoint.js +119 -0
  37. package/dist/marathon/git-checkpoint.js.map +1 -0
  38. package/dist/marathon/git-checkpoint.test.d.ts +2 -0
  39. package/dist/marathon/git-checkpoint.test.d.ts.map +1 -0
  40. package/dist/marathon/git-checkpoint.test.js +72 -0
  41. package/dist/marathon/git-checkpoint.test.js.map +1 -0
  42. package/dist/marathon/planner.d.ts +10 -0
  43. package/dist/marathon/planner.d.ts.map +1 -0
  44. package/dist/marathon/planner.js +109 -0
  45. package/dist/marathon/planner.js.map +1 -0
  46. package/dist/marathon/planner.test.d.ts +2 -0
  47. package/dist/marathon/planner.test.d.ts.map +1 -0
  48. package/dist/marathon/planner.test.js +58 -0
  49. package/dist/marathon/planner.test.js.map +1 -0
  50. package/dist/marathon/state.d.ts +12 -0
  51. package/dist/marathon/state.d.ts.map +1 -0
  52. package/dist/marathon/state.js +146 -0
  53. package/dist/marathon/state.js.map +1 -0
  54. package/dist/marathon/state.test.d.ts +2 -0
  55. package/dist/marathon/state.test.d.ts.map +1 -0
  56. package/dist/marathon/state.test.js +83 -0
  57. package/dist/marathon/state.test.js.map +1 -0
  58. package/dist/marathon/types.d.ts +54 -0
  59. package/dist/marathon/types.d.ts.map +1 -0
  60. package/dist/marathon/types.js +2 -0
  61. package/dist/marathon/types.js.map +1 -0
  62. package/package.json +1 -1
@@ -0,0 +1,119 @@
1
+ import { execSync } from 'child_process';
2
+ export function isGitRepository(cwd) {
3
+ try {
4
+ execSync('git rev-parse --is-inside-work-tree', {
5
+ cwd,
6
+ stdio: 'ignore',
7
+ windowsHide: true,
8
+ });
9
+ return true;
10
+ }
11
+ catch {
12
+ return false;
13
+ }
14
+ }
15
+ export function getMilestoneTag(milestoneId) {
16
+ const clean = milestoneId.toLowerCase().replace(/[^a-z0-9]+/g, '-');
17
+ return `daedalus-checkpoint/${clean}`;
18
+ }
19
+ export function getCurrentCommitSha(cwd) {
20
+ try {
21
+ return execSync('git rev-parse HEAD', {
22
+ cwd,
23
+ encoding: 'utf8',
24
+ windowsHide: true,
25
+ }).trim();
26
+ }
27
+ catch {
28
+ return '';
29
+ }
30
+ }
31
+ export function createMilestoneCheckpoint(cwd, milestone, commitMessage) {
32
+ if (!isGitRepository(cwd))
33
+ return null;
34
+ const tag = getMilestoneTag(milestone.id);
35
+ const msg = commitMessage || `feat(marathon): [${milestone.id.toUpperCase()}] ${milestone.title}`;
36
+ try {
37
+ execSync('git add -A', { cwd, stdio: 'ignore', windowsHide: true });
38
+ try {
39
+ execSync(`git commit -m "${msg.replace(/"/g, '\\"')}"`, {
40
+ cwd,
41
+ stdio: 'ignore',
42
+ windowsHide: true,
43
+ });
44
+ }
45
+ catch {
46
+ // Nothing to commit if already committed, proceed to tagging
47
+ }
48
+ // Force tag to point to current HEAD
49
+ execSync(`git tag -f ${tag}`, { cwd, stdio: 'ignore', windowsHide: true });
50
+ const commit = getCurrentCommitSha(cwd);
51
+ return { tag, commit };
52
+ }
53
+ catch {
54
+ return null;
55
+ }
56
+ }
57
+ export function rollbackToLastCheckpoint(cwd, targetTag) {
58
+ if (!isGitRepository(cwd))
59
+ return false;
60
+ try {
61
+ // Reset to the tagged commit and wipe untracked files
62
+ execSync(`git reset --hard ${targetTag}`, {
63
+ cwd,
64
+ stdio: 'ignore',
65
+ windowsHide: true,
66
+ });
67
+ execSync('git clean -fd', {
68
+ cwd,
69
+ stdio: 'ignore',
70
+ windowsHide: true,
71
+ });
72
+ return true;
73
+ }
74
+ catch {
75
+ return false;
76
+ }
77
+ }
78
+ export function ensureMarathonBranch(cwd, branchName, baseBranch) {
79
+ if (!isGitRepository(cwd))
80
+ return false;
81
+ try {
82
+ // Check if branch exists
83
+ const branches = execSync('git branch --list', {
84
+ cwd,
85
+ encoding: 'utf8',
86
+ windowsHide: true,
87
+ });
88
+ if (branches.includes(branchName)) {
89
+ execSync(`git checkout ${branchName}`, {
90
+ cwd,
91
+ stdio: 'ignore',
92
+ windowsHide: true,
93
+ });
94
+ }
95
+ else {
96
+ // Checkout base first, then create marathon branch
97
+ try {
98
+ execSync(`git checkout ${baseBranch}`, {
99
+ cwd,
100
+ stdio: 'ignore',
101
+ windowsHide: true,
102
+ });
103
+ }
104
+ catch {
105
+ // base might already be current
106
+ }
107
+ execSync(`git checkout -b ${branchName}`, {
108
+ cwd,
109
+ stdio: 'ignore',
110
+ windowsHide: true,
111
+ });
112
+ }
113
+ return true;
114
+ }
115
+ catch {
116
+ return false;
117
+ }
118
+ }
119
+ //# sourceMappingURL=git-checkpoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-checkpoint.js","sourceRoot":"","sources":["../../src/marathon/git-checkpoint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=git-checkpoint.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-checkpoint.test.d.ts","sourceRoot":"","sources":["../../src/marathon/git-checkpoint.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,72 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import os from 'os';
5
+ import { execSync } from 'child_process';
6
+ import { isGitRepository, getMilestoneTag, createMilestoneCheckpoint, rollbackToLastCheckpoint, ensureMarathonBranch, } from './git-checkpoint.js';
7
+ describe('Marathon Git Checkpointing', () => {
8
+ let tmpRepo;
9
+ beforeEach(() => {
10
+ tmpRepo = fs.mkdtempSync(path.join(os.tmpdir(), 'daedalus-git-test-'));
11
+ execSync('git init -b main', { cwd: tmpRepo, stdio: 'ignore' });
12
+ execSync('git config user.name "Test Runner"', { cwd: tmpRepo, stdio: 'ignore' });
13
+ execSync('git config user.email "test@example.com"', { cwd: tmpRepo, stdio: 'ignore' });
14
+ fs.writeFileSync(path.join(tmpRepo, 'README.md'), '# Initial Repo\n');
15
+ execSync('git add README.md && git commit -m "init"', { cwd: tmpRepo, stdio: 'ignore' });
16
+ });
17
+ afterEach(() => {
18
+ try {
19
+ fs.rmSync(tmpRepo, { recursive: true, force: true });
20
+ }
21
+ catch {
22
+ // Best effort
23
+ }
24
+ });
25
+ it('detects valid git repository', () => {
26
+ expect(isGitRepository(tmpRepo)).toBe(true);
27
+ expect(isGitRepository(os.tmpdir())).toBe(false);
28
+ });
29
+ it('formats milestone tag cleanly', () => {
30
+ expect(getMilestoneTag('m-1')).toBe('daedalus-checkpoint/m-1');
31
+ expect(getMilestoneTag('M_2_API')).toBe('daedalus-checkpoint/m-2-api');
32
+ });
33
+ it('creates milestone checkpoints and supports clean rollback', () => {
34
+ const milestone = {
35
+ id: 'm-1',
36
+ title: 'Setup Database',
37
+ description: 'Create SQLite schema',
38
+ targetFiles: ['src/db.ts'],
39
+ acceptanceCriteria: ['DB exists'],
40
+ status: 'in_progress',
41
+ attempts: 0,
42
+ maxAttempts: 3,
43
+ };
44
+ fs.writeFileSync(path.join(tmpRepo, 'db.ts'), 'export const db = 1;\n');
45
+ const cp = createMilestoneCheckpoint(tmpRepo, milestone);
46
+ expect(cp).not.toBeNull();
47
+ expect(cp?.tag).toBe('daedalus-checkpoint/m-1');
48
+ expect(cp?.commit).toBeTruthy();
49
+ // Verify git tag exists
50
+ const tags = execSync('git tag', { cwd: tmpRepo, encoding: 'utf8' });
51
+ expect(tags).toContain('daedalus-checkpoint/m-1');
52
+ // Simulate a broken iteration: add a bad file and corrupt db.ts
53
+ fs.writeFileSync(path.join(tmpRepo, 'db.ts'), 'SYNTAX ERROR BROKEN\n');
54
+ fs.writeFileSync(path.join(tmpRepo, 'corrupt.txt'), 'trash\n');
55
+ // Rollback to m-1 checkpoint
56
+ const ok = rollbackToLastCheckpoint(tmpRepo, cp.tag);
57
+ expect(ok).toBe(true);
58
+ // Verify repository is restored to clean state
59
+ expect(fs.readFileSync(path.join(tmpRepo, 'db.ts'), 'utf8')).toBe('export const db = 1;\n');
60
+ expect(fs.existsSync(path.join(tmpRepo, 'corrupt.txt'))).toBe(false);
61
+ });
62
+ it('ensures marathon branch creation and checkout', () => {
63
+ const ok = ensureMarathonBranch(tmpRepo, 'marathon/test-run', 'main');
64
+ expect(ok).toBe(true);
65
+ const currentBranch = execSync('git branch --show-current', {
66
+ cwd: tmpRepo,
67
+ encoding: 'utf8',
68
+ }).trim();
69
+ expect(currentBranch).toBe('marathon/test-run');
70
+ });
71
+ });
72
+ //# sourceMappingURL=git-checkpoint.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-checkpoint.test.js","sourceRoot":"","sources":["../../src/marathon/git-checkpoint.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,eAAe,EACf,eAAe,EACf,yBAAyB,EACzB,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAG7B,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;IAC1C,IAAI,OAAe,CAAC;IAEpB,UAAU,CAAC,GAAG,EAAE;QACd,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,oBAAoB,CAAC,CAAC,CAAC;QACvE,QAAQ,CAAC,kBAAkB,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChE,QAAQ,CAAC,oCAAoC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAClF,QAAQ,CAAC,0CAA0C,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAExF,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,kBAAkB,CAAC,CAAC;QACtE,QAAQ,CAAC,2CAA2C,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC;YACH,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QAC/D,MAAM,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,SAAS,GAAsB;YACnC,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,gBAAgB;YACvB,WAAW,EAAE,sBAAsB;YACnC,WAAW,EAAE,CAAC,WAAW,CAAC;YAC1B,kBAAkB,EAAE,CAAC,WAAW,CAAC;YACjC,MAAM,EAAE,aAAa;YACrB,QAAQ,EAAE,CAAC;YACX,WAAW,EAAE,CAAC;SACf,CAAC;QAEF,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,wBAAwB,CAAC,CAAC;QACxE,MAAM,EAAE,GAAG,yBAAyB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAEzD,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC1B,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QAChD,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,UAAU,EAAE,CAAC;QAEhC,wBAAwB;QACxB,MAAM,IAAI,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;QACrE,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;QAElD,gEAAgE;QAChE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,uBAAuB,CAAC,CAAC;QACvE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,EAAE,SAAS,CAAC,CAAC;QAE/D,6BAA6B;QAC7B,MAAM,EAAE,GAAG,wBAAwB,CAAC,OAAO,EAAE,EAAG,CAAC,GAAG,CAAC,CAAC;QACtD,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEtB,+CAA+C;QAC/C,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QAC5F,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,EAAE,GAAG,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,EAAE,MAAM,CAAC,CAAC;QACtE,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEtB,MAAM,aAAa,GAAG,QAAQ,CAAC,2BAA2B,EAAE;YAC1D,GAAG,EAAE,OAAO;YACZ,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { LocalRouter } from '../router/index.js';
2
+ import { MarathonMilestone } from './types.js';
3
+ export declare function buildMacroPlanningPrompt(macroGoal: string, projectContext?: string): string;
4
+ export declare function parseMilestonesJson(raw: string): MarathonMilestone[];
5
+ export declare function planMarathonRoadmap(macroGoal: string, opts: {
6
+ router: LocalRouter;
7
+ modelOverride?: string;
8
+ projectContext?: string;
9
+ }): Promise<MarathonMilestone[]>;
10
+ //# sourceMappingURL=planner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../src/marathon/planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,GAAE,MAAW,GAAG,MAAM,CA6B/F;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAwCpE;AAED,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IACJ,MAAM,EAAE,WAAW,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GACA,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAsC9B"}
@@ -0,0 +1,109 @@
1
+ import { messageText } from '../types.js';
2
+ export function buildMacroPlanningPrompt(macroGoal, projectContext = '') {
3
+ return `You are Metis, the master architect and planner for the Daedalus Marathon Engine.
4
+ Your task is to decompose the following high-level project vision into an ordered sequence of 3 to 12 atomic, verifiable milestones.
5
+
6
+ ## Project Vision:
7
+ ${macroGoal}
8
+
9
+ ## Project Context:
10
+ ${projectContext || '(New project or clean workspace)'}
11
+
12
+ ## Requirements for each Milestone:
13
+ 1. Atomic & Focused: Changes 1 to 5 files maximum per milestone.
14
+ 2. Ordered by Dependency: Foundation/Schema first, then Business Logic/APIs, then UI/Polish/Integration.
15
+ 3. Verifiable: Must have explicit, measurable acceptance criteria.
16
+ 4. Output Format: Pure JSON array of milestone objects with NO conversational wrapper:
17
+
18
+ [
19
+ {
20
+ "id": "m-1",
21
+ "title": "Short title",
22
+ "description": "Clear explanation of what is built in this milestone",
23
+ "targetFiles": ["path/to/file1.ts", "path/to/file2.ts"],
24
+ "acceptanceCriteria": [
25
+ "Explicit testable requirement 1",
26
+ "Explicit testable requirement 2"
27
+ ],
28
+ "verifyCommand": "npm test"
29
+ }
30
+ ]`;
31
+ }
32
+ export function parseMilestonesJson(raw) {
33
+ let cleaned = raw.trim();
34
+ if (cleaned.startsWith('```json')) {
35
+ cleaned = cleaned.replace(/^```json\s*/i, '').replace(/```\s*$/, '');
36
+ }
37
+ else if (cleaned.startsWith('```')) {
38
+ cleaned = cleaned.replace(/^```\s*/, '').replace(/```\s*$/, '');
39
+ }
40
+ try {
41
+ const arr = JSON.parse(cleaned);
42
+ if (!Array.isArray(arr) || arr.length === 0) {
43
+ return [];
44
+ }
45
+ return arr.map((item, index) => {
46
+ const id = String(item.id || `m-${index + 1}`).toLowerCase();
47
+ const title = String(item.title || `Milestone ${index + 1}`);
48
+ const description = String(item.description || title);
49
+ const targetFiles = Array.isArray(item.targetFiles) ? item.targetFiles.map(String) : [];
50
+ const acceptanceCriteria = Array.isArray(item.acceptanceCriteria) && item.acceptanceCriteria.length > 0
51
+ ? item.acceptanceCriteria.map(String)
52
+ : ['Code compiles cleanly and tests pass'];
53
+ const verifyCommand = item.verifyCommand ? String(item.verifyCommand) : undefined;
54
+ const milestone = {
55
+ id,
56
+ title,
57
+ description,
58
+ targetFiles,
59
+ acceptanceCriteria,
60
+ verifyCommand,
61
+ status: 'pending',
62
+ attempts: 0,
63
+ maxAttempts: 3,
64
+ };
65
+ return milestone;
66
+ });
67
+ }
68
+ catch {
69
+ return [];
70
+ }
71
+ }
72
+ export async function planMarathonRoadmap(macroGoal, opts) {
73
+ const prompt = buildMacroPlanningPrompt(macroGoal, opts.projectContext);
74
+ const messages = [
75
+ { role: 'system', content: 'You are Metis. Output pure JSON milestone array only.' },
76
+ { role: 'user', content: prompt },
77
+ ];
78
+ try {
79
+ const res = await opts.router.chat.completions.create({
80
+ model: opts.modelOverride || 'intelligence',
81
+ complexity: 'complex',
82
+ messages,
83
+ temperature: 0.2,
84
+ max_tokens: 2500,
85
+ });
86
+ const text = messageText(res.choices?.[0]?.message?.content ?? '');
87
+ const milestones = parseMilestonesJson(text);
88
+ if (milestones.length > 0) {
89
+ return milestones;
90
+ }
91
+ }
92
+ catch {
93
+ // Fallback on failure
94
+ }
95
+ // Fallback default milestone if model generation fails
96
+ return [
97
+ {
98
+ id: 'm-1',
99
+ title: 'Initial Implementation',
100
+ description: `Implement core foundation for: ${macroGoal}`,
101
+ targetFiles: [],
102
+ acceptanceCriteria: ['Project builds without compiler errors', 'Basic unit tests pass'],
103
+ status: 'pending',
104
+ attempts: 0,
105
+ maxAttempts: 3,
106
+ },
107
+ ];
108
+ }
109
+ //# sourceMappingURL=planner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.js","sourceRoot":"","sources":["../../src/marathon/planner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=planner.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.test.d.ts","sourceRoot":"","sources":["../../src/marathon/planner.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,58 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { buildMacroPlanningPrompt, parseMilestonesJson, planMarathonRoadmap, } from './planner.js';
3
+ describe('Metis Macro-Planner (Milestone DAG Synthesis)', () => {
4
+ it('builds clear macro planning prompt', () => {
5
+ const prompt = buildMacroPlanningPrompt('Build a Snake Game in Terminal');
6
+ expect(prompt).toContain('Metis');
7
+ expect(prompt).toContain('Build a Snake Game in Terminal');
8
+ expect(prompt).toContain('Atomic & Focused');
9
+ });
10
+ it('parses valid milestone JSON', () => {
11
+ const raw = JSON.stringify([
12
+ {
13
+ id: 'm-1',
14
+ title: 'Core Grid and Engine',
15
+ description: 'Initialize game grid and movement vectors',
16
+ targetFiles: ['src/grid.ts'],
17
+ acceptanceCriteria: ['Grid initializes with correct dimensions'],
18
+ verifyCommand: 'npm test',
19
+ },
20
+ {
21
+ id: 'm-2',
22
+ title: 'Input Handler and Loop',
23
+ description: 'Process arrow key inputs and tick loop',
24
+ targetFiles: ['src/loop.ts'],
25
+ acceptanceCriteria: ['Arrow keys update heading'],
26
+ },
27
+ ]);
28
+ const milestones = parseMilestonesJson(raw);
29
+ expect(milestones.length).toBe(2);
30
+ expect(milestones[0].id).toBe('m-1');
31
+ expect(milestones[0].status).toBe('pending');
32
+ expect(milestones[0].attempts).toBe(0);
33
+ expect(milestones[0].maxAttempts).toBe(3);
34
+ expect(milestones[1].id).toBe('m-2');
35
+ });
36
+ it('cleans markdown wrappers when parsing JSON', () => {
37
+ const fenced = '```json\n[{"id": "m-1", "title": "Setup", "acceptanceCriteria": ["Done"]}]\n```';
38
+ const milestones = parseMilestonesJson(fenced);
39
+ expect(milestones.length).toBe(1);
40
+ expect(milestones[0].title).toBe('Setup');
41
+ });
42
+ it('calls router and falls back gracefully on error', async () => {
43
+ const mockRouter = {
44
+ chat: {
45
+ completions: {
46
+ create: vi.fn().mockRejectedValue(new Error('Network error')),
47
+ },
48
+ },
49
+ };
50
+ const milestones = await planMarathonRoadmap('Build CLI app', {
51
+ router: mockRouter,
52
+ });
53
+ expect(milestones.length).toBe(1);
54
+ expect(milestones[0].id).toBe('m-1');
55
+ expect(milestones[0].title).toBe('Initial Implementation');
56
+ });
57
+ });
58
+ //# sourceMappingURL=planner.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.test.js","sourceRoot":"","sources":["../../src/marathon/planner.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { MarathonRun, MarathonMilestone, MilestoneStatus } from './types.js';
2
+ export declare function getMarathonDir(projectRoot: string): string;
3
+ export declare function getMarathonStatePath(projectRoot: string): string;
4
+ export declare function getRoadmapPath(projectRoot: string): string;
5
+ export declare function loadMarathonRun(projectRoot: string): MarathonRun | null;
6
+ export declare function saveMarathonRun(projectRoot: string, run: MarathonRun): void;
7
+ export declare function initMarathonRun(projectRoot: string, macroGoal: string, baseBranch: string, milestones?: MarathonMilestone[]): MarathonRun;
8
+ export declare function updateMilestoneStatus(run: MarathonRun, milestoneId: string, status: MilestoneStatus, details?: Partial<MarathonMilestone>): MarathonRun;
9
+ export declare function advanceToNextMilestone(run: MarathonRun): boolean;
10
+ export declare function renderRoadmapMarkdown(run: MarathonRun): string;
11
+ export declare function saveRoadmapFile(projectRoot: string, run: MarathonRun): string;
12
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/marathon/state.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7E,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CASvE;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAQ3E;AAED,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,UAAU,GAAE,iBAAiB,EAAO,GACnC,WAAW,CA6Bb;AAED,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,WAAW,EAChB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,eAAe,EACvB,OAAO,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GACnC,WAAW,CAiBb;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAQhE;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAgD9D;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,MAAM,CAS7E"}
@@ -0,0 +1,146 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ export function getMarathonDir(projectRoot) {
4
+ return path.join(projectRoot, '.daedalus');
5
+ }
6
+ export function getMarathonStatePath(projectRoot) {
7
+ return path.join(getMarathonDir(projectRoot), 'marathon.json');
8
+ }
9
+ export function getRoadmapPath(projectRoot) {
10
+ return path.join(projectRoot, 'MARATHON_ROADMAP.md');
11
+ }
12
+ export function loadMarathonRun(projectRoot) {
13
+ const file = getMarathonStatePath(projectRoot);
14
+ if (!fs.existsSync(file))
15
+ return null;
16
+ try {
17
+ const raw = fs.readFileSync(file, 'utf8');
18
+ return JSON.parse(raw);
19
+ }
20
+ catch {
21
+ return null;
22
+ }
23
+ }
24
+ export function saveMarathonRun(projectRoot, run) {
25
+ const dir = getMarathonDir(projectRoot);
26
+ if (!fs.existsSync(dir)) {
27
+ fs.mkdirSync(dir, { recursive: true });
28
+ }
29
+ run.updatedAt = new Date().toISOString();
30
+ fs.writeFileSync(getMarathonStatePath(projectRoot), JSON.stringify(run, null, 2), 'utf8');
31
+ saveRoadmapFile(projectRoot, run);
32
+ }
33
+ export function initMarathonRun(projectRoot, macroGoal, baseBranch, milestones = []) {
34
+ const slug = macroGoal
35
+ .toLowerCase()
36
+ .replace(/[^a-z0-9]+/g, '-')
37
+ .replace(/^-|-$/g, '')
38
+ .slice(0, 30);
39
+ const runId = `marathon-${Date.now()}-${slug || 'run'}`;
40
+ const marathonBranch = `marathon/${slug || 'main'}`;
41
+ const run = {
42
+ id: runId,
43
+ macroGoal,
44
+ baseBranch,
45
+ marathonBranch,
46
+ status: 'planning',
47
+ createdAt: new Date().toISOString(),
48
+ updatedAt: new Date().toISOString(),
49
+ activeMilestoneIndex: 0,
50
+ milestones,
51
+ roadmapPath: getRoadmapPath(projectRoot),
52
+ metrics: {
53
+ totalIterations: 0,
54
+ totalRollbacks: 0,
55
+ totalEvaluations: 0,
56
+ },
57
+ };
58
+ saveMarathonRun(projectRoot, run);
59
+ return run;
60
+ }
61
+ export function updateMilestoneStatus(run, milestoneId, status, details) {
62
+ const milestone = run.milestones.find((m) => m.id === milestoneId);
63
+ if (!milestone)
64
+ return run;
65
+ milestone.status = status;
66
+ if (details) {
67
+ Object.assign(milestone, details);
68
+ }
69
+ if (status === 'in_progress' && !milestone.startedAt) {
70
+ milestone.startedAt = new Date().toISOString();
71
+ }
72
+ if (status === 'passed' && !milestone.completedAt) {
73
+ milestone.completedAt = new Date().toISOString();
74
+ }
75
+ return run;
76
+ }
77
+ export function advanceToNextMilestone(run) {
78
+ if (run.activeMilestoneIndex < run.milestones.length - 1) {
79
+ run.activeMilestoneIndex += 1;
80
+ return true;
81
+ }
82
+ run.status = 'completed';
83
+ run.completedAt = new Date().toISOString();
84
+ return false;
85
+ }
86
+ export function renderRoadmapMarkdown(run) {
87
+ const completed = run.milestones.filter((m) => m.status === 'passed').length;
88
+ const total = run.milestones.length;
89
+ const pct = total > 0 ? Math.round((completed / total) * 100) : 0;
90
+ const lines = [];
91
+ lines.push(`# Marathon Roadmap: ${run.macroGoal}`);
92
+ lines.push('');
93
+ lines.push(`- **Status**: \`${run.status.toUpperCase()}\``);
94
+ lines.push(`- **Progress**: ${completed}/${total} milestones passed (${pct}%)`);
95
+ lines.push(`- **Base Branch**: \`${run.baseBranch}\``);
96
+ lines.push(`- **Integration Branch**: \`${run.marathonBranch}\``);
97
+ lines.push(`- **Last Updated**: ${run.updatedAt}`);
98
+ lines.push('');
99
+ lines.push('## Milestones');
100
+ lines.push('');
101
+ for (let i = 0; i < run.milestones.length; i++) {
102
+ const m = run.milestones[i];
103
+ const isCurrent = i === run.activeMilestoneIndex && run.status === 'running';
104
+ let icon = '[ ]';
105
+ if (m.status === 'passed')
106
+ icon = '[x]';
107
+ else if (m.status === 'in_progress')
108
+ icon = '[>]';
109
+ else if (m.status === 'failed')
110
+ icon = '[!]';
111
+ else if (m.status === 'rolled_back')
112
+ icon = '[<]';
113
+ lines.push(`### ${icon} ${m.id.toUpperCase()}: ${m.title}${isCurrent ? ' *(Active)*' : ''}`);
114
+ lines.push('');
115
+ lines.push(`${m.description}`);
116
+ lines.push('');
117
+ if (m.targetFiles.length > 0) {
118
+ lines.push(`- **Target Files**: ${m.targetFiles.map((f) => '`' + f + '`').join(', ')}`);
119
+ }
120
+ if (m.gitTag) {
121
+ lines.push(`- **Git Tag**: \`${m.gitTag}\``);
122
+ }
123
+ lines.push(`- **Attempts**: ${m.attempts}/${m.maxAttempts}`);
124
+ lines.push('');
125
+ lines.push('**Acceptance Criteria:**');
126
+ for (const c of m.acceptanceCriteria) {
127
+ const match = m.evalReport?.criteriaResults?.find((cr) => cr.criterion === c);
128
+ const mark = match ? (match.satisfied ? '[x]' : '[ ]') : (m.status === 'passed' ? '[x]' : '[ ]');
129
+ lines.push(`- ${mark} ${c}`);
130
+ }
131
+ lines.push('');
132
+ }
133
+ return lines.join('\n');
134
+ }
135
+ export function saveRoadmapFile(projectRoot, run) {
136
+ const content = renderRoadmapMarkdown(run);
137
+ const target = getRoadmapPath(projectRoot);
138
+ try {
139
+ fs.writeFileSync(target, content, 'utf8');
140
+ }
141
+ catch {
142
+ // Best-effort write
143
+ }
144
+ return target;
145
+ }
146
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/marathon/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=state.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.test.d.ts","sourceRoot":"","sources":["../../src/marathon/state.test.ts"],"names":[],"mappings":""}