maxsimcli 4.1.0 → 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 (79) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/assets/CHANGELOG.md +8 -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-server.cjs +174 -51
  33. package/dist/backend-server.cjs.map +1 -1
  34. package/dist/cli.cjs +310 -146
  35. package/dist/cli.cjs.map +1 -1
  36. package/dist/cli.js +5 -5
  37. package/dist/cli.js.map +1 -1
  38. package/dist/core/artefakte.d.ts.map +1 -1
  39. package/dist/core/artefakte.js +16 -0
  40. package/dist/core/artefakte.js.map +1 -1
  41. package/dist/core/context-loader.d.ts +1 -0
  42. package/dist/core/context-loader.d.ts.map +1 -1
  43. package/dist/core/context-loader.js +58 -0
  44. package/dist/core/context-loader.js.map +1 -1
  45. package/dist/core/core.d.ts +6 -0
  46. package/dist/core/core.d.ts.map +1 -1
  47. package/dist/core/core.js +238 -0
  48. package/dist/core/core.js.map +1 -1
  49. package/dist/core/index.d.ts +1 -1
  50. package/dist/core/index.d.ts.map +1 -1
  51. package/dist/core/index.js +5 -3
  52. package/dist/core/index.js.map +1 -1
  53. package/dist/core/phase.d.ts +11 -11
  54. package/dist/core/phase.d.ts.map +1 -1
  55. package/dist/core/phase.js +88 -73
  56. package/dist/core/phase.js.map +1 -1
  57. package/dist/core/roadmap.d.ts +2 -2
  58. package/dist/core/roadmap.d.ts.map +1 -1
  59. package/dist/core/roadmap.js +11 -10
  60. package/dist/core/roadmap.js.map +1 -1
  61. package/dist/core/state.d.ts +11 -11
  62. package/dist/core/state.d.ts.map +1 -1
  63. package/dist/core/state.js +60 -54
  64. package/dist/core/state.js.map +1 -1
  65. package/dist/core-RRjCSt0G.cjs.map +1 -1
  66. package/dist/{lifecycle-D4E9yP6E.cjs → lifecycle-0M4VqOMm.cjs} +2 -2
  67. package/dist/{lifecycle-D4E9yP6E.cjs.map → lifecycle-0M4VqOMm.cjs.map} +1 -1
  68. package/dist/mcp/context-tools.d.ts.map +1 -1
  69. package/dist/mcp/context-tools.js +7 -3
  70. package/dist/mcp/context-tools.js.map +1 -1
  71. package/dist/mcp/phase-tools.js +3 -3
  72. package/dist/mcp/phase-tools.js.map +1 -1
  73. package/dist/mcp-server.cjs +163 -40
  74. package/dist/mcp-server.cjs.map +1 -1
  75. package/dist/{server-pvY2WbKj.cjs → server-G1MIg_Oe.cjs} +7 -7
  76. package/dist/server-G1MIg_Oe.cjs.map +1 -0
  77. package/package.json +1 -1
  78. package/dist/assets/dashboard/client/assets/index-CmiJKqOU.css +0 -32
  79. package/dist/server-pvY2WbKj.cjs.map +0 -1
