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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/assets/CHANGELOG.md +16 -0
- package/dist/assets/dashboard/client/assets/{index-C_eAetZJ.js → index-BcRHShXD.js} +59 -59
- package/dist/assets/dashboard/client/assets/index-C199D4Eb.css +32 -0
- package/dist/assets/dashboard/client/index.html +2 -2
- package/dist/assets/dashboard/server.js +26 -11
- package/dist/assets/templates/agents/AGENTS.md +18 -69
- package/dist/assets/templates/agents/maxsim-code-reviewer.md +17 -92
- package/dist/assets/templates/agents/maxsim-codebase-mapper.md +57 -694
- package/dist/assets/templates/agents/maxsim-debugger.md +80 -925
- package/dist/assets/templates/agents/maxsim-executor.md +94 -431
- package/dist/assets/templates/agents/maxsim-integration-checker.md +51 -319
- package/dist/assets/templates/agents/maxsim-phase-researcher.md +63 -429
- package/dist/assets/templates/agents/maxsim-plan-checker.md +79 -568
- package/dist/assets/templates/agents/maxsim-planner.md +125 -855
- package/dist/assets/templates/agents/maxsim-project-researcher.md +32 -472
- package/dist/assets/templates/agents/maxsim-research-synthesizer.md +25 -134
- package/dist/assets/templates/agents/maxsim-roadmapper.md +66 -480
- package/dist/assets/templates/agents/maxsim-spec-reviewer.md +13 -55
- package/dist/assets/templates/agents/maxsim-verifier.md +95 -450
- package/dist/assets/templates/commands/maxsim/artefakte.md +122 -0
- package/dist/assets/templates/commands/maxsim/batch.md +42 -0
- package/dist/assets/templates/commands/maxsim/check-todos.md +1 -0
- package/dist/assets/templates/commands/maxsim/sdd.md +39 -0
- package/dist/assets/templates/references/thinking-partner.md +33 -0
- package/dist/assets/templates/workflows/batch.md +420 -0
- package/dist/assets/templates/workflows/check-todos.md +85 -1
- package/dist/assets/templates/workflows/discuss-phase.md +31 -0
- package/dist/assets/templates/workflows/execute-plan.md +96 -27
- package/dist/assets/templates/workflows/help.md +47 -0
- package/dist/assets/templates/workflows/sdd.md +426 -0
- package/dist/backend/index.d.ts +4 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +12 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/lifecycle.d.ts +13 -0
- package/dist/backend/lifecycle.d.ts.map +1 -0
- package/dist/backend/lifecycle.js +168 -0
- package/dist/backend/lifecycle.js.map +1 -0
- package/dist/backend/server.d.ts +13 -0
- package/dist/backend/server.d.ts.map +1 -0
- package/dist/backend/server.js +1013 -0
- package/dist/backend/server.js.map +1 -0
- package/dist/backend/terminal.d.ts +49 -0
- package/dist/backend/terminal.d.ts.map +1 -0
- package/dist/backend/terminal.js +209 -0
- package/dist/backend/terminal.js.map +1 -0
- package/dist/backend/types.d.ts +77 -0
- package/dist/backend/types.d.ts.map +1 -0
- package/dist/backend/types.js +6 -0
- package/dist/backend/types.js.map +1 -0
- package/dist/backend-server.cjs +80636 -0
- package/dist/backend-server.cjs.map +1 -0
- package/dist/backend-server.d.cts +2 -0
- package/dist/backend-server.d.ts +11 -0
- package/dist/backend-server.d.ts.map +1 -0
- package/dist/backend-server.js +43 -0
- package/dist/backend-server.js.map +1 -0
- package/dist/cli.cjs +378 -172
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +28 -8
- package/dist/cli.js.map +1 -1
- package/dist/core/artefakte.d.ts.map +1 -1
- package/dist/core/artefakte.js +16 -0
- package/dist/core/artefakte.js.map +1 -1
- package/dist/core/context-loader.d.ts +1 -0
- package/dist/core/context-loader.d.ts.map +1 -1
- package/dist/core/context-loader.js +58 -0
- package/dist/core/context-loader.js.map +1 -1
- package/dist/core/core.d.ts +6 -0
- package/dist/core/core.d.ts.map +1 -1
- package/dist/core/core.js +238 -0
- package/dist/core/core.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +5 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/phase.d.ts +11 -11
- package/dist/core/phase.d.ts.map +1 -1
- package/dist/core/phase.js +88 -73
- package/dist/core/phase.js.map +1 -1
- package/dist/core/roadmap.d.ts +2 -2
- package/dist/core/roadmap.d.ts.map +1 -1
- package/dist/core/roadmap.js +11 -10
- package/dist/core/roadmap.js.map +1 -1
- package/dist/core/skills.d.ts +4 -3
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +14 -15
- package/dist/core/skills.js.map +1 -1
- package/dist/core/state.d.ts +11 -11
- package/dist/core/state.d.ts.map +1 -1
- package/dist/core/state.js +60 -54
- package/dist/core/state.js.map +1 -1
- package/dist/{core-TFSlUjV1.cjs → core-RRjCSt0G.cjs} +1 -9
- package/dist/{core-TFSlUjV1.cjs.map → core-RRjCSt0G.cjs.map} +1 -1
- package/dist/esm-iIOBzmdz.cjs +1561 -0
- package/dist/esm-iIOBzmdz.cjs.map +1 -0
- package/dist/install.cjs +2 -2
- package/dist/lifecycle-0M4VqOMm.cjs +136 -0
- package/dist/lifecycle-0M4VqOMm.cjs.map +1 -0
- package/dist/mcp/config-tools.d.ts +13 -0
- package/dist/mcp/config-tools.d.ts.map +1 -0
- package/dist/mcp/config-tools.js +66 -0
- package/dist/mcp/config-tools.js.map +1 -0
- package/dist/mcp/context-tools.d.ts +13 -0
- package/dist/mcp/context-tools.d.ts.map +1 -0
- package/dist/mcp/context-tools.js +176 -0
- package/dist/mcp/context-tools.js.map +1 -0
- package/dist/mcp/index.d.ts +0 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +6 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/phase-tools.js +3 -3
- package/dist/mcp/phase-tools.js.map +1 -1
- package/dist/mcp/roadmap-tools.d.ts +13 -0
- package/dist/mcp/roadmap-tools.d.ts.map +1 -0
- package/dist/mcp/roadmap-tools.js +79 -0
- package/dist/mcp/roadmap-tools.js.map +1 -0
- package/dist/mcp-server.cjs +799 -38
- package/dist/mcp-server.cjs.map +1 -1
- package/dist/server-G1MIg_Oe.cjs +2980 -0
- package/dist/server-G1MIg_Oe.cjs.map +1 -0
- package/dist/{skills-BOSxYUzf.cjs → skills-MYlMkYNt.cjs} +41 -29
- package/dist/skills-MYlMkYNt.cjs.map +1 -0
- package/package.json +7 -1
- package/dist/assets/dashboard/client/assets/index-CmiJKqOU.css +0 -32
- package/dist/skills-BOSxYUzf.cjs.map +0 -1
package/dist/cli.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
3
|
//#region \0rolldown/runtime.js
|
|
3
4
|
var __create = Object.create;
|
|
4
5
|
var __defProp$1 = Object.defineProperty;
|
|
@@ -606,7 +607,7 @@ var require_has_flag = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
606
607
|
//#endregion
|
|
607
608
|
//#region ../../node_modules/supports-color/index.js
|
|
608
609
|
var require_supports_color = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
609
|
-
const os$
|
|
610
|
+
const os$6 = require("os");
|
|
610
611
|
const tty$2 = require("tty");
|
|
611
612
|
const hasFlag = require_has_flag();
|
|
612
613
|
const { env } = process;
|
|
@@ -633,7 +634,7 @@ var require_supports_color = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
633
634
|
const min = forceColor || 0;
|
|
634
635
|
if (env.TERM === "dumb") return min;
|
|
635
636
|
if (process.platform === "win32") {
|
|
636
|
-
const osRelease = os$
|
|
637
|
+
const osRelease = os$6.release().split(".");
|
|
637
638
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
638
639
|
return 1;
|
|
639
640
|
}
|
|
@@ -5152,6 +5153,100 @@ function getMilestoneInfo(cwd) {
|
|
|
5152
5153
|
};
|
|
5153
5154
|
}
|
|
5154
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
|
+
}
|
|
5155
5250
|
|
|
5156
5251
|
//#endregion
|
|
5157
5252
|
//#region ../../node_modules/yaml/dist/nodes/identity.js
|
|
@@ -12107,11 +12202,11 @@ function stateReplaceField(content, fieldName, newValue) {
|
|
|
12107
12202
|
replaced = content.replace(plainPattern, (_match, prefix) => `${prefix}${newValue}`);
|
|
12108
12203
|
return replaced !== content ? replaced : null;
|
|
12109
12204
|
}
|
|
12110
|
-
function readTextArgOrFile(cwd, value, filePath, label) {
|
|
12205
|
+
async function readTextArgOrFile(cwd, value, filePath, label) {
|
|
12111
12206
|
if (!filePath) return value;
|
|
12112
12207
|
const resolvedPath = node_path.default.isAbsolute(filePath) ? filePath : node_path.default.join(cwd, filePath);
|
|
12113
12208
|
try {
|
|
12114
|
-
return node_fs.
|
|
12209
|
+
return (await node_fs.promises.readFile(resolvedPath, "utf-8")).trimEnd();
|
|
12115
12210
|
} catch {
|
|
12116
12211
|
throw new Error(`${label} file not found: ${filePath}`);
|
|
12117
12212
|
}
|
|
@@ -12136,8 +12231,8 @@ async function cmdStateLoad(cwd, raw) {
|
|
|
12136
12231
|
const config = loadConfig(cwd);
|
|
12137
12232
|
const [stateContent, configExists, roadmapExists] = await Promise.all([
|
|
12138
12233
|
safeReadFileAsync(statePath(cwd)),
|
|
12139
|
-
|
|
12140
|
-
|
|
12234
|
+
pathExistsAsync(configPath(cwd)),
|
|
12235
|
+
pathExistsAsync(roadmapPath(cwd))
|
|
12141
12236
|
]);
|
|
12142
12237
|
const stateRaw = stateContent ?? "";
|
|
12143
12238
|
const stateExists = stateRaw.length > 0;
|
|
@@ -12167,10 +12262,10 @@ async function cmdStateLoad(cwd, raw) {
|
|
|
12167
12262
|
}
|
|
12168
12263
|
return cmdOk(result);
|
|
12169
12264
|
}
|
|
12170
|
-
function cmdStateGet(cwd, section, raw) {
|
|
12265
|
+
async function cmdStateGet(cwd, section, raw) {
|
|
12171
12266
|
const statePath$2 = statePath(cwd);
|
|
12172
12267
|
try {
|
|
12173
|
-
const content = node_fs.
|
|
12268
|
+
const content = await node_fs.promises.readFile(statePath$2, "utf-8");
|
|
12174
12269
|
if (!section) return cmdOk({ content }, raw ? content : void 0);
|
|
12175
12270
|
const fieldValue = stateExtractField(content, section);
|
|
12176
12271
|
if (fieldValue !== null) return cmdOk({ [section]: fieldValue }, raw ? fieldValue : void 0);
|
|
@@ -12184,10 +12279,10 @@ function cmdStateGet(cwd, section, raw) {
|
|
|
12184
12279
|
return cmdErr("STATE.md not found");
|
|
12185
12280
|
}
|
|
12186
12281
|
}
|
|
12187
|
-
function cmdStatePatch(cwd, patches, raw) {
|
|
12282
|
+
async function cmdStatePatch(cwd, patches, raw) {
|
|
12188
12283
|
const statePath$3 = statePath(cwd);
|
|
12189
12284
|
try {
|
|
12190
|
-
let content = node_fs.
|
|
12285
|
+
let content = await node_fs.promises.readFile(statePath$3, "utf-8");
|
|
12191
12286
|
const results = {
|
|
12192
12287
|
updated: [],
|
|
12193
12288
|
failed: []
|
|
@@ -12199,20 +12294,20 @@ function cmdStatePatch(cwd, patches, raw) {
|
|
|
12199
12294
|
results.updated.push(field);
|
|
12200
12295
|
} else results.failed.push(field);
|
|
12201
12296
|
}
|
|
12202
|
-
if (results.updated.length > 0) node_fs.
|
|
12297
|
+
if (results.updated.length > 0) await node_fs.promises.writeFile(statePath$3, content, "utf-8");
|
|
12203
12298
|
return cmdOk(results, raw ? results.updated.length > 0 ? "true" : "false" : void 0);
|
|
12204
12299
|
} catch (e) {
|
|
12205
12300
|
rethrowCliSignals(e);
|
|
12206
12301
|
return cmdErr("STATE.md not found");
|
|
12207
12302
|
}
|
|
12208
12303
|
}
|
|
12209
|
-
function cmdStateUpdate(cwd, field, value) {
|
|
12304
|
+
async function cmdStateUpdate(cwd, field, value) {
|
|
12210
12305
|
if (!field || value === void 0) return cmdErr("field and value required for state update");
|
|
12211
12306
|
const statePath$4 = statePath(cwd);
|
|
12212
12307
|
try {
|
|
12213
|
-
const result = stateReplaceField(node_fs.
|
|
12308
|
+
const result = stateReplaceField(await node_fs.promises.readFile(statePath$4, "utf-8"), field, value);
|
|
12214
12309
|
if (result) {
|
|
12215
|
-
node_fs.
|
|
12310
|
+
await node_fs.promises.writeFile(statePath$4, result, "utf-8");
|
|
12216
12311
|
return cmdOk({ updated: true });
|
|
12217
12312
|
} else return cmdOk({
|
|
12218
12313
|
updated: false,
|
|
@@ -12226,10 +12321,10 @@ function cmdStateUpdate(cwd, field, value) {
|
|
|
12226
12321
|
});
|
|
12227
12322
|
}
|
|
12228
12323
|
}
|
|
12229
|
-
function cmdStateAdvancePlan(cwd, raw) {
|
|
12324
|
+
async function cmdStateAdvancePlan(cwd, raw) {
|
|
12230
12325
|
const statePath$5 = statePath(cwd);
|
|
12231
|
-
if (!
|
|
12232
|
-
let content = node_fs.
|
|
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");
|
|
12233
12328
|
const currentPlan = parseInt(stateExtractField(content, "Current Plan") ?? "", 10);
|
|
12234
12329
|
const totalPlans = parseInt(stateExtractField(content, "Total Plans in Phase") ?? "", 10);
|
|
12235
12330
|
const today = todayISO();
|
|
@@ -12237,7 +12332,7 @@ function cmdStateAdvancePlan(cwd, raw) {
|
|
|
12237
12332
|
if (currentPlan >= totalPlans) {
|
|
12238
12333
|
content = stateReplaceField(content, "Status", "Phase complete — ready for verification") || content;
|
|
12239
12334
|
content = stateReplaceField(content, "Last Activity", today) || content;
|
|
12240
|
-
node_fs.
|
|
12335
|
+
await node_fs.promises.writeFile(statePath$5, content, "utf-8");
|
|
12241
12336
|
return cmdOk({
|
|
12242
12337
|
advanced: false,
|
|
12243
12338
|
reason: "last_plan",
|
|
@@ -12250,7 +12345,7 @@ function cmdStateAdvancePlan(cwd, raw) {
|
|
|
12250
12345
|
content = stateReplaceField(content, "Current Plan", String(newPlan)) || content;
|
|
12251
12346
|
content = stateReplaceField(content, "Status", "Ready to execute") || content;
|
|
12252
12347
|
content = stateReplaceField(content, "Last Activity", today) || content;
|
|
12253
|
-
node_fs.
|
|
12348
|
+
await node_fs.promises.writeFile(statePath$5, content, "utf-8");
|
|
12254
12349
|
return cmdOk({
|
|
12255
12350
|
advanced: true,
|
|
12256
12351
|
previous_plan: currentPlan,
|
|
@@ -12259,10 +12354,10 @@ function cmdStateAdvancePlan(cwd, raw) {
|
|
|
12259
12354
|
}, raw ? "true" : void 0);
|
|
12260
12355
|
}
|
|
12261
12356
|
}
|
|
12262
|
-
function cmdStateRecordMetric(cwd, options, raw) {
|
|
12357
|
+
async function cmdStateRecordMetric(cwd, options, raw) {
|
|
12263
12358
|
const statePath$6 = statePath(cwd);
|
|
12264
|
-
if (!
|
|
12265
|
-
let content = node_fs.
|
|
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");
|
|
12266
12361
|
const { phase, plan, duration, tasks, files } = options;
|
|
12267
12362
|
if (!phase || !plan || !duration) return cmdOk({ error: "phase, plan, and duration required" });
|
|
12268
12363
|
const metricsPattern = /(#{2,3}\s*Performance Metrics[\s\S]*?\n\|[^\n]+\n\|[\s:|\-]+\n)([\s\S]*?)(?=\n#{2,3}\s|\n$|$)/i;
|
|
@@ -12273,7 +12368,7 @@ function cmdStateRecordMetric(cwd, options, raw) {
|
|
|
12273
12368
|
if (tableBody.trim() === "" || tableBody.includes("None yet")) tableBody = newRow;
|
|
12274
12369
|
else tableBody = tableBody + "\n" + newRow;
|
|
12275
12370
|
content = content.replace(metricsPattern, (_match, header) => `${header}${tableBody}\n`);
|
|
12276
|
-
node_fs.
|
|
12371
|
+
await node_fs.promises.writeFile(statePath$6, content, "utf-8");
|
|
12277
12372
|
return cmdOk({
|
|
12278
12373
|
recorded: true,
|
|
12279
12374
|
phase,
|
|
@@ -12285,19 +12380,25 @@ function cmdStateRecordMetric(cwd, options, raw) {
|
|
|
12285
12380
|
reason: "Performance Metrics section not found in STATE.md"
|
|
12286
12381
|
}, raw ? "false" : void 0);
|
|
12287
12382
|
}
|
|
12288
|
-
function cmdStateUpdateProgress(cwd, raw) {
|
|
12383
|
+
async function cmdStateUpdateProgress(cwd, raw) {
|
|
12289
12384
|
const statePath$7 = statePath(cwd);
|
|
12290
|
-
if (!
|
|
12291
|
-
let content = node_fs.
|
|
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");
|
|
12292
12387
|
const phasesDir = phasesPath(cwd);
|
|
12293
12388
|
let totalPlans = 0;
|
|
12294
12389
|
let totalSummaries = 0;
|
|
12295
|
-
if (
|
|
12296
|
-
const phaseDirs = node_fs.
|
|
12297
|
-
|
|
12298
|
-
const files = node_fs.
|
|
12299
|
-
|
|
12300
|
-
|
|
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;
|
|
12301
12402
|
}
|
|
12302
12403
|
}
|
|
12303
12404
|
const percent = totalPlans > 0 ? Math.min(100, Math.round(totalSummaries / totalPlans * 100)) : 0;
|
|
@@ -12306,7 +12407,7 @@ function cmdStateUpdateProgress(cwd, raw) {
|
|
|
12306
12407
|
const progressStr = `[${"█".repeat(filled) + "░".repeat(barWidth - filled)}] ${percent}%`;
|
|
12307
12408
|
const result = stateReplaceField(content, "Progress", progressStr);
|
|
12308
12409
|
if (result) {
|
|
12309
|
-
node_fs.
|
|
12410
|
+
await node_fs.promises.writeFile(statePath$7, result, "utf-8");
|
|
12310
12411
|
return cmdOk({
|
|
12311
12412
|
updated: true,
|
|
12312
12413
|
percent,
|
|
@@ -12319,15 +12420,15 @@ function cmdStateUpdateProgress(cwd, raw) {
|
|
|
12319
12420
|
reason: "Progress field not found in STATE.md"
|
|
12320
12421
|
}, raw ? "false" : void 0);
|
|
12321
12422
|
}
|
|
12322
|
-
function cmdStateAddDecision(cwd, options, raw) {
|
|
12423
|
+
async function cmdStateAddDecision(cwd, options, raw) {
|
|
12323
12424
|
const statePath$8 = statePath(cwd);
|
|
12324
|
-
if (!
|
|
12425
|
+
if (!await pathExistsAsync(statePath$8)) return cmdOk({ error: "STATE.md not found" });
|
|
12325
12426
|
const { phase, summary, summary_file, rationale, rationale_file } = options;
|
|
12326
12427
|
let summaryText;
|
|
12327
12428
|
let rationaleText = "";
|
|
12328
12429
|
try {
|
|
12329
|
-
summaryText = readTextArgOrFile(cwd, summary, summary_file, "summary");
|
|
12330
|
-
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") || "";
|
|
12331
12432
|
} catch (thrown) {
|
|
12332
12433
|
return cmdOk({
|
|
12333
12434
|
added: false,
|
|
@@ -12335,11 +12436,11 @@ function cmdStateAddDecision(cwd, options, raw) {
|
|
|
12335
12436
|
}, raw ? "false" : void 0);
|
|
12336
12437
|
}
|
|
12337
12438
|
if (!summaryText) return cmdOk({ error: "summary required" });
|
|
12338
|
-
const content = node_fs.
|
|
12439
|
+
const content = await node_fs.promises.readFile(statePath$8, "utf-8");
|
|
12339
12440
|
const entry = `- [Phase ${phase || "?"}]: ${summaryText}${rationaleText ? ` — ${rationaleText}` : ""}`;
|
|
12340
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]);
|
|
12341
12442
|
if (updated) {
|
|
12342
|
-
node_fs.
|
|
12443
|
+
await node_fs.promises.writeFile(statePath$8, updated, "utf-8");
|
|
12343
12444
|
return cmdOk({
|
|
12344
12445
|
added: true,
|
|
12345
12446
|
decision: entry
|
|
@@ -12349,13 +12450,13 @@ function cmdStateAddDecision(cwd, options, raw) {
|
|
|
12349
12450
|
reason: "Decisions section not found in STATE.md"
|
|
12350
12451
|
}, raw ? "false" : void 0);
|
|
12351
12452
|
}
|
|
12352
|
-
function cmdStateAddBlocker(cwd, text, raw) {
|
|
12453
|
+
async function cmdStateAddBlocker(cwd, text, raw) {
|
|
12353
12454
|
const statePath$9 = statePath(cwd);
|
|
12354
|
-
if (!
|
|
12455
|
+
if (!await pathExistsAsync(statePath$9)) return cmdOk({ error: "STATE.md not found" });
|
|
12355
12456
|
const blockerOptions = typeof text === "object" && text !== null ? text : { text };
|
|
12356
12457
|
let blockerText;
|
|
12357
12458
|
try {
|
|
12358
|
-
blockerText = readTextArgOrFile(cwd, blockerOptions.text, blockerOptions.text_file, "blocker");
|
|
12459
|
+
blockerText = await readTextArgOrFile(cwd, blockerOptions.text, blockerOptions.text_file, "blocker");
|
|
12359
12460
|
} catch (thrown) {
|
|
12360
12461
|
return cmdOk({
|
|
12361
12462
|
added: false,
|
|
@@ -12363,9 +12464,9 @@ function cmdStateAddBlocker(cwd, text, raw) {
|
|
|
12363
12464
|
}, raw ? "false" : void 0);
|
|
12364
12465
|
}
|
|
12365
12466
|
if (!blockerText) return cmdOk({ error: "text required" });
|
|
12366
|
-
const updated = appendToStateSection(node_fs.
|
|
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]);
|
|
12367
12468
|
if (updated) {
|
|
12368
|
-
node_fs.
|
|
12469
|
+
await node_fs.promises.writeFile(statePath$9, updated, "utf-8");
|
|
12369
12470
|
return cmdOk({
|
|
12370
12471
|
added: true,
|
|
12371
12472
|
blocker: blockerText
|
|
@@ -12375,11 +12476,11 @@ function cmdStateAddBlocker(cwd, text, raw) {
|
|
|
12375
12476
|
reason: "Blockers section not found in STATE.md"
|
|
12376
12477
|
}, raw ? "false" : void 0);
|
|
12377
12478
|
}
|
|
12378
|
-
function cmdStateResolveBlocker(cwd, text, raw) {
|
|
12479
|
+
async function cmdStateResolveBlocker(cwd, text, raw) {
|
|
12379
12480
|
const statePath$10 = statePath(cwd);
|
|
12380
|
-
if (!
|
|
12481
|
+
if (!await pathExistsAsync(statePath$10)) return cmdOk({ error: "STATE.md not found" });
|
|
12381
12482
|
if (!text) return cmdOk({ error: "text required" });
|
|
12382
|
-
let content = node_fs.
|
|
12483
|
+
let content = await node_fs.promises.readFile(statePath$10, "utf-8");
|
|
12383
12484
|
const sectionPattern = /(#{2,3}\s*(?:Blockers|Blockers\/Concerns|Concerns)\s*\n\s*\n?)([\s\S]*?)(?=\n#{2,3}\s|$)/i;
|
|
12384
12485
|
const match = content.match(sectionPattern);
|
|
12385
12486
|
if (match) {
|
|
@@ -12389,7 +12490,7 @@ function cmdStateResolveBlocker(cwd, text, raw) {
|
|
|
12389
12490
|
}).join("\n");
|
|
12390
12491
|
if (!newBody.trim() || !/^\s*[-*]\s+/m.test(newBody)) newBody = "None\n";
|
|
12391
12492
|
content = content.replace(sectionPattern, (_match, header) => `${header}${newBody}`);
|
|
12392
|
-
node_fs.
|
|
12493
|
+
await node_fs.promises.writeFile(statePath$10, content, "utf-8");
|
|
12393
12494
|
return cmdOk({
|
|
12394
12495
|
resolved: true,
|
|
12395
12496
|
blocker: text
|
|
@@ -12399,10 +12500,10 @@ function cmdStateResolveBlocker(cwd, text, raw) {
|
|
|
12399
12500
|
reason: "Blockers section not found in STATE.md"
|
|
12400
12501
|
}, raw ? "false" : void 0);
|
|
12401
12502
|
}
|
|
12402
|
-
function cmdStateRecordSession(cwd, options, raw) {
|
|
12503
|
+
async function cmdStateRecordSession(cwd, options, raw) {
|
|
12403
12504
|
const statePath$11 = statePath(cwd);
|
|
12404
|
-
if (!
|
|
12405
|
-
let content = node_fs.
|
|
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");
|
|
12406
12507
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12407
12508
|
const updated = [];
|
|
12408
12509
|
let result = stateReplaceField(content, "Last session", now);
|
|
@@ -12431,7 +12532,7 @@ function cmdStateRecordSession(cwd, options, raw) {
|
|
|
12431
12532
|
updated.push("Resume File");
|
|
12432
12533
|
}
|
|
12433
12534
|
if (updated.length > 0) {
|
|
12434
|
-
node_fs.
|
|
12535
|
+
await node_fs.promises.writeFile(statePath$11, content, "utf-8");
|
|
12435
12536
|
return cmdOk({
|
|
12436
12537
|
recorded: true,
|
|
12437
12538
|
updated
|
|
@@ -12441,10 +12542,10 @@ function cmdStateRecordSession(cwd, options, raw) {
|
|
|
12441
12542
|
reason: "No session fields found in STATE.md"
|
|
12442
12543
|
}, raw ? "false" : void 0);
|
|
12443
12544
|
}
|
|
12444
|
-
function cmdStateSnapshot(cwd, raw) {
|
|
12545
|
+
async function cmdStateSnapshot(cwd, raw) {
|
|
12445
12546
|
const statePath$12 = statePath(cwd);
|
|
12446
|
-
if (!
|
|
12447
|
-
const content = node_fs.
|
|
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");
|
|
12448
12549
|
const extractField = (fieldName) => stateExtractField(content, fieldName);
|
|
12449
12550
|
const currentPhase = extractField("Current Phase");
|
|
12450
12551
|
const currentPhaseName = extractField("Current Phase Name");
|
|
@@ -12515,14 +12616,13 @@ function cmdStateSnapshot(cwd, raw) {
|
|
|
12515
12616
|
*
|
|
12516
12617
|
* Ported from maxsim/bin/lib/roadmap.cjs
|
|
12517
12618
|
*/
|
|
12518
|
-
function cmdRoadmapGetPhase(cwd, phaseNum) {
|
|
12519
|
-
const
|
|
12520
|
-
if (!
|
|
12619
|
+
async function cmdRoadmapGetPhase(cwd, phaseNum) {
|
|
12620
|
+
const content = await safeReadFileAsync(roadmapPath(cwd));
|
|
12621
|
+
if (!content) return cmdOk({
|
|
12521
12622
|
found: false,
|
|
12522
12623
|
error: "ROADMAP.md not found"
|
|
12523
12624
|
}, "");
|
|
12524
12625
|
try {
|
|
12525
|
-
const content = node_fs.default.readFileSync(rmPath, "utf-8");
|
|
12526
12626
|
const escapedPhase = phaseNum.replace(/\./g, "\\.");
|
|
12527
12627
|
const phasePattern = getPhasePattern(escapedPhase, "i");
|
|
12528
12628
|
const headerMatch = content.match(phasePattern);
|
|
@@ -12606,7 +12706,7 @@ async function cmdRoadmapAnalyze(cwd) {
|
|
|
12606
12706
|
try {
|
|
12607
12707
|
const dirMatch = allDirs.find((d) => d.startsWith(p.normalized + "-") || d === p.normalized);
|
|
12608
12708
|
if (dirMatch) {
|
|
12609
|
-
const phaseFiles = await node_fs.
|
|
12709
|
+
const phaseFiles = await node_fs.promises.readdir(node_path.default.join(phasesDir, dirMatch));
|
|
12610
12710
|
planCount = phaseFiles.filter((f) => isPlanFile(f)).length;
|
|
12611
12711
|
summaryCount = phaseFiles.filter((f) => isSummaryFile(f)).length;
|
|
12612
12712
|
hasContext = phaseFiles.some((f) => f.endsWith("-CONTEXT.md") || f === "CONTEXT.md");
|
|
@@ -12667,10 +12767,10 @@ async function cmdRoadmapAnalyze(cwd) {
|
|
|
12667
12767
|
missing_phase_details: missingDetails.length > 0 ? missingDetails : null
|
|
12668
12768
|
});
|
|
12669
12769
|
}
|
|
12670
|
-
function cmdRoadmapUpdatePlanProgress(cwd, phaseNum) {
|
|
12770
|
+
async function cmdRoadmapUpdatePlanProgress(cwd, phaseNum) {
|
|
12671
12771
|
if (!phaseNum) return cmdErr("phase number required for roadmap update-plan-progress");
|
|
12672
12772
|
const rmPath = roadmapPath(cwd);
|
|
12673
|
-
const phaseInfo =
|
|
12773
|
+
const phaseInfo = await findPhaseInternalAsync(cwd, phaseNum);
|
|
12674
12774
|
if (!phaseInfo) return cmdErr(`Phase ${phaseNum} not found`);
|
|
12675
12775
|
const planCount = phaseInfo.plans.length;
|
|
12676
12776
|
const summaryCount = phaseInfo.summaries.length;
|
|
@@ -12683,20 +12783,21 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum) {
|
|
|
12683
12783
|
const isComplete = summaryCount >= planCount;
|
|
12684
12784
|
const status = isComplete ? "Complete" : summaryCount > 0 ? "In Progress" : "Planned";
|
|
12685
12785
|
const today = todayISO();
|
|
12686
|
-
|
|
12786
|
+
const rawContent = await safeReadFileAsync(rmPath);
|
|
12787
|
+
if (!rawContent) return cmdOk({
|
|
12687
12788
|
updated: false,
|
|
12688
12789
|
reason: "ROADMAP.md not found",
|
|
12689
12790
|
plan_count: planCount,
|
|
12690
12791
|
summary_count: summaryCount
|
|
12691
12792
|
}, "no roadmap");
|
|
12692
|
-
let roadmapContent =
|
|
12793
|
+
let roadmapContent = rawContent;
|
|
12693
12794
|
const phaseEscaped = phaseNum.replace(".", "\\.");
|
|
12694
12795
|
const dateField = isComplete ? ` ${today} ` : " ";
|
|
12695
12796
|
roadmapContent = roadmapContent.replace(new RegExp(`(\\|\\s*${phaseEscaped}\\.?\\s[^|]*\\|)[^|]*(\\|)\\s*[^|]*(\\|)\\s*[^|]*(\\|)`, "i"), `$1 ${summaryCount}/${planCount} $2 ${status.padEnd(11)}$3${dateField}$4`);
|
|
12696
12797
|
const planCountText = isComplete ? `${summaryCount}/${planCount} plans complete` : `${summaryCount}/${planCount} plans executed`;
|
|
12697
12798
|
roadmapContent = roadmapContent.replace(new RegExp(`(#{2,4}\\s*Phase\\s+${phaseEscaped}[\\s\\S]*?\\*\\*Plans:\\*\\*\\s*)[^\\n]+`, "i"), `$1${planCountText}`);
|
|
12698
12799
|
if (isComplete) roadmapContent = roadmapContent.replace(new RegExp(`(-\\s*\\[)[ ](\\]\\s*.*Phase\\s+${phaseEscaped}[:\\s][^\\n]*)`, "i"), `$1x$2 (completed ${today})`);
|
|
12699
|
-
node_fs.
|
|
12800
|
+
await node_fs.promises.writeFile(rmPath, roadmapContent, "utf-8");
|
|
12700
12801
|
return cmdOk({
|
|
12701
12802
|
updated: true,
|
|
12702
12803
|
phase: phaseNum,
|
|
@@ -14317,15 +14418,18 @@ function cmdValidateHealth(cwd, options) {
|
|
|
14317
14418
|
*
|
|
14318
14419
|
* Ported from maxsim/bin/lib/phase.cjs
|
|
14319
14420
|
*/
|
|
14320
|
-
function scaffoldPhaseStubs(dirPath, phaseId, name) {
|
|
14421
|
+
async function scaffoldPhaseStubs(dirPath, phaseId, name) {
|
|
14321
14422
|
const today = todayISO();
|
|
14322
|
-
node_fs.
|
|
14323
|
-
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`)]);
|
|
14324
14424
|
}
|
|
14325
|
-
function phaseAddCore(cwd, description, options) {
|
|
14425
|
+
async function phaseAddCore(cwd, description, options) {
|
|
14326
14426
|
const rmPath = roadmapPath(cwd);
|
|
14327
|
-
|
|
14328
|
-
|
|
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
|
+
}
|
|
14329
14433
|
const slug = generateSlugInternal(description);
|
|
14330
14434
|
const phasePattern = getPhasePattern();
|
|
14331
14435
|
let maxPhase = 0;
|
|
@@ -14338,15 +14442,15 @@ function phaseAddCore(cwd, description, options) {
|
|
|
14338
14442
|
const paddedNum = String(newPhaseNum).padStart(2, "0");
|
|
14339
14443
|
const dirName = `${paddedNum}-${slug}`;
|
|
14340
14444
|
const dirPath = planningPath(cwd, "phases", dirName);
|
|
14341
|
-
node_fs.
|
|
14342
|
-
node_fs.
|
|
14343
|
-
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);
|
|
14344
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`;
|
|
14345
14449
|
let updatedContent;
|
|
14346
14450
|
const lastSeparator = content.lastIndexOf("\n---");
|
|
14347
14451
|
if (lastSeparator > 0) updatedContent = content.slice(0, lastSeparator) + phaseEntry + content.slice(lastSeparator);
|
|
14348
14452
|
else updatedContent = content + phaseEntry;
|
|
14349
|
-
node_fs.
|
|
14453
|
+
await node_fs.promises.writeFile(rmPath, updatedContent, "utf-8");
|
|
14350
14454
|
return {
|
|
14351
14455
|
phase_number: newPhaseNum,
|
|
14352
14456
|
padded: paddedNum,
|
|
@@ -14355,10 +14459,14 @@ function phaseAddCore(cwd, description, options) {
|
|
|
14355
14459
|
description
|
|
14356
14460
|
};
|
|
14357
14461
|
}
|
|
14358
|
-
function phaseInsertCore(cwd, afterPhase, description, options) {
|
|
14462
|
+
async function phaseInsertCore(cwd, afterPhase, description, options) {
|
|
14359
14463
|
const rmPath = roadmapPath(cwd);
|
|
14360
|
-
|
|
14361
|
-
|
|
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
|
+
}
|
|
14362
14470
|
const slug = generateSlugInternal(description);
|
|
14363
14471
|
const afterPhaseEscaped = "0*" + normalizePhaseName(afterPhase).replace(/^0+/, "").replace(/\./g, "\\.");
|
|
14364
14472
|
if (!getPhasePattern(afterPhaseEscaped, "i").test(content)) throw new Error(`Phase ${afterPhase} not found in ROADMAP.md`);
|
|
@@ -14366,7 +14474,7 @@ function phaseInsertCore(cwd, afterPhase, description, options) {
|
|
|
14366
14474
|
const normalizedBase = normalizePhaseName(afterPhase);
|
|
14367
14475
|
const existingDecimals = [];
|
|
14368
14476
|
try {
|
|
14369
|
-
const dirs =
|
|
14477
|
+
const dirs = await listSubDirsAsync(phasesDirPath);
|
|
14370
14478
|
const decimalPattern = new RegExp(`^${normalizedBase}\\.(\\d+)`);
|
|
14371
14479
|
for (const dir of dirs) {
|
|
14372
14480
|
const dm = dir.match(decimalPattern);
|
|
@@ -14378,9 +14486,9 @@ function phaseInsertCore(cwd, afterPhase, description, options) {
|
|
|
14378
14486
|
const decimalPhase = `${normalizedBase}.${existingDecimals.length === 0 ? 1 : Math.max(...existingDecimals) + 1}`;
|
|
14379
14487
|
const dirName = `${decimalPhase}-${slug}`;
|
|
14380
14488
|
const dirPath = planningPath(cwd, "phases", dirName);
|
|
14381
|
-
node_fs.
|
|
14382
|
-
node_fs.
|
|
14383
|
-
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);
|
|
14384
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`;
|
|
14385
14493
|
const headerPattern = new RegExp(`(#{2,4}\\s*Phase\\s+0*${afterPhaseEscaped}:[^\\n]*\\n)`, "i");
|
|
14386
14494
|
const headerMatch = content.match(headerPattern);
|
|
@@ -14391,7 +14499,7 @@ function phaseInsertCore(cwd, afterPhase, description, options) {
|
|
|
14391
14499
|
if (nextPhaseMatch) insertIdx = headerIdx + headerMatch[0].length + nextPhaseMatch.index;
|
|
14392
14500
|
else insertIdx = content.length;
|
|
14393
14501
|
const updatedContent = content.slice(0, insertIdx) + phaseEntry + content.slice(insertIdx);
|
|
14394
|
-
node_fs.
|
|
14502
|
+
await node_fs.promises.writeFile(rmPath, updatedContent, "utf-8");
|
|
14395
14503
|
return {
|
|
14396
14504
|
phase_number: decimalPhase,
|
|
14397
14505
|
after_phase: afterPhase,
|
|
@@ -14400,18 +14508,19 @@ function phaseInsertCore(cwd, afterPhase, description, options) {
|
|
|
14400
14508
|
description
|
|
14401
14509
|
};
|
|
14402
14510
|
}
|
|
14403
|
-
function phaseCompleteCore(cwd, phaseNum) {
|
|
14511
|
+
async function phaseCompleteCore(cwd, phaseNum) {
|
|
14404
14512
|
const rmPath = roadmapPath(cwd);
|
|
14405
14513
|
const stPath = statePath(cwd);
|
|
14406
14514
|
const phasesDirPath = phasesPath(cwd);
|
|
14407
14515
|
const today = todayISO();
|
|
14408
|
-
const phaseInfo =
|
|
14516
|
+
const phaseInfo = await findPhaseInternalAsync(cwd, phaseNum);
|
|
14409
14517
|
if (!phaseInfo) throw new Error(`Phase ${phaseNum} not found`);
|
|
14410
14518
|
const planCount = phaseInfo.plans.length;
|
|
14411
14519
|
const summaryCount = phaseInfo.summaries.length;
|
|
14412
14520
|
let requirementsUpdated = false;
|
|
14413
|
-
|
|
14414
|
-
|
|
14521
|
+
const rmExists = await pathExistsAsync(rmPath);
|
|
14522
|
+
if (rmExists) {
|
|
14523
|
+
let roadmapContent = await node_fs.promises.readFile(rmPath, "utf-8");
|
|
14415
14524
|
const checkboxPattern = new RegExp(`(-\\s*\\[)[ ](\\]\\s*.*Phase\\s+${escapePhaseNum(phaseNum)}[:\\s][^\\n]*)`, "i");
|
|
14416
14525
|
roadmapContent = roadmapContent.replace(checkboxPattern, `$1x$2 (completed ${today})`);
|
|
14417
14526
|
const phaseEscaped = escapePhaseNum(phaseNum);
|
|
@@ -14420,20 +14529,20 @@ function phaseCompleteCore(cwd, phaseNum) {
|
|
|
14420
14529
|
const planCountPattern = new RegExp(`(#{2,4}\\s*Phase\\s+${phaseEscaped}[\\s\\S]*?\\*\\*Plans:\\*\\*\\s*)[^\\n]+`, "i");
|
|
14421
14530
|
roadmapContent = roadmapContent.replace(planCountPattern, `$1${summaryCount}/${planCount} plans complete`);
|
|
14422
14531
|
debugLog("phase-complete-write", `writing ROADMAP.md for phase ${phaseNum}`);
|
|
14423
|
-
node_fs.
|
|
14532
|
+
await node_fs.promises.writeFile(rmPath, roadmapContent, "utf-8");
|
|
14424
14533
|
debugLog("phase-complete-write", `ROADMAP.md updated for phase ${phaseNum}`);
|
|
14425
14534
|
const reqPath = planningPath(cwd, "REQUIREMENTS.md");
|
|
14426
|
-
if (
|
|
14535
|
+
if (await pathExistsAsync(reqPath)) {
|
|
14427
14536
|
const reqMatch = roadmapContent.match(new RegExp(`Phase\\s+${escapePhaseNum(phaseNum)}[\\s\\S]*?\\*\\*Requirements:\\*\\*\\s*([^\\n]+)`, "i"));
|
|
14428
14537
|
if (reqMatch) {
|
|
14429
14538
|
const reqIds = reqMatch[1].replace(/[\[\]]/g, "").split(/[,\s]+/).map((r) => r.trim()).filter(Boolean);
|
|
14430
|
-
let reqContent = node_fs.
|
|
14539
|
+
let reqContent = await node_fs.promises.readFile(reqPath, "utf-8");
|
|
14431
14540
|
for (const reqId of reqIds) {
|
|
14432
14541
|
reqContent = reqContent.replace(new RegExp(`(-\\s*\\[)[ ](\\]\\s*\\*\\*${reqId}\\*\\*)`, "gi"), "$1x$2");
|
|
14433
14542
|
reqContent = reqContent.replace(new RegExp(`(\\|\\s*${reqId}\\s*\\|[^|]+\\|)\\s*Pending\\s*(\\|)`, "gi"), "$1 Complete $2");
|
|
14434
14543
|
}
|
|
14435
14544
|
debugLog("phase-complete-write", `writing REQUIREMENTS.md for phase ${phaseNum}`);
|
|
14436
|
-
node_fs.
|
|
14545
|
+
await node_fs.promises.writeFile(reqPath, reqContent, "utf-8");
|
|
14437
14546
|
debugLog("phase-complete-write", `REQUIREMENTS.md updated for phase ${phaseNum}`);
|
|
14438
14547
|
requirementsUpdated = true;
|
|
14439
14548
|
}
|
|
@@ -14443,7 +14552,7 @@ function phaseCompleteCore(cwd, phaseNum) {
|
|
|
14443
14552
|
let nextPhaseName = null;
|
|
14444
14553
|
let isLastPhase = true;
|
|
14445
14554
|
try {
|
|
14446
|
-
const dirs =
|
|
14555
|
+
const dirs = await listSubDirsAsync(phasesDirPath, true);
|
|
14447
14556
|
for (const dir of dirs) {
|
|
14448
14557
|
const dm = dir.match(/^(\d+[A-Z]?(?:\.\d+)?)-?(.*)/i);
|
|
14449
14558
|
if (dm) {
|
|
@@ -14458,8 +14567,9 @@ function phaseCompleteCore(cwd, phaseNum) {
|
|
|
14458
14567
|
} catch (e) {
|
|
14459
14568
|
debugLog("phase-complete-next-phase-scan-failed", e);
|
|
14460
14569
|
}
|
|
14461
|
-
|
|
14462
|
-
|
|
14570
|
+
const stExists = await pathExistsAsync(stPath);
|
|
14571
|
+
if (stExists) {
|
|
14572
|
+
let stateContent = await node_fs.promises.readFile(stPath, "utf-8");
|
|
14463
14573
|
stateContent = stateContent.replace(/(\*\*Current Phase:\*\*\s*).*/, `$1${nextPhaseNum || phaseNum}`);
|
|
14464
14574
|
if (nextPhaseName) stateContent = stateContent.replace(/(\*\*Current Phase Name:\*\*\s*).*/, `$1${nextPhaseName.replace(/-/g, " ")}`);
|
|
14465
14575
|
stateContent = stateContent.replace(/(\*\*Status:\*\*\s*).*/, `$1${isLastPhase ? "Milestone complete" : "Ready to plan"}`);
|
|
@@ -14467,7 +14577,7 @@ function phaseCompleteCore(cwd, phaseNum) {
|
|
|
14467
14577
|
stateContent = stateContent.replace(/(\*\*Last Activity:\*\*\s*).*/, `$1${today}`);
|
|
14468
14578
|
stateContent = stateContent.replace(/(\*\*Last Activity Description:\*\*\s*).*/, `$1Phase ${phaseNum} complete${nextPhaseNum ? `, transitioned to Phase ${nextPhaseNum}` : ""}`);
|
|
14469
14579
|
debugLog("phase-complete-write", `writing STATE.md for phase ${phaseNum}`);
|
|
14470
|
-
node_fs.
|
|
14580
|
+
await node_fs.promises.writeFile(stPath, stateContent, "utf-8");
|
|
14471
14581
|
debugLog("phase-complete-write", `STATE.md updated for phase ${phaseNum}`);
|
|
14472
14582
|
}
|
|
14473
14583
|
return {
|
|
@@ -14478,15 +14588,15 @@ function phaseCompleteCore(cwd, phaseNum) {
|
|
|
14478
14588
|
next_phase_name: nextPhaseName,
|
|
14479
14589
|
is_last_phase: isLastPhase,
|
|
14480
14590
|
date: today,
|
|
14481
|
-
roadmap_updated:
|
|
14482
|
-
state_updated:
|
|
14591
|
+
roadmap_updated: rmExists,
|
|
14592
|
+
state_updated: stExists,
|
|
14483
14593
|
requirements_updated: requirementsUpdated
|
|
14484
14594
|
};
|
|
14485
14595
|
}
|
|
14486
14596
|
async function cmdPhasesList(cwd, options) {
|
|
14487
14597
|
const phasesDirPath = phasesPath(cwd);
|
|
14488
14598
|
const { type, phase, includeArchived, offset, limit } = options;
|
|
14489
|
-
if (!
|
|
14599
|
+
if (!await pathExistsAsync(phasesDirPath)) if (type) return cmdOk({
|
|
14490
14600
|
files: [],
|
|
14491
14601
|
count: 0,
|
|
14492
14602
|
total: 0
|
|
@@ -14499,7 +14609,7 @@ async function cmdPhasesList(cwd, options) {
|
|
|
14499
14609
|
try {
|
|
14500
14610
|
let dirs = await listSubDirsAsync(phasesDirPath);
|
|
14501
14611
|
if (includeArchived) {
|
|
14502
|
-
const archived =
|
|
14612
|
+
const archived = await getArchivedPhaseDirsAsync(cwd);
|
|
14503
14613
|
for (const a of archived) dirs.push(`${a.name} [${a.milestone}]`);
|
|
14504
14614
|
}
|
|
14505
14615
|
dirs.sort((a, b) => comparePhaseNum(a, b));
|
|
@@ -14518,7 +14628,7 @@ async function cmdPhasesList(cwd, options) {
|
|
|
14518
14628
|
if (type) {
|
|
14519
14629
|
const files = (await Promise.all(dirs.map(async (dir) => {
|
|
14520
14630
|
const dirPath = node_path.default.join(phasesDirPath, dir);
|
|
14521
|
-
const dirFiles = await node_fs.
|
|
14631
|
+
const dirFiles = await node_fs.promises.readdir(dirPath);
|
|
14522
14632
|
let filtered;
|
|
14523
14633
|
if (type === "plans") filtered = dirFiles.filter(isPlanFile);
|
|
14524
14634
|
else if (type === "summaries") filtered = dirFiles.filter(isSummaryFile);
|
|
@@ -14544,17 +14654,17 @@ async function cmdPhasesList(cwd, options) {
|
|
|
14544
14654
|
return cmdErr("Failed to list phases: " + e.message);
|
|
14545
14655
|
}
|
|
14546
14656
|
}
|
|
14547
|
-
function cmdPhaseNextDecimal(cwd, basePhase) {
|
|
14657
|
+
async function cmdPhaseNextDecimal(cwd, basePhase) {
|
|
14548
14658
|
const phasesDirPath = phasesPath(cwd);
|
|
14549
14659
|
const normalized = normalizePhaseName(basePhase);
|
|
14550
|
-
if (!
|
|
14660
|
+
if (!await pathExistsAsync(phasesDirPath)) return cmdOk({
|
|
14551
14661
|
found: false,
|
|
14552
14662
|
base_phase: normalized,
|
|
14553
14663
|
next: `${normalized}.1`,
|
|
14554
14664
|
existing: []
|
|
14555
14665
|
}, `${normalized}.1`);
|
|
14556
14666
|
try {
|
|
14557
|
-
const dirs =
|
|
14667
|
+
const dirs = await listSubDirsAsync(phasesDirPath);
|
|
14558
14668
|
const baseExists = dirs.some((d) => d.startsWith(normalized + "-") || d === normalized);
|
|
14559
14669
|
const decimalPattern = new RegExp(`^${normalized}\\.(\\d+)`);
|
|
14560
14670
|
const existingDecimals = [];
|
|
@@ -14581,7 +14691,7 @@ function cmdPhaseNextDecimal(cwd, basePhase) {
|
|
|
14581
14691
|
return cmdErr("Failed to calculate next decimal phase: " + e.message);
|
|
14582
14692
|
}
|
|
14583
14693
|
}
|
|
14584
|
-
function cmdFindPhase(cwd, phase) {
|
|
14694
|
+
async function cmdFindPhase(cwd, phase) {
|
|
14585
14695
|
if (!phase) return cmdErr("phase identifier required");
|
|
14586
14696
|
const phasesDirPath = phasesPath(cwd);
|
|
14587
14697
|
const normalized = normalizePhaseName(phase);
|
|
@@ -14594,13 +14704,13 @@ function cmdFindPhase(cwd, phase) {
|
|
|
14594
14704
|
summaries: []
|
|
14595
14705
|
};
|
|
14596
14706
|
try {
|
|
14597
|
-
const match =
|
|
14707
|
+
const match = (await listSubDirsAsync(phasesDirPath, true)).find((d) => d.startsWith(normalized));
|
|
14598
14708
|
if (!match) return cmdOk(notFound, "");
|
|
14599
14709
|
const dirMatch = match.match(/^(\d+[A-Z]?(?:\.\d+)?)-?(.*)/i);
|
|
14600
14710
|
const phaseNumber = dirMatch ? dirMatch[1] : normalized;
|
|
14601
14711
|
const phaseName = dirMatch && dirMatch[2] ? dirMatch[2] : null;
|
|
14602
14712
|
const phaseDir = node_path.default.join(phasesDirPath, match);
|
|
14603
|
-
const phaseFiles = node_fs.
|
|
14713
|
+
const phaseFiles = await node_fs.promises.readdir(phaseDir);
|
|
14604
14714
|
const plans = phaseFiles.filter(isPlanFile).sort();
|
|
14605
14715
|
const summaries = phaseFiles.filter(isSummaryFile).sort();
|
|
14606
14716
|
const result = {
|
|
@@ -14616,13 +14726,13 @@ function cmdFindPhase(cwd, phase) {
|
|
|
14616
14726
|
return cmdOk(notFound, "");
|
|
14617
14727
|
}
|
|
14618
14728
|
}
|
|
14619
|
-
function cmdPhasePlanIndex(cwd, phase) {
|
|
14729
|
+
async function cmdPhasePlanIndex(cwd, phase) {
|
|
14620
14730
|
if (!phase) return cmdErr("phase required for phase-plan-index");
|
|
14621
14731
|
const phasesDirPath = phasesPath(cwd);
|
|
14622
14732
|
const normalized = normalizePhaseName(phase);
|
|
14623
14733
|
let phaseDir = null;
|
|
14624
14734
|
try {
|
|
14625
|
-
const match =
|
|
14735
|
+
const match = (await listSubDirsAsync(phasesDirPath, true)).find((d) => d.startsWith(normalized));
|
|
14626
14736
|
if (match) phaseDir = node_path.default.join(phasesDirPath, match);
|
|
14627
14737
|
} catch (e) {
|
|
14628
14738
|
debugLog("phase-plan-index-failed", e);
|
|
@@ -14635,7 +14745,7 @@ function cmdPhasePlanIndex(cwd, phase) {
|
|
|
14635
14745
|
incomplete: [],
|
|
14636
14746
|
has_checkpoints: false
|
|
14637
14747
|
});
|
|
14638
|
-
const phaseFiles = node_fs.
|
|
14748
|
+
const phaseFiles = await node_fs.promises.readdir(phaseDir);
|
|
14639
14749
|
const planFiles = phaseFiles.filter(isPlanFile).sort();
|
|
14640
14750
|
const summaryFiles = phaseFiles.filter(isSummaryFile);
|
|
14641
14751
|
const completedPlanIds = new Set(summaryFiles.map(summaryId));
|
|
@@ -14643,10 +14753,11 @@ function cmdPhasePlanIndex(cwd, phase) {
|
|
|
14643
14753
|
const waves = {};
|
|
14644
14754
|
const incomplete = [];
|
|
14645
14755
|
let hasCheckpoints = false;
|
|
14646
|
-
|
|
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];
|
|
14647
14759
|
const id = planId(planFile);
|
|
14648
|
-
const
|
|
14649
|
-
const content = node_fs.default.readFileSync(planPath, "utf-8");
|
|
14760
|
+
const content = planContents[i];
|
|
14650
14761
|
const fm = extractFrontmatter(content);
|
|
14651
14762
|
const taskCount = (content.match(/##\s*Task\s*\d+/gi) || []).length;
|
|
14652
14763
|
const wave = parseInt(fm.wave, 10) || 1;
|
|
@@ -14679,10 +14790,10 @@ function cmdPhasePlanIndex(cwd, phase) {
|
|
|
14679
14790
|
has_checkpoints: hasCheckpoints
|
|
14680
14791
|
});
|
|
14681
14792
|
}
|
|
14682
|
-
function cmdPhaseAdd(cwd, description) {
|
|
14793
|
+
async function cmdPhaseAdd(cwd, description) {
|
|
14683
14794
|
if (!description) return cmdErr("description required for phase add");
|
|
14684
14795
|
try {
|
|
14685
|
-
const result = phaseAddCore(cwd, description, { includeStubs: false });
|
|
14796
|
+
const result = await phaseAddCore(cwd, description, { includeStubs: false });
|
|
14686
14797
|
return cmdOk({
|
|
14687
14798
|
phase_number: result.phase_number,
|
|
14688
14799
|
padded: result.padded,
|
|
@@ -14694,10 +14805,10 @@ function cmdPhaseAdd(cwd, description) {
|
|
|
14694
14805
|
return cmdErr(e.message);
|
|
14695
14806
|
}
|
|
14696
14807
|
}
|
|
14697
|
-
function cmdPhaseInsert(cwd, afterPhase, description) {
|
|
14808
|
+
async function cmdPhaseInsert(cwd, afterPhase, description) {
|
|
14698
14809
|
if (!afterPhase || !description) return cmdErr("after-phase and description required for phase insert");
|
|
14699
14810
|
try {
|
|
14700
|
-
const result = phaseInsertCore(cwd, afterPhase, description, { includeStubs: false });
|
|
14811
|
+
const result = await phaseInsertCore(cwd, afterPhase, description, { includeStubs: false });
|
|
14701
14812
|
return cmdOk({
|
|
14702
14813
|
phase_number: result.phase_number,
|
|
14703
14814
|
after_phase: result.after_phase,
|
|
@@ -14709,26 +14820,26 @@ function cmdPhaseInsert(cwd, afterPhase, description) {
|
|
|
14709
14820
|
return cmdErr(e.message);
|
|
14710
14821
|
}
|
|
14711
14822
|
}
|
|
14712
|
-
function cmdPhaseRemove(cwd, targetPhase, options) {
|
|
14823
|
+
async function cmdPhaseRemove(cwd, targetPhase, options) {
|
|
14713
14824
|
if (!targetPhase) return cmdErr("phase number required for phase remove");
|
|
14714
14825
|
const rmPath = roadmapPath(cwd);
|
|
14715
14826
|
const phasesDirPath = phasesPath(cwd);
|
|
14716
14827
|
const force = options.force || false;
|
|
14717
|
-
if (!
|
|
14828
|
+
if (!await pathExistsAsync(rmPath)) return cmdErr("ROADMAP.md not found");
|
|
14718
14829
|
const normalized = normalizePhaseName(targetPhase);
|
|
14719
14830
|
const isDecimal = targetPhase.includes(".");
|
|
14720
14831
|
let targetDir = null;
|
|
14721
14832
|
try {
|
|
14722
|
-
targetDir =
|
|
14833
|
+
targetDir = (await listSubDirsAsync(phasesDirPath, true)).find((d) => d.startsWith(normalized + "-") || d === normalized) || null;
|
|
14723
14834
|
} catch (e) {
|
|
14724
14835
|
debugLog("phase-remove-find-target-failed", e);
|
|
14725
14836
|
}
|
|
14726
14837
|
if (targetDir && !force) {
|
|
14727
14838
|
const targetPath = node_path.default.join(phasesDirPath, targetDir);
|
|
14728
|
-
const summaries = node_fs.
|
|
14839
|
+
const summaries = (await node_fs.promises.readdir(targetPath)).filter(isSummaryFile);
|
|
14729
14840
|
if (summaries.length > 0) return cmdErr(`Phase ${targetPhase} has ${summaries.length} executed plan(s). Use --force to remove anyway.`);
|
|
14730
14841
|
}
|
|
14731
|
-
if (targetDir) node_fs.
|
|
14842
|
+
if (targetDir) await node_fs.promises.rm(node_path.default.join(phasesDirPath, targetDir), {
|
|
14732
14843
|
recursive: true,
|
|
14733
14844
|
force: true
|
|
14734
14845
|
});
|
|
@@ -14739,7 +14850,7 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
|
|
|
14739
14850
|
const baseInt = baseParts[0];
|
|
14740
14851
|
const removedDecimal = parseInt(baseParts[1], 10);
|
|
14741
14852
|
try {
|
|
14742
|
-
const dirs =
|
|
14853
|
+
const dirs = await listSubDirsAsync(phasesDirPath, true);
|
|
14743
14854
|
const decPattern = new RegExp(`^${baseInt}\\.(\\d+)-(.+)$`);
|
|
14744
14855
|
const toRename = [];
|
|
14745
14856
|
for (const dir of dirs) {
|
|
@@ -14756,15 +14867,15 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
|
|
|
14756
14867
|
const oldPhaseId = `${baseInt}.${item.oldDecimal}`;
|
|
14757
14868
|
const newPhaseId = `${baseInt}.${newDecimal}`;
|
|
14758
14869
|
const newDirName = `${baseInt}.${newDecimal}-${item.slug}`;
|
|
14759
|
-
node_fs.
|
|
14870
|
+
await node_fs.promises.rename(node_path.default.join(phasesDirPath, item.dir), node_path.default.join(phasesDirPath, newDirName));
|
|
14760
14871
|
renamedDirs.push({
|
|
14761
14872
|
from: item.dir,
|
|
14762
14873
|
to: newDirName
|
|
14763
14874
|
});
|
|
14764
|
-
const dirFiles = node_fs.
|
|
14875
|
+
const dirFiles = await node_fs.promises.readdir(node_path.default.join(phasesDirPath, newDirName));
|
|
14765
14876
|
for (const f of dirFiles) if (f.includes(oldPhaseId)) {
|
|
14766
14877
|
const newFileName = f.replace(oldPhaseId, newPhaseId);
|
|
14767
|
-
node_fs.
|
|
14878
|
+
await node_fs.promises.rename(node_path.default.join(phasesDirPath, newDirName, f), node_path.default.join(phasesDirPath, newDirName, newFileName));
|
|
14768
14879
|
renamedFiles.push({
|
|
14769
14880
|
from: f,
|
|
14770
14881
|
to: newFileName
|
|
@@ -14780,7 +14891,7 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
|
|
|
14780
14891
|
} else {
|
|
14781
14892
|
const removedInt = parseInt(normalized, 10);
|
|
14782
14893
|
try {
|
|
14783
|
-
const dirs =
|
|
14894
|
+
const dirs = await listSubDirsAsync(phasesDirPath, true);
|
|
14784
14895
|
const toRename = [];
|
|
14785
14896
|
for (const dir of dirs) {
|
|
14786
14897
|
const dm = dir.match(/^(\d+)([A-Z])?(?:\.(\d+))?-(.+)$/i);
|
|
@@ -14807,15 +14918,15 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
|
|
|
14807
14918
|
const oldPrefix = `${oldPadded}${letterSuffix}${decimalSuffix}`;
|
|
14808
14919
|
const newPrefix = `${newPadded}${letterSuffix}${decimalSuffix}`;
|
|
14809
14920
|
const newDirName = `${newPrefix}-${item.slug}`;
|
|
14810
|
-
node_fs.
|
|
14921
|
+
await node_fs.promises.rename(node_path.default.join(phasesDirPath, item.dir), node_path.default.join(phasesDirPath, newDirName));
|
|
14811
14922
|
renamedDirs.push({
|
|
14812
14923
|
from: item.dir,
|
|
14813
14924
|
to: newDirName
|
|
14814
14925
|
});
|
|
14815
|
-
const dirFiles = node_fs.
|
|
14926
|
+
const dirFiles = await node_fs.promises.readdir(node_path.default.join(phasesDirPath, newDirName));
|
|
14816
14927
|
for (const f of dirFiles) if (f.startsWith(oldPrefix)) {
|
|
14817
14928
|
const newFileName = newPrefix + f.slice(oldPrefix.length);
|
|
14818
|
-
node_fs.
|
|
14929
|
+
await node_fs.promises.rename(node_path.default.join(phasesDirPath, newDirName, f), node_path.default.join(phasesDirPath, newDirName, newFileName));
|
|
14819
14930
|
renamedFiles.push({
|
|
14820
14931
|
from: f,
|
|
14821
14932
|
to: newFileName
|
|
@@ -14829,7 +14940,7 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
|
|
|
14829
14940
|
});
|
|
14830
14941
|
}
|
|
14831
14942
|
}
|
|
14832
|
-
let roadmapContent = node_fs.
|
|
14943
|
+
let roadmapContent = await node_fs.promises.readFile(rmPath, "utf-8");
|
|
14833
14944
|
const targetEscaped = escapePhaseNum(targetPhase);
|
|
14834
14945
|
const sectionPattern = new RegExp(`\\n?#{2,4}\\s*Phase\\s+${targetEscaped}\\s*:[\\s\\S]*?(?=\\n#{2,4}\\s+Phase\\s+\\d|$)`, "i");
|
|
14835
14946
|
roadmapContent = roadmapContent.replace(sectionPattern, "");
|
|
@@ -14852,10 +14963,11 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
|
|
|
14852
14963
|
roadmapContent = roadmapContent.replace(new RegExp(`(Depends on:\\*\\*\\s*Phase\\s+)${oldStr}\\b`, "gi"), `$1${newStr}`);
|
|
14853
14964
|
}
|
|
14854
14965
|
}
|
|
14855
|
-
node_fs.
|
|
14966
|
+
await node_fs.promises.writeFile(rmPath, roadmapContent, "utf-8");
|
|
14856
14967
|
const stPath = statePath(cwd);
|
|
14857
|
-
|
|
14858
|
-
|
|
14968
|
+
const stExists = await pathExistsAsync(stPath);
|
|
14969
|
+
if (stExists) {
|
|
14970
|
+
let stateContent = await node_fs.promises.readFile(stPath, "utf-8");
|
|
14859
14971
|
const totalPattern = /(\*\*Total Phases:\*\*\s*)(\d+)/;
|
|
14860
14972
|
const totalMatch = stateContent.match(totalPattern);
|
|
14861
14973
|
if (totalMatch) {
|
|
@@ -14868,7 +14980,7 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
|
|
|
14868
14980
|
const oldTotal = parseInt(ofMatch[2], 10);
|
|
14869
14981
|
stateContent = stateContent.replace(ofPattern, `$1${oldTotal - 1}$3`);
|
|
14870
14982
|
}
|
|
14871
|
-
node_fs.
|
|
14983
|
+
await node_fs.promises.writeFile(stPath, stateContent, "utf-8");
|
|
14872
14984
|
}
|
|
14873
14985
|
return cmdOk({
|
|
14874
14986
|
removed: targetPhase,
|
|
@@ -14876,13 +14988,13 @@ function cmdPhaseRemove(cwd, targetPhase, options) {
|
|
|
14876
14988
|
renamed_directories: renamedDirs,
|
|
14877
14989
|
renamed_files: renamedFiles,
|
|
14878
14990
|
roadmap_updated: true,
|
|
14879
|
-
state_updated:
|
|
14991
|
+
state_updated: stExists
|
|
14880
14992
|
});
|
|
14881
14993
|
}
|
|
14882
|
-
function cmdPhaseComplete(cwd, phaseNum) {
|
|
14994
|
+
async function cmdPhaseComplete(cwd, phaseNum) {
|
|
14883
14995
|
if (!phaseNum) return cmdErr("phase number required for phase complete");
|
|
14884
14996
|
try {
|
|
14885
|
-
const result = phaseCompleteCore(cwd, phaseNum);
|
|
14997
|
+
const result = await phaseCompleteCore(cwd, phaseNum);
|
|
14886
14998
|
return cmdOk({
|
|
14887
14999
|
completed_phase: result.completed_phase,
|
|
14888
15000
|
phase_name: result.phase_name,
|
|
@@ -15137,7 +15249,17 @@ function resolveArtefaktPath(cwd, type, phase) {
|
|
|
15137
15249
|
}
|
|
15138
15250
|
return planningPath(cwd, filename);
|
|
15139
15251
|
}
|
|
15252
|
+
const TEMPLATE_FILES = {
|
|
15253
|
+
"decisions": "decisions.md",
|
|
15254
|
+
"acceptance-criteria": "acceptance-criteria.md",
|
|
15255
|
+
"no-gos": "no-gos.md"
|
|
15256
|
+
};
|
|
15140
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) {
|
|
15141
15263
|
const today = todayISO();
|
|
15142
15264
|
switch (type) {
|
|
15143
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`;
|
|
@@ -15247,6 +15369,36 @@ function addIfExists(files, cwd, relPath, role) {
|
|
|
15247
15369
|
const entry = fileEntry(cwd, relPath, role);
|
|
15248
15370
|
if (entry) files.push(entry);
|
|
15249
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
|
+
}
|
|
15250
15402
|
function loadProjectContext(cwd) {
|
|
15251
15403
|
const files = [];
|
|
15252
15404
|
addIfExists(files, cwd, ".planning/PROJECT.md", "project-vision");
|
|
@@ -15295,6 +15447,16 @@ function loadArtefakteContext(cwd, phase) {
|
|
|
15295
15447
|
}
|
|
15296
15448
|
return files;
|
|
15297
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
|
+
}
|
|
15298
15460
|
function loadHistoryContext(cwd, currentPhase) {
|
|
15299
15461
|
const files = [];
|
|
15300
15462
|
const pd = phasesPath(cwd);
|
|
@@ -15318,6 +15480,8 @@ function cmdContextLoad(cwd, phase, topic, includeHistory) {
|
|
|
15318
15480
|
allFiles.push(...loadProjectContext(cwd));
|
|
15319
15481
|
allFiles.push(...loadRoadmapContext(cwd));
|
|
15320
15482
|
allFiles.push(...loadArtefakteContext(cwd, phase));
|
|
15483
|
+
const selectedDocs = selectCodebaseDocs(topic);
|
|
15484
|
+
allFiles.push(...loadCodebaseContext(cwd, topic));
|
|
15321
15485
|
if (phase) allFiles.push(...loadPhaseContext(cwd, phase));
|
|
15322
15486
|
if (includeHistory) allFiles.push(...loadHistoryContext(cwd, phase));
|
|
15323
15487
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -15330,7 +15494,8 @@ function cmdContextLoad(cwd, phase, topic, includeHistory) {
|
|
|
15330
15494
|
files: deduped,
|
|
15331
15495
|
total_size: deduped.reduce((sum, f) => sum + f.size, 0),
|
|
15332
15496
|
phase: phase ?? null,
|
|
15333
|
-
topic: topic ?? null
|
|
15497
|
+
topic: topic ?? null,
|
|
15498
|
+
codebase_docs_selected: selectedDocs
|
|
15334
15499
|
});
|
|
15335
15500
|
}
|
|
15336
15501
|
|
|
@@ -15372,12 +15537,12 @@ function readSkillInfo(skillDir, dirName) {
|
|
|
15372
15537
|
/**
|
|
15373
15538
|
* List all installed skills from `.claude/skills/`.
|
|
15374
15539
|
*/
|
|
15375
|
-
function cmdSkillList(cwd
|
|
15540
|
+
function cmdSkillList(cwd) {
|
|
15376
15541
|
const dir = skillsDir(cwd);
|
|
15377
|
-
if (!node_fs.default.existsSync(dir))
|
|
15542
|
+
if (!node_fs.default.existsSync(dir)) return cmdOk({
|
|
15378
15543
|
skills: [],
|
|
15379
15544
|
count: 0
|
|
15380
|
-
},
|
|
15545
|
+
}, "No skills installed.");
|
|
15381
15546
|
const entries = node_fs.default.readdirSync(dir, { withFileTypes: true });
|
|
15382
15547
|
const skills = [];
|
|
15383
15548
|
for (const entry of entries) {
|
|
@@ -15385,56 +15550,52 @@ function cmdSkillList(cwd, raw) {
|
|
|
15385
15550
|
const info = readSkillInfo(node_path.default.join(dir, entry.name), entry.name);
|
|
15386
15551
|
if (info) skills.push(info);
|
|
15387
15552
|
}
|
|
15388
|
-
|
|
15553
|
+
return cmdOk({
|
|
15389
15554
|
skills,
|
|
15390
15555
|
count: skills.length
|
|
15391
|
-
},
|
|
15556
|
+
}, skills.map((s) => `${s.name}: ${s.description}`).join("\n"));
|
|
15392
15557
|
}
|
|
15393
15558
|
/**
|
|
15394
15559
|
* Install a specific skill from the templates directory.
|
|
15395
15560
|
*/
|
|
15396
|
-
function cmdSkillInstall(cwd, skillName
|
|
15397
|
-
if (!skillName)
|
|
15561
|
+
function cmdSkillInstall(cwd, skillName) {
|
|
15562
|
+
if (!skillName) return cmdErr("skill name required. Usage: skill-install <name>");
|
|
15398
15563
|
const srcFile = node_path.default.join(skillsTemplateDir(), skillName, "SKILL.md");
|
|
15399
|
-
if (!node_fs.default.existsSync(srcFile))
|
|
15564
|
+
if (!node_fs.default.existsSync(srcFile)) return cmdErr(`Skill "${skillName}" not found in templates. Available: ${listAvailableTemplates().join(", ")}`);
|
|
15400
15565
|
const destDir = node_path.default.join(skillsDir(cwd), skillName);
|
|
15401
15566
|
const destFile = node_path.default.join(destDir, "SKILL.md");
|
|
15402
15567
|
node_fs.default.mkdirSync(destDir, { recursive: true });
|
|
15403
15568
|
node_fs.default.copyFileSync(srcFile, destFile);
|
|
15404
|
-
|
|
15569
|
+
return cmdOk({
|
|
15405
15570
|
installed: true,
|
|
15406
15571
|
skill: skillName,
|
|
15407
15572
|
path: node_path.default.relative(cwd, destFile)
|
|
15408
|
-
},
|
|
15573
|
+
}, `Installed skill: ${skillName}`);
|
|
15409
15574
|
}
|
|
15410
15575
|
/**
|
|
15411
15576
|
* Update one or all installed skills from the templates source.
|
|
15412
15577
|
*/
|
|
15413
|
-
function cmdSkillUpdate(cwd, skillName
|
|
15578
|
+
function cmdSkillUpdate(cwd, skillName) {
|
|
15414
15579
|
const dir = skillsDir(cwd);
|
|
15415
15580
|
const templateDir = skillsTemplateDir();
|
|
15416
15581
|
if (skillName) {
|
|
15417
15582
|
const srcFile = node_path.default.join(templateDir, skillName, "SKILL.md");
|
|
15418
|
-
if (!node_fs.default.existsSync(srcFile))
|
|
15583
|
+
if (!node_fs.default.existsSync(srcFile)) return cmdErr(`Skill template "${skillName}" not found.`);
|
|
15419
15584
|
const destDir = node_path.default.join(dir, skillName);
|
|
15420
|
-
if (!node_fs.default.existsSync(destDir))
|
|
15585
|
+
if (!node_fs.default.existsSync(destDir)) return cmdErr(`Skill "${skillName}" is not installed. Use skill-install first.`);
|
|
15421
15586
|
const destFile = node_path.default.join(destDir, "SKILL.md");
|
|
15422
15587
|
node_fs.default.copyFileSync(srcFile, destFile);
|
|
15423
|
-
|
|
15588
|
+
return cmdOk({
|
|
15424
15589
|
updated: [skillName],
|
|
15425
15590
|
skipped: [],
|
|
15426
15591
|
not_found: []
|
|
15427
|
-
},
|
|
15428
|
-
return;
|
|
15429
|
-
}
|
|
15430
|
-
if (!node_fs.default.existsSync(dir)) {
|
|
15431
|
-
output({
|
|
15432
|
-
updated: [],
|
|
15433
|
-
skipped: [],
|
|
15434
|
-
not_found: []
|
|
15435
|
-
}, raw, "No skills installed.");
|
|
15436
|
-
return;
|
|
15592
|
+
}, `Updated skill: ${skillName}`);
|
|
15437
15593
|
}
|
|
15594
|
+
if (!node_fs.default.existsSync(dir)) return cmdOk({
|
|
15595
|
+
updated: [],
|
|
15596
|
+
skipped: [],
|
|
15597
|
+
not_found: []
|
|
15598
|
+
}, "No skills installed.");
|
|
15438
15599
|
const entries = node_fs.default.readdirSync(dir, { withFileTypes: true });
|
|
15439
15600
|
const updated = [];
|
|
15440
15601
|
const skipped = [];
|
|
@@ -15451,10 +15612,10 @@ function cmdSkillUpdate(cwd, skillName, raw) {
|
|
|
15451
15612
|
updated.push(name);
|
|
15452
15613
|
}
|
|
15453
15614
|
const summary = updated.length > 0 ? `Updated ${updated.length} skill(s): ${updated.join(", ")}` : "No skills updated.";
|
|
15454
|
-
|
|
15615
|
+
return cmdOk({
|
|
15455
15616
|
updated,
|
|
15456
15617
|
skipped
|
|
15457
|
-
},
|
|
15618
|
+
}, summary);
|
|
15458
15619
|
}
|
|
15459
15620
|
function listAvailableTemplates() {
|
|
15460
15621
|
const dir = skillsTemplateDir();
|
|
@@ -16377,7 +16538,7 @@ const handleRoadmap = async (args, cwd, raw) => {
|
|
|
16377
16538
|
if (handler) return handleResult(await handler(), raw);
|
|
16378
16539
|
error("Unknown roadmap subcommand. Available: get-phase, analyze, update-plan-progress");
|
|
16379
16540
|
};
|
|
16380
|
-
const handlePhase = (args, cwd, raw) => {
|
|
16541
|
+
const handlePhase = async (args, cwd, raw) => {
|
|
16381
16542
|
const sub = args[1];
|
|
16382
16543
|
const handler = sub ? {
|
|
16383
16544
|
"next-decimal": () => cmdPhaseNextDecimal(cwd, args[2]),
|
|
@@ -16386,7 +16547,7 @@ const handlePhase = (args, cwd, raw) => {
|
|
|
16386
16547
|
"remove": () => cmdPhaseRemove(cwd, args[2], { force: hasFlag(args, "force") }),
|
|
16387
16548
|
"complete": () => cmdPhaseComplete(cwd, args[2])
|
|
16388
16549
|
}[sub] : void 0;
|
|
16389
|
-
if (handler) return handleResult(handler(), raw);
|
|
16550
|
+
if (handler) return handleResult(await handler(), raw);
|
|
16390
16551
|
error("Unknown phase subcommand. Available: next-decimal, add, insert, remove, complete");
|
|
16391
16552
|
};
|
|
16392
16553
|
const handleMilestone = (args, cwd, raw) => {
|
|
@@ -16439,7 +16600,7 @@ const handleInit = (args, cwd, raw) => {
|
|
|
16439
16600
|
const COMMANDS = {
|
|
16440
16601
|
"state": handleState,
|
|
16441
16602
|
"resolve-model": (args, cwd, raw) => handleResult(cmdResolveModel(cwd, args[1], raw), raw),
|
|
16442
|
-
"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),
|
|
16443
16604
|
"commit": async (args, cwd, raw) => {
|
|
16444
16605
|
const files = args.indexOf("--files") !== -1 ? args.slice(args.indexOf("--files") + 1).filter((a) => !a.startsWith("--")) : [];
|
|
16445
16606
|
handleResult(await cmdCommit(cwd, args[1], files, raw, hasFlag(args, "amend")), raw);
|
|
@@ -16482,8 +16643,8 @@ const COMMANDS = {
|
|
|
16482
16643
|
}, raw), raw);
|
|
16483
16644
|
},
|
|
16484
16645
|
"init": handleInit,
|
|
16485
|
-
"phase-plan-index": (args, cwd, raw) => handleResult(cmdPhasePlanIndex(cwd, args[1]), raw),
|
|
16486
|
-
"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),
|
|
16487
16648
|
"summary-extract": (args, cwd, raw) => {
|
|
16488
16649
|
const fieldsIndex = args.indexOf("--fields");
|
|
16489
16650
|
const fields = fieldsIndex !== -1 ? args[fieldsIndex + 1].split(",") : null;
|
|
@@ -16501,9 +16662,9 @@ const COMMANDS = {
|
|
|
16501
16662
|
"artefakte-append": (args, cwd, raw) => handleResult(cmdArtefakteAppend(cwd, args[1], getFlag(args, "--entry") ?? void 0, getFlag(args, "--phase") ?? void 0, raw), raw),
|
|
16502
16663
|
"artefakte-list": (args, cwd, raw) => handleResult(cmdArtefakteList(cwd, getFlag(args, "--phase") ?? void 0, raw), raw),
|
|
16503
16664
|
"context-load": (args, cwd, raw) => handleResult(cmdContextLoad(cwd, getFlag(args, "--phase") ?? void 0, getFlag(args, "--topic") ?? void 0, hasFlag(args, "include-history")), raw),
|
|
16504
|
-
"skill-list": (_args, cwd, raw) => cmdSkillList(cwd, raw),
|
|
16505
|
-
"skill-install": (args, cwd, raw) => cmdSkillInstall(cwd, args[1], raw),
|
|
16506
|
-
"skill-update": (args, cwd, raw) => cmdSkillUpdate(cwd, args[1], raw),
|
|
16665
|
+
"skill-list": (_args, cwd, raw) => handleResult(cmdSkillList(cwd), raw),
|
|
16666
|
+
"skill-install": (args, cwd, raw) => handleResult(cmdSkillInstall(cwd, args[1]), raw),
|
|
16667
|
+
"skill-update": (args, cwd, raw) => handleResult(cmdSkillUpdate(cwd, args[1]), raw),
|
|
16507
16668
|
"start": async (args, cwd, raw) => handleResult(await cmdStart(cwd, {
|
|
16508
16669
|
noBrowser: hasFlag(args, "no-browser"),
|
|
16509
16670
|
networkMode: hasFlag(args, "network")
|
|
@@ -16512,6 +16673,23 @@ const COMMANDS = {
|
|
|
16512
16673
|
"start-server": async () => {
|
|
16513
16674
|
const serverPath = node_path.join(__dirname, "mcp-server.cjs");
|
|
16514
16675
|
(0, node_child_process.spawn)(process.execPath, [serverPath], { stdio: "inherit" }).on("exit", (code) => process.exit(code ?? 0));
|
|
16676
|
+
},
|
|
16677
|
+
"backend-start": async (args, cwd, raw) => {
|
|
16678
|
+
const { startBackend } = await Promise.resolve().then(() => require("./lifecycle-0M4VqOMm.cjs"));
|
|
16679
|
+
const portFlag = args.find((a) => a.startsWith("--port="))?.split("=")[1];
|
|
16680
|
+
const background = !args.includes("--foreground");
|
|
16681
|
+
output(await startBackend(cwd, {
|
|
16682
|
+
port: portFlag ? parseInt(portFlag, 10) : void 0,
|
|
16683
|
+
background
|
|
16684
|
+
}), raw);
|
|
16685
|
+
},
|
|
16686
|
+
"backend-stop": async (_args, cwd, raw) => {
|
|
16687
|
+
const { stopBackend } = await Promise.resolve().then(() => require("./lifecycle-0M4VqOMm.cjs"));
|
|
16688
|
+
output({ stopped: await stopBackend(cwd) }, raw);
|
|
16689
|
+
},
|
|
16690
|
+
"backend-status": async (_args, cwd, raw) => {
|
|
16691
|
+
const { getBackendStatus } = await Promise.resolve().then(() => require("./lifecycle-0M4VqOMm.cjs"));
|
|
16692
|
+
output(await getBackendStatus(cwd) || { running: false }, raw);
|
|
16515
16693
|
}
|
|
16516
16694
|
};
|
|
16517
16695
|
async function main() {
|
|
@@ -16604,4 +16782,32 @@ async function handleDashboard(args) {
|
|
|
16604
16782
|
main();
|
|
16605
16783
|
|
|
16606
16784
|
//#endregion
|
|
16785
|
+
exports.__commonJSMin = __commonJSMin;
|
|
16786
|
+
exports.__toESM = __toESM;
|
|
16787
|
+
exports.appendToStateSection = appendToStateSection;
|
|
16788
|
+
exports.cmdConfigGet = cmdConfigGet;
|
|
16789
|
+
exports.cmdConfigSet = cmdConfigSet;
|
|
16790
|
+
exports.cmdContextLoad = cmdContextLoad;
|
|
16791
|
+
exports.cmdRoadmapAnalyze = cmdRoadmapAnalyze;
|
|
16792
|
+
exports.comparePhaseNum = comparePhaseNum;
|
|
16793
|
+
exports.escapeStringRegexp = escapeStringRegexp;
|
|
16794
|
+
exports.extractFrontmatter = extractFrontmatter;
|
|
16795
|
+
exports.findPhaseInternal = findPhaseInternal;
|
|
16796
|
+
exports.generateSlugInternal = generateSlugInternal;
|
|
16797
|
+
exports.getArchivedPhaseDirs = getArchivedPhaseDirs;
|
|
16798
|
+
exports.getPhasePattern = getPhasePattern;
|
|
16799
|
+
exports.listSubDirs = listSubDirs;
|
|
16800
|
+
exports.loadConfig = loadConfig;
|
|
16801
|
+
exports.normalizePhaseName = normalizePhaseName;
|
|
16802
|
+
exports.parseTodoFrontmatter = parseTodoFrontmatter;
|
|
16803
|
+
exports.phaseAddCore = phaseAddCore;
|
|
16804
|
+
exports.phaseCompleteCore = phaseCompleteCore;
|
|
16805
|
+
exports.phaseInsertCore = phaseInsertCore;
|
|
16806
|
+
exports.phasesPath = phasesPath;
|
|
16807
|
+
exports.planningPath = planningPath;
|
|
16808
|
+
exports.safeReadFile = safeReadFile;
|
|
16809
|
+
exports.stateExtractField = stateExtractField;
|
|
16810
|
+
exports.statePath = statePath;
|
|
16811
|
+
exports.stateReplaceField = stateReplaceField;
|
|
16812
|
+
exports.todayISO = todayISO;
|
|
16607
16813
|
//# sourceMappingURL=cli.cjs.map
|