maxsimcli 4.0.2 → 4.2.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 (127) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/assets/CHANGELOG.md +16 -0
  3. package/dist/assets/dashboard/client/assets/{index-C_eAetZJ.js → index-BcRHShXD.js} +59 -59
  4. package/dist/assets/dashboard/client/assets/index-C199D4Eb.css +32 -0
  5. package/dist/assets/dashboard/client/index.html +2 -2
  6. package/dist/assets/dashboard/server.js +26 -11
  7. package/dist/assets/templates/agents/AGENTS.md +18 -69
  8. package/dist/assets/templates/agents/maxsim-code-reviewer.md +17 -92
  9. package/dist/assets/templates/agents/maxsim-codebase-mapper.md +57 -694
  10. package/dist/assets/templates/agents/maxsim-debugger.md +80 -925
  11. package/dist/assets/templates/agents/maxsim-executor.md +94 -431
  12. package/dist/assets/templates/agents/maxsim-integration-checker.md +51 -319
  13. package/dist/assets/templates/agents/maxsim-phase-researcher.md +63 -429
  14. package/dist/assets/templates/agents/maxsim-plan-checker.md +79 -568
  15. package/dist/assets/templates/agents/maxsim-planner.md +125 -855
  16. package/dist/assets/templates/agents/maxsim-project-researcher.md +32 -472
  17. package/dist/assets/templates/agents/maxsim-research-synthesizer.md +25 -134
  18. package/dist/assets/templates/agents/maxsim-roadmapper.md +66 -480
  19. package/dist/assets/templates/agents/maxsim-spec-reviewer.md +13 -55
  20. package/dist/assets/templates/agents/maxsim-verifier.md +95 -450
  21. package/dist/assets/templates/commands/maxsim/artefakte.md +122 -0
  22. package/dist/assets/templates/commands/maxsim/batch.md +42 -0
  23. package/dist/assets/templates/commands/maxsim/check-todos.md +1 -0
  24. package/dist/assets/templates/commands/maxsim/sdd.md +39 -0
  25. package/dist/assets/templates/references/thinking-partner.md +33 -0
  26. package/dist/assets/templates/workflows/batch.md +420 -0
  27. package/dist/assets/templates/workflows/check-todos.md +85 -1
  28. package/dist/assets/templates/workflows/discuss-phase.md +31 -0
  29. package/dist/assets/templates/workflows/execute-plan.md +96 -27
  30. package/dist/assets/templates/workflows/help.md +47 -0
  31. package/dist/assets/templates/workflows/sdd.md +426 -0
  32. package/dist/backend/index.d.ts +4 -0
  33. package/dist/backend/index.d.ts.map +1 -0
  34. package/dist/backend/index.js +12 -0
  35. package/dist/backend/index.js.map +1 -0
  36. package/dist/backend/lifecycle.d.ts +13 -0
  37. package/dist/backend/lifecycle.d.ts.map +1 -0
  38. package/dist/backend/lifecycle.js +168 -0
  39. package/dist/backend/lifecycle.js.map +1 -0
  40. package/dist/backend/server.d.ts +13 -0
  41. package/dist/backend/server.d.ts.map +1 -0
  42. package/dist/backend/server.js +1013 -0
  43. package/dist/backend/server.js.map +1 -0
  44. package/dist/backend/terminal.d.ts +49 -0
  45. package/dist/backend/terminal.d.ts.map +1 -0
  46. package/dist/backend/terminal.js +209 -0
  47. package/dist/backend/terminal.js.map +1 -0
  48. package/dist/backend/types.d.ts +77 -0
  49. package/dist/backend/types.d.ts.map +1 -0
  50. package/dist/backend/types.js +6 -0
  51. package/dist/backend/types.js.map +1 -0
  52. package/dist/backend-server.cjs +80636 -0
  53. package/dist/backend-server.cjs.map +1 -0
  54. package/dist/backend-server.d.cts +2 -0
  55. package/dist/backend-server.d.ts +11 -0
  56. package/dist/backend-server.d.ts.map +1 -0
  57. package/dist/backend-server.js +43 -0
  58. package/dist/backend-server.js.map +1 -0
  59. package/dist/cli.cjs +378 -172
  60. package/dist/cli.cjs.map +1 -1
  61. package/dist/cli.js +28 -8
  62. package/dist/cli.js.map +1 -1
  63. package/dist/core/artefakte.d.ts.map +1 -1
  64. package/dist/core/artefakte.js +16 -0
  65. package/dist/core/artefakte.js.map +1 -1
  66. package/dist/core/context-loader.d.ts +1 -0
  67. package/dist/core/context-loader.d.ts.map +1 -1
  68. package/dist/core/context-loader.js +58 -0
  69. package/dist/core/context-loader.js.map +1 -1
  70. package/dist/core/core.d.ts +6 -0
  71. package/dist/core/core.d.ts.map +1 -1
  72. package/dist/core/core.js +238 -0
  73. package/dist/core/core.js.map +1 -1
  74. package/dist/core/index.d.ts +1 -1
  75. package/dist/core/index.d.ts.map +1 -1
  76. package/dist/core/index.js +5 -3
  77. package/dist/core/index.js.map +1 -1
  78. package/dist/core/phase.d.ts +11 -11
  79. package/dist/core/phase.d.ts.map +1 -1
  80. package/dist/core/phase.js +88 -73
  81. package/dist/core/phase.js.map +1 -1
  82. package/dist/core/roadmap.d.ts +2 -2
  83. package/dist/core/roadmap.d.ts.map +1 -1
  84. package/dist/core/roadmap.js +11 -10
  85. package/dist/core/roadmap.js.map +1 -1
  86. package/dist/core/skills.d.ts +4 -3
  87. package/dist/core/skills.d.ts.map +1 -1
  88. package/dist/core/skills.js +14 -15
  89. package/dist/core/skills.js.map +1 -1
  90. package/dist/core/state.d.ts +11 -11
  91. package/dist/core/state.d.ts.map +1 -1
  92. package/dist/core/state.js +60 -54
  93. package/dist/core/state.js.map +1 -1
  94. package/dist/{core-TFSlUjV1.cjs → core-RRjCSt0G.cjs} +1 -9
  95. package/dist/{core-TFSlUjV1.cjs.map → core-RRjCSt0G.cjs.map} +1 -1
  96. package/dist/esm-iIOBzmdz.cjs +1561 -0
  97. package/dist/esm-iIOBzmdz.cjs.map +1 -0
  98. package/dist/install.cjs +2 -2
  99. package/dist/lifecycle-0M4VqOMm.cjs +136 -0
  100. package/dist/lifecycle-0M4VqOMm.cjs.map +1 -0
  101. package/dist/mcp/config-tools.d.ts +13 -0
  102. package/dist/mcp/config-tools.d.ts.map +1 -0
  103. package/dist/mcp/config-tools.js +66 -0
  104. package/dist/mcp/config-tools.js.map +1 -0
  105. package/dist/mcp/context-tools.d.ts +13 -0
  106. package/dist/mcp/context-tools.d.ts.map +1 -0
  107. package/dist/mcp/context-tools.js +176 -0
  108. package/dist/mcp/context-tools.js.map +1 -0
  109. package/dist/mcp/index.d.ts +0 -1
  110. package/dist/mcp/index.d.ts.map +1 -1
  111. package/dist/mcp/index.js +6 -1
  112. package/dist/mcp/index.js.map +1 -1
  113. package/dist/mcp/phase-tools.js +3 -3
  114. package/dist/mcp/phase-tools.js.map +1 -1
  115. package/dist/mcp/roadmap-tools.d.ts +13 -0
  116. package/dist/mcp/roadmap-tools.d.ts.map +1 -0
  117. package/dist/mcp/roadmap-tools.js +79 -0
  118. package/dist/mcp/roadmap-tools.js.map +1 -0
  119. package/dist/mcp-server.cjs +799 -38
  120. package/dist/mcp-server.cjs.map +1 -1
  121. package/dist/server-G1MIg_Oe.cjs +2980 -0
  122. package/dist/server-G1MIg_Oe.cjs.map +1 -0
  123. package/dist/{skills-BOSxYUzf.cjs → skills-MYlMkYNt.cjs} +41 -29
  124. package/dist/skills-MYlMkYNt.cjs.map +1 -0
  125. package/package.json +7 -1
  126. package/dist/assets/dashboard/client/assets/index-CmiJKqOU.css +0 -32
  127. package/dist/skills-BOSxYUzf.cjs.map +0 -1