package/dist/cli.cjs CHANGED
@@ -607,7 +607,7 @@ var require_has_flag = /* @__PURE__ */ __commonJSMin(((exports, module) => {
607
607
  //#endregion
608
608
  //#region ../../node_modules/supports-color/index.js
609
609
  var require_supports_color = /* @__PURE__ */ __commonJSMin(((exports, module) => {
610
- const os$5 = require("os");
610
+ const os$6 = require("os");
611
611
  const tty$2 = require("tty");
612
612
  const hasFlag = require_has_flag();
613
613
  const { env } = process;
@@ -634,7 +634,7 @@ var require_supports_color = /* @__PURE__ */ __commonJSMin(((exports, module) =>
634
634
  const min = forceColor || 0;
635
635
  if (env.TERM === "dumb") return min;
636
636
  if (process.platform === "win32") {
637
- const osRelease = os$5.release().split(".");
637
+ const osRelease = os$6.release().split(".");
638
638
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
639
639
  return 1;
640
640
  }
@@ -5153,6 +5153,100 @@ function getMilestoneInfo(cwd) {
5153
5153
  };
5154
5154
  }
5155
5155
  }
5156
+ async function pathExistsAsync(p) {
5157
+ try {
5158
+ await node_fs.promises.access(p);
5159
+ return true;
5160
+ } catch {
5161
+ return false;
5162
+ }
5163
+ }
5164
+ async function searchPhaseInDirAsync(baseDir, relBase, normalized) {
5165
+ try {
5166
+ const match = (await listSubDirsAsync(baseDir, true)).find((d) => d.startsWith(normalized));
5167
+ if (!match) return null;
5168
+ const dirMatch = match.match(/^(\d+[A-Z]?(?:\.\d+)?)-?(.*)/i);
5169
+ const phaseNumber = dirMatch ? dirMatch[1] : normalized;
5170
+ const phaseName = dirMatch && dirMatch[2] ? dirMatch[2] : null;
5171
+ const phaseDir = node_path.default.join(baseDir, match);
5172
+ const phaseFiles = await node_fs.promises.readdir(phaseDir);
5173
+ const plans = phaseFiles.filter(isPlanFile).sort();
5174
+ const summaries = phaseFiles.filter(isSummaryFile).sort();
5175
+ const hasResearch = phaseFiles.some((f) => f.endsWith("-RESEARCH.md") || f === "RESEARCH.md");
5176
+ const hasContext = phaseFiles.some((f) => f.endsWith("-CONTEXT.md") || f === "CONTEXT.md");
5177
+ const hasVerification = phaseFiles.some((f) => f.endsWith("-VERIFICATION.md") || f === "VERIFICATION.md");
5178
+ const completedPlanIds = new Set(summaries.map(summaryId));
5179
+ const incompletePlans = plans.filter((p) => !completedPlanIds.has(planId(p)));
5180
+ return {
5181
+ found: true,
5182
+ directory: node_path.default.join(relBase, match),
5183
+ phase_number: phaseNumber,
5184
+ phase_name: phaseName,
5185
+ phase_slug: phaseName ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") : null,
5186
+ plans,
5187
+ summaries,
5188
+ incomplete_plans: incompletePlans,
5189
+ has_research: hasResearch,
5190
+ has_context: hasContext,
5191
+ has_verification: hasVerification
5192
+ };
5193
+ } catch (e) {
5194
+ debugLog("search-phase-in-dir-async-failed", {
5195
+ dir: baseDir,
5196
+ phase: normalized,
5197
+ error: errorMsg(e)
5198
+ });
5199
+ return null;
5200
+ }
5201
+ }
5202
+ async function findPhaseInternalAsync(cwd, phase) {
5203
+ if (!phase) return null;
5204
+ const pd = phasesPath(cwd);
5205
+ const normalized = normalizePhaseName(phase);
5206
+ const current = await searchPhaseInDirAsync(pd, node_path.default.join(".planning", "phases"), normalized);
5207
+ if (current) return current;
5208
+ const milestonesDir = planningPath(cwd, "milestones");
5209
+ if (!await pathExistsAsync(milestonesDir)) return null;
5210
+ try {
5211
+ const archiveDirs = (await node_fs.promises.readdir(milestonesDir, { withFileTypes: true })).filter((e) => e.isDirectory() && /^v[\d.]+-phases$/.test(e.name)).map((e) => e.name).sort().reverse();
5212
+ for (const archiveName of archiveDirs) {
5213
+ const versionMatch = archiveName.match(/^(v[\d.]+)-phases$/);
5214
+ if (!versionMatch) continue;
5215
+ const version = versionMatch[1];
5216
+ const result = await searchPhaseInDirAsync(node_path.default.join(milestonesDir, archiveName), node_path.default.join(".planning", "milestones", archiveName), normalized);
5217
+ if (result) {
5218
+ result.archived = version;
5219
+ return result;
5220
+ }
5221
+ }
5222
+ } catch (e) {
5223
+ debugLog("find-phase-async-milestone-search-failed", e);
5224
+ }
5225
+ return null;
5226
+ }
5227
+ async function getArchivedPhaseDirsAsync(cwd) {
5228
+ const milestonesDir = planningPath(cwd, "milestones");
5229
+ const results = [];
5230
+ try {
5231
+ const phaseDirs = (await node_fs.promises.readdir(milestonesDir, { withFileTypes: true })).filter((e) => e.isDirectory() && /^v[\d.]+-phases$/.test(e.name)).map((e) => e.name).sort().reverse();
5232
+ for (const archiveName of phaseDirs) {
5233
+ const versionMatch = archiveName.match(/^(v[\d.]+)-phases$/);
5234
+ if (!versionMatch) continue;
5235
+ const version = versionMatch[1];
5236
+ const archivePath = node_path.default.join(milestonesDir, archiveName);
5237
+ const dirs = await listSubDirsAsync(archivePath, true);
5238
+ for (const dir of dirs) results.push({
5239
+ name: dir,
5240
+ milestone: version,
5241
+ basePath: node_path.default.join(".planning", "milestones", archiveName),
5242
+ fullPath: node_path.default.join(archivePath, dir)
5243
+ });
5244
+ }
5245
+ } catch (e) {
5246
+ debugLog("get-archived-phase-dirs-async-failed", e);
5247
+ }
5248
+ return results;
5249
+ }
5156
5250
 
5157
5251
  //#endregion
5158
5252
  //#region ../../node_modules/yaml/dist/nodes/identity.js
@@ -12108,11 +12202,11 @@ function stateReplaceField(content, fieldName, newValue) {
12108
12202
  replaced = content.replace(plainPattern, (_match, prefix) => `${prefix}${newValue}`);
12109
12203
  return replaced !== content ? replaced : null;
12110
12204
  }
12111
- function readTextArgOrFile(cwd, value, filePath, label) {
12205
+ async function readTextArgOrFile(cwd, value, filePath, label) {
12112
12206
  if (!filePath) return value;
12113
12207
  const resolvedPath = node_path.default.isAbsolute(filePath) ? filePath : node_path.default.join(cwd, filePath);
12114
12208
  try {
12115
- return node_fs.default.readFileSync(resolvedPath, "utf-8").trimEnd();
12209
+ return (await node_fs.promises.readFile(resolvedPath, "utf-8")).trimEnd();
12116
12210
  } catch {
12117
12211
  throw new Error(`${label} file not found: ${filePath}`);
12118
12212
  }
@@ -12137,8 +12231,8 @@ async function cmdStateLoad(cwd, raw) {
12137
12231
  const config = loadConfig(cwd);
12138
12232
  const [stateContent, configExists, roadmapExists] = await Promise.all([
12139
12233
  safeReadFileAsync(statePath(cwd)),
12140
- node_fs.default.promises.access(configPath(cwd)).then(() => true, () => false),
12141
- node_fs.default.promises.access(roadmapPath(cwd)).then(() => true, () => false)
12234
+ pathExistsAsync(configPath(cwd)),
12235
+ pathExistsAsync(roadmapPath(cwd))
12142
12236
  ]);
12143
12237
  const stateRaw = stateContent ?? "";
12144
12238
  const stateExists = stateRaw.length > 0;
@@ -12168,10 +12262,10 @@ async function cmdStateLoad(cwd, raw) {
12168
12262
  }
12169
12263
  return cmdOk(result);
12170
12264
  }
12171
- function cmdStateGet(cwd, section, raw) {
12265
+ async function cmdStateGet(cwd, section, raw) {
12172
12266
  const statePath$2 = statePath(cwd);
12173
12267
  try {
12174
- const content = node_fs.default.readFileSync(statePath$2, "utf-8");
12268
+ const content = await node_fs.promises.readFile(statePath$2, "utf-8");
12175
12269
  if (!section) return cmdOk({ content }, raw ? content : void 0);
12176
12270
  const fieldValue = stateExtractField(content, section);
12177
12271
  if (fieldValue !== null) return cmdOk({ [section]: fieldValue }, raw ? fieldValue : void 0);
@@ -12185,10 +12279,10 @@ function cmdStateGet(cwd, section, raw) {
12185
12279
  return cmdErr("STATE.md not found");
12186
12280
  }
12187
12281
  }
12188
- function cmdStatePatch(cwd, patches, raw) {
12282
+ async function cmdStatePatch(cwd, patches, raw) {
12189
12283
  const statePath$3 = statePath(cwd);
12190
12284
  try {
12191
- let content = node_fs.default.readFileSync(statePath$3, "utf-8");
12285
+ let content = await node_fs.promises.readFile(statePath$3, "utf-8");
12192
12286
  const results = {
12193
12287
  updated: [],
12194
12288
  failed: []
@@ -12200,20 +12294,20 @@ function cmdStatePatch(cwd, patches, raw) {
12200
12294
  results.updated.push(field);
12201
12295
  } else results.failed.push(field);
12202
12296
  }
12203
- if (results.updated.length > 0) node_fs.default.writeFileSync(statePath$3, content, "utf-8");
12297
+ if (results.updated.length > 0) await node_fs.promises.writeFile(statePath$3, content, "utf-8");
12204
12298
  return cmdOk(results, raw ? results.updated.length > 0 ? "true" : "false" : void 0);
12205
12299
  } catch (e) {
12206
12300
  rethrowCliSignals(e);
12207
12301
  return cmdErr("STATE.md not found");
12208
12302
  }
12209
12303
  }
12210
- function cmdStateUpdate(cwd, field, value) {
12304
+ async function cmdStateUpdate(cwd, field, value) {
12211
12305
  if (!field || value === void 0) return cmdErr("field and value required for state update");
12212
12306
  const statePath$4 = statePath(cwd);
12213
12307
  try {
12214
- const result = stateReplaceField(node_fs.default.readFileSync(statePath$4, "utf-8"), field, value);
12308
+ const result = stateReplaceField(await node_fs.promises.readFile(statePath$4, "utf-8"), field, value);
12215
12309
  if (result) {
12216
- node_fs.default.writeFileSync(statePath$4, result, "utf-8");
12310
+ await node_fs.promises.writeFile(statePath$4, result, "utf-8");
12217
12311
  return cmdOk({ updated: true });
12218
12312
  } else return cmdOk({
12219
12313
  updated: false,
@@ -12227,10 +12321,10 @@ function cmdStateUpdate(cwd, field, value) {
12227
12321
  });
12228
12322
  }
12229
12323
  }
12230
- function cmdStateAdvancePlan(cwd, raw) {
12324
+ async function cmdStateAdvancePlan(cwd, raw) {
12231
12325
  const statePath$5 = statePath(cwd);
12232
- if (!node_fs.default.existsSync(statePath$5)) return cmdOk({ error: "STATE.md not found" });
12233
- let content = node_fs.default.readFileSync(statePath$5, "utf-8");
12326
+ if (!await pathExistsAsync(statePath$5)) return cmdOk({ error: "STATE.md not found" });
12327
+ let content = await node_fs.promises.readFile(statePath$5, "utf-8");
12234
12328
  const currentPlan = parseInt(stateExtractField(content, "Current Plan") ?? "", 10);
12235
12329
  const totalPlans = parseInt(stateExtractField(content, "Total Plans in Phase") ?? "", 10);
12236
12330
  const today = todayISO();
@@ -12238,7 +12332,7 @@ function cmdStateAdvancePlan(cwd, raw) {
12238
12332
  if (currentPlan >= totalPlans) {
12239
12333
  content = stateReplaceField(content, "Status", "Phase complete — ready for verification") || content;
12240
12334
  content = stateReplaceField(content, "Last Activity", today) || content;
12241
- node_fs.default.writeFileSync(statePath$5, content, "utf-8");
12335
+ await node_fs.promises.writeFile(statePath$5, content, "utf-8");
12242
12336
  return cmdOk({
12243
12337
  advanced: false,
12244
12338
  reason: "last_plan",
@@ -12251,7 +12345,7 @@ function cmdStateAdvancePlan(cwd, raw) {
12251
12345
  content = stateReplaceField(content, "Current Plan", String(newPlan)) || content;
12252
12346
  content = stateReplaceField(content, "Status", "Ready to execute") || content;
12253
12347
  content = stateReplaceField(content, "Last Activity", today) || content;
12254
- node_fs.default.writeFileSync(statePath$5, content, "utf-8");
12348
+ await node_fs.promises.writeFile(statePath$5, content, "utf-8");
12255
12349
  return cmdOk({
12256
12350
  advanced: true,
12257
12351
  previous_plan: currentPlan,
@@ -12260,10 +12354,10 @@ function cmdStateAdvancePlan(cwd, raw) {
12260
12354
  }, raw ? "true" : void 0);
12261
12355
  }
12262
12356
  }
12263
- function cmdStateRecordMetric(cwd, options, raw) {
12357
+ async function cmdStateRecordMetric(cwd, options, raw) {
12264
12358
  const statePath$6 = statePath(cwd);
12265
- if (!node_fs.default.existsSync(statePath$6)) return cmdOk({ error: "STATE.md not found" });
12266
- let content = node_fs.default.readFileSync(statePath$6, "utf-8");
12359
+ if (!await pathExistsAsync(statePath$6)) return cmdOk({ error: "STATE.md not found" });
12360
+ let content = await node_fs.promises.readFile(statePath$6, "utf-8");
12267
12361
  const { phase, plan, duration, tasks, files } = options;
12268
12362
  if (!phase || !plan || !duration) return cmdOk({ error: "phase, plan, and duration required" });
12269
12363
  const metricsPattern = /(#{2,3}\s*Performance Metrics[\s\S]*?\n\|[^\n]+\n\|[\s:|\-]+\n)([\s\S]*?)(?=\n#{2,3}\s|\n$|$)/i;
@@ -12274,7 +12368,7 @@ function cmdStateRecordMetric(cwd, options, raw) {
12274
12368
  if (tableBody.trim() === "" || tableBody.includes("None yet")) tableBody = newRow;
12275
12369
  else tableBody = tableBody + "\n" + newRow;
12276
12370
  content = content.replace(metricsPattern, (_match, header) => `${header}${tableBody}\n`);
12277
- node_fs.default.writeFileSync(statePath$6, content, "utf-8");
12371
+ await node_fs.promises.writeFile(statePath$6, content, "utf-8");
12278
12372
  return cmdOk({
12279
12373
  recorded: true,
12280
12374
  phase,
@@ -12286,19 +12380,25 @@ function cmdStateRecordMetric(cwd, options, raw) {
12286
12380
  reason: "Performance Metrics section not found in STATE.md"
12287
12381
  }, raw ? "false" : void 0);
12288
12382
  }
12289
- function cmdStateUpdateProgress(cwd, raw) {
12383
+ async function cmdStateUpdateProgress(cwd, raw) {
12290
12384
  const statePath$7 = statePath(cwd);
12291
- if (!node_fs.default.existsSync(statePath$7)) return cmdOk({ error: "STATE.md not found" });
12292
- let content = node_fs.default.readFileSync(statePath$7, "utf-8");
12385
+ if (!await pathExistsAsync(statePath$7)) return cmdOk({ error: "STATE.md not found" });
12386
+ let content = await node_fs.promises.readFile(statePath$7, "utf-8");
12293
12387
  const phasesDir = phasesPath(cwd);
12294
12388
  let totalPlans = 0;
12295
12389
  let totalSummaries = 0;
12296
- if (node_fs.default.existsSync(phasesDir)) {
12297
- const phaseDirs = node_fs.default.readdirSync(phasesDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
12298
- for (const dir of phaseDirs) {
12299
- const files = node_fs.default.readdirSync(node_path.default.join(phasesDir, dir));
12300
- totalPlans += files.filter((f) => isPlanFile(f)).length;
12301
- totalSummaries += files.filter((f) => isSummaryFile(f)).length;
12390
+ if (await pathExistsAsync(phasesDir)) {
12391
+ const phaseDirs = (await node_fs.promises.readdir(phasesDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
12392
+ const counts = await Promise.all(phaseDirs.map(async (dir) => {
12393
+ const files = await node_fs.promises.readdir(node_path.default.join(phasesDir, dir));
12394
+ return {
12395
+ plans: files.filter((f) => isPlanFile(f)).length,
12396
+ summaries: files.filter((f) => isSummaryFile(f)).length
12397
+ };
12398
+ }));
12399
+ for (const c of counts) {
12400
+ totalPlans += c.plans;
12401
+ totalSummaries += c.summaries;
12302
12402
  }
12303
12403
  }
12304
12404
  const percent = totalPlans > 0 ? Math.min(100, Math.round(totalSummaries / totalPlans * 100)) : 0;
@@ -12307,7 +12407,7 @@ function cmdStateUpdateProgress(cwd, raw) {
12307
12407
  const progressStr = `[${"█".repeat(filled) + "░".repeat(barWidth - filled)}] ${percent}%`;
12308
12408
  const result = stateReplaceField(content, "Progress", progressStr);
12309
12409
  if (result) {
12310
- node_fs.default.writeFileSync(statePath$7, result, "utf-8");
12410
+ await node_fs.promises.writeFile(statePath$7, result, "utf-8");
12311
12411
  return cmdOk({
12312
12412
  updated: true,
12313
12413
  percent,
@@ -12320,15 +12420,15 @@ function cmdStateUpdateProgress(cwd, raw) {
12320
12420
  reason: "Progress field not found in STATE.md"
12321
12421
  }, raw ? "false" : void 0);
12322
12422
  }
12323
- function cmdStateAddDecision(cwd, options, raw) {
12423
+ async function cmdStateAddDecision(cwd, options, raw) {
12324
12424
  const statePath$8 = statePath(cwd);
12325
- if (!node_fs.default.existsSync(statePath$8)) return cmdOk({ error: "STATE.md not found" });
12425
+ if (!await pathExistsAsync(statePath$8)) return cmdOk({ error: "STATE.md not found" });
12326
12426
  const { phase, summary, summary_file, rationale, rationale_file } = options;
12327
12427
  let summaryText;
12328
12428
  let rationaleText = "";
12329
12429
  try {
12330
- summaryText = readTextArgOrFile(cwd, summary, summary_file, "summary");
12331
- rationaleText = readTextArgOrFile(cwd, rationale || "", rationale_file, "rationale") || "";
12430
+ summaryText = await readTextArgOrFile(cwd, summary, summary_file, "summary");
12431
+ rationaleText = await readTextArgOrFile(cwd, rationale || "", rationale_file, "rationale") || "";
12332
12432
  } catch (thrown) {
12333
12433
  return cmdOk({
12334
12434
  added: false,
@@ -12336,11 +12436,11 @@ function cmdStateAddDecision(cwd, options, raw) {
12336
12436
  }, raw ? "false" : void 0);
12337
12437
  }
12338
12438
  if (!summaryText) return cmdOk({ error: "summary required" });
12339
- const content = node_fs.default.readFileSync(statePath$8, "utf-8");
12439
+ const content = await node_fs.promises.readFile(statePath$8, "utf-8");
12340
12440
  const entry = `- [Phase ${phase || "?"}]: ${summaryText}${rationaleText ? ` — ${rationaleText}` : ""}`;
12341
12441
  const updated = appendToStateSection(content, /(###?\s*(?:Decisions|Decisions Made|Accumulated.*Decisions)\s*\n)([\s\S]*?)(?=\n###?|\n##[^#]|$)/i, entry, [/None yet\.?\s*\n?/gi, /No decisions yet\.?\s*\n?/gi]);
12342
12442
  if (updated) {
12343
- node_fs.default.writeFileSync(statePath$8, updated, "utf-8");
12443
+ await node_fs.promises.writeFile(statePath$8, updated, "utf-8");
12344
12444
  return cmdOk({
12345
12445
  added: true,
12346
12446
  decision: entry
@@ -12350,13 +12450,13 @@ function cmdStateAddDecision(cwd, options, raw) {
12350
12450
  reason: "Decisions section not found in STATE.md"
12351
12451
  }, raw ? "false" : void 0);
12352
12452
  }
12353
- function cmdStateAddBlocker(cwd, text, raw) {
12453
+ async function cmdStateAddBlocker(cwd, text, raw) {
12354
12454
  const statePath$9 = statePath(cwd);
12355
- if (!node_fs.default.existsSync(statePath$9)) return cmdOk({ error: "STATE.md not found" });
12455
+ if (!await pathExistsAsync(statePath$9)) return cmdOk({ error: "STATE.md not found" });
12356
12456
  const blockerOptions = typeof text === "object" && text !== null ? text : { text };
12357
12457
  let blockerText;
12358
12458
  try {
12359
- blockerText = readTextArgOrFile(cwd, blockerOptions.text, blockerOptions.text_file, "blocker");
12459
+ blockerText = await readTextArgOrFile(cwd, blockerOptions.text, blockerOptions.text_file, "blocker");
12360
12460
  } catch (thrown) {
12361
12461
  return cmdOk({
12362
12462
  added: false,
@@ -12364,9 +12464,9 @@ function cmdStateAddBlocker(cwd, text, raw) {
12364
12464
  }, raw ? "false" : void 0);
12365
12465
  }
12366
12466
  if (!blockerText) return cmdOk({ error: "text required" });
12367
- const updated = appendToStateSection(node_fs.default.readFileSync(statePath$9, "utf-8"), /(###?\s*(?:Blockers|Blockers\/Concerns|Concerns)\s*\n)([\s\S]*?)(?=\n###?|\n##[^#]|$)/i, `- ${blockerText}`, [/None\.?\s*\n?/gi, /None yet\.?\s*\n?/gi]);
12467
+ const updated = appendToStateSection(await node_fs.promises.readFile(statePath$9, "utf-8"), /(###?\s*(?:Blockers|Blockers\/Concerns|Concerns)\s*\n)([\s\S]*?)(?=\n###?|\n##[^#]|$)/i, `- ${blockerText}`, [/None\.?\s*\n?/gi, /None yet\.?\s*\n?/gi]);
12368
12468
  if (updated) {
12369
- node_fs.default.writeFileSync(statePath$9, updated, "utf-8");
12469
+ await node_fs.promises.writeFile(statePath$9, updated, "utf-8");
12370
12470
  return cmdOk({
12371
12471
  added: true,
12372
12472
  blocker: blockerText
@@ -12376,11 +12476,11 @@ function cmdStateAddBlocker(cwd, text, raw) {
12376
12476
  reason: "Blockers section not found in STATE.md"
12377
12477
  }, raw ? "false" : void 0);
12378
12478
  }
12379
- function cmdStateResolveBlocker(cwd, text, raw) {
12479
+ async function cmdStateResolveBlocker(cwd, text, raw) {
12380
12480
  const statePath$10 = statePath(cwd);
12381
- if (!node_fs.default.existsSync(statePath$10)) return cmdOk({ error: "STATE.md not found" });
12481
+ if (!await pathExistsAsync(statePath$10)) return cmdOk({ error: "STATE.md not found" });
12382
12482
  if (!text) return cmdOk({ error: "text required" });
12383
- let content = node_fs.default.readFileSync(statePath$10, "utf-8");
12483
+ let content = await node_fs.promises.readFile(statePath$10, "utf-8");
12384
12484
  const sectionPattern = /(#{2,3}\s*(?:Blockers|Blockers\/Concerns|Concerns)\s*\n\s*\n?)([\s\S]*?)(?=\n#{2,3}\s|$)/i;
12385
12485
  const match = content.match(sectionPattern);
12386
12486
  if (match) {
@@ -12390,7 +12490,7 @@ function cmdStateResolveBlocker(cwd, text, raw) {
12390
12490
  }).join("\n");
12391
12491
  if (!newBody.trim() || !/^\s*[-*]\s+/m.test(newBody)) newBody = "None\n";
12392
12492
  content = content.replace(sectionPattern, (_match, header) => `${header}${newBody}`);
12393
- node_fs.default.writeFileSync(statePath$10, content, "utf-8");
12493
+ await node_fs.promises.writeFile(statePath$10, content, "utf-8");
12394
12494
  return cmdOk({
12395
12495
  resolved: true,
12396
12496
  blocker: text
@@ -12400,10 +12500,10 @@ function cmdStateResolveBlocker(cwd, text, raw) {
12400
12500
  reason: "Blockers section not found in STATE.md"
12401
12501
  }, raw ? "false" : void 0);
12402
12502
  }
12403
- function cmdStateRecordSession(cwd, options, raw) {
12503
+ async function cmdStateRecordSession(cwd, options, raw) {
12404
12504
  const statePath$11 = statePath(cwd);
12405
- if (!node_fs.default.existsSync(statePath$11)) return cmdOk({ error: "STATE.md not found" });
12406
- let content = node_fs.default.readFileSync(statePath$11, "utf-8");
12505
+ if (!await pathExistsAsync(statePath$11)) return cmdOk({ error: "STATE.md not found" });
12506
+ let content = await node_fs.promises.readFile(statePath$11, "utf-8");
12407
12507
  const now = (/* @__PURE__ */ new Date()).toISOString();
12408
12508
  const updated = [];
12409
12509
  let result = stateReplaceField(content, "Last session", now);
@@ -12432,7 +12532,7 @@ function cmdStateRecordSession(cwd, options, raw) {
12432
12532
  updated.push("Resume File");
12433
12533
  }
12434
12534
  if (updated.length > 0) {
12435
- node_fs.default.writeFileSync(statePath$11, content, "utf-8");
12535
+ await node_fs.promises.writeFile(statePath$11, content, "utf-8");
12436
12536
  return cmdOk({
12437
12537
  recorded: true,
12438
12538
  updated
@@ -12442,10 +12542,10 @@ function cmdStateRecordSession(cwd, options, raw) {
12442
12542
  reason: "No session fields found in STATE.md"
12443
12543
  }, raw ? "false" : void 0);
12444
12544
  }
12445
- function cmdStateSnapshot(cwd, raw) {
12545
+ async function cmdStateSnapshot(cwd, raw) {
12446
12546
  const statePath$12 = statePath(cwd);
12447
- if (!node_fs.default.existsSync(statePath$12)) return cmdOk({ error: "STATE.md not found" });
12448
- const content = node_fs.default.readFileSync(statePath$12, "utf-8");
12547
+ if (!await pathExistsAsync(statePath$12)) return cmdOk({ error: "STATE.md not found" });
12548
+ const content = await node_fs.promises.readFile(statePath$12, "utf-8");
12449
12549
  const extractField = (fieldName) => stateExtractField(content, fieldName);
12450
12550
  const currentPhase = extractField("Current Phase");
12451
12551
  const currentPhaseName = extractField("Current Phase Name");
@@ -12516,14 +12616,13 @@ function cmdStateSnapshot(cwd, raw) {
12516
12616
  *
12517
12617
  * Ported from maxsim/bin/lib/roadmap.cjs
12518
12618
  */
12519
- function cmdRoadmapGetPhase(cwd, phaseNum) {
12520
- const rmPath = roadmapPath(cwd);
12521
- if (!node_fs.default.existsSync(rmPath)) return cmdOk({
12619
+ async function cmdRoadmapGetPhase(cwd, phaseNum) {
12620
+ const content = await safeReadFileAsync(roadmapPath(cwd));
12621
+ if (!content) return cmdOk({
12522
12622
  found: false,
12523
12623
  error: "ROADMAP.md not found"
12524
12624
  }, "");
12525
12625
  try {
12526
- const content = node_fs.default.readFileSync(rmPath, "utf-8");
12527
12626
  const escapedPhase = phaseNum.replace(/\./g, "\\.");
12528
12627
  const phasePattern = getPhasePattern(escapedPhase, "i");
12529
12628
  const headerMatch = content.match(phasePattern);
@@ -12607,7 +12706,7 @@ async function cmdRoadmapAnalyze(cwd) {
12607
12706
  try {
12608
12707
  const dirMatch = allDirs.find((d) => d.startsWith(p.normalized + "-") || d === p.normalized);
12609
12708
  if (dirMatch) {
12610
- const phaseFiles = await node_fs.default.promises.readdir(node_path.default.join(phasesDir, dirMatch));
12709
+ const phaseFiles = await node_fs.promises.readdir(node_path.default.join(phasesDir, dirMatch));
12611
12710
  planCount = phaseFiles.filter((f) => isPlanFile(f)).length;
12612
12711
  summaryCount = phaseFiles.filter((f) => isSummaryFile(f)).length;
12613
12712
  hasContext = phaseFiles.some((f) => f.endsWith("-CONTEXT.md") || f === "CONTEXT.md");
@@ -12668,10 +12767,10 @@ async function cmdRoadmapAnalyze(cwd) {
12668
12767
  missing_phase_details: missingDetails.length > 0 ? missingDetails : null
12669
12768
  });
12670
12769
  }
12671
- function cmdRoadmapUpdatePlanProgress(cwd, phaseNum) {
12770
+ async function cmdRoadmapUpdatePlanProgress(cwd, phaseNum) {
12672
12771
  if (!phaseNum) return cmdErr("phase number required for roadmap update-plan-progress");
12673
12772
  const rmPath = roadmapPath(cwd);
12674
- const phaseInfo = findPhaseInternal(cwd, phaseNum);
12773
+ const phaseInfo = await findPhaseInternalAsync(cwd, phaseNum);
12675
12774
  if (!phaseInfo) return cmdErr(`Phase ${phaseNum} not found`);
12676
12775
  const planCount = phaseInfo.plans.length;
12677
12776
  const summaryCount = phaseInfo.summaries.length;
@@ -12684,20 +12783,21 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum) {
12684
12783
  const isComplete = summaryCount >= planCount;
12685
12784
  const status = isComplete ? "Complete" : summaryCount > 0 ? "In Progress" : "Planned";
12686
12785
  const today = todayISO();
12687
- if (!node_fs.default.existsSync(rmPath)) return cmdOk({
12786
+ const rawContent = await safeReadFileAsync(rmPath);
12787
+ if (!rawContent) return cmdOk({
12688
12788
  updated: false,
12689
12789
  reason: "ROADMAP.md not found",
12690
12790
  plan_count: planCount,
12691
12791
  summary_count: summaryCount
12692
12792
  }, "no roadmap");
12693
- let roadmapContent = node_fs.default.readFileSync(rmPath, "utf-8");
12793
+ let roadmapContent = rawContent;
12694
12794
  const phaseEscaped = phaseNum.replace(".", "\\.");
12695
12795
  const dateField = isComplete ? ` ${today} ` : " ";
12696
12796
  roadmapContent = roadmapContent.replace(new RegExp(`(\\|\\s*${phaseEscaped}\\.?\\s[^|]*\\|)[^|]*(\\|)\\s*[^|]*(\\|)\\s*[^|]*(\\|)`, "i"), `$1 ${summaryCount}/${planCount} $2 ${status.padEnd(11)}$3${dateField}$4`);
12697
12797
  const planCountText = isComplete ? `${summaryCount}/${planCount} plans complete` : `${summaryCount}/${planCount} plans executed`;
12698
12798
  roadmapContent = roadmapContent.replace(new RegExp(`(#{2,4}\\s*Phase\\s+${phaseEscaped}[\\s\\S]*?\\*\\*Plans:\\*\\*\\s*)[^\\n]+`, "i"), `$1${planCountText}`);
12699
12799
  if (isComplete) roadmapContent = roadmapContent.replace(new RegExp(`(-\\s*\\[)[ ](\\]\\s*.*Phase\\s+${phaseEscaped}[:\\s][^\\n]*)`, "i"), `$1x$2 (completed ${today})`);
12700
- node_fs.default.writeFileSync(rmPath, roadmapContent, "utf-8");
12800
+ await node_fs.promises.writeFile(rmPath, roadmapContent, "utf-8");
12701
12801
  return cmdOk({
12702
12802
  updated: true,
12703
12803
  phase: phaseNum,
@@ -14318,15 +14418,18 @@ function cmdValidateHealth(cwd, options) {
14318
14418
  *
14319
14419
  * Ported from maxsim/bin/lib/phase.cjs
14320
14420
  */
14321
- function scaffoldPhaseStubs(dirPath, phaseId, name) {
14421
+ async function scaffoldPhaseStubs(dirPath, phaseId, name) {
14322
14422
  const today = todayISO();
14323
- node_fs.default.writeFileSync(node_path.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`);
14324
- node_fs.default.writeFileSync(node_path.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`);
14423
+ await Promise.all([node_fs.promises.writeFile(node_path.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`), node_fs.promises.writeFile(node_path.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`)]);
14325
14424
  }
14326
- function phaseAddCore(cwd, description, options) {
14425
+ async function phaseAddCore(cwd, description, options) {
14327
14426
  const rmPath = roadmapPath(cwd);
14328
- if (!node_fs.default.existsSync(rmPath)) throw new Error("ROADMAP.md not found");
14329
- const content = node_fs.default.readFileSync(rmPath, "utf-8");
14427
+ let content;
14428
+ try {
14429
+ content = await node_fs.promises.readFile(rmPath, "utf-8");
14430
+ } catch {
14431
+ throw new Error("ROADMAP.md not found");
14432
+ }
14330
14433
  const slug = generateSlugInternal(description);
14331
14434
  const phasePattern = getPhasePattern();
14332
14435
  let maxPhase = 0;
@@ -14339,15 +14442,15 @@ function phaseAddCore(cwd, description, options) {
14339
14442
  const paddedNum = String(newPhaseNum).padStart(2, "0");
14340
14443
  const dirName = `${paddedNum}-${slug}`;
14341
14444
  const dirPath = planningPath(cwd, "phases", dirName);
14342
- node_fs.default.mkdirSync(dirPath, { recursive: true });
14343
- node_fs.default.writeFileSync(node_path.default.join(dirPath, ".gitkeep"), "");
14344
- if (options?.includeStubs) scaffoldPhaseStubs(dirPath, paddedNum, description);
14445
+ await node_fs.promises.mkdir(dirPath, { recursive: true });
14446
+ await node_fs.promises.writeFile(node_path.default.join(dirPath, ".gitkeep"), "");
14447
+ if (options?.includeStubs) await scaffoldPhaseStubs(dirPath, paddedNum, description);
14345
14448
  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`;
14346
14449
  let updatedContent;
14347
14450
  const lastSeparator = content.lastIndexOf("\n---");
14348
14451
  if (lastSeparator > 0) updatedContent = content.slice(0, lastSeparator) + phaseEntry + content.slice(lastSeparator);
14349
14452
  else updatedContent = content + phaseEntry;
14350
- node_fs.default.writeFileSync(rmPath, updatedContent, "utf-8");
14453
+ await node_fs.promises.writeFile(rmPath, updatedContent, "utf-8");
14351
14454
  return {
14352
14455
  phase_number: newPhaseNum,
14353
14456
  padded: paddedNum,
@@ -14356,10 +14459,14 @@ function phaseAddCore(cwd, description, options) {
14356
14459
  description
14357
14460
  };
14358
14461
  }
14359
- function phaseInsertCore(cwd, afterPhase, description, options) {
14462
+ async function phaseInsertCore(cwd, afterPhase, description, options) {
14360
14463
  const rmPath = roadmapPath(cwd);
14361
- if (!node_fs.default.existsSync(rmPath)) throw new Error("ROADMAP.md not found");
14362
- const content = node_fs.default.readFileSync(rmPath, "utf-8");
14464
+ let content;
14465
+ try {
14466
+ content = await node_fs.promises.readFile(rmPath, "utf-8");
14467
+ } catch {
14468
+ throw new Error("ROADMAP.md not found");
14469
+ }
14363
14470
  const slug = generateSlugInternal(description);
14364
14471
  const afterPhaseEscaped = "0*" + normalizePhaseName(afterPhase).replace(/^0+/, "").replace(/\./g, "\\.");
14365
14472
  if (!getPhasePattern(afterPhaseEscaped, "i").test(content)) throw new Error(`Phase ${afterPhase} not found in ROADMAP.md`);
@@ -14367,7 +14474,7 @@ function phaseInsertCore(cwd, afterPhase, description, options) {
14367
14474
  const normalizedBase = normalizePhaseName(afterPhase);
14368
14475
  const existingDecimals = [];
14369
14476
  try {
14370
- const dirs = listSubDirs(phasesDirPath);
14477
+ const dirs = await listSubDirsAsync(phasesDirPath);
14371
14478
  const decimalPattern = new RegExp(`^${normalizedBase}\\.(\\d+)`);
14372
14479
  for (const dir of dirs) {
14373
14480
  const dm = dir.match(decimalPattern);
@@ -14379,9 +14486,9 @@ function phaseInsertCore(cwd, afterPhase, description, options) {
14379
14486
  const decimalPhase = `${normalizedBase}.${existingDecimals.length === 0 ? 1 : Math.max(...existingDecimals) + 1}`;
14380
14487
  const dirName = `${decimalPhase}-${slug}`;
14381
14488
  const dirPath = planningPath(cwd, "phases", dirName);
14382
- node_fs.default.mkdirSync(dirPath, { recursive: true });
14383
- node_fs.default.writeFileSync(node_path.default.join(dirPath, ".gitkeep"), "");
14384
- if (options?.includeStubs) scaffoldPhaseStubs(dirPath, decimalPhase, description);
14489
+ await node_fs.promises.mkdir(dirPath, { recursive: true });
14490
+ await node_fs.promises.writeFile(node_path.default.join(dirPath, ".gitkeep"), "");
14491
+ if (options?.includeStubs) await scaffoldPhaseStubs(dirPath, decimalPhase, description);
14385
14492
  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`;
14386
14493
  const headerPattern = new RegExp(`(#{2,4}\\s*Phase\\s+0*${afterPhaseEscaped}:[^\\n]*\\n)`, "i");
14387
14494
  const headerMatch = content.match(headerPattern);
@@ -14392,7 +14499,7 @@ function phaseInsertCore(cwd, afterPhase, description, options) {
14392
14499
  if (nextPhaseMatch) insertIdx = headerIdx + headerMatch[0].length + nextPhaseMatch.index;
14393
14500
  else insertIdx = content.length;
14394
14501
  const updatedContent = content.slice(0, insertIdx) + phaseEntry + content.slice(insertIdx);
14395
- node_fs.default.writeFileSync(rmPath, updatedContent, "utf-8");
14502
+ await node_fs.promises.writeFile(rmPath, updatedContent, "utf-8");
14396
14503
  return {
14397
14504
  phase_number: decimalPhase,
14398
14505
  after_phase: afterPhase,
@@ -14401,18 +14508,19 @@ function phaseInsertCore(cwd, afterPhase, description, options) {
14401
14508
  description
14402
14509
  };
14403
14510
  }
14404
- function phaseCompleteCore(cwd, phaseNum) {
14511
+ async function phaseCompleteCore(cwd, phaseNum) {
14405
14512
  const rmPath = roadmapPath(cwd);
14406
14513
  const stPath = statePath(cwd);
14407
14514
  const phasesDirPath = phasesPath(cwd);
14408
14515
  const today = todayISO();
14409
- const phaseInfo = findPhaseInternal(cwd, phaseNum);
14516
+ const phaseInfo = await findPhaseInternalAsync(cwd, phaseNum);
14410
14517
  if (!phaseInfo) throw new Error(`Phase ${phaseNum} not found`);
14411
14518
  const planCount = phaseInfo.plans.length;
14412
14519
  const summaryCount = phaseInfo.summaries.length;
14413
14520
  let requirementsUpdated = false;
14414
- if (node_fs.default.existsSync(rmPath)) {
14415
- let roadmapContent = node_fs.default.readFileSync(rmPath, "utf-8");
14521
+ const rmExists = await pathExistsAsync(rmPath);
14522
+ if (rmExists) {
14523
+ let roadmapContent = await node_fs.promises.readFile(rmPath, "utf-8");
14416
14524
  const checkboxPattern = new RegExp(`(-\\s*\\[)[ ](\\]\\s*.*Phase\\s+${escapePhaseNum(phaseNum)}[:\\s][^\\n]*)`, "i");
14417
14525
  roadmapContent = roadmapContent.replace(checkboxPattern, `$1x$2 (completed ${today})`);
14418
14526
  const phaseEscaped = escapePhaseNum(phaseNum);
@@ -14421,20 +14529,20 @@ function phaseCompleteCore(cwd, phaseNum) {
14421
14529
  const planCountPattern = new RegExp(`(#{2,4}\\s*Phase\\s+${phaseEscaped}[\\s\\S]*?\\*\\*Plans:\\*\\*\\s*)[^\\n]+`, "i");
14422
14530
  roadmapContent = roadmapContent.replace(planCountPattern, `$1${summaryCount}/${planCount} plans complete`);
14423
14531
  debugLog("phase-complete-write", `writing ROADMAP.md for phase ${phaseNum}`);
14424
- node_fs.default.writeFileSync(rmPath, roadmapContent, "utf-8");
14532
+ await node_fs.promises.writeFile(rmPath, roadmapContent, "utf-8");
14425
14533
  debugLog("phase-complete-write", `ROADMAP.md updated for phase ${phaseNum}`);
14426
14534
  const reqPath = planningPath(cwd, "REQUIREMENTS.md");
14427
- if (node_fs.default.existsSync(reqPath)) {
14535
+ if (await pathExistsAsync(reqPath)) {
14428
14536
  const reqMatch = roadmapContent.match(new RegExp(`Phase\\s+${escapePhaseNum(phaseNum)}[\\s\\S]*?\\*\\*Requirements:\\*\\*\\s*([^\\n]+)`, "i"));
14429
14537
  if (reqMatch) {
14430
14538
  const reqIds = reqMatch[1].replace(/[\[\]]/g, "").split(/[,\s]+/).map((r) => r.trim()).filter(Boolean);
14431
- let reqContent = node_fs.default.readFileSync(reqPath, "utf-8");
14539
+ let reqContent = await node_fs.promises.readFile(reqPath, "utf-8");
14432
14540
  for (const reqId of reqIds) {
14433
14541
  reqContent = reqContent.replace(new RegExp(`(-\\s*\\[)[ ](\\]\\s*\\*\\*${reqId}\\*\\*)`, "gi"), "$1x$2");
14434
14542
  reqContent = reqContent.replace(new RegExp(`(\\|\\s*${reqId}\\s*\\|[^|]+\\|)\\s*Pending\\s*(\\|)`, "gi"), "$1 Complete $2");
14435
14543
  }
14436
14544
  debugLog("phase-complete-write", `writing REQUIREMENTS.md for phase ${phaseNum}`);
14437
- node_fs.default.writeFileSync(reqPath, reqContent, "utf-8");
14545
+ await node_fs.promises.writeFile(reqPath, reqContent, "utf-8");
14438
14546
  debugLog("phase-complete-write", `REQUIREMENTS.md updated for phase ${phaseNum}`);
14439
14547
  requirementsUpdated = true;
14440
14548
  }
@@ -14444,7 +14552,7 @@ function phaseCompleteCore(cwd, phaseNum) {
14444
14552
  let nextPhaseName = null;
14445
14553
  let isLastPhase = true;
14446
14554
  try {
14447
- const dirs = listSubDirs(phasesDirPath, true);
14555
+ const dirs = await listSubDirsAsync(phasesDirPath, true);
14448
14556
  for (const dir of dirs) {
14449
14557
  const dm = dir.match(/^(\d+[A-Z]?(?:\.\d+)?)-?(.*)/i);
14450
14558
  if (dm) {
@@ -14459,8 +14567,9 @@ function phaseCompleteCore(cwd, phaseNum) {
14459
14567
  } catch (e) {
14460
14568
  debugLog("phase-complete-next-phase-scan-failed", e);
14461
14569
  }
14462
- if (node_fs.default.existsSync(stPath)) {
14463
- let stateContent = node_fs.default.readFileSync(stPath, "utf-8");
14570
+ const stExists = await pathExistsAsync(stPath);
14571
+ if (stExists) {
14572
+ let stateContent = await node_fs.promises.readFile(stPath, "utf-8");
14464
14573
  stateContent = stateContent.replace(/(\*\*Current Phase:\*\*\s*).*/, `$1${nextPhaseNum || phaseNum}`);
14465
14574
  if (nextPhaseName) stateContent = stateContent.replace(/(\*\*Current Phase Name:\*\*\s*).*/, `$1${nextPhaseName.replace(/-/g, " ")}`);
14466
14575
  stateContent = stateContent.replace(/(\*\*Status:\*\*\s*).*/, `$1${isLastPhase ? "Milestone complete" : "Ready to plan"}`);
@@ -14468,7 +14577,7 @@ function phaseCompleteCore(cwd, phaseNum) {
14468
14577
  stateContent = stateContent.replace(/(\*\*Last Activity:\*\*\s*).*/, `$1${today}`);
14469
14578
  stateContent = stateContent.replace(/(\*\*Last Activity Description:\*\*\s*).*/, `$1Phase ${phaseNum} complete${nextPhaseNum ? `, transitioned to Phase ${nextPhaseNum}` : ""}`);
14470
14579
  debugLog("phase-complete-write", `writing STATE.md for phase ${phaseNum}`);
14471
- node_fs.default.writeFileSync(stPath, stateContent, "utf-8");
14580
+ await node_fs.promises.writeFile(stPath, stateContent, "utf-8");
14472
14581
  debugLog("phase-complete-write", `STATE.md updated for phase ${phaseNum}`);
14473
14582
  }
14474
14583
  return {
@@ -14479,15 +14588,15 @@ function phaseCompleteCore(cwd, phaseNum) {
14479
14588
  next_phase_name: nextPhaseName,
14480
14589
  is_last_phase: isLastPhase,
14481
14590
  date: today,
14482
- roadmap_updated: node_fs.default.existsSync(rmPath),
14483
- state_updated: node_fs.default.existsSync(stPath),
14591
+ roadmap_updated: rmExists,
14592
+ state_updated: stExists,
14484
14593
  requirements_updated: requirementsUpdated
14485
14594
  };
14486
14595
  }
14487
14596
  async function cmdPhasesList(cwd, options) {
14488
14597
  const phasesDirPath = phasesPath(cwd);
14489
14598
  const { type, phase, includeArchived, offset, limit } = options;
14490
- if (!node_fs.default.existsSync(phasesDirPath)) if (type) return cmdOk({
14599
+ if (!await pathExistsAsync(phasesDirPath)) if (type) return cmdOk({
14491
14600
  files: [],
14492
14601
  count: 0,
14493
14602
  total: 0
@@ -14500,7 +14609,7 @@ async function cmdPhasesList(cwd, options) {
14500
14609
  try {
14501
14610
  let dirs = await listSubDirsAsync(phasesDirPath);
14502
14611
  if (includeArchived) {
14503
- const archived = getArchivedPhaseDirs(cwd);
14612
+ const archived = await getArchivedPhaseDirsAsync(cwd);
14504
14613
  for (const a of archived) dirs.push(`${a.name} [${a.milestone}]`);
14505
14614
  }
14506
14615
  dirs.sort((a, b) => comparePhaseNum(a, b));
@@ -14519,7 +14628,7 @@ async function cmdPhasesList(cwd, options) {
14519
14628
  if (type) {
14520
14629
  const files = (await Promise.all(dirs.map(async (dir) => {
14521
14630
  const dirPath = node_path.default.join(phasesDirPath, dir);
14522
- const dirFiles = await node_fs.default.promises.readdir(dirPath);
14631
+ const dirFiles = await node_fs.promises.readdir(dirPath);
14523
14632
  let filtered;
14524
14633
  if (type === "plans") filtered = dirFiles.filter(isPlanFile);
14525
14634
  else if (type === "summaries") filtered = dirFiles.filter(isSummaryFile);
@@ -14545,17 +14654,17 @@ async function cmdPhasesList(cwd, options) {
14545
14654
  return cmdErr("Failed to list phases: " + e.message);
14546
14655
  }
14547
14656
  }
14548
- function cmdPhaseNextDecimal(cwd, basePhase) {
14657
+ async function cmdPhaseNextDecimal(cwd, basePhase) {
14549
14658
  const phasesDirPath = phasesPath(cwd);
14550
14659
  const normalized = normalizePhaseName(basePhase);
14551
- if (!node_fs.default.existsSync(phasesDirPath)) return cmdOk({
14660
+ if (!await pathExistsAsync(phasesDirPath)) return cmdOk({
14552
14661
  found: false,
14553
14662
  base_phase: normalized,
14554
14663
  next: `${normalized}.1`,
14555
14664
  existing: []
14556
14665
  }, `${normalized}.1`);
14557
14666
  try {
14558
- const dirs = listSubDirs(phasesDirPath);
14667
+ const dirs = await listSubDirsAsync(phasesDirPath);
14559
14668
  const baseExists = dirs.some((d) => d.startsWith(normalized + "-") || d === normalized);
14560
14669
  const decimalPattern = new RegExp(`^${normalized}\\.(\\d+)`);
14561
14670
  const existingDecimals = [];
@@ -14582,7 +14691,7 @@ function cmdPhaseNextDecimal(cwd, basePhase) {
14582
14691
  return cmdErr("Failed to calculate next decimal phase: " + e.message);
14583
14692
  }
14584
14693
  }
14585
- function cmdFindPhase(cwd, phase) {
14694
+ async function cmdFindPhase(cwd, phase) {
14586
14695
  if (!phase) return cmdErr("phase identifier required");
14587
14696
  const phasesDirPath = phasesPath(cwd);
14588
14697
  const normalized = normalizePhaseName(phase);
@@ -14595,13 +14704,13 @@ function cmdFindPhase(cwd, phase) {
14595
14704
  summaries: []
14596
14705
  };
14597
14706
  try {
14598
- const match = listSubDirs(phasesDirPath, true).find((d) => d.startsWith(normalized));
14707
+ const match = (await listSubDirsAsync(phasesDirPath, true)).find((d) => d.startsWith(normalized));
14599
14708
  if (!match) return cmdOk(notFound, "");
14600
14709
  const dirMatch = match.match(/^(\d+[A-Z]?(?:\.\d+)?)-?(.*)/i);
14601
14710
  const phaseNumber = dirMatch ? dirMatch[1] : normalized;
14602
14711
  const phaseName = dirMatch && dirMatch[2] ? dirMatch[2] : null;
14603
14712
  const phaseDir = node_path.default.join(phasesDirPath, match);
14604
- const phaseFiles = node_fs.default.readdirSync(phaseDir);
14713
+ const phaseFiles = await node_fs.promises.readdir(phaseDir);
14605
14714
  const plans = phaseFiles.filter(isPlanFile).sort();
14606
14715
  const summaries = phaseFiles.filter(isSummaryFile).sort();
14607
14716
  const result = {
@@ -14617,13 +14726,13 @@ function cmdFindPhase(cwd, phase) {
14617
14726
  return cmdOk(notFound, "");
14618
14727
  }
14619
14728
  }
14620
- function cmdPhasePlanIndex(cwd, phase) {
14729
+ async function cmdPhasePlanIndex(cwd, phase) {
14621
14730
  if (!phase) return cmdErr("phase required for phase-plan-index");
14622
14731
  const phasesDirPath = phasesPath(cwd);
14623
14732
  const normalized = normalizePhaseName(phase);
14624
14733
  let phaseDir = null;
14625
14734
  try {
14626
- const match = listSubDirs(phasesDirPath, true).find((d) => d.startsWith(normalized));
14735
+ const match = (await listSubDirsAsync(phasesDirPath, true)).find((d) => d.startsWith(normalized));
14627
14736
  if (match) phaseDir = node_path.default.join(phasesDirPath, match);
14628
14737
  } catch (e) {
14629
14738
  debugLog("phase-plan-index-failed", e);
@@ -14636,7 +14745,7 @@ function cmdPhasePlanIndex(cwd, phase) {
14636
14745
  incomplete: [],
14637
14746
  has_checkpoints: false
14638
14747
  });
14639
- const phaseFiles = node_fs.default.readdirSync(phaseDir);
14748
+ const phaseFiles = await node_fs.promises.readdir(phaseDir);
14640
14749
  const planFiles = phaseFiles.filter(isPlanFile).sort();
14641
14750
  const summaryFiles = phaseFiles.filter(isSummaryFile);
14642
14751
  const completedPlanIds = new Set(summaryFiles.map(summaryId));
@@ -14644,10 +14753,11 @@ function cmdPhasePlanIndex(cwd, phase) {
14644
14753
  const waves = {};
14645
14754
  const incomplete = [];
14646
14755
  let hasCheckpoints = false;
14647
- for (const planFile of planFiles) {
14756
+ const planContents = await Promise.all(planFiles.map((planFile) => node_fs.promises.readFile(node_path.default.join(phaseDir, planFile), "utf-8")));
14757
+ for (let i = 0; i < planFiles.length; i++) {
14758
+ const planFile = planFiles[i];
14648
14759
  const id = planId(planFile);
14649
- const planPath = node_path.default.join(phaseDir, planFile);
14650
- const content = node_fs.default.readFileSync(planPath, "utf-8");
14760
+ const content = planContents[i];
14651
14761
  const fm = extractFrontmatter(content);
14652
14762
  const taskCount = (content.match(/##\s*Task\s*\d+/gi) || []).length;
14653
14763
  const wave = parseInt(fm.wave, 10) || 1;
@@ -14680,10 +14790,10 @@ function cmdPhasePlanIndex(cwd, phase) {
14680
14790
  has_checkpoints: hasCheckpoints
14681
14791
  });
14682
14792
  }
14683
- function cmdPhaseAdd(cwd, description) {
14793
+ async function cmdPhaseAdd(cwd, description) {
14684
14794
  if (!description) return cmdErr("description required for phase add");
14685
14795
  try {
14686
- const result = phaseAddCore(cwd, description, { includeStubs: false });
14796
+ const result = await phaseAddCore(cwd, description, { includeStubs: false });
14687
14797
  return cmdOk({
14688
14798
  phase_number: result.phase_number,
14689
14799
  padded: result.padded,
@@ -14695,10 +14805,10 @@ function cmdPhaseAdd(cwd, description) {
14695
14805
  return cmdErr(e.message);
14696
14806
  }
14697
14807
  }
14698
- function cmdPhaseInsert(cwd, afterPhase, description) {
14808
+ async function cmdPhaseInsert(cwd, afterPhase, description) {
14699
14809
  if (!afterPhase || !description) return cmdErr("after-phase and description required for phase insert");
14700
14810
  try {
14701
- const result = phaseInsertCore(cwd, afterPhase, description, { includeStubs: false });
14811
+ const result = await phaseInsertCore(cwd, afterPhase, description, { includeStubs: false });
14702
14812
  return cmdOk({
14703
14813
  phase_number: result.phase_number,
14704
14814
  after_phase: result.after_phase,
@@ -14710,26 +14820,26 @@ function cmdPhaseInsert(cwd, afterPhase, description) {
14710
14820
  return cmdErr(e.message);
14711
14821
  }
14712
14822
  }
14713
- function cmdPhaseRemove(cwd, targetPhase, options) {
14823
+ async function cmdPhaseRemove(cwd, targetPhase, options) {
14714
14824
  if (!targetPhase) return cmdErr("phase number required for phase remove");
14715
14825
  const rmPath = roadmapPath(cwd);
14716
14826
  const phasesDirPath = phasesPath(cwd);
14717
14827
  const force = options.force || false;
14718
- if (!node_fs.default.existsSync(rmPath)) return cmdErr("ROADMAP.md not found");
14828
+ if (!await pathExistsAsync(rmPath)) return cmdErr("ROADMAP.md not found");
14719
14829
  const normalized = normalizePhaseName(targetPhase);
14720
14830
  const isDecimal = targetPhase.includes(".");
14721
14831
  let targetDir = null;
14722
14832
  try {
14723
- targetDir = listSubDirs(phasesDirPath, true).find((d) => d.startsWith(normalized + "-") || d === normalized) || null;
14833
+ targetDir = (await listSubDirsAsync(phasesDirPath, true)).find((d) => d.startsWith(normalized + "-") || d === normalized) || null;
14724
14834
  } catch (e) {
14725
14835
  debugLog("phase-remove-find-target-failed", e);
14726
14836
  }
14727
14837
  if (targetDir && !force) {
14728
14838
  const targetPath = node_path.default.join(phasesDirPath, targetDir);
14729
- const summaries = node_fs.default.readdirSync(targetPath).filter(isSummaryFile);
14839
+ const summaries = (await node_fs.promises.readdir(targetPath)).filter(isSummaryFile);
14730
14840
  if (summaries.length > 0) return cmdErr(`Phase ${targetPhase} has ${summaries.length} executed plan(s). Use --force to remove anyway.`);
14731
14841
  }
14732
- if (targetDir) node_fs.default.rmSync(node_path.default.join(phasesDirPath, targetDir), {
14842
+ if (targetDir) await node_fs.promises.rm(node_path.default.join(phasesDirPath, targetDir), {
14733
14843
  recursive: true,
14734
14844
  force: true
14735
14845
  });
@@ -14740,7 +14850,7 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
14740
14850
  const baseInt = baseParts[0];
14741
14851
  const removedDecimal = parseInt(baseParts[1], 10);
14742
14852
  try {
14743
- const dirs = listSubDirs(phasesDirPath, true);
14853
+ const dirs = await listSubDirsAsync(phasesDirPath, true);
14744
14854
  const decPattern = new RegExp(`^${baseInt}\\.(\\d+)-(.+)$`);
14745
14855
  const toRename = [];
14746
14856
  for (const dir of dirs) {
@@ -14757,15 +14867,15 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
14757
14867
  const oldPhaseId = `${baseInt}.${item.oldDecimal}`;
14758
14868
  const newPhaseId = `${baseInt}.${newDecimal}`;
14759
14869
  const newDirName = `${baseInt}.${newDecimal}-${item.slug}`;
14760
- node_fs.default.renameSync(node_path.default.join(phasesDirPath, item.dir), node_path.default.join(phasesDirPath, newDirName));
14870
+ await node_fs.promises.rename(node_path.default.join(phasesDirPath, item.dir), node_path.default.join(phasesDirPath, newDirName));
14761
14871
  renamedDirs.push({
14762
14872
  from: item.dir,
14763
14873
  to: newDirName
14764
14874
  });
14765
- const dirFiles = node_fs.default.readdirSync(node_path.default.join(phasesDirPath, newDirName));
14875
+ const dirFiles = await node_fs.promises.readdir(node_path.default.join(phasesDirPath, newDirName));
14766
14876
  for (const f of dirFiles) if (f.includes(oldPhaseId)) {
14767
14877
  const newFileName = f.replace(oldPhaseId, newPhaseId);
14768
- node_fs.default.renameSync(node_path.default.join(phasesDirPath, newDirName, f), node_path.default.join(phasesDirPath, newDirName, newFileName));
14878
+ await node_fs.promises.rename(node_path.default.join(phasesDirPath, newDirName, f), node_path.default.join(phasesDirPath, newDirName, newFileName));
14769
14879
  renamedFiles.push({
14770
14880
  from: f,
14771
14881
  to: newFileName
@@ -14781,7 +14891,7 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
14781
14891
  } else {
14782
14892
  const removedInt = parseInt(normalized, 10);
14783
14893
  try {
14784
- const dirs = listSubDirs(phasesDirPath, true);
14894
+ const dirs = await listSubDirsAsync(phasesDirPath, true);
14785
14895
  const toRename = [];
14786
14896
  for (const dir of dirs) {
14787
14897
  const dm = dir.match(/^(\d+)([A-Z])?(?:\.(\d+))?-(.+)$/i);
@@ -14808,15 +14918,15 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
14808
14918
  const oldPrefix = `${oldPadded}${letterSuffix}${decimalSuffix}`;
14809
14919
  const newPrefix = `${newPadded}${letterSuffix}${decimalSuffix}`;
14810
14920
  const newDirName = `${newPrefix}-${item.slug}`;
14811
- node_fs.default.renameSync(node_path.default.join(phasesDirPath, item.dir), node_path.default.join(phasesDirPath, newDirName));
14921
+ await node_fs.promises.rename(node_path.default.join(phasesDirPath, item.dir), node_path.default.join(phasesDirPath, newDirName));
14812
14922
  renamedDirs.push({
14813
14923
  from: item.dir,
14814
14924
  to: newDirName
14815
14925
  });
14816
- const dirFiles = node_fs.default.readdirSync(node_path.default.join(phasesDirPath, newDirName));
14926
+ const dirFiles = await node_fs.promises.readdir(node_path.default.join(phasesDirPath, newDirName));
14817
14927
  for (const f of dirFiles) if (f.startsWith(oldPrefix)) {
14818
14928
  const newFileName = newPrefix + f.slice(oldPrefix.length);
14819
- node_fs.default.renameSync(node_path.default.join(phasesDirPath, newDirName, f), node_path.default.join(phasesDirPath, newDirName, newFileName));
14929
+ await node_fs.promises.rename(node_path.default.join(phasesDirPath, newDirName, f), node_path.default.join(phasesDirPath, newDirName, newFileName));
14820
14930
  renamedFiles.push({
14821
14931
  from: f,
14822
14932
  to: newFileName
@@ -14830,7 +14940,7 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
14830
14940
  });
14831
14941
  }
14832
14942
  }
14833
- let roadmapContent = node_fs.default.readFileSync(rmPath, "utf-8");
14943
+ let roadmapContent = await node_fs.promises.readFile(rmPath, "utf-8");
14834
14944
  const targetEscaped = escapePhaseNum(targetPhase);
14835
14945
  const sectionPattern = new RegExp(`\\n?#{2,4}\\s*Phase\\s+${targetEscaped}\\s*:[\\s\\S]*?(?=\\n#{2,4}\\s+Phase\\s+\\d|$)`, "i");
14836
14946
  roadmapContent = roadmapContent.replace(sectionPattern, "");
@@ -14853,10 +14963,11 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
14853
14963
  roadmapContent = roadmapContent.replace(new RegExp(`(Depends on:\\*\\*\\s*Phase\\s+)${oldStr}\\b`, "gi"), `$1${newStr}`);
14854
14964
  }
14855
14965
  }
14856
- node_fs.default.writeFileSync(rmPath, roadmapContent, "utf-8");
14966
+ await node_fs.promises.writeFile(rmPath, roadmapContent, "utf-8");
14857
14967
  const stPath = statePath(cwd);
14858
- if (node_fs.default.existsSync(stPath)) {
14859
- let stateContent = node_fs.default.readFileSync(stPath, "utf-8");
14968
+ const stExists = await pathExistsAsync(stPath);
14969
+ if (stExists) {
14970
+ let stateContent = await node_fs.promises.readFile(stPath, "utf-8");
14860
14971
  const totalPattern = /(\*\*Total Phases:\*\*\s*)(\d+)/;
14861
14972
  const totalMatch = stateContent.match(totalPattern);
14862
14973
  if (totalMatch) {
@@ -14869,7 +14980,7 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
14869
14980
  const oldTotal = parseInt(ofMatch[2], 10);
14870
14981
  stateContent = stateContent.replace(ofPattern, `$1${oldTotal - 1}$3`);
14871
14982
  }
14872
- node_fs.default.writeFileSync(stPath, stateContent, "utf-8");
14983
+ await node_fs.promises.writeFile(stPath, stateContent, "utf-8");
14873
14984
  }
14874
14985
  return cmdOk({
14875
14986
  removed: targetPhase,
@@ -14877,13 +14988,13 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
14877
14988
  renamed_directories: renamedDirs,
14878
14989
  renamed_files: renamedFiles,
14879
14990
  roadmap_updated: true,
14880
- state_updated: node_fs.default.existsSync(stPath)
14991
+ state_updated: stExists
14881
14992
  });
14882
14993
  }
14883
- function cmdPhaseComplete(cwd, phaseNum) {
14994
+ async function cmdPhaseComplete(cwd, phaseNum) {
14884
14995
  if (!phaseNum) return cmdErr("phase number required for phase complete");
14885
14996
  try {
14886
- const result = phaseCompleteCore(cwd, phaseNum);
14997
+ const result = await phaseCompleteCore(cwd, phaseNum);
14887
14998
  return cmdOk({
14888
14999
  completed_phase: result.completed_phase,
14889
15000
  phase_name: result.phase_name,
@@ -15138,7 +15249,17 @@ function resolveArtefaktPath(cwd, type, phase) {
15138
15249
  }
15139
15250
  return planningPath(cwd, filename);
15140
15251
  }
15252
+ const TEMPLATE_FILES = {
15253
+ "decisions": "decisions.md",
15254
+ "acceptance-criteria": "acceptance-criteria.md",
15255
+ "no-gos": "no-gos.md"
15256
+ };
15141
15257
  function getTemplate(type) {
15258
+ const content = safeReadFile(node_path.default.join(node_os.default.homedir(), ".claude", "maxsim", "templates", TEMPLATE_FILES[type]));
15259
+ if (content) return content.replace(/\{\{date\}\}/g, todayISO());
15260
+ return getHardcodedTemplate(type);
15261
+ }
15262
+ function getHardcodedTemplate(type) {
15142
15263
  const today = todayISO();
15143
15264
  switch (type) {
15144
15265
  case "decisions": return `# Decisions\n\n> Architectural and design decisions for this project.\n\n**Created:** ${today}\n\n## Decision Log\n\n| # | Decision | Rationale | Date | Phase |\n|---|----------|-----------|------|-------|\n`;
@@ -15248,6 +15369,36 @@ function addIfExists(files, cwd, relPath, role) {
15248
15369
  const entry = fileEntry(cwd, relPath, role);
15249
15370
  if (entry) files.push(entry);
15250
15371
  }
15372
+ const TOPIC_TO_CODEBASE_DOCS = {
15373
+ ui: ["CONVENTIONS.md", "STRUCTURE.md"],
15374
+ frontend: ["CONVENTIONS.md", "STRUCTURE.md"],
15375
+ component: ["CONVENTIONS.md", "STRUCTURE.md"],
15376
+ api: ["ARCHITECTURE.md", "CONVENTIONS.md"],
15377
+ backend: ["ARCHITECTURE.md", "CONVENTIONS.md"],
15378
+ server: ["ARCHITECTURE.md", "CONVENTIONS.md"],
15379
+ database: ["ARCHITECTURE.md", "STACK.md"],
15380
+ schema: ["ARCHITECTURE.md", "STACK.md"],
15381
+ data: ["ARCHITECTURE.md", "STACK.md"],
15382
+ testing: ["TESTING.md", "CONVENTIONS.md"],
15383
+ test: ["TESTING.md", "CONVENTIONS.md"],
15384
+ integration: ["INTEGRATIONS.md", "STACK.md"],
15385
+ deploy: ["INTEGRATIONS.md", "STACK.md"],
15386
+ refactor: ["CONCERNS.md", "ARCHITECTURE.md"],
15387
+ cleanup: ["CONCERNS.md", "ARCHITECTURE.md"],
15388
+ setup: ["STACK.md", "STRUCTURE.md"],
15389
+ config: ["STACK.md", "STRUCTURE.md"],
15390
+ auth: ["ARCHITECTURE.md", "INTEGRATIONS.md"],
15391
+ performance: ["ARCHITECTURE.md", "STACK.md"],
15392
+ install: ["STACK.md", "STRUCTURE.md"]
15393
+ };
15394
+ const DEFAULT_CODEBASE_DOCS = ["STACK.md", "ARCHITECTURE.md"];
15395
+ function selectCodebaseDocs(topic) {
15396
+ if (!topic) return DEFAULT_CODEBASE_DOCS;
15397
+ const topicLower = topic.toLowerCase();
15398
+ const matched = /* @__PURE__ */ new Set();
15399
+ for (const [keyword, docs] of Object.entries(TOPIC_TO_CODEBASE_DOCS)) if (topicLower.includes(keyword)) for (const doc of docs) matched.add(doc);
15400
+ return matched.size > 0 ? Array.from(matched) : DEFAULT_CODEBASE_DOCS;
15401
+ }
15251
15402
  function loadProjectContext(cwd) {
15252
15403
  const files = [];
15253
15404
  addIfExists(files, cwd, ".planning/PROJECT.md", "project-vision");
@@ -15296,6 +15447,16 @@ function loadArtefakteContext(cwd, phase) {
15296
15447
  }
15297
15448
  return files;
15298
15449
  }
15450
+ function loadCodebaseContext(cwd, topic) {
15451
+ const files = [];
15452
+ const codebaseDir = planningPath(cwd, "codebase");
15453
+ try {
15454
+ const existing = node_fs.default.readdirSync(codebaseDir).filter((f) => f.endsWith(".md"));
15455
+ const selected = selectCodebaseDocs(topic);
15456
+ for (const filename of selected) if (existing.includes(filename)) addIfExists(files, cwd, `.planning/codebase/${filename}`, `codebase-${filename.replace(".md", "").toLowerCase()}`);
15457
+ } catch {}
15458
+ return files;
15459
+ }
15299
15460
  function loadHistoryContext(cwd, currentPhase) {
15300
15461
  const files = [];
15301
15462
  const pd = phasesPath(cwd);
@@ -15319,6 +15480,8 @@ function cmdContextLoad(cwd, phase, topic, includeHistory) {
15319
15480
  allFiles.push(...loadProjectContext(cwd));
15320
15481
  allFiles.push(...loadRoadmapContext(cwd));
15321
15482
  allFiles.push(...loadArtefakteContext(cwd, phase));
15483
+ const selectedDocs = selectCodebaseDocs(topic);
15484
+ allFiles.push(...loadCodebaseContext(cwd, topic));
15322
15485
  if (phase) allFiles.push(...loadPhaseContext(cwd, phase));
15323
15486
  if (includeHistory) allFiles.push(...loadHistoryContext(cwd, phase));
15324
15487
  const seen = /* @__PURE__ */ new Set();
@@ -15331,7 +15494,8 @@ function cmdContextLoad(cwd, phase, topic, includeHistory) {
15331
15494
  files: deduped,
15332
15495
  total_size: deduped.reduce((sum, f) => sum + f.size, 0),
15333
15496
  phase: phase ?? null,
15334
- topic: topic ?? null
15497
+ topic: topic ?? null,
15498
+ codebase_docs_selected: selectedDocs
15335
15499
  });
15336
15500
  }
15337
15501
 
@@ -16374,7 +16538,7 @@ const handleRoadmap = async (args, cwd, raw) => {
16374
16538
  if (handler) return handleResult(await handler(), raw);
16375
16539
  error("Unknown roadmap subcommand. Available: get-phase, analyze, update-plan-progress");
16376
16540
  };
16377
- const handlePhase = (args, cwd, raw) => {
16541
+ const handlePhase = async (args, cwd, raw) => {
16378
16542
  const sub = args[1];
16379
16543
  const handler = sub ? {
16380
16544
  "next-decimal": () => cmdPhaseNextDecimal(cwd, args[2]),
@@ -16383,7 +16547,7 @@ const handlePhase = (args, cwd, raw) => {
16383
16547
  "remove": () => cmdPhaseRemove(cwd, args[2], { force: hasFlag(args, "force") }),
16384
16548
  "complete": () => cmdPhaseComplete(cwd, args[2])
16385
16549
  }[sub] : void 0;
16386
- if (handler) return handleResult(handler(), raw);
16550
+ if (handler) return handleResult(await handler(), raw);
16387
16551
  error("Unknown phase subcommand. Available: next-decimal, add, insert, remove, complete");
16388
16552
  };
16389
16553
  const handleMilestone = (args, cwd, raw) => {
@@ -16436,7 +16600,7 @@ const handleInit = (args, cwd, raw) => {
16436
16600
  const COMMANDS = {
16437
16601
  "state": handleState,
16438
16602
  "resolve-model": (args, cwd, raw) => handleResult(cmdResolveModel(cwd, args[1], raw), raw),
16439
- "find-phase": (args, cwd, raw) => handleResult(cmdFindPhase(cwd, args[1]), raw),
16603
+ "find-phase": async (args, cwd, raw) => handleResult(await cmdFindPhase(cwd, args[1]), raw),
16440
16604
  "commit": async (args, cwd, raw) => {
16441
16605
  const files = args.indexOf("--files") !== -1 ? args.slice(args.indexOf("--files") + 1).filter((a) => !a.startsWith("--")) : [];
16442
16606
  handleResult(await cmdCommit(cwd, args[1], files, raw, hasFlag(args, "amend")), raw);
@@ -16479,8 +16643,8 @@ const COMMANDS = {
16479
16643
  }, raw), raw);
16480
16644
  },
16481
16645
  "init": handleInit,
16482
- "phase-plan-index": (args, cwd, raw) => handleResult(cmdPhasePlanIndex(cwd, args[1]), raw),
16483
- "state-snapshot": (_args, cwd, raw) => handleResult(cmdStateSnapshot(cwd, raw), raw),
16646
+ "phase-plan-index": async (args, cwd, raw) => handleResult(await cmdPhasePlanIndex(cwd, args[1]), raw),
16647
+ "state-snapshot": async (_args, cwd, raw) => handleResult(await cmdStateSnapshot(cwd, raw), raw),
16484
16648
  "summary-extract": (args, cwd, raw) => {
16485
16649
  const fieldsIndex = args.indexOf("--fields");
16486
16650
  const fields = fieldsIndex !== -1 ? args[fieldsIndex + 1].split(",") : null;
@@ -16511,7 +16675,7 @@ const COMMANDS = {
16511
16675
  (0, node_child_process.spawn)(process.execPath, [serverPath], { stdio: "inherit" }).on("exit", (code) => process.exit(code ?? 0));
16512
16676
  },
16513
16677
  "backend-start": async (args, cwd, raw) => {
16514
- const { startBackend } = await Promise.resolve().then(() => require("./lifecycle-D4E9yP6E.cjs"));
16678
+ const { startBackend } = await Promise.resolve().then(() => require("./lifecycle-0M4VqOMm.cjs"));
16515
16679
  const portFlag = args.find((a) => a.startsWith("--port="))?.split("=")[1];
16516
16680
  const background = !args.includes("--foreground");
16517
16681
  output(await startBackend(cwd, {
@@ -16520,11 +16684,11 @@ const COMMANDS = {
16520
16684
  }), raw);
16521
16685
  },
16522
16686
  "backend-stop": async (_args, cwd, raw) => {
16523
- const { stopBackend } = await Promise.resolve().then(() => require("./lifecycle-D4E9yP6E.cjs"));
16687
+ const { stopBackend } = await Promise.resolve().then(() => require("./lifecycle-0M4VqOMm.cjs"));
16524
16688
  output({ stopped: await stopBackend(cwd) }, raw);
16525
16689
  },
16526
16690
  "backend-status": async (_args, cwd, raw) => {
16527
- const { getBackendStatus } = await Promise.resolve().then(() => require("./lifecycle-D4E9yP6E.cjs"));
16691
+ const { getBackendStatus } = await Promise.resolve().then(() => require("./lifecycle-0M4VqOMm.cjs"));
16528
16692
  output(await getBackendStatus(cwd) || { running: false }, raw);
16529
16693
  }
16530
16694
  };