@@ -20,24 +20,29 @@ exports.cmdPhaseAdd = cmdPhaseAdd;
20
20
  exports.cmdPhaseInsert = cmdPhaseInsert;
21
21
  exports.cmdPhaseRemove = cmdPhaseRemove;
22
22
  exports.cmdPhaseComplete = cmdPhaseComplete;
23
- const node_fs_1 = __importDefault(require("node:fs"));
23
+ const node_fs_1 = require("node:fs");
24
24
  const node_path_1 = __importDefault(require("node:path"));
25
25
  const core_js_1 = require("./core.js");
26
26
  const frontmatter_js_1 = require("./frontmatter.js");
27
27
  const types_js_1 = require("./types.js");
28
28
  // ─── Stub scaffolding ───────────────────────────────────────────────────────
29
- function scaffoldPhaseStubs(dirPath, phaseId, name) {
29
+ async function scaffoldPhaseStubs(dirPath, phaseId, name) {
30
30
  const today = (0, core_js_1.todayISO)();
31
- node_fs_1.default.writeFileSync(node_path_1.default.join(dirPath, `${phaseId}-CONTEXT.md`), `# Phase ${phaseId} Context: ${name}\n\n**Created:** ${today}\n**Phase goal:** [To be defined during /maxsim:discuss-phase]\n\n---\n\n_Context will be populated by /maxsim:discuss-phase_\n`);
32
- node_fs_1.default.writeFileSync(node_path_1.default.join(dirPath, `${phaseId}-RESEARCH.md`), `# Phase ${phaseId}: ${name} - Research\n\n**Researched:** Not yet\n**Domain:** TBD\n**Confidence:** TBD\n\n---\n\n_Research will be populated by /maxsim:research-phase_\n`);
31
+ await Promise.all([
32
+ node_fs_1.promises.writeFile(node_path_1.default.join(dirPath, `${phaseId}-CONTEXT.md`), `# Phase ${phaseId} Context: ${name}\n\n**Created:** ${today}\n**Phase goal:** [To be defined during /maxsim:discuss-phase]\n\n---\n\n_Context will be populated by /maxsim:discuss-phase_\n`),
33
+ node_fs_1.promises.writeFile(node_path_1.default.join(dirPath, `${phaseId}-RESEARCH.md`), `# Phase ${phaseId}: ${name} - Research\n\n**Researched:** Not yet\n**Domain:** TBD\n**Confidence:** TBD\n\n---\n\n_Research will be populated by /maxsim:research-phase_\n`),
34
+ ]);
33
35
  }
34
36
  // ─── Core functions ─────────────────────────────────────────────────────────
35
- function phaseAddCore(cwd, description, options) {
37
+ async function phaseAddCore(cwd, description, options) {
36
38
  const rmPath = (0, core_js_1.roadmapPath)(cwd);
37
- if (!node_fs_1.default.existsSync(rmPath)) {
39
+ let content;
40
+ try {
41
+ content = await node_fs_1.promises.readFile(rmPath, 'utf-8');
42
+ }
43
+ catch {
38
44
  throw new Error('ROADMAP.md not found');
39
45
  }
40
- const content = node_fs_1.default.readFileSync(rmPath, 'utf-8');
41
46
  const slug = (0, core_js_1.generateSlugInternal)(description);
42
47
  const phasePattern = (0, core_js_1.getPhasePattern)();
43
48
  let maxPhase = 0;
@@ -51,10 +56,10 @@ function phaseAddCore(cwd, description, options) {
51
56
  const paddedNum = String(newPhaseNum).padStart(2, '0');
52
57
  const dirName = `${paddedNum}-${slug}`;
53
58
  const dirPath = (0, core_js_1.planningPath)(cwd, 'phases', dirName);
54
- node_fs_1.default.mkdirSync(dirPath, { recursive: true });
55
- node_fs_1.default.writeFileSync(node_path_1.default.join(dirPath, '.gitkeep'), '');
59
+ await node_fs_1.promises.mkdir(dirPath, { recursive: true });
60
+ await node_fs_1.promises.writeFile(node_path_1.default.join(dirPath, '.gitkeep'), '');
56
61
  if (options?.includeStubs) {
57
- scaffoldPhaseStubs(dirPath, paddedNum, description);
62
+ await scaffoldPhaseStubs(dirPath, paddedNum, description);
58
63
  }
59
64
  const phaseEntry = `\n### Phase ${newPhaseNum}: ${description}\n\n**Goal:** [To be planned]\n**Requirements**: TBD\n**Depends on:** Phase ${maxPhase}\n**Plans:** 0 plans\n\nPlans:\n- [ ] TBD (run /maxsim:plan-phase ${newPhaseNum} to break down)\n`;
60
65
  let updatedContent;
@@ -65,7 +70,7 @@ function phaseAddCore(cwd, description, options) {
65
70
  else {
66
71
  updatedContent = content + phaseEntry;
67
72
  }
68
- node_fs_1.default.writeFileSync(rmPath, updatedContent, 'utf-8');
73
+ await node_fs_1.promises.writeFile(rmPath, updatedContent, 'utf-8');
69
74
  return {
70
75
  phase_number: newPhaseNum,
71
76
  padded: paddedNum,
@@ -74,12 +79,15 @@ function phaseAddCore(cwd, description, options) {
74
79
  description,
75
80
  };
76
81
  }
77
- function phaseInsertCore(cwd, afterPhase, description, options) {
82
+ async function phaseInsertCore(cwd, afterPhase, description, options) {
78
83
  const rmPath = (0, core_js_1.roadmapPath)(cwd);
79
- if (!node_fs_1.default.existsSync(rmPath)) {
84
+ let content;
85
+ try {
86
+ content = await node_fs_1.promises.readFile(rmPath, 'utf-8');
87
+ }
88
+ catch {
80
89
  throw new Error('ROADMAP.md not found');
81
90
  }
82
- const content = node_fs_1.default.readFileSync(rmPath, 'utf-8');
83
91
  const slug = (0, core_js_1.generateSlugInternal)(description);
84
92
  const normalizedAfter = (0, core_js_1.normalizePhaseName)(afterPhase);
85
93
  const unpadded = normalizedAfter.replace(/^0+/, '');
@@ -92,7 +100,7 @@ function phaseInsertCore(cwd, afterPhase, description, options) {
92
100
  const normalizedBase = (0, core_js_1.normalizePhaseName)(afterPhase);
93
101
  const existingDecimals = [];
94
102
  try {
95
- const dirs = (0, core_js_1.listSubDirs)(phasesDirPath);
103
+ const dirs = await (0, core_js_1.listSubDirsAsync)(phasesDirPath);
96
104
  const decimalPattern = new RegExp(`^${normalizedBase}\\.(\\d+)`);
97
105
  for (const dir of dirs) {
98
106
  const dm = dir.match(decimalPattern);
@@ -107,10 +115,10 @@ function phaseInsertCore(cwd, afterPhase, description, options) {
107
115
  const decimalPhase = `${normalizedBase}.${nextDecimal}`;
108
116
  const dirName = `${decimalPhase}-${slug}`;
109
117
  const dirPath = (0, core_js_1.planningPath)(cwd, 'phases', dirName);
110
- node_fs_1.default.mkdirSync(dirPath, { recursive: true });
111
- node_fs_1.default.writeFileSync(node_path_1.default.join(dirPath, '.gitkeep'), '');
118
+ await node_fs_1.promises.mkdir(dirPath, { recursive: true });
119
+ await node_fs_1.promises.writeFile(node_path_1.default.join(dirPath, '.gitkeep'), '');
112
120
  if (options?.includeStubs) {
113
- scaffoldPhaseStubs(dirPath, decimalPhase, description);
121
+ await scaffoldPhaseStubs(dirPath, decimalPhase, description);
114
122
  }
115
123
  const phaseEntry = `\n### Phase ${decimalPhase}: ${description} (INSERTED)\n\n**Goal:** [Urgent work - to be planned]\n**Requirements**: TBD\n**Depends on:** Phase ${afterPhase}\n**Plans:** 0 plans\n\nPlans:\n- [ ] TBD (run /maxsim:plan-phase ${decimalPhase} to break down)\n`;
116
124
  const headerPattern = new RegExp(`(#{2,4}\\s*Phase\\s+0*${afterPhaseEscaped}:[^\\n]*\\n)`, 'i');
@@ -129,7 +137,7 @@ function phaseInsertCore(cwd, afterPhase, description, options) {
129
137
  insertIdx = content.length;
130
138
  }
131
139
  const updatedContent = content.slice(0, insertIdx) + phaseEntry + content.slice(insertIdx);
132
- node_fs_1.default.writeFileSync(rmPath, updatedContent, 'utf-8');
140
+ await node_fs_1.promises.writeFile(rmPath, updatedContent, 'utf-8');
133
141
  return {
134
142
  phase_number: decimalPhase,
135
143
  after_phase: afterPhase,
@@ -138,20 +146,21 @@ function phaseInsertCore(cwd, afterPhase, description, options) {
138
146
  description,
139
147
  };
140
148
  }
141
- function phaseCompleteCore(cwd, phaseNum) {
149
+ async function phaseCompleteCore(cwd, phaseNum) {
142
150
  const rmPath = (0, core_js_1.roadmapPath)(cwd);
143
151
  const stPath = (0, core_js_1.statePath)(cwd);
144
152
  const phasesDirPath = (0, core_js_1.phasesPath)(cwd);
145
153
  const today = (0, core_js_1.todayISO)();
146
- const phaseInfo = (0, core_js_1.findPhaseInternal)(cwd, phaseNum);
154
+ const phaseInfo = await (0, core_js_1.findPhaseInternalAsync)(cwd, phaseNum);
147
155
  if (!phaseInfo) {
148
156
  throw new Error(`Phase ${phaseNum} not found`);
149
157
  }
150
158
  const planCount = phaseInfo.plans.length;
151
159
  const summaryCount = phaseInfo.summaries.length;
152
160
  let requirementsUpdated = false;
153
- if (node_fs_1.default.existsSync(rmPath)) {
154
- let roadmapContent = node_fs_1.default.readFileSync(rmPath, 'utf-8');
161
+ const rmExists = await (0, core_js_1.pathExistsAsync)(rmPath);
162
+ if (rmExists) {
163
+ let roadmapContent = await node_fs_1.promises.readFile(rmPath, 'utf-8');
155
164
  const checkboxPattern = new RegExp(`(-\\s*\\[)[ ](\\]\\s*.*Phase\\s+${(0, core_js_1.escapePhaseNum)(phaseNum)}[:\\s][^\\n]*)`, 'i');
156
165
  roadmapContent = roadmapContent.replace(checkboxPattern, `$1x$2 (completed ${today})`);
157
166
  const phaseEscaped = (0, core_js_1.escapePhaseNum)(phaseNum);
@@ -160,21 +169,21 @@ function phaseCompleteCore(cwd, phaseNum) {
160
169
  const planCountPattern = new RegExp(`(#{2,4}\\s*Phase\\s+${phaseEscaped}[\\s\\S]*?\\*\\*Plans:\\*\\*\\s*)[^\\n]+`, 'i');
161
170
  roadmapContent = roadmapContent.replace(planCountPattern, `$1${summaryCount}/${planCount} plans complete`);
162
171
  (0, core_js_1.debugLog)('phase-complete-write', `writing ROADMAP.md for phase ${phaseNum}`);
163
- node_fs_1.default.writeFileSync(rmPath, roadmapContent, 'utf-8');
172
+ await node_fs_1.promises.writeFile(rmPath, roadmapContent, 'utf-8');
164
173
  (0, core_js_1.debugLog)('phase-complete-write', `ROADMAP.md updated for phase ${phaseNum}`);
165
174
  // Update REQUIREMENTS.md
166
175
  const reqPath = (0, core_js_1.planningPath)(cwd, 'REQUIREMENTS.md');
167
- if (node_fs_1.default.existsSync(reqPath)) {
176
+ if (await (0, core_js_1.pathExistsAsync)(reqPath)) {
168
177
  const reqMatch = roadmapContent.match(new RegExp(`Phase\\s+${(0, core_js_1.escapePhaseNum)(phaseNum)}[\\s\\S]*?\\*\\*Requirements:\\*\\*\\s*([^\\n]+)`, 'i'));
169
178
  if (reqMatch) {
170
179
  const reqIds = reqMatch[1].replace(/[\[\]]/g, '').split(/[,\s]+/).map(r => r.trim()).filter(Boolean);
171
- let reqContent = node_fs_1.default.readFileSync(reqPath, 'utf-8');
180
+ let reqContent = await node_fs_1.promises.readFile(reqPath, 'utf-8');
172
181
  for (const reqId of reqIds) {
173
182
  reqContent = reqContent.replace(new RegExp(`(-\\s*\\[)[ ](\\]\\s*\\*\\*${reqId}\\*\\*)`, 'gi'), '$1x$2');
174
183
  reqContent = reqContent.replace(new RegExp(`(\\|\\s*${reqId}\\s*\\|[^|]+\\|)\\s*Pending\\s*(\\|)`, 'gi'), '$1 Complete $2');
175
184
  }
176
185
  (0, core_js_1.debugLog)('phase-complete-write', `writing REQUIREMENTS.md for phase ${phaseNum}`);
177
- node_fs_1.default.writeFileSync(reqPath, reqContent, 'utf-8');
186
+ await node_fs_1.promises.writeFile(reqPath, reqContent, 'utf-8');
178
187
  (0, core_js_1.debugLog)('phase-complete-write', `REQUIREMENTS.md updated for phase ${phaseNum}`);
179
188
  requirementsUpdated = true;
180
189
  }
@@ -185,7 +194,7 @@ function phaseCompleteCore(cwd, phaseNum) {
185
194
  let nextPhaseName = null;
186
195
  let isLastPhase = true;
187
196
  try {
188
- const dirs = (0, core_js_1.listSubDirs)(phasesDirPath, true);
197
+ const dirs = await (0, core_js_1.listSubDirsAsync)(phasesDirPath, true);
189
198
  for (const dir of dirs) {
190
199
  const dm = dir.match(/^(\d+[A-Z]?(?:\.\d+)?)-?(.*)/i);
191
200
  if (dm) {
@@ -202,8 +211,9 @@ function phaseCompleteCore(cwd, phaseNum) {
202
211
  (0, core_js_1.debugLog)('phase-complete-next-phase-scan-failed', e);
203
212
  }
204
213
  // Update STATE.md
205
- if (node_fs_1.default.existsSync(stPath)) {
206
- let stateContent = node_fs_1.default.readFileSync(stPath, 'utf-8');
214
+ const stExists = await (0, core_js_1.pathExistsAsync)(stPath);
215
+ if (stExists) {
216
+ let stateContent = await node_fs_1.promises.readFile(stPath, 'utf-8');
207
217
  stateContent = stateContent.replace(/(\*\*Current Phase:\*\*\s*).*/, `$1${nextPhaseNum || phaseNum}`);
208
218
  if (nextPhaseName) {
209
219
  stateContent = stateContent.replace(/(\*\*Current Phase Name:\*\*\s*).*/, `$1${nextPhaseName.replace(/-/g, ' ')}`);
@@ -213,7 +223,7 @@ function phaseCompleteCore(cwd, phaseNum) {
213
223
  stateContent = stateContent.replace(/(\*\*Last Activity:\*\*\s*).*/, `$1${today}`);
214
224
  stateContent = stateContent.replace(/(\*\*Last Activity Description:\*\*\s*).*/, `$1Phase ${phaseNum} complete${nextPhaseNum ? `, transitioned to Phase ${nextPhaseNum}` : ''}`);
215
225
  (0, core_js_1.debugLog)('phase-complete-write', `writing STATE.md for phase ${phaseNum}`);
216
- node_fs_1.default.writeFileSync(stPath, stateContent, 'utf-8');
226
+ await node_fs_1.promises.writeFile(stPath, stateContent, 'utf-8');
217
227
  (0, core_js_1.debugLog)('phase-complete-write', `STATE.md updated for phase ${phaseNum}`);
218
228
  }
219
229
  return {
@@ -224,8 +234,8 @@ function phaseCompleteCore(cwd, phaseNum) {
224
234
  next_phase_name: nextPhaseName,
225
235
  is_last_phase: isLastPhase,
226
236
  date: today,
227
- roadmap_updated: node_fs_1.default.existsSync(rmPath),
228
- state_updated: node_fs_1.default.existsSync(stPath),
237
+ roadmap_updated: rmExists,
238
+ state_updated: stExists,
229
239
  requirements_updated: requirementsUpdated,
230
240
  };
231
241
  }
@@ -233,7 +243,7 @@ function phaseCompleteCore(cwd, phaseNum) {
233
243
  async function cmdPhasesList(cwd, options) {
234
244
  const phasesDirPath = (0, core_js_1.phasesPath)(cwd);
235
245
  const { type, phase, includeArchived, offset, limit } = options;
236
- if (!node_fs_1.default.existsSync(phasesDirPath)) {
246
+ if (!(await (0, core_js_1.pathExistsAsync)(phasesDirPath))) {
237
247
  if (type) {
238
248
  return (0, types_js_1.cmdOk)({ files: [], count: 0, total: 0 }, '');
239
249
  }
@@ -244,7 +254,7 @@ async function cmdPhasesList(cwd, options) {
244
254
  try {
245
255
  let dirs = await (0, core_js_1.listSubDirsAsync)(phasesDirPath);
246
256
  if (includeArchived) {
247
- const archived = (0, core_js_1.getArchivedPhaseDirs)(cwd);
257
+ const archived = await (0, core_js_1.getArchivedPhaseDirsAsync)(cwd);
248
258
  for (const a of archived) {
249
259
  dirs.push(`${a.name} [${a.milestone}]`);
250
260
  }
@@ -261,7 +271,7 @@ async function cmdPhasesList(cwd, options) {
261
271
  if (type) {
262
272
  const fileResults = await Promise.all(dirs.map(async (dir) => {
263
273
  const dirPath = node_path_1.default.join(phasesDirPath, dir);
264
- const dirFiles = await node_fs_1.default.promises.readdir(dirPath);
274
+ const dirFiles = await node_fs_1.promises.readdir(dirPath);
265
275
  let filtered;
266
276
  if (type === 'plans') {
267
277
  filtered = dirFiles.filter(core_js_1.isPlanFile);
@@ -294,14 +304,14 @@ async function cmdPhasesList(cwd, options) {
294
304
  }
295
305
  }
296
306
  // ─── Next decimal ───────────────────────────────────────────────────────────
297
- function cmdPhaseNextDecimal(cwd, basePhase) {
307
+ async function cmdPhaseNextDecimal(cwd, basePhase) {
298
308
  const phasesDirPath = (0, core_js_1.phasesPath)(cwd);
299
309
  const normalized = (0, core_js_1.normalizePhaseName)(basePhase);
300
- if (!node_fs_1.default.existsSync(phasesDirPath)) {
310
+ if (!(await (0, core_js_1.pathExistsAsync)(phasesDirPath))) {
301
311
  return (0, types_js_1.cmdOk)({ found: false, base_phase: normalized, next: `${normalized}.1`, existing: [] }, `${normalized}.1`);
302
312
  }
303
313
  try {
304
- const dirs = (0, core_js_1.listSubDirs)(phasesDirPath);
314
+ const dirs = await (0, core_js_1.listSubDirsAsync)(phasesDirPath);
305
315
  const baseExists = dirs.some(d => d.startsWith(normalized + '-') || d === normalized);
306
316
  const decimalPattern = new RegExp(`^${normalized}\\.(\\d+)`);
307
317
  const existingDecimals = [];
@@ -332,7 +342,7 @@ function cmdPhaseNextDecimal(cwd, basePhase) {
332
342
  }
333
343
  }
334
344
  // ─── Find phase ─────────────────────────────────────────────────────────────
335
- function cmdFindPhase(cwd, phase) {
345
+ async function cmdFindPhase(cwd, phase) {
336
346
  if (!phase) {
337
347
  return (0, types_js_1.cmdErr)('phase identifier required');
338
348
  }
@@ -340,7 +350,7 @@ function cmdFindPhase(cwd, phase) {
340
350
  const normalized = (0, core_js_1.normalizePhaseName)(phase);
341
351
  const notFound = { found: false, directory: null, phase_number: null, phase_name: null, plans: [], summaries: [] };
342
352
  try {
343
- const dirs = (0, core_js_1.listSubDirs)(phasesDirPath, true);
353
+ const dirs = await (0, core_js_1.listSubDirsAsync)(phasesDirPath, true);
344
354
  const match = dirs.find(d => d.startsWith(normalized));
345
355
  if (!match) {
346
356
  return (0, types_js_1.cmdOk)(notFound, '');
@@ -349,7 +359,7 @@ function cmdFindPhase(cwd, phase) {
349
359
  const phaseNumber = dirMatch ? dirMatch[1] : normalized;
350
360
  const phaseName = dirMatch && dirMatch[2] ? dirMatch[2] : null;
351
361
  const phaseDir = node_path_1.default.join(phasesDirPath, match);
352
- const phaseFiles = node_fs_1.default.readdirSync(phaseDir);
362
+ const phaseFiles = await node_fs_1.promises.readdir(phaseDir);
353
363
  const plans = phaseFiles.filter(core_js_1.isPlanFile).sort();
354
364
  const summaries = phaseFiles.filter(core_js_1.isSummaryFile).sort();
355
365
  const result = {
@@ -367,7 +377,7 @@ function cmdFindPhase(cwd, phase) {
367
377
  }
368
378
  }
369
379
  // ─── Phase plan index ───────────────────────────────────────────────────────
370
- function cmdPhasePlanIndex(cwd, phase) {
380
+ async function cmdPhasePlanIndex(cwd, phase) {
371
381
  if (!phase) {
372
382
  return (0, types_js_1.cmdErr)('phase required for phase-plan-index');
373
383
  }
@@ -376,7 +386,7 @@ function cmdPhasePlanIndex(cwd, phase) {
376
386
  let phaseDir = null;
377
387
  let phaseDirName = null;
378
388
  try {
379
- const dirs = (0, core_js_1.listSubDirs)(phasesDirPath, true);
389
+ const dirs = await (0, core_js_1.listSubDirsAsync)(phasesDirPath, true);
380
390
  const match = dirs.find(d => d.startsWith(normalized));
381
391
  if (match) {
382
392
  phaseDir = node_path_1.default.join(phasesDirPath, match);
@@ -389,7 +399,7 @@ function cmdPhasePlanIndex(cwd, phase) {
389
399
  if (!phaseDir) {
390
400
  return (0, types_js_1.cmdOk)({ phase: normalized, error: 'Phase not found', plans: [], waves: {}, incomplete: [], has_checkpoints: false });
391
401
  }
392
- const phaseFiles = node_fs_1.default.readdirSync(phaseDir);
402
+ const phaseFiles = await node_fs_1.promises.readdir(phaseDir);
393
403
  const planFiles = phaseFiles.filter(core_js_1.isPlanFile).sort();
394
404
  const summaryFiles = phaseFiles.filter(core_js_1.isSummaryFile);
395
405
  const completedPlanIds = new Set(summaryFiles.map(core_js_1.summaryId));
@@ -397,10 +407,12 @@ function cmdPhasePlanIndex(cwd, phase) {
397
407
  const waves = {};
398
408
  const incomplete = [];
399
409
  let hasCheckpoints = false;
400
- for (const planFile of planFiles) {
410
+ // Read all plan files in parallel since each read is independent
411
+ const planContents = await Promise.all(planFiles.map(planFile => node_fs_1.promises.readFile(node_path_1.default.join(phaseDir, planFile), 'utf-8')));
412
+ for (let i = 0; i < planFiles.length; i++) {
413
+ const planFile = planFiles[i];
401
414
  const id = (0, core_js_1.planId)(planFile);
402
- const planPath = node_path_1.default.join(phaseDir, planFile);
403
- const content = node_fs_1.default.readFileSync(planPath, 'utf-8');
415
+ const content = planContents[i];
404
416
  const fm = (0, frontmatter_js_1.extractFrontmatter)(content);
405
417
  const taskMatches = content.match(/##\s*Task\s*\d+/gi) || [];
406
418
  const taskCount = taskMatches.length;
@@ -439,12 +451,12 @@ function cmdPhasePlanIndex(cwd, phase) {
439
451
  return (0, types_js_1.cmdOk)({ phase: normalized, plans, waves, incomplete, has_checkpoints: hasCheckpoints });
440
452
  }
441
453
  // ─── Phase add ──────────────────────────────────────────────────────────────
442
- function cmdPhaseAdd(cwd, description) {
454
+ async function cmdPhaseAdd(cwd, description) {
443
455
  if (!description) {
444
456
  return (0, types_js_1.cmdErr)('description required for phase add');
445
457
  }
446
458
  try {
447
- const result = phaseAddCore(cwd, description, { includeStubs: false });
459
+ const result = await phaseAddCore(cwd, description, { includeStubs: false });
448
460
  return (0, types_js_1.cmdOk)({ phase_number: result.phase_number, padded: result.padded, name: result.description, slug: result.slug, directory: result.directory }, result.padded);
449
461
  }
450
462
  catch (e) {
@@ -452,12 +464,12 @@ function cmdPhaseAdd(cwd, description) {
452
464
  }
453
465
  }
454
466
  // ─── Phase insert ───────────────────────────────────────────────────────────
455
- function cmdPhaseInsert(cwd, afterPhase, description) {
467
+ async function cmdPhaseInsert(cwd, afterPhase, description) {
456
468
  if (!afterPhase || !description) {
457
469
  return (0, types_js_1.cmdErr)('after-phase and description required for phase insert');
458
470
  }
459
471
  try {
460
- const result = phaseInsertCore(cwd, afterPhase, description, { includeStubs: false });
472
+ const result = await phaseInsertCore(cwd, afterPhase, description, { includeStubs: false });
461
473
  return (0, types_js_1.cmdOk)({ phase_number: result.phase_number, after_phase: result.after_phase, name: result.description, slug: result.slug, directory: result.directory }, result.phase_number);
462
474
  }
463
475
  catch (e) {
@@ -465,21 +477,21 @@ function cmdPhaseInsert(cwd, afterPhase, description) {
465
477
  }
466
478
  }
467
479
  // ─── Phase remove ───────────────────────────────────────────────────────────
468
- function cmdPhaseRemove(cwd, targetPhase, options) {
480
+ async function cmdPhaseRemove(cwd, targetPhase, options) {
469
481
  if (!targetPhase) {
470
482
  return (0, types_js_1.cmdErr)('phase number required for phase remove');
471
483
  }
472
484
  const rmPath = (0, core_js_1.roadmapPath)(cwd);
473
485
  const phasesDirPath = (0, core_js_1.phasesPath)(cwd);
474
486
  const force = options.force || false;
475
- if (!node_fs_1.default.existsSync(rmPath)) {
487
+ if (!(await (0, core_js_1.pathExistsAsync)(rmPath))) {
476
488
  return (0, types_js_1.cmdErr)('ROADMAP.md not found');
477
489
  }
478
490
  const normalized = (0, core_js_1.normalizePhaseName)(targetPhase);
479
491
  const isDecimal = targetPhase.includes('.');
480
492
  let targetDir = null;
481
493
  try {
482
- const dirs = (0, core_js_1.listSubDirs)(phasesDirPath, true);
494
+ const dirs = await (0, core_js_1.listSubDirsAsync)(phasesDirPath, true);
483
495
  targetDir = dirs.find(d => d.startsWith(normalized + '-') || d === normalized) || null;
484
496
  }
485
497
  catch (e) {
@@ -487,14 +499,14 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
487
499
  }
488
500
  if (targetDir && !force) {
489
501
  const targetPath = node_path_1.default.join(phasesDirPath, targetDir);
490
- const files = node_fs_1.default.readdirSync(targetPath);
502
+ const files = await node_fs_1.promises.readdir(targetPath);
491
503
  const summaries = files.filter(core_js_1.isSummaryFile);
492
504
  if (summaries.length > 0) {
493
505
  return (0, types_js_1.cmdErr)(`Phase ${targetPhase} has ${summaries.length} executed plan(s). Use --force to remove anyway.`);
494
506
  }
495
507
  }
496
508
  if (targetDir) {
497
- node_fs_1.default.rmSync(node_path_1.default.join(phasesDirPath, targetDir), { recursive: true, force: true });
509
+ await node_fs_1.promises.rm(node_path_1.default.join(phasesDirPath, targetDir), { recursive: true, force: true });
498
510
  }
499
511
  const renamedDirs = [];
500
512
  const renamedFiles = [];
@@ -503,7 +515,7 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
503
515
  const baseInt = baseParts[0];
504
516
  const removedDecimal = parseInt(baseParts[1], 10);
505
517
  try {
506
- const dirs = (0, core_js_1.listSubDirs)(phasesDirPath, true);
518
+ const dirs = await (0, core_js_1.listSubDirsAsync)(phasesDirPath, true);
507
519
  const decPattern = new RegExp(`^${baseInt}\\.(\\d+)-(.+)$`);
508
520
  const toRename = [];
509
521
  for (const dir of dirs) {
@@ -513,18 +525,19 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
513
525
  }
514
526
  }
515
527
  toRename.sort((a, b) => b.oldDecimal - a.oldDecimal);
528
+ // Sequential renames — order matters
516
529
  for (const item of toRename) {
517
530
  const newDecimal = item.oldDecimal - 1;
518
531
  const oldPhaseId = `${baseInt}.${item.oldDecimal}`;
519
532
  const newPhaseId = `${baseInt}.${newDecimal}`;
520
533
  const newDirName = `${baseInt}.${newDecimal}-${item.slug}`;
521
- node_fs_1.default.renameSync(node_path_1.default.join(phasesDirPath, item.dir), node_path_1.default.join(phasesDirPath, newDirName));
534
+ await node_fs_1.promises.rename(node_path_1.default.join(phasesDirPath, item.dir), node_path_1.default.join(phasesDirPath, newDirName));
522
535
  renamedDirs.push({ from: item.dir, to: newDirName });
523
- const dirFiles = node_fs_1.default.readdirSync(node_path_1.default.join(phasesDirPath, newDirName));
536
+ const dirFiles = await node_fs_1.promises.readdir(node_path_1.default.join(phasesDirPath, newDirName));
524
537
  for (const f of dirFiles) {
525
538
  if (f.includes(oldPhaseId)) {
526
539
  const newFileName = f.replace(oldPhaseId, newPhaseId);
527
- node_fs_1.default.renameSync(node_path_1.default.join(phasesDirPath, newDirName, f), node_path_1.default.join(phasesDirPath, newDirName, newFileName));
540
+ await node_fs_1.promises.rename(node_path_1.default.join(phasesDirPath, newDirName, f), node_path_1.default.join(phasesDirPath, newDirName, newFileName));
528
541
  renamedFiles.push({ from: f, to: newFileName });
529
542
  }
530
543
  }
@@ -537,7 +550,7 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
537
550
  else {
538
551
  const removedInt = parseInt(normalized, 10);
539
552
  try {
540
- const dirs = (0, core_js_1.listSubDirs)(phasesDirPath, true);
553
+ const dirs = await (0, core_js_1.listSubDirsAsync)(phasesDirPath, true);
541
554
  const toRename = [];
542
555
  for (const dir of dirs) {
543
556
  const dm = dir.match(/^(\d+)([A-Z])?(?:\.(\d+))?-(.+)$/i);
@@ -559,6 +572,7 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
559
572
  return b.oldInt - a.oldInt;
560
573
  return (b.decimal || 0) - (a.decimal || 0);
561
574
  });
575
+ // Sequential renames — order matters
562
576
  for (const item of toRename) {
563
577
  const newInt = item.oldInt - 1;
564
578
  const newPadded = String(newInt).padStart(2, '0');
@@ -568,13 +582,13 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
568
582
  const oldPrefix = `${oldPadded}${letterSuffix}${decimalSuffix}`;
569
583
  const newPrefix = `${newPadded}${letterSuffix}${decimalSuffix}`;
570
584
  const newDirName = `${newPrefix}-${item.slug}`;
571
- node_fs_1.default.renameSync(node_path_1.default.join(phasesDirPath, item.dir), node_path_1.default.join(phasesDirPath, newDirName));
585
+ await node_fs_1.promises.rename(node_path_1.default.join(phasesDirPath, item.dir), node_path_1.default.join(phasesDirPath, newDirName));
572
586
  renamedDirs.push({ from: item.dir, to: newDirName });
573
- const dirFiles = node_fs_1.default.readdirSync(node_path_1.default.join(phasesDirPath, newDirName));
587
+ const dirFiles = await node_fs_1.promises.readdir(node_path_1.default.join(phasesDirPath, newDirName));
574
588
  for (const f of dirFiles) {
575
589
  if (f.startsWith(oldPrefix)) {
576
590
  const newFileName = newPrefix + f.slice(oldPrefix.length);
577
- node_fs_1.default.renameSync(node_path_1.default.join(phasesDirPath, newDirName, f), node_path_1.default.join(phasesDirPath, newDirName, newFileName));
591
+ await node_fs_1.promises.rename(node_path_1.default.join(phasesDirPath, newDirName, f), node_path_1.default.join(phasesDirPath, newDirName, newFileName));
578
592
  renamedFiles.push({ from: f, to: newFileName });
579
593
  }
580
594
  }
@@ -585,7 +599,7 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
585
599
  }
586
600
  }
587
601
  // Update ROADMAP.md
588
- let roadmapContent = node_fs_1.default.readFileSync(rmPath, 'utf-8');
602
+ let roadmapContent = await node_fs_1.promises.readFile(rmPath, 'utf-8');
589
603
  const targetEscaped = (0, core_js_1.escapePhaseNum)(targetPhase);
590
604
  const sectionPattern = new RegExp(`\\n?#{2,4}\\s*Phase\\s+${targetEscaped}\\s*:[\\s\\S]*?(?=\\n#{2,4}\\s+Phase\\s+\\d|$)`, 'i');
591
605
  roadmapContent = roadmapContent.replace(sectionPattern, '');
@@ -609,11 +623,12 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
609
623
  roadmapContent = roadmapContent.replace(new RegExp(`(Depends on:\\*\\*\\s*Phase\\s+)${oldStr}\\b`, 'gi'), `$1${newStr}`);
610
624
  }
611
625
  }
612
- node_fs_1.default.writeFileSync(rmPath, roadmapContent, 'utf-8');
626
+ await node_fs_1.promises.writeFile(rmPath, roadmapContent, 'utf-8');
613
627
  // Update STATE.md phase count
614
628
  const stPath = (0, core_js_1.statePath)(cwd);
615
- if (node_fs_1.default.existsSync(stPath)) {
616
- let stateContent = node_fs_1.default.readFileSync(stPath, 'utf-8');
629
+ const stExists = await (0, core_js_1.pathExistsAsync)(stPath);
630
+ if (stExists) {
631
+ let stateContent = await node_fs_1.promises.readFile(stPath, 'utf-8');
617
632
  const totalPattern = /(\*\*Total Phases:\*\*\s*)(\d+)/;
618
633
  const totalMatch = stateContent.match(totalPattern);
619
634
  if (totalMatch) {
@@ -626,7 +641,7 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
626
641
  const oldTotal = parseInt(ofMatch[2], 10);
627
642
  stateContent = stateContent.replace(ofPattern, `$1${oldTotal - 1}$3`);
628
643
  }
629
- node_fs_1.default.writeFileSync(stPath, stateContent, 'utf-8');
644
+ await node_fs_1.promises.writeFile(stPath, stateContent, 'utf-8');
630
645
  }
631
646
  return (0, types_js_1.cmdOk)({
632
647
  removed: targetPhase,
@@ -634,16 +649,16 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
634
649
  renamed_directories: renamedDirs,
635
650
  renamed_files: renamedFiles,
636
651
  roadmap_updated: true,
637
- state_updated: node_fs_1.default.existsSync(stPath),
652
+ state_updated: stExists,
638
653
  });
639
654
  }
640
655
  // ─── Phase complete ─────────────────────────────────────────────────────────
641
- function cmdPhaseComplete(cwd, phaseNum) {
656
+ async function cmdPhaseComplete(cwd, phaseNum) {
642
657
  if (!phaseNum) {
643
658
  return (0, types_js_1.cmdErr)('phase number required for phase complete');
644
659
  }
645
660
  try {
646
- const result = phaseCompleteCore(cwd, phaseNum);
661
+ const result = await phaseCompleteCore(cwd, phaseNum);
647
662
  return (0, types_js_1.cmdOk)({
648
663
  completed_phase: result.completed_phase,
649
664
  phase_name: result.phase_name,