maxsimcli 4.7.0 → 4.8.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/assets/CHANGELOG.md +30 -0
- package/dist/cli.cjs +470 -961
- package/dist/cli.cjs.map +1 -1
- package/dist/{core-RRjCSt0G.cjs → core-D5zUr9cb.cjs} +4 -3
- package/dist/core-D5zUr9cb.cjs.map +1 -0
- package/dist/install.cjs +43 -533
- package/dist/install.cjs.map +1 -1
- package/dist/mcp-server.cjs +5326 -2443
- package/dist/mcp-server.cjs.map +1 -1
- package/dist/{skills-MYlMkYNt.cjs → skills-CjFWZIGM.cjs} +6 -6
- package/dist/{skills-MYlMkYNt.cjs.map → skills-CjFWZIGM.cjs.map} +1 -1
- package/package.json +4 -7
- package/dist/assets/dashboard/client/assets/index-C199D4Eb.css +0 -32
- package/dist/assets/dashboard/client/assets/index-nAXJLp0_.js +0 -233
- package/dist/assets/dashboard/client/index.html +0 -19
- package/dist/assets/dashboard/server.js +0 -78813
- package/dist/backend-server.cjs +0 -83370
- package/dist/backend-server.cjs.map +0 -1
- package/dist/core-RRjCSt0G.cjs.map +0 -1
- package/dist/esm-iIOBzmdz.cjs +0 -1561
- package/dist/esm-iIOBzmdz.cjs.map +0 -1
- package/dist/lifecycle-D8mcsEjy.cjs +0 -136
- package/dist/lifecycle-D8mcsEjy.cjs.map +0 -1
- package/dist/server-BAHfh_vw.cjs +0 -5694
- package/dist/server-BAHfh_vw.cjs.map +0 -1
package/dist/cli.cjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
3
2
|
//#region \0rolldown/runtime.js
|
|
4
3
|
var __create = Object.create;
|
|
5
4
|
var __defProp$1 = Object.defineProperty;
|
|
@@ -42,7 +41,6 @@ let node_process = require("node:process");
|
|
|
42
41
|
node_process = __toESM(node_process);
|
|
43
42
|
let node_tty = require("node:tty");
|
|
44
43
|
node_tty = __toESM(node_tty);
|
|
45
|
-
let node_module = require("node:module");
|
|
46
44
|
|
|
47
45
|
//#region src/core/types.ts
|
|
48
46
|
function cmdOk(result, rawValue) {
|
|
@@ -607,7 +605,7 @@ var require_has_flag = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
607
605
|
//#endregion
|
|
608
606
|
//#region ../../node_modules/supports-color/index.js
|
|
609
607
|
var require_supports_color = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
610
|
-
const os$
|
|
608
|
+
const os$5 = require("os");
|
|
611
609
|
const tty$2 = require("tty");
|
|
612
610
|
const hasFlag = require_has_flag();
|
|
613
611
|
const { env } = process;
|
|
@@ -634,7 +632,7 @@ var require_supports_color = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
634
632
|
const min = forceColor || 0;
|
|
635
633
|
if (env.TERM === "dumb") return min;
|
|
636
634
|
if (process.platform === "win32") {
|
|
637
|
-
const osRelease = os$
|
|
635
|
+
const osRelease = os$5.release().split(".");
|
|
638
636
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
639
637
|
return 1;
|
|
640
638
|
}
|
|
@@ -4799,17 +4797,12 @@ const isSummaryFile = (f) => f.endsWith("-SUMMARY.md") || f === "SUMMARY.md";
|
|
|
4799
4797
|
const planId = (f) => f.replace("-PLAN.md", "").replace("PLAN.md", "");
|
|
4800
4798
|
const summaryId = (f) => f.replace("-SUMMARY.md", "").replace("SUMMARY.md", "");
|
|
4801
4799
|
/** List subdirectory names, optionally sorted by phase number. */
|
|
4802
|
-
function listSubDirs(dir, sortByPhase = false) {
|
|
4803
|
-
const dirs = node_fs.default.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
4804
|
-
return sortByPhase ? dirs.sort((a, b) => comparePhaseNum(a, b)) : dirs;
|
|
4805
|
-
}
|
|
4806
|
-
/** Async version of listSubDirs using fs.promises. */
|
|
4807
|
-
async function listSubDirsAsync(dir, sortByPhase = false) {
|
|
4800
|
+
async function listSubDirs(dir, sortByPhase = false) {
|
|
4808
4801
|
const dirs = (await node_fs.promises.readdir(dir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
4809
4802
|
return sortByPhase ? dirs.sort((a, b) => comparePhaseNum(a, b)) : dirs;
|
|
4810
4803
|
}
|
|
4811
|
-
/**
|
|
4812
|
-
async function
|
|
4804
|
+
/** Read a file, returning null if it doesn't exist or fails. */
|
|
4805
|
+
async function safeReadFile(filePath) {
|
|
4813
4806
|
try {
|
|
4814
4807
|
return await node_fs.promises.readFile(filePath, "utf-8");
|
|
4815
4808
|
} catch {
|
|
@@ -4830,104 +4823,7 @@ function debugLog(contextOrError, error) {
|
|
|
4830
4823
|
function escapePhaseNum(phase) {
|
|
4831
4824
|
return String(phase).replace(/\./g, "\\.");
|
|
4832
4825
|
}
|
|
4833
|
-
function safeReadFile(filePath) {
|
|
4834
|
-
try {
|
|
4835
|
-
return node_fs.default.readFileSync(filePath, "utf-8");
|
|
4836
|
-
} catch {
|
|
4837
|
-
return null;
|
|
4838
|
-
}
|
|
4839
|
-
}
|
|
4840
4826
|
let _configCache = null;
|
|
4841
|
-
function loadConfig(cwd) {
|
|
4842
|
-
if (_configCache && _configCache.cwd === cwd) return _configCache.config;
|
|
4843
|
-
const cfgPath = configPath(cwd);
|
|
4844
|
-
const defaults = {
|
|
4845
|
-
model_profile: "balanced",
|
|
4846
|
-
commit_docs: true,
|
|
4847
|
-
search_gitignored: false,
|
|
4848
|
-
branching_strategy: "none",
|
|
4849
|
-
phase_branch_template: "maxsim/phase-{phase}-{slug}",
|
|
4850
|
-
milestone_branch_template: "maxsim/{milestone}-{slug}",
|
|
4851
|
-
research: true,
|
|
4852
|
-
plan_checker: true,
|
|
4853
|
-
verifier: true,
|
|
4854
|
-
parallelization: true,
|
|
4855
|
-
brave_search: false
|
|
4856
|
-
};
|
|
4857
|
-
try {
|
|
4858
|
-
const raw = node_fs.default.readFileSync(cfgPath, "utf-8");
|
|
4859
|
-
const parsed = JSON.parse(raw);
|
|
4860
|
-
const get = (key, nested) => {
|
|
4861
|
-
if (parsed[key] !== void 0) return parsed[key];
|
|
4862
|
-
if (nested) {
|
|
4863
|
-
const section = parsed[nested.section];
|
|
4864
|
-
if (section && typeof section === "object" && section !== null && nested.field in section) return section[nested.field];
|
|
4865
|
-
}
|
|
4866
|
-
};
|
|
4867
|
-
const parallelization = (() => {
|
|
4868
|
-
const val = get("parallelization");
|
|
4869
|
-
if (typeof val === "boolean") return val;
|
|
4870
|
-
if (typeof val === "object" && val !== null && "enabled" in val) return val.enabled;
|
|
4871
|
-
return defaults.parallelization;
|
|
4872
|
-
})();
|
|
4873
|
-
const result = {
|
|
4874
|
-
model_profile: get("model_profile") ?? defaults.model_profile,
|
|
4875
|
-
commit_docs: get("commit_docs", {
|
|
4876
|
-
section: "planning",
|
|
4877
|
-
field: "commit_docs"
|
|
4878
|
-
}) ?? defaults.commit_docs,
|
|
4879
|
-
search_gitignored: get("search_gitignored", {
|
|
4880
|
-
section: "planning",
|
|
4881
|
-
field: "search_gitignored"
|
|
4882
|
-
}) ?? defaults.search_gitignored,
|
|
4883
|
-
branching_strategy: get("branching_strategy", {
|
|
4884
|
-
section: "git",
|
|
4885
|
-
field: "branching_strategy"
|
|
4886
|
-
}) ?? defaults.branching_strategy,
|
|
4887
|
-
phase_branch_template: get("phase_branch_template", {
|
|
4888
|
-
section: "git",
|
|
4889
|
-
field: "phase_branch_template"
|
|
4890
|
-
}) ?? defaults.phase_branch_template,
|
|
4891
|
-
milestone_branch_template: get("milestone_branch_template", {
|
|
4892
|
-
section: "git",
|
|
4893
|
-
field: "milestone_branch_template"
|
|
4894
|
-
}) ?? defaults.milestone_branch_template,
|
|
4895
|
-
research: get("research", {
|
|
4896
|
-
section: "workflow",
|
|
4897
|
-
field: "research"
|
|
4898
|
-
}) ?? defaults.research,
|
|
4899
|
-
plan_checker: get("plan_checker", {
|
|
4900
|
-
section: "workflow",
|
|
4901
|
-
field: "plan_checker"
|
|
4902
|
-
}) ?? get("plan_checker", {
|
|
4903
|
-
section: "workflow",
|
|
4904
|
-
field: "plan_check"
|
|
4905
|
-
}) ?? defaults.plan_checker,
|
|
4906
|
-
verifier: get("verifier", {
|
|
4907
|
-
section: "workflow",
|
|
4908
|
-
field: "verifier"
|
|
4909
|
-
}) ?? defaults.verifier,
|
|
4910
|
-
parallelization,
|
|
4911
|
-
brave_search: get("brave_search") ?? defaults.brave_search,
|
|
4912
|
-
model_overrides: parsed["model_overrides"]
|
|
4913
|
-
};
|
|
4914
|
-
_configCache = {
|
|
4915
|
-
cwd,
|
|
4916
|
-
config: result
|
|
4917
|
-
};
|
|
4918
|
-
return result;
|
|
4919
|
-
} catch (e) {
|
|
4920
|
-
if (node_fs.default.existsSync(cfgPath)) {
|
|
4921
|
-
console.warn(`[maxsim] Warning: config.json exists but could not be parsed — using defaults.`);
|
|
4922
|
-
debugLog("config-load-failed", e);
|
|
4923
|
-
}
|
|
4924
|
-
_configCache = {
|
|
4925
|
-
cwd,
|
|
4926
|
-
config: defaults
|
|
4927
|
-
};
|
|
4928
|
-
return defaults;
|
|
4929
|
-
}
|
|
4930
|
-
}
|
|
4931
4827
|
async function isGitIgnored(cwd, targetPath) {
|
|
4932
4828
|
try {
|
|
4933
4829
|
return (await simpleGit(cwd).checkIgnore(targetPath)).length > 0;
|
|
@@ -4997,128 +4893,8 @@ function getPhasePattern(escapedPhaseNum, flags = "gim") {
|
|
|
4997
4893
|
if (escapedPhaseNum) return new RegExp(`^#{2,4}\\s*Phase\\s+${escapedPhaseNum}:\\s*([^\\n]+)`, flags);
|
|
4998
4894
|
return new RegExp(`^#{2,4}\\s*Phase\\s+(\\d+[A-Z]?(?:\\.\\d+)?)\\s*:\\s*([^\\n]+)`, flags);
|
|
4999
4895
|
}
|
|
5000
|
-
function
|
|
5001
|
-
|
|
5002
|
-
const match = listSubDirs(baseDir, true).find((d) => d.startsWith(normalized));
|
|
5003
|
-
if (!match) return null;
|
|
5004
|
-
const dirMatch = match.match(/^(\d+[A-Z]?(?:\.\d+)?)-?(.*)/i);
|
|
5005
|
-
const phaseNumber = dirMatch ? dirMatch[1] : normalized;
|
|
5006
|
-
const phaseName = dirMatch && dirMatch[2] ? dirMatch[2] : null;
|
|
5007
|
-
const phaseDir = node_path.default.join(baseDir, match);
|
|
5008
|
-
const phaseFiles = node_fs.default.readdirSync(phaseDir);
|
|
5009
|
-
const plans = phaseFiles.filter(isPlanFile).sort();
|
|
5010
|
-
const summaries = phaseFiles.filter(isSummaryFile).sort();
|
|
5011
|
-
const hasResearch = phaseFiles.some((f) => f.endsWith("-RESEARCH.md") || f === "RESEARCH.md");
|
|
5012
|
-
const hasContext = phaseFiles.some((f) => f.endsWith("-CONTEXT.md") || f === "CONTEXT.md");
|
|
5013
|
-
const hasVerification = phaseFiles.some((f) => f.endsWith("-VERIFICATION.md") || f === "VERIFICATION.md");
|
|
5014
|
-
const completedPlanIds = new Set(summaries.map(summaryId));
|
|
5015
|
-
const incompletePlans = plans.filter((p) => !completedPlanIds.has(planId(p)));
|
|
5016
|
-
return {
|
|
5017
|
-
found: true,
|
|
5018
|
-
directory: node_path.default.join(relBase, match),
|
|
5019
|
-
phase_number: phaseNumber,
|
|
5020
|
-
phase_name: phaseName,
|
|
5021
|
-
phase_slug: phaseName ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") : null,
|
|
5022
|
-
plans,
|
|
5023
|
-
summaries,
|
|
5024
|
-
incomplete_plans: incompletePlans,
|
|
5025
|
-
has_research: hasResearch,
|
|
5026
|
-
has_context: hasContext,
|
|
5027
|
-
has_verification: hasVerification
|
|
5028
|
-
};
|
|
5029
|
-
} catch (e) {
|
|
5030
|
-
debugLog("search-phase-in-dir-failed", {
|
|
5031
|
-
dir: baseDir,
|
|
5032
|
-
phase: normalized,
|
|
5033
|
-
error: errorMsg(e)
|
|
5034
|
-
});
|
|
5035
|
-
return null;
|
|
5036
|
-
}
|
|
5037
|
-
}
|
|
5038
|
-
function findPhaseInternal(cwd, phase) {
|
|
5039
|
-
if (!phase) return null;
|
|
5040
|
-
const pd = phasesPath(cwd);
|
|
5041
|
-
const normalized = normalizePhaseName(phase);
|
|
5042
|
-
const current = searchPhaseInDir(pd, node_path.default.join(".planning", "phases"), normalized);
|
|
5043
|
-
if (current) return current;
|
|
5044
|
-
const milestonesDir = planningPath(cwd, "milestones");
|
|
5045
|
-
try {
|
|
5046
|
-
node_fs.default.statSync(milestonesDir);
|
|
5047
|
-
} catch {
|
|
5048
|
-
return null;
|
|
5049
|
-
}
|
|
5050
|
-
try {
|
|
5051
|
-
const archiveDirs = node_fs.default.readdirSync(milestonesDir, { withFileTypes: true }).filter((e) => e.isDirectory() && /^v[\d.]+-phases$/.test(e.name)).map((e) => e.name).sort().reverse();
|
|
5052
|
-
for (const archiveName of archiveDirs) {
|
|
5053
|
-
const versionMatch = archiveName.match(/^(v[\d.]+)-phases$/);
|
|
5054
|
-
if (!versionMatch) continue;
|
|
5055
|
-
const version = versionMatch[1];
|
|
5056
|
-
const result = searchPhaseInDir(node_path.default.join(milestonesDir, archiveName), node_path.default.join(".planning", "milestones", archiveName), normalized);
|
|
5057
|
-
if (result) {
|
|
5058
|
-
result.archived = version;
|
|
5059
|
-
return result;
|
|
5060
|
-
}
|
|
5061
|
-
}
|
|
5062
|
-
} catch (e) {
|
|
5063
|
-
debugLog("find-phase-milestone-search-failed", e);
|
|
5064
|
-
}
|
|
5065
|
-
return null;
|
|
5066
|
-
}
|
|
5067
|
-
function getArchivedPhaseDirs(cwd) {
|
|
5068
|
-
const milestonesDir = planningPath(cwd, "milestones");
|
|
5069
|
-
const results = [];
|
|
5070
|
-
try {
|
|
5071
|
-
const phaseDirs = node_fs.default.readdirSync(milestonesDir, { withFileTypes: true }).filter((e) => e.isDirectory() && /^v[\d.]+-phases$/.test(e.name)).map((e) => e.name).sort().reverse();
|
|
5072
|
-
for (const archiveName of phaseDirs) {
|
|
5073
|
-
const versionMatch = archiveName.match(/^(v[\d.]+)-phases$/);
|
|
5074
|
-
if (!versionMatch) continue;
|
|
5075
|
-
const version = versionMatch[1];
|
|
5076
|
-
const archivePath = node_path.default.join(milestonesDir, archiveName);
|
|
5077
|
-
const dirs = listSubDirs(archivePath, true);
|
|
5078
|
-
for (const dir of dirs) results.push({
|
|
5079
|
-
name: dir,
|
|
5080
|
-
milestone: version,
|
|
5081
|
-
basePath: node_path.default.join(".planning", "milestones", archiveName),
|
|
5082
|
-
fullPath: node_path.default.join(archivePath, dir)
|
|
5083
|
-
});
|
|
5084
|
-
}
|
|
5085
|
-
} catch (e) {
|
|
5086
|
-
debugLog("get-archived-phase-dirs-failed", e);
|
|
5087
|
-
}
|
|
5088
|
-
return results;
|
|
5089
|
-
}
|
|
5090
|
-
function getRoadmapPhaseInternal(cwd, phaseNum) {
|
|
5091
|
-
if (!phaseNum) return null;
|
|
5092
|
-
const rp = roadmapPath(cwd);
|
|
5093
|
-
try {
|
|
5094
|
-
const content = node_fs.default.readFileSync(rp, "utf-8");
|
|
5095
|
-
const phasePattern = getPhasePattern(escapePhaseNum(phaseNum), "i");
|
|
5096
|
-
const headerMatch = content.match(phasePattern);
|
|
5097
|
-
if (!headerMatch) return null;
|
|
5098
|
-
const phaseName = headerMatch[1].trim();
|
|
5099
|
-
const headerIndex = headerMatch.index;
|
|
5100
|
-
const nextHeaderMatch = content.slice(headerIndex).match(/\n#{2,4}\s+Phase\s+\d/i);
|
|
5101
|
-
const sectionEnd = nextHeaderMatch ? headerIndex + nextHeaderMatch.index : content.length;
|
|
5102
|
-
const section = content.slice(headerIndex, sectionEnd).trim();
|
|
5103
|
-
const goalMatch = section.match(/\*\*Goal(?::\*\*|\*\*:)\s*([^\n]+)/i);
|
|
5104
|
-
const goal = goalMatch ? goalMatch[1].trim() : null;
|
|
5105
|
-
return {
|
|
5106
|
-
found: true,
|
|
5107
|
-
phase_number: phaseNum.toString(),
|
|
5108
|
-
phase_name: phaseName,
|
|
5109
|
-
goal,
|
|
5110
|
-
section
|
|
5111
|
-
};
|
|
5112
|
-
} catch (e) {
|
|
5113
|
-
debugLog("get-roadmap-phase-failed", {
|
|
5114
|
-
phase: phaseNum,
|
|
5115
|
-
error: errorMsg(e)
|
|
5116
|
-
});
|
|
5117
|
-
return null;
|
|
5118
|
-
}
|
|
5119
|
-
}
|
|
5120
|
-
function resolveModelInternal(cwd, agentType, config) {
|
|
5121
|
-
config = config ?? loadConfig(cwd);
|
|
4896
|
+
async function resolveModelInternal(cwd, agentType, config) {
|
|
4897
|
+
config = config ?? await loadConfig(cwd);
|
|
5122
4898
|
const override = config.model_overrides?.[agentType];
|
|
5123
4899
|
if (override) return override === "opus" ? "inherit" : override;
|
|
5124
4900
|
const profile = config.model_profile || "balanced";
|
|
@@ -5127,15 +4903,6 @@ function resolveModelInternal(cwd, agentType, config) {
|
|
|
5127
4903
|
const resolved = agentModels[profile] || agentModels["balanced"] || "sonnet";
|
|
5128
4904
|
return resolved === "opus" ? "inherit" : resolved;
|
|
5129
4905
|
}
|
|
5130
|
-
function pathExistsInternal(cwd, targetPath) {
|
|
5131
|
-
const fullPath = node_path.default.isAbsolute(targetPath) ? targetPath : node_path.default.join(cwd, targetPath);
|
|
5132
|
-
try {
|
|
5133
|
-
node_fs.default.statSync(fullPath);
|
|
5134
|
-
return true;
|
|
5135
|
-
} catch {
|
|
5136
|
-
return false;
|
|
5137
|
-
}
|
|
5138
|
-
}
|
|
5139
4906
|
function generateSlugInternal(text) {
|
|
5140
4907
|
if (!text) return null;
|
|
5141
4908
|
return (0, import_slugify.default)(text, {
|
|
@@ -5143,23 +4910,7 @@ function generateSlugInternal(text) {
|
|
|
5143
4910
|
strict: true
|
|
5144
4911
|
});
|
|
5145
4912
|
}
|
|
5146
|
-
function
|
|
5147
|
-
try {
|
|
5148
|
-
const roadmap = node_fs.default.readFileSync(roadmapPath(cwd), "utf-8");
|
|
5149
|
-
const versionMatch = roadmap.match(/v(\d+\.\d+)/);
|
|
5150
|
-
const nameMatch = roadmap.match(/## .*v\d+\.\d+[:\s]+([^\n(]+)/);
|
|
5151
|
-
return {
|
|
5152
|
-
version: versionMatch ? versionMatch[0] : "v1.0",
|
|
5153
|
-
name: nameMatch ? nameMatch[1].trim() : "milestone"
|
|
5154
|
-
};
|
|
5155
|
-
} catch {
|
|
5156
|
-
return {
|
|
5157
|
-
version: "v1.0",
|
|
5158
|
-
name: "milestone"
|
|
5159
|
-
};
|
|
5160
|
-
}
|
|
5161
|
-
}
|
|
5162
|
-
async function pathExistsAsync(p) {
|
|
4913
|
+
async function pathExistsInternal(p) {
|
|
5163
4914
|
try {
|
|
5164
4915
|
await node_fs.promises.access(p);
|
|
5165
4916
|
return true;
|
|
@@ -5167,9 +4918,99 @@ async function pathExistsAsync(p) {
|
|
|
5167
4918
|
return false;
|
|
5168
4919
|
}
|
|
5169
4920
|
}
|
|
5170
|
-
async function
|
|
4921
|
+
async function loadConfig(cwd) {
|
|
4922
|
+
if (_configCache && _configCache.cwd === cwd) return _configCache.config;
|
|
4923
|
+
const cfgPath = configPath(cwd);
|
|
4924
|
+
const defaults = {
|
|
4925
|
+
model_profile: "balanced",
|
|
4926
|
+
commit_docs: true,
|
|
4927
|
+
search_gitignored: false,
|
|
4928
|
+
branching_strategy: "none",
|
|
4929
|
+
phase_branch_template: "maxsim/phase-{phase}-{slug}",
|
|
4930
|
+
milestone_branch_template: "maxsim/{milestone}-{slug}",
|
|
4931
|
+
research: true,
|
|
4932
|
+
plan_checker: true,
|
|
4933
|
+
verifier: true,
|
|
4934
|
+
parallelization: true,
|
|
4935
|
+
brave_search: false
|
|
4936
|
+
};
|
|
4937
|
+
try {
|
|
4938
|
+
const raw = await node_fs.promises.readFile(cfgPath, "utf-8");
|
|
4939
|
+
const parsed = JSON.parse(raw);
|
|
4940
|
+
const get = (key, nested) => {
|
|
4941
|
+
if (parsed[key] !== void 0) return parsed[key];
|
|
4942
|
+
if (nested) {
|
|
4943
|
+
const section = parsed[nested.section];
|
|
4944
|
+
if (section && typeof section === "object" && section !== null && nested.field in section) return section[nested.field];
|
|
4945
|
+
}
|
|
4946
|
+
};
|
|
4947
|
+
const parallelization = (() => {
|
|
4948
|
+
const val = get("parallelization");
|
|
4949
|
+
if (typeof val === "boolean") return val;
|
|
4950
|
+
if (typeof val === "object" && val !== null && "enabled" in val) return val.enabled;
|
|
4951
|
+
return defaults.parallelization;
|
|
4952
|
+
})();
|
|
4953
|
+
const result = {
|
|
4954
|
+
model_profile: get("model_profile") ?? defaults.model_profile,
|
|
4955
|
+
commit_docs: get("commit_docs", {
|
|
4956
|
+
section: "planning",
|
|
4957
|
+
field: "commit_docs"
|
|
4958
|
+
}) ?? defaults.commit_docs,
|
|
4959
|
+
search_gitignored: get("search_gitignored", {
|
|
4960
|
+
section: "planning",
|
|
4961
|
+
field: "search_gitignored"
|
|
4962
|
+
}) ?? defaults.search_gitignored,
|
|
4963
|
+
branching_strategy: get("branching_strategy", {
|
|
4964
|
+
section: "git",
|
|
4965
|
+
field: "branching_strategy"
|
|
4966
|
+
}) ?? defaults.branching_strategy,
|
|
4967
|
+
phase_branch_template: get("phase_branch_template", {
|
|
4968
|
+
section: "git",
|
|
4969
|
+
field: "phase_branch_template"
|
|
4970
|
+
}) ?? defaults.phase_branch_template,
|
|
4971
|
+
milestone_branch_template: get("milestone_branch_template", {
|
|
4972
|
+
section: "git",
|
|
4973
|
+
field: "milestone_branch_template"
|
|
4974
|
+
}) ?? defaults.milestone_branch_template,
|
|
4975
|
+
research: get("research", {
|
|
4976
|
+
section: "workflow",
|
|
4977
|
+
field: "research"
|
|
4978
|
+
}) ?? defaults.research,
|
|
4979
|
+
plan_checker: get("plan_checker", {
|
|
4980
|
+
section: "workflow",
|
|
4981
|
+
field: "plan_checker"
|
|
4982
|
+
}) ?? get("plan_checker", {
|
|
4983
|
+
section: "workflow",
|
|
4984
|
+
field: "plan_check"
|
|
4985
|
+
}) ?? defaults.plan_checker,
|
|
4986
|
+
verifier: get("verifier", {
|
|
4987
|
+
section: "workflow",
|
|
4988
|
+
field: "verifier"
|
|
4989
|
+
}) ?? defaults.verifier,
|
|
4990
|
+
parallelization,
|
|
4991
|
+
brave_search: get("brave_search") ?? defaults.brave_search,
|
|
4992
|
+
model_overrides: parsed["model_overrides"]
|
|
4993
|
+
};
|
|
4994
|
+
_configCache = {
|
|
4995
|
+
cwd,
|
|
4996
|
+
config: result
|
|
4997
|
+
};
|
|
4998
|
+
return result;
|
|
4999
|
+
} catch (e) {
|
|
5000
|
+
if (await pathExistsInternal(cfgPath)) {
|
|
5001
|
+
console.warn(`[maxsim] Warning: config.json exists but could not be parsed — using defaults.`);
|
|
5002
|
+
debugLog("config-load-failed", e);
|
|
5003
|
+
}
|
|
5004
|
+
_configCache = {
|
|
5005
|
+
cwd,
|
|
5006
|
+
config: defaults
|
|
5007
|
+
};
|
|
5008
|
+
return defaults;
|
|
5009
|
+
}
|
|
5010
|
+
}
|
|
5011
|
+
async function searchPhaseInDir(baseDir, relBase, normalized) {
|
|
5171
5012
|
try {
|
|
5172
|
-
const match = (await
|
|
5013
|
+
const match = (await listSubDirs(baseDir, true)).find((d) => d.startsWith(normalized));
|
|
5173
5014
|
if (!match) return null;
|
|
5174
5015
|
const dirMatch = match.match(/^(\d+[A-Z]?(?:\.\d+)?)-?(.*)/i);
|
|
5175
5016
|
const phaseNumber = dirMatch ? dirMatch[1] : normalized;
|
|
@@ -5205,17 +5046,17 @@ async function searchPhaseInDirAsync(baseDir, relBase, normalized) {
|
|
|
5205
5046
|
return null;
|
|
5206
5047
|
}
|
|
5207
5048
|
}
|
|
5208
|
-
async function
|
|
5049
|
+
async function findPhaseInternal(cwd, phase) {
|
|
5209
5050
|
if (!phase) return null;
|
|
5210
5051
|
const pd = phasesPath(cwd);
|
|
5211
5052
|
const normalized = normalizePhaseName(phase);
|
|
5212
|
-
const current = await
|
|
5053
|
+
const current = await searchPhaseInDir(pd, node_path.default.join(".planning", "phases"), normalized);
|
|
5213
5054
|
if (current) return current;
|
|
5214
5055
|
const archiveDir = planningPath(cwd, "archive");
|
|
5215
|
-
if (await
|
|
5056
|
+
if (await pathExistsInternal(archiveDir)) try {
|
|
5216
5057
|
const versionDirs = (await node_fs.promises.readdir(archiveDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name).sort().reverse();
|
|
5217
5058
|
for (const versionName of versionDirs) {
|
|
5218
|
-
const result = await
|
|
5059
|
+
const result = await searchPhaseInDir(node_path.default.join(archiveDir, versionName), node_path.default.join(".planning", "archive", versionName), normalized);
|
|
5219
5060
|
if (result) {
|
|
5220
5061
|
result.archived = versionName;
|
|
5221
5062
|
return result;
|
|
@@ -5225,14 +5066,14 @@ async function findPhaseInternalAsync(cwd, phase) {
|
|
|
5225
5066
|
debugLog("find-phase-async-archive-search-failed", e);
|
|
5226
5067
|
}
|
|
5227
5068
|
const milestonesDir = planningPath(cwd, "milestones");
|
|
5228
|
-
if (!await
|
|
5069
|
+
if (!await pathExistsInternal(milestonesDir)) return null;
|
|
5229
5070
|
try {
|
|
5230
5071
|
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();
|
|
5231
5072
|
for (const archiveName of archiveDirs) {
|
|
5232
5073
|
const versionMatch = archiveName.match(/^(v[\d.]+)-phases$/);
|
|
5233
5074
|
if (!versionMatch) continue;
|
|
5234
5075
|
const version = versionMatch[1];
|
|
5235
|
-
const result = await
|
|
5076
|
+
const result = await searchPhaseInDir(node_path.default.join(milestonesDir, archiveName), node_path.default.join(".planning", "milestones", archiveName), normalized);
|
|
5236
5077
|
if (result) {
|
|
5237
5078
|
result.archived = version;
|
|
5238
5079
|
return result;
|
|
@@ -5243,14 +5084,14 @@ async function findPhaseInternalAsync(cwd, phase) {
|
|
|
5243
5084
|
}
|
|
5244
5085
|
return null;
|
|
5245
5086
|
}
|
|
5246
|
-
async function
|
|
5087
|
+
async function getArchivedPhaseDirs(cwd) {
|
|
5247
5088
|
const results = [];
|
|
5248
5089
|
const archiveDir = planningPath(cwd, "archive");
|
|
5249
5090
|
try {
|
|
5250
5091
|
const versionDirs = (await node_fs.promises.readdir(archiveDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name).sort().reverse();
|
|
5251
5092
|
for (const versionName of versionDirs) {
|
|
5252
5093
|
const versionPath = node_path.default.join(archiveDir, versionName);
|
|
5253
|
-
const dirs = await
|
|
5094
|
+
const dirs = await listSubDirs(versionPath, true);
|
|
5254
5095
|
for (const dir of dirs) results.push({
|
|
5255
5096
|
name: dir,
|
|
5256
5097
|
milestone: versionName,
|
|
@@ -5269,7 +5110,7 @@ async function getArchivedPhaseDirsAsync(cwd) {
|
|
|
5269
5110
|
if (!versionMatch) continue;
|
|
5270
5111
|
const version = versionMatch[1];
|
|
5271
5112
|
const archiveMilestonePath = node_path.default.join(milestonesDir, archiveName);
|
|
5272
|
-
const dirs = await
|
|
5113
|
+
const dirs = await listSubDirs(archiveMilestonePath, true);
|
|
5273
5114
|
for (const dir of dirs) results.push({
|
|
5274
5115
|
name: dir,
|
|
5275
5116
|
milestone: version,
|
|
@@ -5282,15 +5123,43 @@ async function getArchivedPhaseDirsAsync(cwd) {
|
|
|
5282
5123
|
}
|
|
5283
5124
|
return results;
|
|
5284
5125
|
}
|
|
5285
|
-
function
|
|
5286
|
-
|
|
5126
|
+
async function getRoadmapPhaseInternal(cwd, phaseNum) {
|
|
5127
|
+
if (!phaseNum) return null;
|
|
5128
|
+
const rp = roadmapPath(cwd);
|
|
5129
|
+
try {
|
|
5130
|
+
const content = await safeReadFile(rp);
|
|
5131
|
+
if (!content) return null;
|
|
5132
|
+
const phasePattern = getPhasePattern(escapePhaseNum(phaseNum), "i");
|
|
5133
|
+
const headerMatch = content.match(phasePattern);
|
|
5134
|
+
if (!headerMatch) return null;
|
|
5135
|
+
const phaseName = headerMatch[1].trim();
|
|
5136
|
+
const headerIndex = headerMatch.index;
|
|
5137
|
+
const nextHeaderMatch = content.slice(headerIndex).match(/\n#{2,4}\s+Phase\s+\d/i);
|
|
5138
|
+
const sectionEnd = nextHeaderMatch ? headerIndex + nextHeaderMatch.index : content.length;
|
|
5139
|
+
const section = content.slice(headerIndex, sectionEnd).trim();
|
|
5140
|
+
const goalMatch = section.match(/\*\*Goal(?::\*\*|\*\*:)\s*([^\n]+)/i);
|
|
5141
|
+
const goal = goalMatch ? goalMatch[1].trim() : null;
|
|
5142
|
+
return {
|
|
5143
|
+
found: true,
|
|
5144
|
+
phase_number: phaseNum.toString(),
|
|
5145
|
+
phase_name: phaseName,
|
|
5146
|
+
goal,
|
|
5147
|
+
section
|
|
5148
|
+
};
|
|
5149
|
+
} catch (e) {
|
|
5150
|
+
debugLog("get-roadmap-phase-async-failed", {
|
|
5151
|
+
phase: phaseNum,
|
|
5152
|
+
error: errorMsg(e)
|
|
5153
|
+
});
|
|
5154
|
+
return null;
|
|
5155
|
+
}
|
|
5287
5156
|
}
|
|
5288
|
-
async function
|
|
5289
|
-
return planningPath(cwd, "archive", milestone ?? (await
|
|
5157
|
+
async function archivePath(cwd, milestone) {
|
|
5158
|
+
return planningPath(cwd, "archive", milestone ?? (await getMilestoneInfo(cwd)).version);
|
|
5290
5159
|
}
|
|
5291
|
-
async function
|
|
5160
|
+
async function getMilestoneInfo(cwd) {
|
|
5292
5161
|
try {
|
|
5293
|
-
const roadmap = await
|
|
5162
|
+
const roadmap = await safeReadFile(roadmapPath(cwd));
|
|
5294
5163
|
if (!roadmap) return {
|
|
5295
5164
|
version: "v1.0",
|
|
5296
5165
|
name: "milestone"
|
|
@@ -12051,9 +11920,9 @@ const FRONTMATTER_SCHEMAS = {
|
|
|
12051
11920
|
"info_count"
|
|
12052
11921
|
] }
|
|
12053
11922
|
};
|
|
12054
|
-
function cmdFrontmatterGet(cwd, filePath, field) {
|
|
11923
|
+
async function cmdFrontmatterGet(cwd, filePath, field) {
|
|
12055
11924
|
if (!filePath) return cmdErr("file path required");
|
|
12056
|
-
const content = safeReadFile(node_path.default.isAbsolute(filePath) ? filePath : node_path.default.join(cwd, filePath));
|
|
11925
|
+
const content = await safeReadFile(node_path.default.isAbsolute(filePath) ? filePath : node_path.default.join(cwd, filePath));
|
|
12057
11926
|
if (!content) return cmdOk({
|
|
12058
11927
|
error: "File not found",
|
|
12059
11928
|
path: filePath
|
|
@@ -12115,11 +11984,11 @@ function cmdFrontmatterMerge(cwd, filePath, data) {
|
|
|
12115
11984
|
fields: Object.keys(mergeData)
|
|
12116
11985
|
}, "true");
|
|
12117
11986
|
}
|
|
12118
|
-
function cmdFrontmatterValidate(cwd, filePath, schemaName) {
|
|
11987
|
+
async function cmdFrontmatterValidate(cwd, filePath, schemaName) {
|
|
12119
11988
|
if (!filePath || !schemaName) return cmdErr("file and schema required");
|
|
12120
11989
|
const schema = FRONTMATTER_SCHEMAS[schemaName];
|
|
12121
11990
|
if (!schema) return cmdErr(`Unknown schema: ${schemaName}. Available: ${Object.keys(FRONTMATTER_SCHEMAS).join(", ")}`);
|
|
12122
|
-
const content = safeReadFile(node_path.default.isAbsolute(filePath) ? filePath : node_path.default.join(cwd, filePath));
|
|
11991
|
+
const content = await safeReadFile(node_path.default.isAbsolute(filePath) ? filePath : node_path.default.join(cwd, filePath));
|
|
12123
11992
|
if (!content) return cmdOk({
|
|
12124
11993
|
error: "File not found",
|
|
12125
11994
|
path: filePath
|
|
@@ -12302,11 +12171,11 @@ function appendToStateSection(content, sectionPattern, entry, placeholderPattern
|
|
|
12302
12171
|
return content.replace(sectionPattern, (_m, header) => `${header}${sectionBody}`);
|
|
12303
12172
|
}
|
|
12304
12173
|
async function cmdStateLoad(cwd, raw) {
|
|
12305
|
-
const config = loadConfig(cwd);
|
|
12174
|
+
const config = await loadConfig(cwd);
|
|
12306
12175
|
const [stateContent, configExists, roadmapExists] = await Promise.all([
|
|
12307
|
-
|
|
12308
|
-
|
|
12309
|
-
|
|
12176
|
+
safeReadFile(statePath(cwd)),
|
|
12177
|
+
pathExistsInternal(configPath(cwd)),
|
|
12178
|
+
pathExistsInternal(roadmapPath(cwd))
|
|
12310
12179
|
]);
|
|
12311
12180
|
const stateRaw = stateContent ?? "";
|
|
12312
12181
|
const stateExists = stateRaw.length > 0;
|
|
@@ -12397,7 +12266,7 @@ async function cmdStateUpdate(cwd, field, value) {
|
|
|
12397
12266
|
}
|
|
12398
12267
|
async function cmdStateAdvancePlan(cwd, raw) {
|
|
12399
12268
|
const statePath$5 = statePath(cwd);
|
|
12400
|
-
if (!await
|
|
12269
|
+
if (!await pathExistsInternal(statePath$5)) return cmdOk({ error: "STATE.md not found" });
|
|
12401
12270
|
let content = await node_fs.promises.readFile(statePath$5, "utf-8");
|
|
12402
12271
|
const currentPlan = parseInt(stateExtractField(content, "Current Plan") ?? "", 10);
|
|
12403
12272
|
const totalPlans = parseInt(stateExtractField(content, "Total Plans in Phase") ?? "", 10);
|
|
@@ -12430,7 +12299,7 @@ async function cmdStateAdvancePlan(cwd, raw) {
|
|
|
12430
12299
|
}
|
|
12431
12300
|
async function cmdStateRecordMetric(cwd, options, raw) {
|
|
12432
12301
|
const statePath$6 = statePath(cwd);
|
|
12433
|
-
if (!await
|
|
12302
|
+
if (!await pathExistsInternal(statePath$6)) return cmdOk({ error: "STATE.md not found" });
|
|
12434
12303
|
let content = await node_fs.promises.readFile(statePath$6, "utf-8");
|
|
12435
12304
|
const { phase, plan, duration, tasks, files } = options;
|
|
12436
12305
|
if (!phase || !plan || !duration) return cmdOk({ error: "phase, plan, and duration required" });
|
|
@@ -12456,12 +12325,12 @@ async function cmdStateRecordMetric(cwd, options, raw) {
|
|
|
12456
12325
|
}
|
|
12457
12326
|
async function cmdStateUpdateProgress(cwd, raw) {
|
|
12458
12327
|
const statePath$7 = statePath(cwd);
|
|
12459
|
-
if (!await
|
|
12328
|
+
if (!await pathExistsInternal(statePath$7)) return cmdOk({ error: "STATE.md not found" });
|
|
12460
12329
|
let content = await node_fs.promises.readFile(statePath$7, "utf-8");
|
|
12461
12330
|
const phasesDir = phasesPath(cwd);
|
|
12462
12331
|
let totalPlans = 0;
|
|
12463
12332
|
let totalSummaries = 0;
|
|
12464
|
-
if (await
|
|
12333
|
+
if (await pathExistsInternal(phasesDir)) {
|
|
12465
12334
|
const phaseDirs = (await node_fs.promises.readdir(phasesDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
12466
12335
|
const counts = await Promise.all(phaseDirs.map(async (dir) => {
|
|
12467
12336
|
const files = await node_fs.promises.readdir(node_path.default.join(phasesDir, dir));
|
|
@@ -12496,7 +12365,7 @@ async function cmdStateUpdateProgress(cwd, raw) {
|
|
|
12496
12365
|
}
|
|
12497
12366
|
async function cmdStateAddDecision(cwd, options, raw) {
|
|
12498
12367
|
const statePath$8 = statePath(cwd);
|
|
12499
|
-
if (!await
|
|
12368
|
+
if (!await pathExistsInternal(statePath$8)) return cmdOk({ error: "STATE.md not found" });
|
|
12500
12369
|
const { phase, summary, summary_file, rationale, rationale_file } = options;
|
|
12501
12370
|
let summaryText;
|
|
12502
12371
|
let rationaleText = "";
|
|
@@ -12526,7 +12395,7 @@ async function cmdStateAddDecision(cwd, options, raw) {
|
|
|
12526
12395
|
}
|
|
12527
12396
|
async function cmdStateAddBlocker(cwd, text, raw) {
|
|
12528
12397
|
const statePath$9 = statePath(cwd);
|
|
12529
|
-
if (!await
|
|
12398
|
+
if (!await pathExistsInternal(statePath$9)) return cmdOk({ error: "STATE.md not found" });
|
|
12530
12399
|
const blockerOptions = typeof text === "object" && text !== null ? text : { text };
|
|
12531
12400
|
let blockerText;
|
|
12532
12401
|
try {
|
|
@@ -12552,7 +12421,7 @@ async function cmdStateAddBlocker(cwd, text, raw) {
|
|
|
12552
12421
|
}
|
|
12553
12422
|
async function cmdStateResolveBlocker(cwd, text, raw) {
|
|
12554
12423
|
const statePath$10 = statePath(cwd);
|
|
12555
|
-
if (!await
|
|
12424
|
+
if (!await pathExistsInternal(statePath$10)) return cmdOk({ error: "STATE.md not found" });
|
|
12556
12425
|
if (!text) return cmdOk({ error: "text required" });
|
|
12557
12426
|
let content = await node_fs.promises.readFile(statePath$10, "utf-8");
|
|
12558
12427
|
const sectionPattern = /(#{2,3}\s*(?:Blockers|Blockers\/Concerns|Concerns)\s*\n\s*\n?)([\s\S]*?)(?=\n#{2,3}\s|$)/i;
|
|
@@ -12576,7 +12445,7 @@ async function cmdStateResolveBlocker(cwd, text, raw) {
|
|
|
12576
12445
|
}
|
|
12577
12446
|
async function cmdStateRecordSession(cwd, options, raw) {
|
|
12578
12447
|
const statePath$11 = statePath(cwd);
|
|
12579
|
-
if (!await
|
|
12448
|
+
if (!await pathExistsInternal(statePath$11)) return cmdOk({ error: "STATE.md not found" });
|
|
12580
12449
|
let content = await node_fs.promises.readFile(statePath$11, "utf-8");
|
|
12581
12450
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12582
12451
|
const updated = [];
|
|
@@ -12618,7 +12487,7 @@ async function cmdStateRecordSession(cwd, options, raw) {
|
|
|
12618
12487
|
}
|
|
12619
12488
|
async function cmdStateSnapshot(cwd, raw) {
|
|
12620
12489
|
const statePath$12 = statePath(cwd);
|
|
12621
|
-
if (!await
|
|
12490
|
+
if (!await pathExistsInternal(statePath$12)) return cmdOk({ error: "STATE.md not found" });
|
|
12622
12491
|
const content = await node_fs.promises.readFile(statePath$12, "utf-8");
|
|
12623
12492
|
const extractField = (fieldName) => stateExtractField(content, fieldName);
|
|
12624
12493
|
const currentPhase = extractField("Current Phase");
|
|
@@ -12685,7 +12554,7 @@ async function cmdStateSnapshot(cwd, raw) {
|
|
|
12685
12554
|
async function cmdDetectStaleContext(cwd) {
|
|
12686
12555
|
const rmPath = roadmapPath(cwd);
|
|
12687
12556
|
const stPath = statePath(cwd);
|
|
12688
|
-
const [roadmapContent, stateContent] = await Promise.all([
|
|
12557
|
+
const [roadmapContent, stateContent] = await Promise.all([safeReadFile(rmPath), safeReadFile(stPath)]);
|
|
12689
12558
|
if (!roadmapContent) return cmdErr("ROADMAP.md not found");
|
|
12690
12559
|
if (!stateContent) return cmdErr("STATE.md not found");
|
|
12691
12560
|
const completedPhases = [];
|
|
@@ -12740,7 +12609,7 @@ async function cmdDetectStaleContext(cwd) {
|
|
|
12740
12609
|
* Ported from maxsim/bin/lib/roadmap.cjs
|
|
12741
12610
|
*/
|
|
12742
12611
|
async function cmdRoadmapGetPhase(cwd, phaseNum) {
|
|
12743
|
-
const content = await
|
|
12612
|
+
const content = await safeReadFile(roadmapPath(cwd));
|
|
12744
12613
|
if (!content) return cmdOk({
|
|
12745
12614
|
found: false,
|
|
12746
12615
|
error: "ROADMAP.md not found"
|
|
@@ -12785,7 +12654,7 @@ async function cmdRoadmapGetPhase(cwd, phaseNum) {
|
|
|
12785
12654
|
}
|
|
12786
12655
|
}
|
|
12787
12656
|
async function cmdRoadmapAnalyze(cwd) {
|
|
12788
|
-
const content = await
|
|
12657
|
+
const content = await safeReadFile(roadmapPath(cwd));
|
|
12789
12658
|
if (!content) return cmdOk({
|
|
12790
12659
|
error: "ROADMAP.md not found",
|
|
12791
12660
|
milestones: [],
|
|
@@ -12818,7 +12687,7 @@ async function cmdRoadmapAnalyze(cwd) {
|
|
|
12818
12687
|
}
|
|
12819
12688
|
let allDirs = [];
|
|
12820
12689
|
try {
|
|
12821
|
-
allDirs = await
|
|
12690
|
+
allDirs = await listSubDirs(phasesDir);
|
|
12822
12691
|
} catch {}
|
|
12823
12692
|
const phases = await Promise.all(parsedPhases.map(async (p) => {
|
|
12824
12693
|
let diskStatus = "no_directory";
|
|
@@ -12893,7 +12762,7 @@ async function cmdRoadmapAnalyze(cwd) {
|
|
|
12893
12762
|
async function cmdRoadmapUpdatePlanProgress(cwd, phaseNum) {
|
|
12894
12763
|
if (!phaseNum) return cmdErr("phase number required for roadmap update-plan-progress");
|
|
12895
12764
|
const rmPath = roadmapPath(cwd);
|
|
12896
|
-
const phaseInfo = await
|
|
12765
|
+
const phaseInfo = await findPhaseInternal(cwd, phaseNum);
|
|
12897
12766
|
if (!phaseInfo) return cmdErr(`Phase ${phaseNum} not found`);
|
|
12898
12767
|
const planCount = phaseInfo.plans.length;
|
|
12899
12768
|
const summaryCount = phaseInfo.summaries.length;
|
|
@@ -12906,7 +12775,7 @@ async function cmdRoadmapUpdatePlanProgress(cwd, phaseNum) {
|
|
|
12906
12775
|
const isComplete = summaryCount >= planCount;
|
|
12907
12776
|
const status = isComplete ? "Complete" : summaryCount > 0 ? "In Progress" : "Planned";
|
|
12908
12777
|
const today = todayISO();
|
|
12909
|
-
const rawContent = await
|
|
12778
|
+
const rawContent = await safeReadFile(rmPath);
|
|
12910
12779
|
if (!rawContent) return cmdOk({
|
|
12911
12780
|
updated: false,
|
|
12912
12781
|
reason: "ROADMAP.md not found",
|
|
@@ -12979,7 +12848,7 @@ async function cmdMilestoneComplete(cwd, version, options) {
|
|
|
12979
12848
|
const reqPath = planningPath(cwd, "REQUIREMENTS.md");
|
|
12980
12849
|
const statePath$1 = statePath(cwd);
|
|
12981
12850
|
const milestonesPath = planningPath(cwd, "MILESTONES.md");
|
|
12982
|
-
const archiveDir = archivePath(cwd, version);
|
|
12851
|
+
const archiveDir = await archivePath(cwd, version);
|
|
12983
12852
|
const phasesDir = phasesPath(cwd);
|
|
12984
12853
|
const today = todayISO();
|
|
12985
12854
|
const milestoneName = options.name || version;
|
|
@@ -12989,7 +12858,7 @@ async function cmdMilestoneComplete(cwd, version, options) {
|
|
|
12989
12858
|
let totalTasks = 0;
|
|
12990
12859
|
const accomplishments = [];
|
|
12991
12860
|
try {
|
|
12992
|
-
const dirs = await
|
|
12861
|
+
const dirs = await listSubDirs(phasesDir, true);
|
|
12993
12862
|
for (const dir of dirs) {
|
|
12994
12863
|
phaseCount++;
|
|
12995
12864
|
const phaseFiles = await node_fs.promises.readdir(node_path.default.join(phasesDir, dir));
|
|
@@ -13009,12 +12878,12 @@ async function cmdMilestoneComplete(cwd, version, options) {
|
|
|
13009
12878
|
} catch (e) {
|
|
13010
12879
|
debugLog(e);
|
|
13011
12880
|
}
|
|
13012
|
-
const stateExists = await
|
|
12881
|
+
const stateExists = await pathExistsInternal(statePath$1);
|
|
13013
12882
|
if (stateExists) {
|
|
13014
12883
|
const stateContent = await node_fs.promises.readFile(statePath$1, "utf-8");
|
|
13015
12884
|
await node_fs.promises.writeFile(node_path.default.join(archiveDir, "STATE.md"), stateContent, "utf-8");
|
|
13016
12885
|
}
|
|
13017
|
-
const roadmapExists = await
|
|
12886
|
+
const roadmapExists = await pathExistsInternal(roadmapPath$1);
|
|
13018
12887
|
if (roadmapExists) {
|
|
13019
12888
|
const roadmapContent = await node_fs.promises.readFile(roadmapPath$1, "utf-8");
|
|
13020
12889
|
await node_fs.promises.writeFile(node_path.default.join(archiveDir, "ROADMAP.md"), roadmapContent, "utf-8");
|
|
@@ -13023,16 +12892,16 @@ async function cmdMilestoneComplete(cwd, version, options) {
|
|
|
13023
12892
|
const roadmapContent = await node_fs.promises.readFile(roadmapPath$1, "utf-8");
|
|
13024
12893
|
await node_fs.promises.writeFile(node_path.default.join(archiveDir, `${version}-ROADMAP.md`), roadmapContent, "utf-8");
|
|
13025
12894
|
}
|
|
13026
|
-
if (await
|
|
12895
|
+
if (await pathExistsInternal(reqPath)) {
|
|
13027
12896
|
const reqContent = await node_fs.promises.readFile(reqPath, "utf-8");
|
|
13028
12897
|
const archiveHeader = `# Requirements Archive: ${version} ${milestoneName}\n\n**Archived:** ${today}\n**Status:** SHIPPED\n\nFor current requirements, see \`.planning/REQUIREMENTS.md\`.\n\n---\n\n`;
|
|
13029
12898
|
await node_fs.promises.writeFile(node_path.default.join(archiveDir, `${version}-REQUIREMENTS.md`), archiveHeader + reqContent, "utf-8");
|
|
13030
12899
|
}
|
|
13031
12900
|
const auditFile = node_path.default.join(cwd, ".planning", `${version}-MILESTONE-AUDIT.md`);
|
|
13032
|
-
if (await
|
|
12901
|
+
if (await pathExistsInternal(auditFile)) await node_fs.promises.rename(auditFile, node_path.default.join(archiveDir, `${version}-MILESTONE-AUDIT.md`));
|
|
13033
12902
|
const accomplishmentsList = accomplishments.map((a) => `- ${a}`).join("\n");
|
|
13034
12903
|
const milestoneEntry = `## ${version} ${milestoneName} (Shipped: ${today})\n\n**Phases completed:** ${phaseCount} phases, ${totalPlans} plans, ${totalTasks} tasks\n\n**Key accomplishments:**\n${accomplishmentsList || "- (none recorded)"}\n\n---\n\n`;
|
|
13035
|
-
if (await
|
|
12904
|
+
if (await pathExistsInternal(milestonesPath)) {
|
|
13036
12905
|
const existing = await node_fs.promises.readFile(milestonesPath, "utf-8");
|
|
13037
12906
|
await node_fs.promises.writeFile(milestonesPath, existing + "\n" + milestoneEntry, "utf-8");
|
|
13038
12907
|
} else await node_fs.promises.writeFile(milestonesPath, `# Milestones\n\n${milestoneEntry}`, "utf-8");
|
|
@@ -13078,7 +12947,7 @@ Last session: ${today}
|
|
|
13078
12947
|
if (options.archivePhases) try {
|
|
13079
12948
|
const phaseArchiveDir = node_path.default.join(archiveDir, "phases");
|
|
13080
12949
|
await node_fs.promises.mkdir(phaseArchiveDir, { recursive: true });
|
|
13081
|
-
const phaseDirNames = await
|
|
12950
|
+
const phaseDirNames = await listSubDirs(phasesDir);
|
|
13082
12951
|
for (const dir of phaseDirNames) await node_fs.promises.rename(node_path.default.join(phasesDir, dir), node_path.default.join(phaseArchiveDir, dir));
|
|
13083
12952
|
phasesArchived = phaseDirNames.length > 0;
|
|
13084
12953
|
} catch (e) {
|
|
@@ -13093,12 +12962,12 @@ Last session: ${today}
|
|
|
13093
12962
|
tasks: totalTasks,
|
|
13094
12963
|
accomplishments,
|
|
13095
12964
|
archived: {
|
|
13096
|
-
roadmap: await
|
|
13097
|
-
requirements: await
|
|
13098
|
-
audit: await
|
|
12965
|
+
roadmap: await pathExistsInternal(node_path.default.join(archiveDir, `${version}-ROADMAP.md`)),
|
|
12966
|
+
requirements: await pathExistsInternal(node_path.default.join(archiveDir, `${version}-REQUIREMENTS.md`)),
|
|
12967
|
+
audit: await pathExistsInternal(node_path.default.join(archiveDir, `${version}-MILESTONE-AUDIT.md`)),
|
|
13099
12968
|
phases: phasesArchived,
|
|
13100
|
-
state_snapshot: await
|
|
13101
|
-
roadmap_snapshot: await
|
|
12969
|
+
state_snapshot: await pathExistsInternal(node_path.default.join(archiveDir, "STATE.md")),
|
|
12970
|
+
roadmap_snapshot: await pathExistsInternal(node_path.default.join(archiveDir, "ROADMAP.md"))
|
|
13102
12971
|
},
|
|
13103
12972
|
milestones_updated: true,
|
|
13104
12973
|
state_updated: stateExists,
|
|
@@ -13600,7 +13469,7 @@ function cmdVerifyPathExists(cwd, targetPath, raw) {
|
|
|
13600
13469
|
}, raw ? "false" : void 0);
|
|
13601
13470
|
}
|
|
13602
13471
|
}
|
|
13603
|
-
function cmdHistoryDigest(cwd, raw) {
|
|
13472
|
+
async function cmdHistoryDigest(cwd, raw) {
|
|
13604
13473
|
const phasesDir = phasesPath(cwd);
|
|
13605
13474
|
const digest = {
|
|
13606
13475
|
phases: {},
|
|
@@ -13608,14 +13477,14 @@ function cmdHistoryDigest(cwd, raw) {
|
|
|
13608
13477
|
tech_stack: /* @__PURE__ */ new Set()
|
|
13609
13478
|
};
|
|
13610
13479
|
const allPhaseDirs = [];
|
|
13611
|
-
const archived = getArchivedPhaseDirs(cwd);
|
|
13480
|
+
const archived = await getArchivedPhaseDirs(cwd);
|
|
13612
13481
|
for (const a of archived) allPhaseDirs.push({
|
|
13613
13482
|
name: a.name,
|
|
13614
13483
|
fullPath: a.fullPath,
|
|
13615
13484
|
milestone: a.milestone
|
|
13616
13485
|
});
|
|
13617
13486
|
if (node_fs.default.existsSync(phasesDir)) try {
|
|
13618
|
-
const currentDirs = listSubDirs(phasesDir, true);
|
|
13487
|
+
const currentDirs = await listSubDirs(phasesDir, true);
|
|
13619
13488
|
for (const dir of currentDirs) allPhaseDirs.push({
|
|
13620
13489
|
name: dir,
|
|
13621
13490
|
fullPath: node_path.default.join(phasesDir, dir),
|
|
@@ -13675,9 +13544,9 @@ function cmdHistoryDigest(cwd, raw) {
|
|
|
13675
13544
|
return cmdErr("Failed to generate history digest: " + e.message);
|
|
13676
13545
|
}
|
|
13677
13546
|
}
|
|
13678
|
-
function cmdResolveModel(cwd, agentType, raw) {
|
|
13547
|
+
async function cmdResolveModel(cwd, agentType, raw) {
|
|
13679
13548
|
if (!agentType) return cmdErr("agent-type required");
|
|
13680
|
-
const profile = loadConfig(cwd).model_profile || "balanced";
|
|
13549
|
+
const profile = (await loadConfig(cwd)).model_profile || "balanced";
|
|
13681
13550
|
const agentModels = MODEL_PROFILES[agentType];
|
|
13682
13551
|
if (!agentModels) return cmdOk({
|
|
13683
13552
|
model: "sonnet",
|
|
@@ -13693,7 +13562,7 @@ function cmdResolveModel(cwd, agentType, raw) {
|
|
|
13693
13562
|
}
|
|
13694
13563
|
async function cmdCommit(cwd, message, files, raw, amend) {
|
|
13695
13564
|
if (!message && !amend) return cmdErr("commit message required");
|
|
13696
|
-
if (!loadConfig(cwd).commit_docs) return cmdOk({
|
|
13565
|
+
if (!(await loadConfig(cwd)).commit_docs) return cmdOk({
|
|
13697
13566
|
committed: false,
|
|
13698
13567
|
hash: null,
|
|
13699
13568
|
reason: "skipped_commit_docs_false"
|
|
@@ -13825,9 +13694,9 @@ async function cmdWebsearch(query, options, raw) {
|
|
|
13825
13694
|
}, raw ? "" : void 0);
|
|
13826
13695
|
}
|
|
13827
13696
|
}
|
|
13828
|
-
function cmdProgressRender(cwd, format, raw) {
|
|
13697
|
+
async function cmdProgressRender(cwd, format, raw) {
|
|
13829
13698
|
const phasesDir = phasesPath(cwd);
|
|
13830
|
-
const milestone = getMilestoneInfo(cwd);
|
|
13699
|
+
const milestone = await getMilestoneInfo(cwd);
|
|
13831
13700
|
const phases = [];
|
|
13832
13701
|
let totalPlans = 0;
|
|
13833
13702
|
let totalSummaries = 0;
|
|
@@ -13934,11 +13803,11 @@ function cmdTodoComplete(cwd, filename, raw) {
|
|
|
13934
13803
|
date: today
|
|
13935
13804
|
}, raw ? "completed" : void 0);
|
|
13936
13805
|
}
|
|
13937
|
-
function cmdScaffold(cwd, type, options, raw) {
|
|
13806
|
+
async function cmdScaffold(cwd, type, options, raw) {
|
|
13938
13807
|
const { phase, name } = options;
|
|
13939
13808
|
const padded = phase ? normalizePhaseName(phase) : "00";
|
|
13940
13809
|
const today = todayISO();
|
|
13941
|
-
const phaseInfo = phase ? findPhaseInternal(cwd, phase) : null;
|
|
13810
|
+
const phaseInfo = phase ? await findPhaseInternal(cwd, phase) : null;
|
|
13942
13811
|
const phaseDir = phaseInfo ? node_path.default.join(cwd, phaseInfo.directory) : null;
|
|
13943
13812
|
if (phase && !phaseDir && type !== "phase-dir") return cmdErr(`Phase ${phase} directory not found`);
|
|
13944
13813
|
let filePath;
|
|
@@ -14064,9 +13933,9 @@ async function cmdVerifySummary(cwd, summaryPath, checkFileCount) {
|
|
|
14064
13933
|
errors
|
|
14065
13934
|
}, passed ? "passed" : "failed");
|
|
14066
13935
|
}
|
|
14067
|
-
function cmdVerifyPlanStructure(cwd, filePath) {
|
|
13936
|
+
async function cmdVerifyPlanStructure(cwd, filePath) {
|
|
14068
13937
|
if (!filePath) return cmdErr("file path required");
|
|
14069
|
-
const content = safeReadFile(node_path.default.isAbsolute(filePath) ? filePath : node_path.default.join(cwd, filePath));
|
|
13938
|
+
const content = await safeReadFile(node_path.default.isAbsolute(filePath) ? filePath : node_path.default.join(cwd, filePath));
|
|
14070
13939
|
if (!content) return cmdOk({
|
|
14071
13940
|
error: "File not found",
|
|
14072
13941
|
path: filePath
|
|
@@ -14120,9 +13989,9 @@ function cmdVerifyPlanStructure(cwd, filePath) {
|
|
|
14120
13989
|
frontmatter_fields: Object.keys(fm)
|
|
14121
13990
|
}, errors.length === 0 ? "valid" : "invalid");
|
|
14122
13991
|
}
|
|
14123
|
-
function cmdVerifyPhaseCompleteness(cwd, phase) {
|
|
13992
|
+
async function cmdVerifyPhaseCompleteness(cwd, phase) {
|
|
14124
13993
|
if (!phase) return cmdErr("phase required");
|
|
14125
|
-
const phaseInfo = findPhaseInternal(cwd, phase);
|
|
13994
|
+
const phaseInfo = await findPhaseInternal(cwd, phase);
|
|
14126
13995
|
if (!phaseInfo) return cmdOk({
|
|
14127
13996
|
error: "Phase not found",
|
|
14128
13997
|
phase
|
|
@@ -14155,9 +14024,9 @@ function cmdVerifyPhaseCompleteness(cwd, phase) {
|
|
|
14155
14024
|
warnings
|
|
14156
14025
|
}, errors.length === 0 ? "complete" : "incomplete");
|
|
14157
14026
|
}
|
|
14158
|
-
function cmdVerifyReferences(cwd, filePath) {
|
|
14027
|
+
async function cmdVerifyReferences(cwd, filePath) {
|
|
14159
14028
|
if (!filePath) return cmdErr("file path required");
|
|
14160
|
-
const content = safeReadFile(node_path.default.isAbsolute(filePath) ? filePath : node_path.default.join(cwd, filePath));
|
|
14029
|
+
const content = await safeReadFile(node_path.default.isAbsolute(filePath) ? filePath : node_path.default.join(cwd, filePath));
|
|
14161
14030
|
if (!content) return cmdOk({
|
|
14162
14031
|
error: "File not found",
|
|
14163
14032
|
path: filePath
|
|
@@ -14207,9 +14076,9 @@ async function cmdVerifyCommits(cwd, hashes) {
|
|
|
14207
14076
|
total: hashes.length
|
|
14208
14077
|
}, invalid.length === 0 ? "valid" : "invalid");
|
|
14209
14078
|
}
|
|
14210
|
-
function cmdVerifyArtifacts(cwd, planFilePath) {
|
|
14079
|
+
async function cmdVerifyArtifacts(cwd, planFilePath) {
|
|
14211
14080
|
if (!planFilePath) return cmdErr("plan file path required");
|
|
14212
|
-
const content = safeReadFile(node_path.default.isAbsolute(planFilePath) ? planFilePath : node_path.default.join(cwd, planFilePath));
|
|
14081
|
+
const content = await safeReadFile(node_path.default.isAbsolute(planFilePath) ? planFilePath : node_path.default.join(cwd, planFilePath));
|
|
14213
14082
|
if (!content) return cmdOk({
|
|
14214
14083
|
error: "File not found",
|
|
14215
14084
|
path: planFilePath
|
|
@@ -14234,7 +14103,7 @@ function cmdVerifyArtifacts(cwd, planFilePath) {
|
|
|
14234
14103
|
passed: false
|
|
14235
14104
|
};
|
|
14236
14105
|
if (exists) {
|
|
14237
|
-
const fileContent = safeReadFile(artFullPath) || "";
|
|
14106
|
+
const fileContent = await safeReadFile(artFullPath) || "";
|
|
14238
14107
|
const lineCount = fileContent.split("\n").length;
|
|
14239
14108
|
if (artObj.min_lines && lineCount < artObj.min_lines) check.issues.push(`Only ${lineCount} lines, need ${artObj.min_lines}`);
|
|
14240
14109
|
if (artObj.contains && !fileContent.includes(artObj.contains)) check.issues.push(`Missing pattern: ${artObj.contains}`);
|
|
@@ -14254,9 +14123,9 @@ function cmdVerifyArtifacts(cwd, planFilePath) {
|
|
|
14254
14123
|
artifacts: results
|
|
14255
14124
|
}, passed === results.length ? "valid" : "invalid");
|
|
14256
14125
|
}
|
|
14257
|
-
function cmdVerifyKeyLinks(cwd, planFilePath) {
|
|
14126
|
+
async function cmdVerifyKeyLinks(cwd, planFilePath) {
|
|
14258
14127
|
if (!planFilePath) return cmdErr("plan file path required");
|
|
14259
|
-
const content = safeReadFile(node_path.default.isAbsolute(planFilePath) ? planFilePath : node_path.default.join(cwd, planFilePath));
|
|
14128
|
+
const content = await safeReadFile(node_path.default.isAbsolute(planFilePath) ? planFilePath : node_path.default.join(cwd, planFilePath));
|
|
14260
14129
|
if (!content) return cmdOk({
|
|
14261
14130
|
error: "File not found",
|
|
14262
14131
|
path: planFilePath
|
|
@@ -14277,7 +14146,7 @@ function cmdVerifyKeyLinks(cwd, planFilePath) {
|
|
|
14277
14146
|
verified: false,
|
|
14278
14147
|
detail: ""
|
|
14279
14148
|
};
|
|
14280
|
-
const sourceContent = safeReadFile(node_path.default.join(cwd, linkObj.from || ""));
|
|
14149
|
+
const sourceContent = await safeReadFile(node_path.default.join(cwd, linkObj.from || ""));
|
|
14281
14150
|
if (!sourceContent) check.detail = "Source file not found";
|
|
14282
14151
|
else if (linkObj.pattern) try {
|
|
14283
14152
|
const regex = new RegExp(linkObj.pattern);
|
|
@@ -14285,7 +14154,7 @@ function cmdVerifyKeyLinks(cwd, planFilePath) {
|
|
|
14285
14154
|
check.verified = true;
|
|
14286
14155
|
check.detail = "Pattern found in source";
|
|
14287
14156
|
} else {
|
|
14288
|
-
const targetContent = safeReadFile(node_path.default.join(cwd, linkObj.to || ""));
|
|
14157
|
+
const targetContent = await safeReadFile(node_path.default.join(cwd, linkObj.to || ""));
|
|
14289
14158
|
if (targetContent && regex.test(targetContent)) {
|
|
14290
14159
|
check.verified = true;
|
|
14291
14160
|
check.detail = "Pattern found in target";
|
|
@@ -14308,7 +14177,7 @@ function cmdVerifyKeyLinks(cwd, planFilePath) {
|
|
|
14308
14177
|
links: results
|
|
14309
14178
|
}, verified === results.length ? "valid" : "invalid");
|
|
14310
14179
|
}
|
|
14311
|
-
function cmdValidateConsistency(cwd) {
|
|
14180
|
+
async function cmdValidateConsistency(cwd) {
|
|
14312
14181
|
const rmPath = roadmapPath(cwd);
|
|
14313
14182
|
const phasesDir = phasesPath(cwd);
|
|
14314
14183
|
const errors = [];
|
|
@@ -14328,7 +14197,7 @@ function cmdValidateConsistency(cwd) {
|
|
|
14328
14197
|
while ((m = phasePattern.exec(roadmapContent)) !== null) roadmapPhases.add(m[1]);
|
|
14329
14198
|
const diskPhases = /* @__PURE__ */ new Set();
|
|
14330
14199
|
try {
|
|
14331
|
-
const dirs = listSubDirs(phasesDir);
|
|
14200
|
+
const dirs = await listSubDirs(phasesDir);
|
|
14332
14201
|
for (const dir of dirs) {
|
|
14333
14202
|
const dm = dir.match(/^(\d+[A-Z]?(?:\.\d+)?)/i);
|
|
14334
14203
|
if (dm) diskPhases.add(dm[1]);
|
|
@@ -14344,7 +14213,7 @@ function cmdValidateConsistency(cwd) {
|
|
|
14344
14213
|
const integerPhases = [...diskPhases].filter((p) => !p.includes(".")).map((p) => parseInt(p, 10)).sort((a, b) => a - b);
|
|
14345
14214
|
for (let i = 1; i < integerPhases.length; i++) if (integerPhases[i] !== integerPhases[i - 1] + 1) warnings.push(`Gap in phase numbering: ${integerPhases[i - 1]} → ${integerPhases[i]}`);
|
|
14346
14215
|
try {
|
|
14347
|
-
const dirs = listSubDirs(phasesDir, true);
|
|
14216
|
+
const dirs = await listSubDirs(phasesDir, true);
|
|
14348
14217
|
for (const dir of dirs) {
|
|
14349
14218
|
const phaseFiles = node_fs.default.readdirSync(node_path.default.join(phasesDir, dir));
|
|
14350
14219
|
const plans = phaseFiles.filter((f) => isPlanFile(f)).sort();
|
|
@@ -14362,7 +14231,7 @@ function cmdValidateConsistency(cwd) {
|
|
|
14362
14231
|
debugLog(e);
|
|
14363
14232
|
}
|
|
14364
14233
|
try {
|
|
14365
|
-
const dirs = listSubDirs(phasesDir);
|
|
14234
|
+
const dirs = await listSubDirs(phasesDir);
|
|
14366
14235
|
for (const dir of dirs) {
|
|
14367
14236
|
const plans = node_fs.default.readdirSync(node_path.default.join(phasesDir, dir)).filter((f) => isPlanFile(f));
|
|
14368
14237
|
for (const plan of plans) if (!extractFrontmatter(node_fs.default.readFileSync(node_path.default.join(phasesDir, dir, plan), "utf-8")).wave) warnings.push(`${dir}/${plan}: missing 'wave' in frontmatter`);
|
|
@@ -14378,7 +14247,7 @@ function cmdValidateConsistency(cwd) {
|
|
|
14378
14247
|
warning_count: warnings.length
|
|
14379
14248
|
}, passed ? "passed" : "failed");
|
|
14380
14249
|
}
|
|
14381
|
-
function cmdValidateHealth(cwd, options) {
|
|
14250
|
+
async function cmdValidateHealth(cwd, options) {
|
|
14382
14251
|
const planningDir = planningPath(cwd);
|
|
14383
14252
|
const projectPath = planningPath(cwd, "PROJECT.md");
|
|
14384
14253
|
const rmPath = roadmapPath(cwd);
|
|
@@ -14427,7 +14296,7 @@ function cmdValidateHealth(cwd, options) {
|
|
|
14427
14296
|
const phaseRefs = [...node_fs.default.readFileSync(stPath, "utf-8").matchAll(/[Pp]hase\s+(\d+(?:\.\d+)?)/g)].map((m) => m[1]);
|
|
14428
14297
|
const diskPhases = /* @__PURE__ */ new Set();
|
|
14429
14298
|
try {
|
|
14430
|
-
for (const dir of listSubDirs(phasesDir)) {
|
|
14299
|
+
for (const dir of await listSubDirs(phasesDir)) {
|
|
14431
14300
|
const dm = dir.match(/^(\d+(?:\.\d+)?)/);
|
|
14432
14301
|
if (dm) diskPhases.add(dm[1]);
|
|
14433
14302
|
}
|
|
@@ -14462,12 +14331,12 @@ function cmdValidateHealth(cwd, options) {
|
|
|
14462
14331
|
repairs.push("resetConfig");
|
|
14463
14332
|
}
|
|
14464
14333
|
try {
|
|
14465
|
-
for (const dirName of listSubDirs(phasesDir)) if (!dirName.match(/^\d{2}(?:\.\d+)?-[\w-]+$/)) addIssue("warning", "W005", `Phase directory "${dirName}" doesn't follow NN-name format`, "Rename to match pattern (e.g., 01-setup)");
|
|
14334
|
+
for (const dirName of await listSubDirs(phasesDir)) if (!dirName.match(/^\d{2}(?:\.\d+)?-[\w-]+$/)) addIssue("warning", "W005", `Phase directory "${dirName}" doesn't follow NN-name format`, "Rename to match pattern (e.g., 01-setup)");
|
|
14466
14335
|
} catch (e) {
|
|
14467
14336
|
debugLog(e);
|
|
14468
14337
|
}
|
|
14469
14338
|
try {
|
|
14470
|
-
const orphanDirs = listSubDirs(phasesDir);
|
|
14339
|
+
const orphanDirs = await listSubDirs(phasesDir);
|
|
14471
14340
|
for (const dirName of orphanDirs) {
|
|
14472
14341
|
const phaseFiles = node_fs.default.readdirSync(node_path.default.join(phasesDir, dirName));
|
|
14473
14342
|
const plans = phaseFiles.filter((f) => isPlanFile(f));
|
|
@@ -14489,7 +14358,7 @@ function cmdValidateHealth(cwd, options) {
|
|
|
14489
14358
|
while ((m = phasePattern.exec(roadmapContent)) !== null) roadmapPhases.add(m[1]);
|
|
14490
14359
|
const diskPhases = /* @__PURE__ */ new Set();
|
|
14491
14360
|
try {
|
|
14492
|
-
for (const dir of listSubDirs(phasesDir)) {
|
|
14361
|
+
for (const dir of await listSubDirs(phasesDir)) {
|
|
14493
14362
|
const dm = dir.match(/^(\d+[A-Z]?(?:\.\d+)?)/i);
|
|
14494
14363
|
if (dm) diskPhases.add(dm[1]);
|
|
14495
14364
|
}
|
|
@@ -14536,7 +14405,7 @@ function cmdValidateHealth(cwd, options) {
|
|
|
14536
14405
|
path: backupPath
|
|
14537
14406
|
});
|
|
14538
14407
|
}
|
|
14539
|
-
const milestone = getMilestoneInfo(cwd);
|
|
14408
|
+
const milestone = await getMilestoneInfo(cwd);
|
|
14540
14409
|
let stateContent = `# Session State\n\n`;
|
|
14541
14410
|
stateContent += `## Project Reference\n\n`;
|
|
14542
14411
|
stateContent += `See: .planning/PROJECT.md\n\n`;
|
|
@@ -14590,8 +14459,8 @@ const DRIFT_REPORT_NAME = "DRIFT-REPORT.md";
|
|
|
14590
14459
|
* Read the drift report from .planning/DRIFT-REPORT.md.
|
|
14591
14460
|
* Returns parsed frontmatter and body content, or structured error if not found.
|
|
14592
14461
|
*/
|
|
14593
|
-
function cmdDriftReadReport(cwd) {
|
|
14594
|
-
const content = safeReadFile(planningPath(cwd, DRIFT_REPORT_NAME));
|
|
14462
|
+
async function cmdDriftReadReport(cwd) {
|
|
14463
|
+
const content = await safeReadFile(planningPath(cwd, DRIFT_REPORT_NAME));
|
|
14595
14464
|
if (!content) return cmdOk({
|
|
14596
14465
|
found: false,
|
|
14597
14466
|
path: `.planning/${DRIFT_REPORT_NAME}`,
|
|
@@ -14611,10 +14480,10 @@ function cmdDriftReadReport(cwd) {
|
|
|
14611
14480
|
* Write content to .planning/DRIFT-REPORT.md.
|
|
14612
14481
|
* Supports direct content or reading from a file (tmpfile pattern for large reports).
|
|
14613
14482
|
*/
|
|
14614
|
-
function cmdDriftWriteReport(cwd, content, contentFile) {
|
|
14483
|
+
async function cmdDriftWriteReport(cwd, content, contentFile) {
|
|
14615
14484
|
let reportContent;
|
|
14616
14485
|
if (contentFile) {
|
|
14617
|
-
const fileContent = safeReadFile(node_path.default.isAbsolute(contentFile) ? contentFile : node_path.default.join(cwd, contentFile));
|
|
14486
|
+
const fileContent = await safeReadFile(node_path.default.isAbsolute(contentFile) ? contentFile : node_path.default.join(cwd, contentFile));
|
|
14618
14487
|
if (!fileContent) return cmdErr(`Content file not found: ${contentFile}`);
|
|
14619
14488
|
reportContent = fileContent;
|
|
14620
14489
|
} else if (content) reportContent = content;
|
|
@@ -14637,8 +14506,8 @@ function cmdDriftWriteReport(cwd, content, contentFile) {
|
|
|
14637
14506
|
* Extract all requirements from .planning/REQUIREMENTS.md.
|
|
14638
14507
|
* Parses requirement lines matching `- [ ] **ID**: description` or `- [x] **ID**: description`.
|
|
14639
14508
|
*/
|
|
14640
|
-
function cmdDriftExtractRequirements(cwd) {
|
|
14641
|
-
const content = safeReadFile(planningPath(cwd, "REQUIREMENTS.md"));
|
|
14509
|
+
async function cmdDriftExtractRequirements(cwd) {
|
|
14510
|
+
const content = await safeReadFile(planningPath(cwd, "REQUIREMENTS.md"));
|
|
14642
14511
|
if (!content) return cmdOk({
|
|
14643
14512
|
found: false,
|
|
14644
14513
|
path: ".planning/REQUIREMENTS.md",
|
|
@@ -14666,8 +14535,8 @@ function cmdDriftExtractRequirements(cwd) {
|
|
|
14666
14535
|
* Extract no-go rules from .planning/NO-GOS.md.
|
|
14667
14536
|
* Returns array of no-go items with section context, or empty if file missing.
|
|
14668
14537
|
*/
|
|
14669
|
-
function cmdDriftExtractNoGos(cwd) {
|
|
14670
|
-
const content = safeReadFile(planningPath(cwd, "NO-GOS.md"));
|
|
14538
|
+
async function cmdDriftExtractNoGos(cwd) {
|
|
14539
|
+
const content = await safeReadFile(planningPath(cwd, "NO-GOS.md"));
|
|
14671
14540
|
if (!content) return cmdOk({
|
|
14672
14541
|
found: false,
|
|
14673
14542
|
path: ".planning/NO-GOS.md",
|
|
@@ -14704,8 +14573,8 @@ function cmdDriftExtractNoGos(cwd) {
|
|
|
14704
14573
|
* Read .planning/CONVENTIONS.md and return its full content.
|
|
14705
14574
|
* Returns the raw content for agent analysis, or null if missing.
|
|
14706
14575
|
*/
|
|
14707
|
-
function cmdDriftExtractConventions(cwd) {
|
|
14708
|
-
const content = safeReadFile(planningPath(cwd, "CONVENTIONS.md"));
|
|
14576
|
+
async function cmdDriftExtractConventions(cwd) {
|
|
14577
|
+
const content = await safeReadFile(planningPath(cwd, "CONVENTIONS.md"));
|
|
14709
14578
|
if (!content) return cmdOk({
|
|
14710
14579
|
found: false,
|
|
14711
14580
|
path: ".planning/CONVENTIONS.md",
|
|
@@ -14721,8 +14590,8 @@ function cmdDriftExtractConventions(cwd) {
|
|
|
14721
14590
|
* Read existing DRIFT-REPORT.md frontmatter for diff tracking.
|
|
14722
14591
|
* Returns previous_hash and checked date, or null if no report exists.
|
|
14723
14592
|
*/
|
|
14724
|
-
function cmdDriftPreviousHash(cwd) {
|
|
14725
|
-
const content = safeReadFile(planningPath(cwd, DRIFT_REPORT_NAME));
|
|
14593
|
+
async function cmdDriftPreviousHash(cwd) {
|
|
14594
|
+
const content = await safeReadFile(planningPath(cwd, DRIFT_REPORT_NAME));
|
|
14726
14595
|
if (!content) return cmdOk({
|
|
14727
14596
|
found: false,
|
|
14728
14597
|
hash: null,
|
|
@@ -14799,7 +14668,7 @@ async function phaseInsertCore(cwd, afterPhase, description, options) {
|
|
|
14799
14668
|
const normalizedBase = normalizePhaseName(afterPhase);
|
|
14800
14669
|
const existingDecimals = [];
|
|
14801
14670
|
try {
|
|
14802
|
-
const dirs = await
|
|
14671
|
+
const dirs = await listSubDirs(phasesDirPath);
|
|
14803
14672
|
const decimalPattern = new RegExp(`^${normalizedBase}\\.(\\d+)`);
|
|
14804
14673
|
for (const dir of dirs) {
|
|
14805
14674
|
const dm = dir.match(decimalPattern);
|
|
@@ -14838,12 +14707,12 @@ async function phaseCompleteCore(cwd, phaseNum) {
|
|
|
14838
14707
|
const stPath = statePath(cwd);
|
|
14839
14708
|
const phasesDirPath = phasesPath(cwd);
|
|
14840
14709
|
const today = todayISO();
|
|
14841
|
-
const phaseInfo = await
|
|
14710
|
+
const phaseInfo = await findPhaseInternal(cwd, phaseNum);
|
|
14842
14711
|
if (!phaseInfo) throw new Error(`Phase ${phaseNum} not found`);
|
|
14843
14712
|
const planCount = phaseInfo.plans.length;
|
|
14844
14713
|
const summaryCount = phaseInfo.summaries.length;
|
|
14845
14714
|
let requirementsUpdated = false;
|
|
14846
|
-
const rmExists = await
|
|
14715
|
+
const rmExists = await pathExistsInternal(rmPath);
|
|
14847
14716
|
if (rmExists) {
|
|
14848
14717
|
let roadmapContent = await node_fs.promises.readFile(rmPath, "utf-8");
|
|
14849
14718
|
const checkboxPattern = new RegExp(`(-\\s*\\[)[ ](\\]\\s*.*Phase\\s+${escapePhaseNum(phaseNum)}[:\\s][^\\n]*)`, "i");
|
|
@@ -14857,7 +14726,7 @@ async function phaseCompleteCore(cwd, phaseNum) {
|
|
|
14857
14726
|
await node_fs.promises.writeFile(rmPath, roadmapContent, "utf-8");
|
|
14858
14727
|
debugLog("phase-complete-write", `ROADMAP.md updated for phase ${phaseNum}`);
|
|
14859
14728
|
const reqPath = planningPath(cwd, "REQUIREMENTS.md");
|
|
14860
|
-
if (await
|
|
14729
|
+
if (await pathExistsInternal(reqPath)) {
|
|
14861
14730
|
const reqMatch = roadmapContent.match(new RegExp(`Phase\\s+${escapePhaseNum(phaseNum)}[\\s\\S]*?\\*\\*Requirements:\\*\\*\\s*([^\\n]+)`, "i"));
|
|
14862
14731
|
if (reqMatch) {
|
|
14863
14732
|
const reqIds = reqMatch[1].replace(/[\[\]]/g, "").split(/[,\s]+/).map((r) => r.trim()).filter(Boolean);
|
|
@@ -14877,7 +14746,7 @@ async function phaseCompleteCore(cwd, phaseNum) {
|
|
|
14877
14746
|
let nextPhaseName = null;
|
|
14878
14747
|
let isLastPhase = true;
|
|
14879
14748
|
try {
|
|
14880
|
-
const dirs = await
|
|
14749
|
+
const dirs = await listSubDirs(phasesDirPath, true);
|
|
14881
14750
|
for (const dir of dirs) {
|
|
14882
14751
|
const dm = dir.match(/^(\d+[A-Z]?(?:\.\d+)?)-?(.*)/i);
|
|
14883
14752
|
if (dm) {
|
|
@@ -14892,7 +14761,7 @@ async function phaseCompleteCore(cwd, phaseNum) {
|
|
|
14892
14761
|
} catch (e) {
|
|
14893
14762
|
debugLog("phase-complete-next-phase-scan-failed", e);
|
|
14894
14763
|
}
|
|
14895
|
-
const stExists = await
|
|
14764
|
+
const stExists = await pathExistsInternal(stPath);
|
|
14896
14765
|
if (stExists) {
|
|
14897
14766
|
let stateContent = await node_fs.promises.readFile(stPath, "utf-8");
|
|
14898
14767
|
stateContent = stateContent.replace(/(\*\*Current Phase:\*\*\s*).*/, `$1${nextPhaseNum || phaseNum}`);
|
|
@@ -14921,7 +14790,7 @@ async function phaseCompleteCore(cwd, phaseNum) {
|
|
|
14921
14790
|
async function cmdPhasesList(cwd, options) {
|
|
14922
14791
|
const phasesDirPath = phasesPath(cwd);
|
|
14923
14792
|
const { type, phase, includeArchived, offset, limit } = options;
|
|
14924
|
-
if (!await
|
|
14793
|
+
if (!await pathExistsInternal(phasesDirPath)) if (type) return cmdOk({
|
|
14925
14794
|
files: [],
|
|
14926
14795
|
count: 0,
|
|
14927
14796
|
total: 0
|
|
@@ -14932,9 +14801,9 @@ async function cmdPhasesList(cwd, options) {
|
|
|
14932
14801
|
total: 0
|
|
14933
14802
|
}, "");
|
|
14934
14803
|
try {
|
|
14935
|
-
let dirs = await
|
|
14804
|
+
let dirs = await listSubDirs(phasesDirPath);
|
|
14936
14805
|
if (includeArchived) {
|
|
14937
|
-
const archived = await
|
|
14806
|
+
const archived = await getArchivedPhaseDirs(cwd);
|
|
14938
14807
|
for (const a of archived) dirs.push(`${a.name} [${a.milestone}]`);
|
|
14939
14808
|
}
|
|
14940
14809
|
dirs.sort((a, b) => comparePhaseNum(a, b));
|
|
@@ -14982,14 +14851,14 @@ async function cmdPhasesList(cwd, options) {
|
|
|
14982
14851
|
async function cmdPhaseNextDecimal(cwd, basePhase) {
|
|
14983
14852
|
const phasesDirPath = phasesPath(cwd);
|
|
14984
14853
|
const normalized = normalizePhaseName(basePhase);
|
|
14985
|
-
if (!await
|
|
14854
|
+
if (!await pathExistsInternal(phasesDirPath)) return cmdOk({
|
|
14986
14855
|
found: false,
|
|
14987
14856
|
base_phase: normalized,
|
|
14988
14857
|
next: `${normalized}.1`,
|
|
14989
14858
|
existing: []
|
|
14990
14859
|
}, `${normalized}.1`);
|
|
14991
14860
|
try {
|
|
14992
|
-
const dirs = await
|
|
14861
|
+
const dirs = await listSubDirs(phasesDirPath);
|
|
14993
14862
|
const baseExists = dirs.some((d) => d.startsWith(normalized + "-") || d === normalized);
|
|
14994
14863
|
const decimalPattern = new RegExp(`^${normalized}\\.(\\d+)`);
|
|
14995
14864
|
const existingDecimals = [];
|
|
@@ -15029,7 +14898,7 @@ async function cmdFindPhase(cwd, phase) {
|
|
|
15029
14898
|
summaries: []
|
|
15030
14899
|
};
|
|
15031
14900
|
try {
|
|
15032
|
-
const match = (await
|
|
14901
|
+
const match = (await listSubDirs(phasesDirPath, true)).find((d) => d.startsWith(normalized));
|
|
15033
14902
|
if (!match) return cmdOk(notFound, "");
|
|
15034
14903
|
const dirMatch = match.match(/^(\d+[A-Z]?(?:\.\d+)?)-?(.*)/i);
|
|
15035
14904
|
const phaseNumber = dirMatch ? dirMatch[1] : normalized;
|
|
@@ -15057,7 +14926,7 @@ async function cmdPhasePlanIndex(cwd, phase) {
|
|
|
15057
14926
|
const normalized = normalizePhaseName(phase);
|
|
15058
14927
|
let phaseDir = null;
|
|
15059
14928
|
try {
|
|
15060
|
-
const match = (await
|
|
14929
|
+
const match = (await listSubDirs(phasesDirPath, true)).find((d) => d.startsWith(normalized));
|
|
15061
14930
|
if (match) phaseDir = node_path.default.join(phasesDirPath, match);
|
|
15062
14931
|
} catch (e) {
|
|
15063
14932
|
debugLog("phase-plan-index-failed", e);
|
|
@@ -15150,12 +15019,12 @@ async function cmdPhaseRemove(cwd, targetPhase, options) {
|
|
|
15150
15019
|
const rmPath = roadmapPath(cwd);
|
|
15151
15020
|
const phasesDirPath = phasesPath(cwd);
|
|
15152
15021
|
const force = options.force || false;
|
|
15153
|
-
if (!await
|
|
15022
|
+
if (!await pathExistsInternal(rmPath)) return cmdErr("ROADMAP.md not found");
|
|
15154
15023
|
const normalized = normalizePhaseName(targetPhase);
|
|
15155
15024
|
const isDecimal = targetPhase.includes(".");
|
|
15156
15025
|
let targetDir = null;
|
|
15157
15026
|
try {
|
|
15158
|
-
targetDir = (await
|
|
15027
|
+
targetDir = (await listSubDirs(phasesDirPath, true)).find((d) => d.startsWith(normalized + "-") || d === normalized) || null;
|
|
15159
15028
|
} catch (e) {
|
|
15160
15029
|
debugLog("phase-remove-find-target-failed", e);
|
|
15161
15030
|
}
|
|
@@ -15175,7 +15044,7 @@ async function cmdPhaseRemove(cwd, targetPhase, options) {
|
|
|
15175
15044
|
const baseInt = baseParts[0];
|
|
15176
15045
|
const removedDecimal = parseInt(baseParts[1], 10);
|
|
15177
15046
|
try {
|
|
15178
|
-
const dirs = await
|
|
15047
|
+
const dirs = await listSubDirs(phasesDirPath, true);
|
|
15179
15048
|
const decPattern = new RegExp(`^${baseInt}\\.(\\d+)-(.+)$`);
|
|
15180
15049
|
const toRename = [];
|
|
15181
15050
|
for (const dir of dirs) {
|
|
@@ -15216,7 +15085,7 @@ async function cmdPhaseRemove(cwd, targetPhase, options) {
|
|
|
15216
15085
|
} else {
|
|
15217
15086
|
const removedInt = parseInt(normalized, 10);
|
|
15218
15087
|
try {
|
|
15219
|
-
const dirs = await
|
|
15088
|
+
const dirs = await listSubDirs(phasesDirPath, true);
|
|
15220
15089
|
const toRename = [];
|
|
15221
15090
|
for (const dir of dirs) {
|
|
15222
15091
|
const dm = dir.match(/^(\d+)([A-Z])?(?:\.(\d+))?-(.+)$/i);
|
|
@@ -15290,7 +15159,7 @@ async function cmdPhaseRemove(cwd, targetPhase, options) {
|
|
|
15290
15159
|
}
|
|
15291
15160
|
await node_fs.promises.writeFile(rmPath, roadmapContent, "utf-8");
|
|
15292
15161
|
const stPath = statePath(cwd);
|
|
15293
|
-
const stExists = await
|
|
15162
|
+
const stExists = await pathExistsInternal(stPath);
|
|
15294
15163
|
if (stExists) {
|
|
15295
15164
|
let stateContent = await node_fs.promises.readFile(stPath, "utf-8");
|
|
15296
15165
|
const totalPattern = /(\*\*Total Phases:\*\*\s*)(\d+)/;
|
|
@@ -15348,15 +15217,15 @@ function findPhaseTaggedLines(content, sectionPattern, phaseNum) {
|
|
|
15348
15217
|
const DECISIONS_SECTION_PATTERN = /(#{2,3}\s*(?:Decisions|Decisions Made|Accumulated.*Decisions)\s*\n)([\s\S]*?)(?=\n#{2,3}\s|\n##[^#]|$)/i;
|
|
15349
15218
|
const BLOCKERS_SECTION_PATTERN = /(#{2,3}\s*(?:Blockers|Blockers\/Concerns|Concerns)\s*\n\s*\n?)([\s\S]*?)(?=\n#{2,3}\s|$)/i;
|
|
15350
15219
|
async function archivePhasePreview(cwd, phaseNum, outcomeSummary) {
|
|
15351
|
-
const phaseInfo = await
|
|
15220
|
+
const phaseInfo = await findPhaseInternal(cwd, phaseNum);
|
|
15352
15221
|
if (!phaseInfo) return cmdErr(`Phase ${phaseNum} not found`);
|
|
15353
|
-
const archiveDir = await
|
|
15222
|
+
const archiveDir = await archivePath(cwd);
|
|
15354
15223
|
const phaseDirName = node_path.default.basename(phaseInfo.directory);
|
|
15355
15224
|
const archiveDest = node_path.default.join(archiveDir, phaseDirName);
|
|
15356
|
-
const stContent = await
|
|
15225
|
+
const stContent = await safeReadFile(statePath(cwd)) ?? "";
|
|
15357
15226
|
const decisionsToRemove = findPhaseTaggedLines(stContent, DECISIONS_SECTION_PATTERN, phaseNum);
|
|
15358
15227
|
const blockersToRemove = findPhaseTaggedLines(stContent, BLOCKERS_SECTION_PATTERN, phaseNum);
|
|
15359
|
-
const rmContent = await
|
|
15228
|
+
const rmContent = await safeReadFile(roadmapPath(cwd)) ?? "";
|
|
15360
15229
|
const escaped = escapePhaseNum(phaseNum);
|
|
15361
15230
|
const sectionPattern = new RegExp(`#{2,4}\\s*Phase\\s+${escaped}\\s*:[\\s\\S]*?(?=\\n#{2,4}\\s+Phase\\s+\\d|\\n## |$)`, "i");
|
|
15362
15231
|
const sectionMatch = rmContent.match(sectionPattern);
|
|
@@ -15384,9 +15253,9 @@ function pruneSection(content, sectionPattern, phaseNum) {
|
|
|
15384
15253
|
return content.replace(sectionPattern, (_m, header) => `${header}${newBody}`);
|
|
15385
15254
|
}
|
|
15386
15255
|
async function archivePhaseExecute(cwd, phaseNum, outcomeSummary) {
|
|
15387
|
-
const phaseInfo = await
|
|
15256
|
+
const phaseInfo = await findPhaseInternal(cwd, phaseNum);
|
|
15388
15257
|
if (!phaseInfo) return cmdErr(`Phase ${phaseNum} not found`);
|
|
15389
|
-
const archiveDir = await
|
|
15258
|
+
const archiveDir = await archivePath(cwd);
|
|
15390
15259
|
const phaseDirName = node_path.default.basename(phaseInfo.directory);
|
|
15391
15260
|
const archiveDest = node_path.default.join(archiveDir, phaseDirName);
|
|
15392
15261
|
const phaseDirFull = node_path.default.join(cwd, phaseInfo.directory);
|
|
@@ -15404,14 +15273,14 @@ async function archivePhaseExecute(cwd, phaseNum, outcomeSummary) {
|
|
|
15404
15273
|
} else throw e;
|
|
15405
15274
|
}
|
|
15406
15275
|
const stPath = statePath(cwd);
|
|
15407
|
-
let stContent = await
|
|
15276
|
+
let stContent = await safeReadFile(stPath);
|
|
15408
15277
|
if (stContent) {
|
|
15409
15278
|
stContent = pruneSection(stContent, DECISIONS_SECTION_PATTERN, phaseNum);
|
|
15410
15279
|
stContent = pruneSection(stContent, BLOCKERS_SECTION_PATTERN, phaseNum);
|
|
15411
15280
|
await node_fs.promises.writeFile(stPath, stContent, "utf-8");
|
|
15412
15281
|
}
|
|
15413
15282
|
const rmPath = roadmapPath(cwd);
|
|
15414
|
-
let rmContent = await
|
|
15283
|
+
let rmContent = await safeReadFile(rmPath);
|
|
15415
15284
|
if (rmContent) {
|
|
15416
15285
|
const escaped = escapePhaseNum(phaseNum);
|
|
15417
15286
|
const sectionPattern = new RegExp(`\\n?#{2,4}\\s*Phase\\s+${escaped}\\s*:[\\s\\S]*?(?=\\n#{2,4}\\s+Phase\\s+\\d|\\n## |$)`, "i");
|
|
@@ -15436,7 +15305,7 @@ async function archivePhaseExecute(cwd, phaseNum, outcomeSummary) {
|
|
|
15436
15305
|
archived: true,
|
|
15437
15306
|
phase: phaseNum,
|
|
15438
15307
|
archive_path: node_path.default.relative(cwd, archiveDest).replace(/\\/g, "/"),
|
|
15439
|
-
decisions_pruned: findPhaseTaggedLines(await
|
|
15308
|
+
decisions_pruned: findPhaseTaggedLines(await safeReadFile(statePath(cwd)) ?? "", DECISIONS_SECTION_PATTERN, phaseNum).length === 0,
|
|
15440
15309
|
blockers_pruned: true,
|
|
15441
15310
|
roadmap_collapsed: true
|
|
15442
15311
|
});
|
|
@@ -15447,7 +15316,7 @@ async function cmdGetArchivedPhase(cwd, phaseNum) {
|
|
|
15447
15316
|
const found = await searchArchiveLocations(planningPath(cwd, "archive"), normalized);
|
|
15448
15317
|
if (found) return cmdOk(found);
|
|
15449
15318
|
const milestonesDir = planningPath(cwd, "milestones");
|
|
15450
|
-
if (await
|
|
15319
|
+
if (await pathExistsInternal(milestonesDir)) try {
|
|
15451
15320
|
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();
|
|
15452
15321
|
for (const archiveName of phaseDirs) {
|
|
15453
15322
|
const result = await searchForPhaseInDir(node_path.default.join(milestonesDir, archiveName), normalized, archiveName);
|
|
@@ -15459,7 +15328,7 @@ async function cmdGetArchivedPhase(cwd, phaseNum) {
|
|
|
15459
15328
|
return cmdErr(`Phase ${phaseNum} not found in archive`);
|
|
15460
15329
|
}
|
|
15461
15330
|
async function searchArchiveLocations(archiveDir, normalized) {
|
|
15462
|
-
if (!await
|
|
15331
|
+
if (!await pathExistsInternal(archiveDir)) return null;
|
|
15463
15332
|
try {
|
|
15464
15333
|
const versionDirs = (await node_fs.promises.readdir(archiveDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name).sort().reverse();
|
|
15465
15334
|
for (const versionName of versionDirs) {
|
|
@@ -15473,7 +15342,7 @@ async function searchArchiveLocations(archiveDir, normalized) {
|
|
|
15473
15342
|
}
|
|
15474
15343
|
async function searchForPhaseInDir(baseDir, normalized, milestone) {
|
|
15475
15344
|
try {
|
|
15476
|
-
const match = (await
|
|
15345
|
+
const match = (await listSubDirs(baseDir, true)).find((d) => d.startsWith(normalized));
|
|
15477
15346
|
if (!match) return null;
|
|
15478
15347
|
const phaseDir = node_path.default.join(baseDir, match);
|
|
15479
15348
|
const mdFiles = (await node_fs.promises.readdir(phaseDir)).filter((f) => f.endsWith(".md"));
|
|
@@ -15535,10 +15404,10 @@ function cmdTemplateSelect(cwd, planPath) {
|
|
|
15535
15404
|
}, "templates/summary-standard.md");
|
|
15536
15405
|
}
|
|
15537
15406
|
}
|
|
15538
|
-
function cmdTemplateFill(cwd, templateType, options) {
|
|
15407
|
+
async function cmdTemplateFill(cwd, templateType, options) {
|
|
15539
15408
|
if (!templateType) return cmdErr("template type required: summary, plan, or verification");
|
|
15540
15409
|
if (!options.phase) return cmdErr("--phase required");
|
|
15541
|
-
const phaseInfo = findPhaseInternal(cwd, options.phase);
|
|
15410
|
+
const phaseInfo = await findPhaseInternal(cwd, options.phase);
|
|
15542
15411
|
if (!phaseInfo) return cmdOk({
|
|
15543
15412
|
error: "Phase not found",
|
|
15544
15413
|
phase: options.phase
|
|
@@ -15721,10 +15590,10 @@ const ARTEFAKT_FILES = {
|
|
|
15721
15590
|
function isValidType(type) {
|
|
15722
15591
|
return !!type && type in ARTEFAKT_FILES;
|
|
15723
15592
|
}
|
|
15724
|
-
function resolveArtefaktPath(cwd, type, phase) {
|
|
15593
|
+
async function resolveArtefaktPath(cwd, type, phase) {
|
|
15725
15594
|
const filename = ARTEFAKT_FILES[type];
|
|
15726
15595
|
if (phase) {
|
|
15727
|
-
const phaseInfo = findPhaseInternal(cwd, phase);
|
|
15596
|
+
const phaseInfo = await findPhaseInternal(cwd, phase);
|
|
15728
15597
|
if (!phaseInfo?.directory) return null;
|
|
15729
15598
|
return node_path.default.join(cwd, phaseInfo.directory, filename);
|
|
15730
15599
|
}
|
|
@@ -15735,8 +15604,8 @@ const TEMPLATE_FILES = {
|
|
|
15735
15604
|
"acceptance-criteria": "acceptance-criteria.md",
|
|
15736
15605
|
"no-gos": "no-gos.md"
|
|
15737
15606
|
};
|
|
15738
|
-
function getTemplate(type) {
|
|
15739
|
-
const content = safeReadFile(node_path.default.join(node_os.default.homedir(), ".claude", "maxsim", "templates", TEMPLATE_FILES[type]));
|
|
15607
|
+
async function getTemplate(type) {
|
|
15608
|
+
const content = await safeReadFile(node_path.default.join(node_os.default.homedir(), ".claude", "maxsim", "templates", TEMPLATE_FILES[type]));
|
|
15740
15609
|
if (content) return content.replace(/\{\{date\}\}/g, todayISO());
|
|
15741
15610
|
return getHardcodedTemplate(type);
|
|
15742
15611
|
}
|
|
@@ -15748,11 +15617,11 @@ function getHardcodedTemplate(type) {
|
|
|
15748
15617
|
case "no-gos": return `# No-Gos\n\n> Things explicitly out of scope or forbidden.\n\n**Created:** ${today}\n\n## Boundaries\n\n- _No entries yet._\n`;
|
|
15749
15618
|
}
|
|
15750
15619
|
}
|
|
15751
|
-
function cmdArtefakteRead(cwd, type, phase, raw) {
|
|
15620
|
+
async function cmdArtefakteRead(cwd, type, phase, raw) {
|
|
15752
15621
|
if (!isValidType(type)) return cmdErr(`Invalid artefakt type: ${type}. Available: ${Object.keys(ARTEFAKT_FILES).join(", ")}`);
|
|
15753
|
-
const filePath = resolveArtefaktPath(cwd, type, phase);
|
|
15622
|
+
const filePath = await resolveArtefaktPath(cwd, type, phase);
|
|
15754
15623
|
if (!filePath) return cmdErr(`Phase ${phase} not found`);
|
|
15755
|
-
const content = safeReadFile(filePath);
|
|
15624
|
+
const content = await safeReadFile(filePath);
|
|
15756
15625
|
if (content === null) return cmdOk({
|
|
15757
15626
|
exists: false,
|
|
15758
15627
|
type,
|
|
@@ -15766,10 +15635,10 @@ function cmdArtefakteRead(cwd, type, phase, raw) {
|
|
|
15766
15635
|
content
|
|
15767
15636
|
}, raw ? content : void 0);
|
|
15768
15637
|
}
|
|
15769
|
-
function cmdArtefakteWrite(cwd, type, content, phase, raw) {
|
|
15638
|
+
async function cmdArtefakteWrite(cwd, type, content, phase, raw) {
|
|
15770
15639
|
if (!isValidType(type)) return cmdErr(`Invalid artefakt type: ${type}. Available: ${Object.keys(ARTEFAKT_FILES).join(", ")}`);
|
|
15771
|
-
const fileContent = content ?? getTemplate(type);
|
|
15772
|
-
const filePath = resolveArtefaktPath(cwd, type, phase);
|
|
15640
|
+
const fileContent = content ?? await getTemplate(type);
|
|
15641
|
+
const filePath = await resolveArtefaktPath(cwd, type, phase);
|
|
15773
15642
|
if (!filePath) return cmdErr(`Phase ${phase} not found`);
|
|
15774
15643
|
node_fs.default.mkdirSync(node_path.default.dirname(filePath), { recursive: true });
|
|
15775
15644
|
node_fs.default.writeFileSync(filePath, fileContent, "utf-8");
|
|
@@ -15781,13 +15650,13 @@ function cmdArtefakteWrite(cwd, type, content, phase, raw) {
|
|
|
15781
15650
|
path: relPath
|
|
15782
15651
|
}, raw ? relPath : void 0);
|
|
15783
15652
|
}
|
|
15784
|
-
function cmdArtefakteAppend(cwd, type, entry, phase, raw) {
|
|
15653
|
+
async function cmdArtefakteAppend(cwd, type, entry, phase, raw) {
|
|
15785
15654
|
if (!entry) return cmdErr("entry required for artefakte append");
|
|
15786
15655
|
if (!isValidType(type)) return cmdErr(`Invalid artefakt type: ${type}. Available: ${Object.keys(ARTEFAKT_FILES).join(", ")}`);
|
|
15787
|
-
const filePath = resolveArtefaktPath(cwd, type, phase);
|
|
15656
|
+
const filePath = await resolveArtefaktPath(cwd, type, phase);
|
|
15788
15657
|
if (!filePath) return cmdErr(`Phase ${phase} not found`);
|
|
15789
|
-
let fileContent = safeReadFile(filePath);
|
|
15790
|
-
if (fileContent === null) fileContent = getTemplate(type);
|
|
15658
|
+
let fileContent = await safeReadFile(filePath);
|
|
15659
|
+
if (fileContent === null) fileContent = await getTemplate(type);
|
|
15791
15660
|
fileContent = fileContent.replace(/^-\s*_No entries yet\._\s*$/m, "");
|
|
15792
15661
|
const today = todayISO();
|
|
15793
15662
|
let appendLine;
|
|
@@ -15805,12 +15674,12 @@ function cmdArtefakteAppend(cwd, type, entry, phase, raw) {
|
|
|
15805
15674
|
path: relPath
|
|
15806
15675
|
}, raw ? "true" : void 0);
|
|
15807
15676
|
}
|
|
15808
|
-
function cmdArtefakteList(cwd, phase, raw) {
|
|
15677
|
+
async function cmdArtefakteList(cwd, phase, raw) {
|
|
15809
15678
|
const results = [];
|
|
15810
15679
|
for (const [type, filename] of Object.entries(ARTEFAKT_FILES)) {
|
|
15811
15680
|
let filePath;
|
|
15812
15681
|
if (phase) {
|
|
15813
|
-
const phaseInfo = findPhaseInternal(cwd, phase);
|
|
15682
|
+
const phaseInfo = await findPhaseInternal(cwd, phase);
|
|
15814
15683
|
if (!phaseInfo?.directory) return cmdOk({ error: `Phase ${phase} not found` });
|
|
15815
15684
|
filePath = node_path.default.join(cwd, phaseInfo.directory, filename);
|
|
15816
15685
|
} else filePath = planningPath(cwd, filename);
|
|
@@ -15893,9 +15762,9 @@ function loadRoadmapContext(cwd) {
|
|
|
15893
15762
|
addIfExists(files, cwd, ".planning/ROADMAP.md", "roadmap");
|
|
15894
15763
|
return files;
|
|
15895
15764
|
}
|
|
15896
|
-
function loadPhaseContext(cwd, phase) {
|
|
15765
|
+
async function loadPhaseContext(cwd, phase) {
|
|
15897
15766
|
const files = [];
|
|
15898
|
-
const phaseInfo = findPhaseInternal(cwd, phase);
|
|
15767
|
+
const phaseInfo = await findPhaseInternal(cwd, phase);
|
|
15899
15768
|
if (!phaseInfo?.directory) return files;
|
|
15900
15769
|
const phaseDir = phaseInfo.directory;
|
|
15901
15770
|
try {
|
|
@@ -15913,7 +15782,7 @@ function loadPhaseContext(cwd, phase) {
|
|
|
15913
15782
|
}
|
|
15914
15783
|
return files;
|
|
15915
15784
|
}
|
|
15916
|
-
function loadArtefakteContext(cwd, phase) {
|
|
15785
|
+
async function loadArtefakteContext(cwd, phase) {
|
|
15917
15786
|
const files = [];
|
|
15918
15787
|
for (const filename of [
|
|
15919
15788
|
"DECISIONS.md",
|
|
@@ -15921,7 +15790,7 @@ function loadArtefakteContext(cwd, phase) {
|
|
|
15921
15790
|
"NO-GOS.md"
|
|
15922
15791
|
]) {
|
|
15923
15792
|
if (phase) {
|
|
15924
|
-
const phaseInfo = findPhaseInternal(cwd, phase);
|
|
15793
|
+
const phaseInfo = await findPhaseInternal(cwd, phase);
|
|
15925
15794
|
if (phaseInfo?.directory) addIfExists(files, cwd, node_path.default.join(phaseInfo.directory, filename), `artefakt-${filename.toLowerCase()}`);
|
|
15926
15795
|
}
|
|
15927
15796
|
addIfExists(files, cwd, `.planning/${filename}`, `artefakt-${filename.toLowerCase()}`);
|
|
@@ -15938,11 +15807,11 @@ function loadCodebaseContext(cwd, topic) {
|
|
|
15938
15807
|
} catch {}
|
|
15939
15808
|
return files;
|
|
15940
15809
|
}
|
|
15941
|
-
function loadHistoryContext(cwd, currentPhase) {
|
|
15810
|
+
async function loadHistoryContext(cwd, currentPhase) {
|
|
15942
15811
|
const files = [];
|
|
15943
15812
|
const pd = phasesPath(cwd);
|
|
15944
15813
|
try {
|
|
15945
|
-
const dirs = listSubDirs(pd, true);
|
|
15814
|
+
const dirs = await listSubDirs(pd, true);
|
|
15946
15815
|
for (const dir of dirs) {
|
|
15947
15816
|
if (currentPhase) {
|
|
15948
15817
|
if (dir.match(/^(\d+[A-Z]?(?:\.\d+)?)/i)?.[1] === currentPhase) continue;
|
|
@@ -15956,15 +15825,15 @@ function loadHistoryContext(cwd, currentPhase) {
|
|
|
15956
15825
|
}
|
|
15957
15826
|
return files;
|
|
15958
15827
|
}
|
|
15959
|
-
function cmdContextLoad(cwd, phase, topic, includeHistory) {
|
|
15828
|
+
async function cmdContextLoad(cwd, phase, topic, includeHistory) {
|
|
15960
15829
|
const allFiles = [];
|
|
15961
15830
|
allFiles.push(...loadProjectContext(cwd));
|
|
15962
15831
|
allFiles.push(...loadRoadmapContext(cwd));
|
|
15963
|
-
allFiles.push(...loadArtefakteContext(cwd, phase));
|
|
15832
|
+
allFiles.push(...await loadArtefakteContext(cwd, phase));
|
|
15964
15833
|
const selectedDocs = selectCodebaseDocs(topic);
|
|
15965
15834
|
allFiles.push(...loadCodebaseContext(cwd, topic));
|
|
15966
|
-
if (phase) allFiles.push(...loadPhaseContext(cwd, phase));
|
|
15967
|
-
if (includeHistory) allFiles.push(...loadHistoryContext(cwd, phase));
|
|
15835
|
+
if (phase) allFiles.push(...await loadPhaseContext(cwd, phase));
|
|
15836
|
+
if (includeHistory) allFiles.push(...await loadHistoryContext(cwd, phase));
|
|
15968
15837
|
const seen = /* @__PURE__ */ new Set();
|
|
15969
15838
|
const deduped = allFiles.filter((f) => {
|
|
15970
15839
|
if (seen.has(f.path)) return false;
|
|
@@ -16005,8 +15874,8 @@ function skillsTemplateDir() {
|
|
|
16005
15874
|
/**
|
|
16006
15875
|
* Read a single skill's metadata from its SKILL.md frontmatter.
|
|
16007
15876
|
*/
|
|
16008
|
-
function readSkillInfo(skillDir, dirName) {
|
|
16009
|
-
const content = safeReadFile(node_path.default.join(skillDir, "SKILL.md"));
|
|
15877
|
+
async function readSkillInfo(skillDir, dirName) {
|
|
15878
|
+
const content = await safeReadFile(node_path.default.join(skillDir, "SKILL.md"));
|
|
16010
15879
|
if (!content) return null;
|
|
16011
15880
|
const fm = extractFrontmatter(content);
|
|
16012
15881
|
return {
|
|
@@ -16018,7 +15887,7 @@ function readSkillInfo(skillDir, dirName) {
|
|
|
16018
15887
|
/**
|
|
16019
15888
|
* List all installed skills from `.claude/skills/`.
|
|
16020
15889
|
*/
|
|
16021
|
-
function cmdSkillList(cwd) {
|
|
15890
|
+
async function cmdSkillList(cwd) {
|
|
16022
15891
|
const dir = skillsDir(cwd);
|
|
16023
15892
|
if (!node_fs.default.existsSync(dir)) return cmdOk({
|
|
16024
15893
|
skills: [],
|
|
@@ -16028,7 +15897,7 @@ function cmdSkillList(cwd) {
|
|
|
16028
15897
|
const skills = [];
|
|
16029
15898
|
for (const entry of entries) {
|
|
16030
15899
|
if (!entry.isDirectory()) continue;
|
|
16031
|
-
const info = readSkillInfo(node_path.default.join(dir, entry.name), entry.name);
|
|
15900
|
+
const info = await readSkillInfo(node_path.default.join(dir, entry.name), entry.name);
|
|
16032
15901
|
if (info) skills.push(info);
|
|
16033
15902
|
}
|
|
16034
15903
|
return cmdOk({
|
|
@@ -16104,268 +15973,6 @@ function listAvailableTemplates() {
|
|
|
16104
15973
|
return node_fs.default.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
16105
15974
|
}
|
|
16106
15975
|
|
|
16107
|
-
//#endregion
|
|
16108
|
-
//#region src/core/dashboard-launcher.ts
|
|
16109
|
-
/**
|
|
16110
|
-
* Dashboard Launcher — Shared dashboard lifecycle utilities
|
|
16111
|
-
*
|
|
16112
|
-
* Used by both cli.ts (tool-router) and install.ts (npx entry point).
|
|
16113
|
-
*/
|
|
16114
|
-
const DEFAULT_PORT = 3333;
|
|
16115
|
-
const PORT_RANGE_END = 3343;
|
|
16116
|
-
const HEALTH_TIMEOUT_MS = 1e4;
|
|
16117
|
-
/**
|
|
16118
|
-
* Check if a dashboard health endpoint is responding on the given port.
|
|
16119
|
-
*/
|
|
16120
|
-
async function checkHealth(port, timeoutMs = HEALTH_TIMEOUT_MS) {
|
|
16121
|
-
try {
|
|
16122
|
-
const controller = new AbortController();
|
|
16123
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
16124
|
-
const res = await fetch(`http://localhost:${port}/api/health`, { signal: controller.signal });
|
|
16125
|
-
clearTimeout(timer);
|
|
16126
|
-
if (res.ok) return (await res.json()).status === "ok";
|
|
16127
|
-
return false;
|
|
16128
|
-
} catch (e) {
|
|
16129
|
-
debugLog("health-check-failed", {
|
|
16130
|
-
port,
|
|
16131
|
-
error: errorMsg(e)
|
|
16132
|
-
});
|
|
16133
|
-
return false;
|
|
16134
|
-
}
|
|
16135
|
-
}
|
|
16136
|
-
/**
|
|
16137
|
-
* Scan the port range for a running dashboard instance.
|
|
16138
|
-
* Returns the port number if found, null otherwise.
|
|
16139
|
-
*/
|
|
16140
|
-
async function findRunningDashboard(timeoutMs = HEALTH_TIMEOUT_MS) {
|
|
16141
|
-
for (let port = DEFAULT_PORT; port <= PORT_RANGE_END; port++) if (await checkHealth(port, timeoutMs)) return port;
|
|
16142
|
-
return null;
|
|
16143
|
-
}
|
|
16144
|
-
/**
|
|
16145
|
-
* Kill processes listening on the given port. Cross-platform.
|
|
16146
|
-
*/
|
|
16147
|
-
function killProcessOnPort(port) {
|
|
16148
|
-
if (process.platform === "win32") try {
|
|
16149
|
-
const lines = (0, node_child_process.execSync)(`netstat -ano | findstr :${port} | findstr LISTENING`, { encoding: "utf-8" }).trim().split("\n");
|
|
16150
|
-
const pids = /* @__PURE__ */ new Set();
|
|
16151
|
-
for (const line of lines) {
|
|
16152
|
-
const parts = line.trim().split(/\s+/);
|
|
16153
|
-
const pid = parts[parts.length - 1];
|
|
16154
|
-
if (pid && pid !== "0") pids.add(pid);
|
|
16155
|
-
}
|
|
16156
|
-
for (const pid of pids) try {
|
|
16157
|
-
(0, node_child_process.execSync)(`taskkill /PID ${pid} /F`, { stdio: "ignore" });
|
|
16158
|
-
} catch (e) {
|
|
16159
|
-
debugLog("kill-process-on-port-taskkill-failed", {
|
|
16160
|
-
port,
|
|
16161
|
-
pid,
|
|
16162
|
-
error: errorMsg(e)
|
|
16163
|
-
});
|
|
16164
|
-
}
|
|
16165
|
-
} catch (e) {
|
|
16166
|
-
debugLog("kill-process-on-port-netstat-failed", {
|
|
16167
|
-
port,
|
|
16168
|
-
platform: "win32",
|
|
16169
|
-
error: errorMsg(e)
|
|
16170
|
-
});
|
|
16171
|
-
}
|
|
16172
|
-
else try {
|
|
16173
|
-
(0, node_child_process.execSync)(`lsof -i :${port} -t | xargs kill -SIGTERM 2>/dev/null`, { stdio: "ignore" });
|
|
16174
|
-
} catch (e) {
|
|
16175
|
-
debugLog("kill-process-on-port-lsof-failed", {
|
|
16176
|
-
port,
|
|
16177
|
-
platform: process.platform,
|
|
16178
|
-
error: errorMsg(e)
|
|
16179
|
-
});
|
|
16180
|
-
}
|
|
16181
|
-
}
|
|
16182
|
-
/**
|
|
16183
|
-
* Resolve the dashboard server entry point path.
|
|
16184
|
-
* Tries: local project install, global install, @maxsim/dashboard package, monorepo walk.
|
|
16185
|
-
*/
|
|
16186
|
-
function resolveDashboardServer() {
|
|
16187
|
-
const localDashboard = node_path.default.join(process.cwd(), ".claude", "dashboard", "server.js");
|
|
16188
|
-
if (node_fs.default.existsSync(localDashboard)) return localDashboard;
|
|
16189
|
-
const globalDashboard = node_path.default.join(node_os.default.homedir(), ".claude", "dashboard", "server.js");
|
|
16190
|
-
if (node_fs.default.existsSync(globalDashboard)) return globalDashboard;
|
|
16191
|
-
try {
|
|
16192
|
-
const pkgPath = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href).resolve("@maxsim/dashboard/package.json");
|
|
16193
|
-
const pkgDir = node_path.default.dirname(pkgPath);
|
|
16194
|
-
const serverJs = node_path.default.join(pkgDir, "server.js");
|
|
16195
|
-
if (node_fs.default.existsSync(serverJs)) return serverJs;
|
|
16196
|
-
const serverTs = node_path.default.join(pkgDir, "server.ts");
|
|
16197
|
-
if (node_fs.default.existsSync(serverTs)) return serverTs;
|
|
16198
|
-
} catch (e) {
|
|
16199
|
-
debugLog("resolve-dashboard-strategy1-failed", {
|
|
16200
|
-
strategy: "@maxsim/dashboard package",
|
|
16201
|
-
error: errorMsg(e)
|
|
16202
|
-
});
|
|
16203
|
-
}
|
|
16204
|
-
try {
|
|
16205
|
-
let dir = node_path.default.dirname(new URL(require("url").pathToFileURL(__filename).href).pathname);
|
|
16206
|
-
if (process.platform === "win32" && dir.startsWith("/")) dir = dir.slice(1);
|
|
16207
|
-
for (let i = 0; i < 5; i++) {
|
|
16208
|
-
const candidate = node_path.default.join(dir, "packages", "dashboard", "server.ts");
|
|
16209
|
-
if (node_fs.default.existsSync(candidate)) return candidate;
|
|
16210
|
-
const candidateJs = node_path.default.join(dir, "packages", "dashboard", "server.js");
|
|
16211
|
-
if (node_fs.default.existsSync(candidateJs)) return candidateJs;
|
|
16212
|
-
dir = node_path.default.dirname(dir);
|
|
16213
|
-
}
|
|
16214
|
-
} catch (e) {
|
|
16215
|
-
debugLog("resolve-dashboard-strategy2-failed", {
|
|
16216
|
-
strategy: "monorepo walk",
|
|
16217
|
-
error: errorMsg(e)
|
|
16218
|
-
});
|
|
16219
|
-
}
|
|
16220
|
-
return null;
|
|
16221
|
-
}
|
|
16222
|
-
/**
|
|
16223
|
-
* Ensure node-pty is installed in the dashboard directory.
|
|
16224
|
-
* Returns true if node-pty is available after this call.
|
|
16225
|
-
*/
|
|
16226
|
-
function ensureNodePty(serverDir) {
|
|
16227
|
-
const ptyModulePath = node_path.default.join(serverDir, "node_modules", "node-pty");
|
|
16228
|
-
if (node_fs.default.existsSync(ptyModulePath)) return true;
|
|
16229
|
-
const dashPkgPath = node_path.default.join(serverDir, "package.json");
|
|
16230
|
-
if (!node_fs.default.existsSync(dashPkgPath)) node_fs.default.writeFileSync(dashPkgPath, "{\"private\":true}\n");
|
|
16231
|
-
try {
|
|
16232
|
-
(0, node_child_process.execSync)("npm install node-pty --save-optional --no-audit --no-fund --loglevel=error", {
|
|
16233
|
-
cwd: serverDir,
|
|
16234
|
-
stdio: "inherit",
|
|
16235
|
-
timeout: 12e4
|
|
16236
|
-
});
|
|
16237
|
-
return true;
|
|
16238
|
-
} catch (e) {
|
|
16239
|
-
debugLog("ensure-node-pty-install-failed", {
|
|
16240
|
-
serverDir,
|
|
16241
|
-
error: errorMsg(e)
|
|
16242
|
-
});
|
|
16243
|
-
return false;
|
|
16244
|
-
}
|
|
16245
|
-
}
|
|
16246
|
-
/**
|
|
16247
|
-
* Read dashboard.json config from the parent directory of the dashboard dir.
|
|
16248
|
-
*/
|
|
16249
|
-
function readDashboardConfig(serverPath) {
|
|
16250
|
-
const dashboardDir = node_path.default.dirname(serverPath);
|
|
16251
|
-
const dashboardConfigPath = node_path.default.join(node_path.default.dirname(dashboardDir), "dashboard.json");
|
|
16252
|
-
let projectCwd = process.cwd();
|
|
16253
|
-
let networkMode = false;
|
|
16254
|
-
if (node_fs.default.existsSync(dashboardConfigPath)) try {
|
|
16255
|
-
const config = JSON.parse(node_fs.default.readFileSync(dashboardConfigPath, "utf8"));
|
|
16256
|
-
if (config.projectCwd) projectCwd = config.projectCwd;
|
|
16257
|
-
networkMode = config.networkMode ?? false;
|
|
16258
|
-
} catch (e) {
|
|
16259
|
-
debugLog("read-dashboard-config-failed", {
|
|
16260
|
-
path: dashboardConfigPath,
|
|
16261
|
-
error: errorMsg(e)
|
|
16262
|
-
});
|
|
16263
|
-
}
|
|
16264
|
-
return {
|
|
16265
|
-
projectCwd,
|
|
16266
|
-
networkMode
|
|
16267
|
-
};
|
|
16268
|
-
}
|
|
16269
|
-
/**
|
|
16270
|
-
* Spawn the dashboard server as a detached background process.
|
|
16271
|
-
* Returns the child process PID, or null if spawn failed.
|
|
16272
|
-
*/
|
|
16273
|
-
function spawnDashboard(options) {
|
|
16274
|
-
const { serverPath, projectCwd, networkMode = false, nodeEnv = "production" } = options;
|
|
16275
|
-
const serverDir = node_path.default.dirname(serverPath);
|
|
16276
|
-
const isTsFile = serverPath.endsWith(".ts");
|
|
16277
|
-
const child = (0, node_child_process.spawn)("node", isTsFile ? [
|
|
16278
|
-
"--import",
|
|
16279
|
-
"tsx",
|
|
16280
|
-
serverPath
|
|
16281
|
-
] : [serverPath], {
|
|
16282
|
-
cwd: serverDir,
|
|
16283
|
-
detached: true,
|
|
16284
|
-
stdio: "ignore",
|
|
16285
|
-
env: {
|
|
16286
|
-
...process.env,
|
|
16287
|
-
MAXSIM_PROJECT_CWD: projectCwd,
|
|
16288
|
-
MAXSIM_NETWORK_MODE: networkMode ? "1" : "0",
|
|
16289
|
-
NODE_ENV: isTsFile ? "development" : nodeEnv
|
|
16290
|
-
},
|
|
16291
|
-
...process.platform === "win32" ? { shell: true } : {}
|
|
16292
|
-
});
|
|
16293
|
-
child.unref();
|
|
16294
|
-
return child.pid ?? null;
|
|
16295
|
-
}
|
|
16296
|
-
/**
|
|
16297
|
-
* Poll the port range until a dashboard health endpoint responds.
|
|
16298
|
-
* Returns the URL if found within the timeout, null otherwise.
|
|
16299
|
-
*/
|
|
16300
|
-
async function waitForDashboard(pollIntervalMs = 500, pollTimeoutMs = 2e4, healthTimeoutMs = 1e3) {
|
|
16301
|
-
const deadline = Date.now() + pollTimeoutMs;
|
|
16302
|
-
while (Date.now() < deadline) {
|
|
16303
|
-
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
16304
|
-
for (let p = DEFAULT_PORT; p <= PORT_RANGE_END; p++) if (await checkHealth(p, healthTimeoutMs)) return `http://localhost:${p}`;
|
|
16305
|
-
}
|
|
16306
|
-
return null;
|
|
16307
|
-
}
|
|
16308
|
-
|
|
16309
|
-
//#endregion
|
|
16310
|
-
//#region src/core/start.ts
|
|
16311
|
-
/**
|
|
16312
|
-
* Start — Orchestrates Dashboard launch + browser open
|
|
16313
|
-
*
|
|
16314
|
-
* Provides a unified `maxsimcli start` entry point that:
|
|
16315
|
-
* 1. Checks for a running dashboard
|
|
16316
|
-
* 2. Starts the dashboard if needed
|
|
16317
|
-
* 3. Opens the browser
|
|
16318
|
-
* 4. Reports status
|
|
16319
|
-
*/
|
|
16320
|
-
function openBrowser(url) {
|
|
16321
|
-
(0, node_child_process.exec)(process.platform === "win32" ? `start "" "${url}"` : process.platform === "darwin" ? `open "${url}"` : `xdg-open "${url}"`, (err) => {
|
|
16322
|
-
if (err) debugLog("open-browser-failed", err);
|
|
16323
|
-
});
|
|
16324
|
-
}
|
|
16325
|
-
async function cmdStart(cwd, options) {
|
|
16326
|
-
const existingPort = await findRunningDashboard();
|
|
16327
|
-
if (existingPort) {
|
|
16328
|
-
const url = `http://localhost:${existingPort}`;
|
|
16329
|
-
if (!options.noBrowser) openBrowser(url);
|
|
16330
|
-
return cmdOk({
|
|
16331
|
-
started: true,
|
|
16332
|
-
url,
|
|
16333
|
-
already_running: true,
|
|
16334
|
-
port: existingPort
|
|
16335
|
-
}, url);
|
|
16336
|
-
}
|
|
16337
|
-
const serverPath = resolveDashboardServer();
|
|
16338
|
-
if (!serverPath) return cmdErr("Dashboard server not found. Run `npx maxsimcli` to install first.");
|
|
16339
|
-
const serverDir = node_path.default.dirname(serverPath);
|
|
16340
|
-
const dashConfig = readDashboardConfig(serverPath);
|
|
16341
|
-
ensureNodePty(serverDir);
|
|
16342
|
-
const pid = spawnDashboard({
|
|
16343
|
-
serverPath,
|
|
16344
|
-
projectCwd: dashConfig.projectCwd,
|
|
16345
|
-
networkMode: options.networkMode
|
|
16346
|
-
});
|
|
16347
|
-
if (!pid) return cmdErr("Failed to spawn dashboard process.");
|
|
16348
|
-
const url = await waitForDashboard();
|
|
16349
|
-
if (url) {
|
|
16350
|
-
if (!options.noBrowser) openBrowser(url);
|
|
16351
|
-
return cmdOk({
|
|
16352
|
-
started: true,
|
|
16353
|
-
url,
|
|
16354
|
-
already_running: false,
|
|
16355
|
-
pid
|
|
16356
|
-
}, url);
|
|
16357
|
-
} else {
|
|
16358
|
-
const fallbackUrl = `http://localhost:${DEFAULT_PORT}`;
|
|
16359
|
-
return cmdOk({
|
|
16360
|
-
started: true,
|
|
16361
|
-
url: fallbackUrl,
|
|
16362
|
-
already_running: false,
|
|
16363
|
-
pid,
|
|
16364
|
-
warning: "Dashboard spawned but health check timed out. It may still be starting."
|
|
16365
|
-
}, fallbackUrl);
|
|
16366
|
-
}
|
|
16367
|
-
}
|
|
16368
|
-
|
|
16369
15976
|
//#endregion
|
|
16370
15977
|
//#region src/core/init.ts
|
|
16371
15978
|
/**
|
|
@@ -16373,8 +15980,8 @@ async function cmdStart(cwd, options) {
|
|
|
16373
15980
|
*
|
|
16374
15981
|
* Ported from maxsim/bin/lib/init.cjs
|
|
16375
15982
|
*/
|
|
16376
|
-
function extractReqIds(cwd, phase) {
|
|
16377
|
-
const reqMatch = getRoadmapPhaseInternal(cwd, phase)?.section?.match(/^\*\*Requirements\*\*:[^\S\n]*([^\n]*)$/m);
|
|
15983
|
+
async function extractReqIds(cwd, phase) {
|
|
15984
|
+
const reqMatch = (await getRoadmapPhaseInternal(cwd, phase))?.section?.match(/^\*\*Requirements\*\*:[^\S\n]*([^\n]*)$/m);
|
|
16378
15985
|
const reqExtracted = reqMatch ? reqMatch[1].replace(/[\[\]]/g, "").split(",").map((s) => s.trim()).filter(Boolean).join(", ") : null;
|
|
16379
15986
|
return reqExtracted && reqExtracted !== "TBD" ? reqExtracted : null;
|
|
16380
15987
|
}
|
|
@@ -16430,15 +16037,15 @@ function findCodeFiles(dir, maxDepth = 3, limit = 5) {
|
|
|
16430
16037
|
walk(dir, 1);
|
|
16431
16038
|
return results;
|
|
16432
16039
|
}
|
|
16433
|
-
function cmdInitExecutePhase(cwd, phase) {
|
|
16040
|
+
async function cmdInitExecutePhase(cwd, phase) {
|
|
16434
16041
|
if (!phase) return cmdErr("phase required for init execute-phase");
|
|
16435
|
-
const config = loadConfig(cwd);
|
|
16436
|
-
const phaseInfo = findPhaseInternal(cwd, phase);
|
|
16437
|
-
const milestone = getMilestoneInfo(cwd);
|
|
16438
|
-
const phase_req_ids = extractReqIds(cwd, phase);
|
|
16042
|
+
const config = await loadConfig(cwd);
|
|
16043
|
+
const phaseInfo = await findPhaseInternal(cwd, phase);
|
|
16044
|
+
const milestone = await getMilestoneInfo(cwd);
|
|
16045
|
+
const phase_req_ids = await extractReqIds(cwd, phase);
|
|
16439
16046
|
return cmdOk({
|
|
16440
|
-
executor_model: resolveModelInternal(cwd, "maxsim-executor"),
|
|
16441
|
-
verifier_model: resolveModelInternal(cwd, "maxsim-verifier"),
|
|
16047
|
+
executor_model: await resolveModelInternal(cwd, "maxsim-executor"),
|
|
16048
|
+
verifier_model: await resolveModelInternal(cwd, "maxsim-verifier"),
|
|
16442
16049
|
commit_docs: config.commit_docs,
|
|
16443
16050
|
parallelization: config.parallelization,
|
|
16444
16051
|
branching_strategy: config.branching_strategy,
|
|
@@ -16460,23 +16067,23 @@ function cmdInitExecutePhase(cwd, phase) {
|
|
|
16460
16067
|
milestone_version: milestone.version,
|
|
16461
16068
|
milestone_name: milestone.name,
|
|
16462
16069
|
milestone_slug: generateSlugInternal(milestone.name),
|
|
16463
|
-
state_exists: pathExistsInternal(cwd, "
|
|
16464
|
-
roadmap_exists: pathExistsInternal(cwd, "
|
|
16465
|
-
config_exists: pathExistsInternal(cwd, "
|
|
16070
|
+
state_exists: await pathExistsInternal(planningPath(cwd, "STATE.md")),
|
|
16071
|
+
roadmap_exists: await pathExistsInternal(planningPath(cwd, "ROADMAP.md")),
|
|
16072
|
+
config_exists: await pathExistsInternal(planningPath(cwd, "config.json")),
|
|
16466
16073
|
state_path: ".planning/STATE.md",
|
|
16467
16074
|
roadmap_path: ".planning/ROADMAP.md",
|
|
16468
16075
|
config_path: ".planning/config.json"
|
|
16469
16076
|
});
|
|
16470
16077
|
}
|
|
16471
|
-
function cmdInitPlanPhase(cwd, phase) {
|
|
16078
|
+
async function cmdInitPlanPhase(cwd, phase) {
|
|
16472
16079
|
if (!phase) return cmdErr("phase required for init plan-phase");
|
|
16473
|
-
const config = loadConfig(cwd);
|
|
16474
|
-
const phaseInfo = findPhaseInternal(cwd, phase);
|
|
16475
|
-
const phase_req_ids = extractReqIds(cwd, phase);
|
|
16080
|
+
const config = await loadConfig(cwd);
|
|
16081
|
+
const phaseInfo = await findPhaseInternal(cwd, phase);
|
|
16082
|
+
const phase_req_ids = await extractReqIds(cwd, phase);
|
|
16476
16083
|
const result = {
|
|
16477
|
-
researcher_model: resolveModelInternal(cwd, "maxsim-phase-researcher"),
|
|
16478
|
-
planner_model: resolveModelInternal(cwd, "maxsim-planner"),
|
|
16479
|
-
checker_model: resolveModelInternal(cwd, "maxsim-plan-checker"),
|
|
16084
|
+
researcher_model: await resolveModelInternal(cwd, "maxsim-phase-researcher"),
|
|
16085
|
+
planner_model: await resolveModelInternal(cwd, "maxsim-planner"),
|
|
16086
|
+
checker_model: await resolveModelInternal(cwd, "maxsim-plan-checker"),
|
|
16480
16087
|
research_enabled: config.research,
|
|
16481
16088
|
plan_checker_enabled: config.plan_checker,
|
|
16482
16089
|
commit_docs: config.commit_docs,
|
|
@@ -16491,13 +16098,13 @@ function cmdInitPlanPhase(cwd, phase) {
|
|
|
16491
16098
|
has_context: phaseInfo?.has_context ?? false,
|
|
16492
16099
|
has_plans: (phaseInfo?.plans?.length ?? 0) > 0,
|
|
16493
16100
|
plan_count: phaseInfo?.plans?.length ?? 0,
|
|
16494
|
-
planning_exists: pathExistsInternal(cwd
|
|
16495
|
-
roadmap_exists: pathExistsInternal(cwd, "
|
|
16101
|
+
planning_exists: await pathExistsInternal(planningPath(cwd)),
|
|
16102
|
+
roadmap_exists: await pathExistsInternal(planningPath(cwd, "ROADMAP.md")),
|
|
16496
16103
|
state_path: ".planning/STATE.md",
|
|
16497
16104
|
roadmap_path: ".planning/ROADMAP.md",
|
|
16498
16105
|
requirements_path: ".planning/REQUIREMENTS.md"
|
|
16499
16106
|
};
|
|
16500
|
-
if (pathExistsInternal(cwd, "
|
|
16107
|
+
if (await pathExistsInternal(planningPath(cwd, "CONVENTIONS.md"))) result.conventions_path = ".planning/CONVENTIONS.md";
|
|
16501
16108
|
if (phaseInfo?.directory) {
|
|
16502
16109
|
const artifacts = scanPhaseArtifacts(cwd, phaseInfo.directory);
|
|
16503
16110
|
if (artifacts.context_path) result.context_path = artifacts.context_path;
|
|
@@ -16507,51 +16114,52 @@ function cmdInitPlanPhase(cwd, phase) {
|
|
|
16507
16114
|
}
|
|
16508
16115
|
return cmdOk(result);
|
|
16509
16116
|
}
|
|
16510
|
-
function cmdInitNewProject(cwd) {
|
|
16511
|
-
const config = loadConfig(cwd);
|
|
16117
|
+
async function cmdInitNewProject(cwd) {
|
|
16118
|
+
const config = await loadConfig(cwd);
|
|
16512
16119
|
const homedir = node_os.default.homedir();
|
|
16513
16120
|
const braveKeyFile = node_path.default.join(homedir, ".maxsim", "brave_api_key");
|
|
16514
16121
|
const hasBraveSearch = !!(process.env.BRAVE_API_KEY || node_fs.default.existsSync(braveKeyFile));
|
|
16515
16122
|
const hasCode = findCodeFiles(cwd).length > 0;
|
|
16516
|
-
const hasPackageFile = pathExistsInternal(cwd, "package.json") || pathExistsInternal(cwd, "requirements.txt") || pathExistsInternal(cwd, "Cargo.toml") || pathExistsInternal(cwd, "go.mod") || pathExistsInternal(cwd, "Package.swift");
|
|
16123
|
+
const hasPackageFile = await pathExistsInternal(node_path.default.join(cwd, "package.json")) || await pathExistsInternal(node_path.default.join(cwd, "requirements.txt")) || await pathExistsInternal(node_path.default.join(cwd, "Cargo.toml")) || await pathExistsInternal(node_path.default.join(cwd, "go.mod")) || await pathExistsInternal(node_path.default.join(cwd, "Package.swift"));
|
|
16124
|
+
const hasCodebaseMap = await pathExistsInternal(planningPath(cwd, "codebase"));
|
|
16517
16125
|
return cmdOk({
|
|
16518
|
-
researcher_model: resolveModelInternal(cwd, "maxsim-project-researcher"),
|
|
16519
|
-
synthesizer_model: resolveModelInternal(cwd, "maxsim-research-synthesizer"),
|
|
16520
|
-
roadmapper_model: resolveModelInternal(cwd, "maxsim-roadmapper"),
|
|
16126
|
+
researcher_model: await resolveModelInternal(cwd, "maxsim-project-researcher"),
|
|
16127
|
+
synthesizer_model: await resolveModelInternal(cwd, "maxsim-research-synthesizer"),
|
|
16128
|
+
roadmapper_model: await resolveModelInternal(cwd, "maxsim-roadmapper"),
|
|
16521
16129
|
commit_docs: config.commit_docs,
|
|
16522
|
-
project_exists: pathExistsInternal(cwd, "
|
|
16523
|
-
has_codebase_map:
|
|
16524
|
-
planning_exists: pathExistsInternal(cwd
|
|
16130
|
+
project_exists: await pathExistsInternal(planningPath(cwd, "PROJECT.md")),
|
|
16131
|
+
has_codebase_map: hasCodebaseMap,
|
|
16132
|
+
planning_exists: await pathExistsInternal(planningPath(cwd)),
|
|
16525
16133
|
has_existing_code: hasCode,
|
|
16526
16134
|
has_package_file: hasPackageFile,
|
|
16527
16135
|
is_brownfield: hasCode || hasPackageFile,
|
|
16528
|
-
needs_codebase_map: (hasCode || hasPackageFile) && !
|
|
16529
|
-
has_git: pathExistsInternal(cwd, ".git"),
|
|
16136
|
+
needs_codebase_map: (hasCode || hasPackageFile) && !hasCodebaseMap,
|
|
16137
|
+
has_git: await pathExistsInternal(node_path.default.join(cwd, ".git")),
|
|
16530
16138
|
brave_search_available: hasBraveSearch,
|
|
16531
16139
|
project_path: ".planning/PROJECT.md"
|
|
16532
16140
|
});
|
|
16533
16141
|
}
|
|
16534
|
-
function cmdInitNewMilestone(cwd) {
|
|
16535
|
-
const config = loadConfig(cwd);
|
|
16536
|
-
const milestone = getMilestoneInfo(cwd);
|
|
16142
|
+
async function cmdInitNewMilestone(cwd) {
|
|
16143
|
+
const config = await loadConfig(cwd);
|
|
16144
|
+
const milestone = await getMilestoneInfo(cwd);
|
|
16537
16145
|
return cmdOk({
|
|
16538
|
-
researcher_model: resolveModelInternal(cwd, "maxsim-project-researcher"),
|
|
16539
|
-
synthesizer_model: resolveModelInternal(cwd, "maxsim-research-synthesizer"),
|
|
16540
|
-
roadmapper_model: resolveModelInternal(cwd, "maxsim-roadmapper"),
|
|
16146
|
+
researcher_model: await resolveModelInternal(cwd, "maxsim-project-researcher"),
|
|
16147
|
+
synthesizer_model: await resolveModelInternal(cwd, "maxsim-research-synthesizer"),
|
|
16148
|
+
roadmapper_model: await resolveModelInternal(cwd, "maxsim-roadmapper"),
|
|
16541
16149
|
commit_docs: config.commit_docs,
|
|
16542
16150
|
research_enabled: config.research,
|
|
16543
16151
|
current_milestone: milestone.version,
|
|
16544
16152
|
current_milestone_name: milestone.name,
|
|
16545
|
-
project_exists: pathExistsInternal(cwd, "
|
|
16546
|
-
roadmap_exists: pathExistsInternal(cwd, "
|
|
16547
|
-
state_exists: pathExistsInternal(cwd, "
|
|
16153
|
+
project_exists: await pathExistsInternal(planningPath(cwd, "PROJECT.md")),
|
|
16154
|
+
roadmap_exists: await pathExistsInternal(planningPath(cwd, "ROADMAP.md")),
|
|
16155
|
+
state_exists: await pathExistsInternal(planningPath(cwd, "STATE.md")),
|
|
16548
16156
|
project_path: ".planning/PROJECT.md",
|
|
16549
16157
|
roadmap_path: ".planning/ROADMAP.md",
|
|
16550
16158
|
state_path: ".planning/STATE.md"
|
|
16551
16159
|
});
|
|
16552
16160
|
}
|
|
16553
|
-
function cmdInitQuick(cwd, description) {
|
|
16554
|
-
const config = loadConfig(cwd);
|
|
16161
|
+
async function cmdInitQuick(cwd, description) {
|
|
16162
|
+
const config = await loadConfig(cwd);
|
|
16555
16163
|
const now = /* @__PURE__ */ new Date();
|
|
16556
16164
|
const slug = description ? generateSlugInternal(description)?.substring(0, 40) ?? null : null;
|
|
16557
16165
|
const quickDir = planningPath(cwd, "quick");
|
|
@@ -16563,10 +16171,10 @@ function cmdInitQuick(cwd, description) {
|
|
|
16563
16171
|
debugLog(e);
|
|
16564
16172
|
}
|
|
16565
16173
|
return cmdOk({
|
|
16566
|
-
planner_model: resolveModelInternal(cwd, "maxsim-planner"),
|
|
16567
|
-
executor_model: resolveModelInternal(cwd, "maxsim-executor"),
|
|
16568
|
-
checker_model: resolveModelInternal(cwd, "maxsim-plan-checker"),
|
|
16569
|
-
verifier_model: resolveModelInternal(cwd, "maxsim-verifier"),
|
|
16174
|
+
planner_model: await resolveModelInternal(cwd, "maxsim-planner"),
|
|
16175
|
+
executor_model: await resolveModelInternal(cwd, "maxsim-executor"),
|
|
16176
|
+
checker_model: await resolveModelInternal(cwd, "maxsim-plan-checker"),
|
|
16177
|
+
verifier_model: await resolveModelInternal(cwd, "maxsim-verifier"),
|
|
16570
16178
|
commit_docs: config.commit_docs,
|
|
16571
16179
|
next_num: nextNum,
|
|
16572
16180
|
slug,
|
|
@@ -16575,12 +16183,12 @@ function cmdInitQuick(cwd, description) {
|
|
|
16575
16183
|
timestamp: now.toISOString(),
|
|
16576
16184
|
quick_dir: ".planning/quick",
|
|
16577
16185
|
task_dir: slug ? `.planning/quick/${nextNum}-${slug}` : null,
|
|
16578
|
-
roadmap_exists: pathExistsInternal(cwd, "
|
|
16579
|
-
planning_exists: pathExistsInternal(cwd
|
|
16186
|
+
roadmap_exists: await pathExistsInternal(planningPath(cwd, "ROADMAP.md")),
|
|
16187
|
+
planning_exists: await pathExistsInternal(planningPath(cwd))
|
|
16580
16188
|
});
|
|
16581
16189
|
}
|
|
16582
|
-
function cmdInitResume(cwd) {
|
|
16583
|
-
const config = loadConfig(cwd);
|
|
16190
|
+
async function cmdInitResume(cwd) {
|
|
16191
|
+
const config = await loadConfig(cwd);
|
|
16584
16192
|
let interruptedAgentId = null;
|
|
16585
16193
|
try {
|
|
16586
16194
|
interruptedAgentId = node_fs.default.readFileSync(planningPath(cwd, "current-agent-id.txt"), "utf-8").trim();
|
|
@@ -16588,10 +16196,10 @@ function cmdInitResume(cwd) {
|
|
|
16588
16196
|
debugLog(e);
|
|
16589
16197
|
}
|
|
16590
16198
|
return cmdOk({
|
|
16591
|
-
state_exists: pathExistsInternal(cwd, "
|
|
16592
|
-
roadmap_exists: pathExistsInternal(cwd, "
|
|
16593
|
-
project_exists: pathExistsInternal(cwd, "
|
|
16594
|
-
planning_exists: pathExistsInternal(cwd
|
|
16199
|
+
state_exists: await pathExistsInternal(planningPath(cwd, "STATE.md")),
|
|
16200
|
+
roadmap_exists: await pathExistsInternal(planningPath(cwd, "ROADMAP.md")),
|
|
16201
|
+
project_exists: await pathExistsInternal(planningPath(cwd, "PROJECT.md")),
|
|
16202
|
+
planning_exists: await pathExistsInternal(planningPath(cwd)),
|
|
16595
16203
|
state_path: ".planning/STATE.md",
|
|
16596
16204
|
roadmap_path: ".planning/ROADMAP.md",
|
|
16597
16205
|
project_path: ".planning/PROJECT.md",
|
|
@@ -16600,13 +16208,13 @@ function cmdInitResume(cwd) {
|
|
|
16600
16208
|
commit_docs: config.commit_docs
|
|
16601
16209
|
});
|
|
16602
16210
|
}
|
|
16603
|
-
function cmdInitVerifyWork(cwd, phase) {
|
|
16211
|
+
async function cmdInitVerifyWork(cwd, phase) {
|
|
16604
16212
|
if (!phase) return cmdErr("phase required for init verify-work");
|
|
16605
|
-
const config = loadConfig(cwd);
|
|
16606
|
-
const phaseInfo = findPhaseInternal(cwd, phase);
|
|
16213
|
+
const config = await loadConfig(cwd);
|
|
16214
|
+
const phaseInfo = await findPhaseInternal(cwd, phase);
|
|
16607
16215
|
return cmdOk({
|
|
16608
|
-
planner_model: resolveModelInternal(cwd, "maxsim-planner"),
|
|
16609
|
-
checker_model: resolveModelInternal(cwd, "maxsim-plan-checker"),
|
|
16216
|
+
planner_model: await resolveModelInternal(cwd, "maxsim-planner"),
|
|
16217
|
+
checker_model: await resolveModelInternal(cwd, "maxsim-plan-checker"),
|
|
16610
16218
|
commit_docs: config.commit_docs,
|
|
16611
16219
|
phase_found: !!phaseInfo,
|
|
16612
16220
|
phase_dir: phaseInfo?.directory ?? null,
|
|
@@ -16615,11 +16223,11 @@ function cmdInitVerifyWork(cwd, phase) {
|
|
|
16615
16223
|
has_verification: phaseInfo?.has_verification ?? false
|
|
16616
16224
|
});
|
|
16617
16225
|
}
|
|
16618
|
-
function cmdInitPhaseOp(cwd, phase) {
|
|
16619
|
-
const config = loadConfig(cwd);
|
|
16620
|
-
let phaseInfo = findPhaseInternal(cwd, phase ?? "");
|
|
16226
|
+
async function cmdInitPhaseOp(cwd, phase) {
|
|
16227
|
+
const config = await loadConfig(cwd);
|
|
16228
|
+
let phaseInfo = await findPhaseInternal(cwd, phase ?? "");
|
|
16621
16229
|
if (!phaseInfo) {
|
|
16622
|
-
const roadmapPhase = getRoadmapPhaseInternal(cwd, phase ?? "");
|
|
16230
|
+
const roadmapPhase = await getRoadmapPhaseInternal(cwd, phase ?? "");
|
|
16623
16231
|
if (roadmapPhase?.found) {
|
|
16624
16232
|
const phaseName = roadmapPhase.phase_name;
|
|
16625
16233
|
phaseInfo = {
|
|
@@ -16651,13 +16259,13 @@ function cmdInitPhaseOp(cwd, phase) {
|
|
|
16651
16259
|
has_plans: (phaseInfo?.plans?.length ?? 0) > 0,
|
|
16652
16260
|
has_verification: phaseInfo?.has_verification ?? false,
|
|
16653
16261
|
plan_count: phaseInfo?.plans?.length ?? 0,
|
|
16654
|
-
roadmap_exists: pathExistsInternal(cwd, "
|
|
16655
|
-
planning_exists: pathExistsInternal(cwd
|
|
16262
|
+
roadmap_exists: await pathExistsInternal(planningPath(cwd, "ROADMAP.md")),
|
|
16263
|
+
planning_exists: await pathExistsInternal(planningPath(cwd)),
|
|
16656
16264
|
state_path: ".planning/STATE.md",
|
|
16657
16265
|
roadmap_path: ".planning/ROADMAP.md",
|
|
16658
16266
|
requirements_path: ".planning/REQUIREMENTS.md"
|
|
16659
16267
|
};
|
|
16660
|
-
if (pathExistsInternal(cwd, "
|
|
16268
|
+
if (await pathExistsInternal(planningPath(cwd, "CONVENTIONS.md"))) result.conventions_path = ".planning/CONVENTIONS.md";
|
|
16661
16269
|
if (phaseInfo?.directory) {
|
|
16662
16270
|
const artifacts = scanPhaseArtifacts(cwd, phaseInfo.directory);
|
|
16663
16271
|
if (artifacts.context_path) result.context_path = artifacts.context_path;
|
|
@@ -16667,8 +16275,8 @@ function cmdInitPhaseOp(cwd, phase) {
|
|
|
16667
16275
|
}
|
|
16668
16276
|
return cmdOk(result);
|
|
16669
16277
|
}
|
|
16670
|
-
function cmdInitTodos(cwd, area) {
|
|
16671
|
-
const config = loadConfig(cwd);
|
|
16278
|
+
async function cmdInitTodos(cwd, area) {
|
|
16279
|
+
const config = await loadConfig(cwd);
|
|
16672
16280
|
const now = /* @__PURE__ */ new Date();
|
|
16673
16281
|
const pendingDir = planningPath(cwd, "todos", "pending");
|
|
16674
16282
|
let count = 0;
|
|
@@ -16705,19 +16313,19 @@ function cmdInitTodos(cwd, area) {
|
|
|
16705
16313
|
area_filter: area ?? null,
|
|
16706
16314
|
pending_dir: ".planning/todos/pending",
|
|
16707
16315
|
completed_dir: ".planning/todos/completed",
|
|
16708
|
-
planning_exists: pathExistsInternal(cwd
|
|
16709
|
-
todos_dir_exists: pathExistsInternal(cwd, "
|
|
16710
|
-
pending_dir_exists: pathExistsInternal(cwd, "
|
|
16316
|
+
planning_exists: await pathExistsInternal(planningPath(cwd)),
|
|
16317
|
+
todos_dir_exists: await pathExistsInternal(planningPath(cwd, "todos")),
|
|
16318
|
+
pending_dir_exists: await pathExistsInternal(planningPath(cwd, "todos", "pending"))
|
|
16711
16319
|
});
|
|
16712
16320
|
}
|
|
16713
|
-
function cmdInitMilestoneOp(cwd) {
|
|
16714
|
-
const config = loadConfig(cwd);
|
|
16715
|
-
const milestone = getMilestoneInfo(cwd);
|
|
16321
|
+
async function cmdInitMilestoneOp(cwd) {
|
|
16322
|
+
const config = await loadConfig(cwd);
|
|
16323
|
+
const milestone = await getMilestoneInfo(cwd);
|
|
16716
16324
|
let phaseCount = 0;
|
|
16717
16325
|
let completedPhases = 0;
|
|
16718
16326
|
const phasesDir = phasesPath(cwd);
|
|
16719
16327
|
try {
|
|
16720
|
-
const dirs = listSubDirs(phasesDir);
|
|
16328
|
+
const dirs = await listSubDirs(phasesDir);
|
|
16721
16329
|
phaseCount = dirs.length;
|
|
16722
16330
|
for (const dir of dirs) try {
|
|
16723
16331
|
if (node_fs.default.readdirSync(node_path.default.join(phasesDir, dir)).some((f) => isSummaryFile(f))) completedPhases++;
|
|
@@ -16730,7 +16338,7 @@ function cmdInitMilestoneOp(cwd) {
|
|
|
16730
16338
|
const archiveDir = planningPath(cwd, "archive");
|
|
16731
16339
|
let archivedMilestones = [];
|
|
16732
16340
|
try {
|
|
16733
|
-
archivedMilestones = listSubDirs(archiveDir);
|
|
16341
|
+
archivedMilestones = await listSubDirs(archiveDir);
|
|
16734
16342
|
} catch (e) {
|
|
16735
16343
|
debugLog(e);
|
|
16736
16344
|
}
|
|
@@ -16744,15 +16352,15 @@ function cmdInitMilestoneOp(cwd) {
|
|
|
16744
16352
|
all_phases_complete: phaseCount > 0 && phaseCount === completedPhases,
|
|
16745
16353
|
archived_milestones: archivedMilestones,
|
|
16746
16354
|
archive_count: archivedMilestones.length,
|
|
16747
|
-
project_exists: pathExistsInternal(cwd, "
|
|
16748
|
-
roadmap_exists: pathExistsInternal(cwd, "
|
|
16749
|
-
state_exists: pathExistsInternal(cwd, "
|
|
16750
|
-
archive_exists: pathExistsInternal(cwd, "
|
|
16751
|
-
phases_dir_exists: pathExistsInternal(cwd, "
|
|
16355
|
+
project_exists: await pathExistsInternal(planningPath(cwd, "PROJECT.md")),
|
|
16356
|
+
roadmap_exists: await pathExistsInternal(planningPath(cwd, "ROADMAP.md")),
|
|
16357
|
+
state_exists: await pathExistsInternal(planningPath(cwd, "STATE.md")),
|
|
16358
|
+
archive_exists: await pathExistsInternal(planningPath(cwd, "archive")),
|
|
16359
|
+
phases_dir_exists: await pathExistsInternal(planningPath(cwd, "phases"))
|
|
16752
16360
|
});
|
|
16753
16361
|
}
|
|
16754
|
-
function cmdInitMapCodebase(cwd) {
|
|
16755
|
-
const config = loadConfig(cwd);
|
|
16362
|
+
async function cmdInitMapCodebase(cwd) {
|
|
16363
|
+
const config = await loadConfig(cwd);
|
|
16756
16364
|
const codebaseDir = planningPath(cwd, "codebase");
|
|
16757
16365
|
let existingMaps = [];
|
|
16758
16366
|
try {
|
|
@@ -16761,24 +16369,24 @@ function cmdInitMapCodebase(cwd) {
|
|
|
16761
16369
|
debugLog(e);
|
|
16762
16370
|
}
|
|
16763
16371
|
return cmdOk({
|
|
16764
|
-
mapper_model: resolveModelInternal(cwd, "maxsim-codebase-mapper"),
|
|
16372
|
+
mapper_model: await resolveModelInternal(cwd, "maxsim-codebase-mapper"),
|
|
16765
16373
|
commit_docs: config.commit_docs,
|
|
16766
16374
|
search_gitignored: config.search_gitignored,
|
|
16767
16375
|
parallelization: config.parallelization,
|
|
16768
16376
|
codebase_dir: ".planning/codebase",
|
|
16769
16377
|
existing_maps: existingMaps,
|
|
16770
16378
|
has_maps: existingMaps.length > 0,
|
|
16771
|
-
planning_exists: pathExistsInternal(cwd
|
|
16772
|
-
codebase_dir_exists: pathExistsInternal(cwd, "
|
|
16379
|
+
planning_exists: await pathExistsInternal(planningPath(cwd)),
|
|
16380
|
+
codebase_dir_exists: await pathExistsInternal(planningPath(cwd, "codebase"))
|
|
16773
16381
|
});
|
|
16774
16382
|
}
|
|
16775
|
-
function cmdInitExisting(cwd) {
|
|
16776
|
-
const config = loadConfig(cwd);
|
|
16383
|
+
async function cmdInitExisting(cwd) {
|
|
16384
|
+
const config = await loadConfig(cwd);
|
|
16777
16385
|
const homedir = node_os.default.homedir();
|
|
16778
16386
|
const braveKeyFile = node_path.default.join(homedir, ".maxsim", "brave_api_key");
|
|
16779
16387
|
const hasBraveSearch = !!(process.env.BRAVE_API_KEY || node_fs.default.existsSync(braveKeyFile));
|
|
16780
16388
|
const hasCode = findCodeFiles(cwd).length > 0;
|
|
16781
|
-
const hasPackageFile = pathExistsInternal(cwd, "package.json") || pathExistsInternal(cwd, "requirements.txt") || pathExistsInternal(cwd, "Cargo.toml") || pathExistsInternal(cwd, "go.mod") || pathExistsInternal(cwd, "Package.swift");
|
|
16389
|
+
const hasPackageFile = await pathExistsInternal(node_path.default.join(cwd, "package.json")) || await pathExistsInternal(node_path.default.join(cwd, "requirements.txt")) || await pathExistsInternal(node_path.default.join(cwd, "Cargo.toml")) || await pathExistsInternal(node_path.default.join(cwd, "go.mod")) || await pathExistsInternal(node_path.default.join(cwd, "Package.swift"));
|
|
16782
16390
|
let planningFiles = [];
|
|
16783
16391
|
try {
|
|
16784
16392
|
const planDir = planningPath(cwd);
|
|
@@ -16787,19 +16395,19 @@ function cmdInitExisting(cwd) {
|
|
|
16787
16395
|
debugLog(e);
|
|
16788
16396
|
}
|
|
16789
16397
|
return cmdOk({
|
|
16790
|
-
researcher_model: resolveModelInternal(cwd, "maxsim-project-researcher"),
|
|
16791
|
-
synthesizer_model: resolveModelInternal(cwd, "maxsim-research-synthesizer"),
|
|
16792
|
-
roadmapper_model: resolveModelInternal(cwd, "maxsim-roadmapper"),
|
|
16793
|
-
mapper_model: resolveModelInternal(cwd, "maxsim-codebase-mapper"),
|
|
16398
|
+
researcher_model: await resolveModelInternal(cwd, "maxsim-project-researcher"),
|
|
16399
|
+
synthesizer_model: await resolveModelInternal(cwd, "maxsim-research-synthesizer"),
|
|
16400
|
+
roadmapper_model: await resolveModelInternal(cwd, "maxsim-roadmapper"),
|
|
16401
|
+
mapper_model: await resolveModelInternal(cwd, "maxsim-codebase-mapper"),
|
|
16794
16402
|
commit_docs: config.commit_docs,
|
|
16795
|
-
project_exists: pathExistsInternal(cwd, "
|
|
16796
|
-
planning_exists: pathExistsInternal(cwd
|
|
16403
|
+
project_exists: await pathExistsInternal(planningPath(cwd, "PROJECT.md")),
|
|
16404
|
+
planning_exists: await pathExistsInternal(planningPath(cwd)),
|
|
16797
16405
|
planning_files: planningFiles,
|
|
16798
|
-
has_codebase_map: pathExistsInternal(cwd, "
|
|
16406
|
+
has_codebase_map: await pathExistsInternal(planningPath(cwd, "codebase")),
|
|
16799
16407
|
has_existing_code: hasCode,
|
|
16800
16408
|
has_package_file: hasPackageFile,
|
|
16801
|
-
has_git: pathExistsInternal(cwd, ".git"),
|
|
16802
|
-
has_readme: pathExistsInternal(cwd, "README.md"),
|
|
16409
|
+
has_git: await pathExistsInternal(node_path.default.join(cwd, ".git")),
|
|
16410
|
+
has_readme: await pathExistsInternal(node_path.default.join(cwd, "README.md")),
|
|
16803
16411
|
conflict_detected: planningFiles.length > 0,
|
|
16804
16412
|
existing_file_count: planningFiles.length,
|
|
16805
16413
|
brave_search_available: hasBraveSearch,
|
|
@@ -16808,15 +16416,15 @@ function cmdInitExisting(cwd) {
|
|
|
16808
16416
|
codebase_dir: ".planning/codebase"
|
|
16809
16417
|
});
|
|
16810
16418
|
}
|
|
16811
|
-
function cmdInitProgress(cwd) {
|
|
16812
|
-
const config = loadConfig(cwd);
|
|
16813
|
-
const milestone = getMilestoneInfo(cwd);
|
|
16419
|
+
async function cmdInitProgress(cwd) {
|
|
16420
|
+
const config = await loadConfig(cwd);
|
|
16421
|
+
const milestone = await getMilestoneInfo(cwd);
|
|
16814
16422
|
const progressPhasesDir = phasesPath(cwd);
|
|
16815
16423
|
const phases = [];
|
|
16816
16424
|
let currentPhase = null;
|
|
16817
16425
|
let nextPhase = null;
|
|
16818
16426
|
try {
|
|
16819
|
-
const dirs = listSubDirs(progressPhasesDir, true);
|
|
16427
|
+
const dirs = await listSubDirs(progressPhasesDir, true);
|
|
16820
16428
|
for (const dir of dirs) {
|
|
16821
16429
|
const match = dir.match(/^(\d+(?:\.\d+)?)-?(.*)/);
|
|
16822
16430
|
const phaseNumber = match ? match[1] : dir;
|
|
@@ -16851,8 +16459,8 @@ function cmdInitProgress(cwd) {
|
|
|
16851
16459
|
debugLog(e);
|
|
16852
16460
|
}
|
|
16853
16461
|
return cmdOk({
|
|
16854
|
-
executor_model: resolveModelInternal(cwd, "maxsim-executor"),
|
|
16855
|
-
planner_model: resolveModelInternal(cwd, "maxsim-planner"),
|
|
16462
|
+
executor_model: await resolveModelInternal(cwd, "maxsim-executor"),
|
|
16463
|
+
planner_model: await resolveModelInternal(cwd, "maxsim-planner"),
|
|
16856
16464
|
commit_docs: config.commit_docs,
|
|
16857
16465
|
milestone_version: milestone.version,
|
|
16858
16466
|
milestone_name: milestone.name,
|
|
@@ -16864,9 +16472,9 @@ function cmdInitProgress(cwd) {
|
|
|
16864
16472
|
next_phase: nextPhase,
|
|
16865
16473
|
paused_at: pausedAt,
|
|
16866
16474
|
has_work_in_progress: !!currentPhase,
|
|
16867
|
-
project_exists: pathExistsInternal(cwd, "
|
|
16868
|
-
roadmap_exists: pathExistsInternal(cwd, "
|
|
16869
|
-
state_exists: pathExistsInternal(cwd, "
|
|
16475
|
+
project_exists: await pathExistsInternal(planningPath(cwd, "PROJECT.md")),
|
|
16476
|
+
roadmap_exists: await pathExistsInternal(planningPath(cwd, "ROADMAP.md")),
|
|
16477
|
+
state_exists: await pathExistsInternal(planningPath(cwd, "STATE.md")),
|
|
16870
16478
|
state_path: ".planning/STATE.md",
|
|
16871
16479
|
roadmap_path: ".planning/ROADMAP.md",
|
|
16872
16480
|
project_path: ".planning/PROJECT.md",
|
|
@@ -16885,14 +16493,14 @@ function listCodebaseDocs(cwd) {
|
|
|
16885
16493
|
return [];
|
|
16886
16494
|
}
|
|
16887
16495
|
}
|
|
16888
|
-
function cmdInitExecutor(cwd, phase) {
|
|
16496
|
+
async function cmdInitExecutor(cwd, phase) {
|
|
16889
16497
|
if (!phase) return cmdErr("phase required for init executor");
|
|
16890
|
-
const config = loadConfig(cwd);
|
|
16891
|
-
const phaseInfo = findPhaseInternal(cwd, phase);
|
|
16498
|
+
const config = await loadConfig(cwd);
|
|
16499
|
+
const phaseInfo = await findPhaseInternal(cwd, phase);
|
|
16892
16500
|
const codebaseDocs = listCodebaseDocs(cwd);
|
|
16893
16501
|
const result = {
|
|
16894
|
-
executor_model: resolveModelInternal(cwd, "maxsim-executor"),
|
|
16895
|
-
verifier_model: resolveModelInternal(cwd, "maxsim-verifier"),
|
|
16502
|
+
executor_model: await resolveModelInternal(cwd, "maxsim-executor"),
|
|
16503
|
+
verifier_model: await resolveModelInternal(cwd, "maxsim-verifier"),
|
|
16896
16504
|
commit_docs: config.commit_docs,
|
|
16897
16505
|
parallelization: config.parallelization,
|
|
16898
16506
|
branching_strategy: config.branching_strategy,
|
|
@@ -16905,18 +16513,18 @@ function cmdInitExecutor(cwd, phase) {
|
|
|
16905
16513
|
state_path: ".planning/STATE.md",
|
|
16906
16514
|
codebase_docs: codebaseDocs
|
|
16907
16515
|
};
|
|
16908
|
-
if (pathExistsInternal(cwd, "
|
|
16516
|
+
if (await pathExistsInternal(planningPath(cwd, "CONVENTIONS.md"))) result.conventions_path = ".planning/CONVENTIONS.md";
|
|
16909
16517
|
return cmdOk(result);
|
|
16910
16518
|
}
|
|
16911
|
-
function cmdInitPlanner(cwd, phase) {
|
|
16519
|
+
async function cmdInitPlanner(cwd, phase) {
|
|
16912
16520
|
if (!phase) return cmdErr("phase required for init planner");
|
|
16913
|
-
const config = loadConfig(cwd);
|
|
16914
|
-
const phaseInfo = findPhaseInternal(cwd, phase);
|
|
16915
|
-
const phase_req_ids = extractReqIds(cwd, phase);
|
|
16521
|
+
const config = await loadConfig(cwd);
|
|
16522
|
+
const phaseInfo = await findPhaseInternal(cwd, phase);
|
|
16523
|
+
const phase_req_ids = await extractReqIds(cwd, phase);
|
|
16916
16524
|
const codebaseDocs = listCodebaseDocs(cwd);
|
|
16917
16525
|
const result = {
|
|
16918
|
-
planner_model: resolveModelInternal(cwd, "maxsim-planner"),
|
|
16919
|
-
checker_model: resolveModelInternal(cwd, "maxsim-plan-checker"),
|
|
16526
|
+
planner_model: await resolveModelInternal(cwd, "maxsim-planner"),
|
|
16527
|
+
checker_model: await resolveModelInternal(cwd, "maxsim-plan-checker"),
|
|
16920
16528
|
commit_docs: config.commit_docs,
|
|
16921
16529
|
research_enabled: config.research,
|
|
16922
16530
|
plan_checker_enabled: config.plan_checker,
|
|
@@ -16934,7 +16542,7 @@ function cmdInitPlanner(cwd, phase) {
|
|
|
16934
16542
|
requirements_path: ".planning/REQUIREMENTS.md",
|
|
16935
16543
|
codebase_docs: codebaseDocs
|
|
16936
16544
|
};
|
|
16937
|
-
if (pathExistsInternal(cwd, "
|
|
16545
|
+
if (await pathExistsInternal(planningPath(cwd, "CONVENTIONS.md"))) result.conventions_path = ".planning/CONVENTIONS.md";
|
|
16938
16546
|
if (phaseInfo?.directory) {
|
|
16939
16547
|
const artifacts = scanPhaseArtifacts(cwd, phaseInfo.directory);
|
|
16940
16548
|
if (artifacts.context_path) result.context_path = artifacts.context_path;
|
|
@@ -16942,14 +16550,14 @@ function cmdInitPlanner(cwd, phase) {
|
|
|
16942
16550
|
}
|
|
16943
16551
|
return cmdOk(result);
|
|
16944
16552
|
}
|
|
16945
|
-
function cmdInitResearcher(cwd, phase) {
|
|
16553
|
+
async function cmdInitResearcher(cwd, phase) {
|
|
16946
16554
|
if (!phase) return cmdErr("phase required for init researcher");
|
|
16947
|
-
const config = loadConfig(cwd);
|
|
16948
|
-
const phaseInfo = findPhaseInternal(cwd, phase);
|
|
16949
|
-
const phase_req_ids = extractReqIds(cwd, phase);
|
|
16555
|
+
const config = await loadConfig(cwd);
|
|
16556
|
+
const phaseInfo = await findPhaseInternal(cwd, phase);
|
|
16557
|
+
const phase_req_ids = await extractReqIds(cwd, phase);
|
|
16950
16558
|
const codebaseDocs = listCodebaseDocs(cwd);
|
|
16951
16559
|
const result = {
|
|
16952
|
-
researcher_model: resolveModelInternal(cwd, "maxsim-phase-researcher"),
|
|
16560
|
+
researcher_model: await resolveModelInternal(cwd, "maxsim-phase-researcher"),
|
|
16953
16561
|
commit_docs: config.commit_docs,
|
|
16954
16562
|
brave_search: config.brave_search,
|
|
16955
16563
|
phase_found: !!phaseInfo,
|
|
@@ -16965,21 +16573,21 @@ function cmdInitResearcher(cwd, phase) {
|
|
|
16965
16573
|
requirements_path: ".planning/REQUIREMENTS.md",
|
|
16966
16574
|
codebase_docs: codebaseDocs
|
|
16967
16575
|
};
|
|
16968
|
-
if (pathExistsInternal(cwd, "
|
|
16576
|
+
if (await pathExistsInternal(planningPath(cwd, "CONVENTIONS.md"))) result.conventions_path = ".planning/CONVENTIONS.md";
|
|
16969
16577
|
if (phaseInfo?.directory) {
|
|
16970
16578
|
const artifacts = scanPhaseArtifacts(cwd, phaseInfo.directory);
|
|
16971
16579
|
if (artifacts.context_path) result.context_path = artifacts.context_path;
|
|
16972
16580
|
}
|
|
16973
16581
|
return cmdOk(result);
|
|
16974
16582
|
}
|
|
16975
|
-
function cmdInitVerifier(cwd, phase) {
|
|
16583
|
+
async function cmdInitVerifier(cwd, phase) {
|
|
16976
16584
|
if (!phase) return cmdErr("phase required for init verifier");
|
|
16977
|
-
const config = loadConfig(cwd);
|
|
16978
|
-
const phaseInfo = findPhaseInternal(cwd, phase);
|
|
16979
|
-
const phase_req_ids = extractReqIds(cwd, phase);
|
|
16585
|
+
const config = await loadConfig(cwd);
|
|
16586
|
+
const phaseInfo = await findPhaseInternal(cwd, phase);
|
|
16587
|
+
const phase_req_ids = await extractReqIds(cwd, phase);
|
|
16980
16588
|
const codebaseDocs = listCodebaseDocs(cwd);
|
|
16981
16589
|
return cmdOk({
|
|
16982
|
-
verifier_model: resolveModelInternal(cwd, "maxsim-verifier"),
|
|
16590
|
+
verifier_model: await resolveModelInternal(cwd, "maxsim-verifier"),
|
|
16983
16591
|
commit_docs: config.commit_docs,
|
|
16984
16592
|
phase_found: !!phaseInfo,
|
|
16985
16593
|
phase_dir: phaseInfo?.directory ?? null,
|
|
@@ -16992,12 +16600,12 @@ function cmdInitVerifier(cwd, phase) {
|
|
|
16992
16600
|
codebase_docs: codebaseDocs
|
|
16993
16601
|
});
|
|
16994
16602
|
}
|
|
16995
|
-
function cmdInitDebugger(cwd, phase) {
|
|
16996
|
-
const config = loadConfig(cwd);
|
|
16997
|
-
const phaseInfo = phase ? findPhaseInternal(cwd, phase) : null;
|
|
16603
|
+
async function cmdInitDebugger(cwd, phase) {
|
|
16604
|
+
const config = await loadConfig(cwd);
|
|
16605
|
+
const phaseInfo = phase ? await findPhaseInternal(cwd, phase) : null;
|
|
16998
16606
|
const codebaseDocs = listCodebaseDocs(cwd);
|
|
16999
16607
|
const result = {
|
|
17000
|
-
debugger_model: resolveModelInternal(cwd, "maxsim-debugger"),
|
|
16608
|
+
debugger_model: await resolveModelInternal(cwd, "maxsim-debugger"),
|
|
17001
16609
|
commit_docs: config.commit_docs,
|
|
17002
16610
|
phase_found: !!phaseInfo,
|
|
17003
16611
|
phase_dir: phaseInfo?.directory ?? null,
|
|
@@ -17006,31 +16614,31 @@ function cmdInitDebugger(cwd, phase) {
|
|
|
17006
16614
|
state_path: ".planning/STATE.md",
|
|
17007
16615
|
codebase_docs: codebaseDocs
|
|
17008
16616
|
};
|
|
17009
|
-
if (pathExistsInternal(cwd, "
|
|
16617
|
+
if (await pathExistsInternal(planningPath(cwd, "CONVENTIONS.md"))) result.conventions_path = ".planning/CONVENTIONS.md";
|
|
17010
16618
|
return cmdOk(result);
|
|
17011
16619
|
}
|
|
17012
|
-
function cmdInitCheckDrift(cwd) {
|
|
17013
|
-
const config = loadConfig(cwd);
|
|
17014
|
-
const driftModel = resolveModelInternal(cwd, "maxsim-drift-checker");
|
|
17015
|
-
const hasPlanning = pathExistsInternal(cwd
|
|
17016
|
-
const hasRequirements = pathExistsInternal(cwd, "
|
|
17017
|
-
const hasRoadmap = pathExistsInternal(cwd, "
|
|
17018
|
-
const hasNogos = pathExistsInternal(cwd, "
|
|
17019
|
-
const hasConventions = pathExistsInternal(cwd, "
|
|
17020
|
-
const hasPreviousReport = pathExistsInternal(cwd, "
|
|
16620
|
+
async function cmdInitCheckDrift(cwd) {
|
|
16621
|
+
const config = await loadConfig(cwd);
|
|
16622
|
+
const driftModel = await resolveModelInternal(cwd, "maxsim-drift-checker");
|
|
16623
|
+
const hasPlanning = await pathExistsInternal(planningPath(cwd));
|
|
16624
|
+
const hasRequirements = await pathExistsInternal(planningPath(cwd, "REQUIREMENTS.md"));
|
|
16625
|
+
const hasRoadmap = await pathExistsInternal(planningPath(cwd, "ROADMAP.md"));
|
|
16626
|
+
const hasNogos = await pathExistsInternal(planningPath(cwd, "NO-GOS.md"));
|
|
16627
|
+
const hasConventions = await pathExistsInternal(planningPath(cwd, "CONVENTIONS.md"));
|
|
16628
|
+
const hasPreviousReport = await pathExistsInternal(planningPath(cwd, "DRIFT-REPORT.md"));
|
|
17021
16629
|
const specFiles = [];
|
|
17022
16630
|
if (hasRequirements) specFiles.push(".planning/REQUIREMENTS.md");
|
|
17023
16631
|
if (hasRoadmap) specFiles.push(".planning/ROADMAP.md");
|
|
17024
|
-
if (pathExistsInternal(cwd, "
|
|
16632
|
+
if (await pathExistsInternal(planningPath(cwd, "STATE.md"))) specFiles.push(".planning/STATE.md");
|
|
17025
16633
|
if (hasNogos) specFiles.push(".planning/NO-GOS.md");
|
|
17026
16634
|
if (hasConventions) specFiles.push(".planning/CONVENTIONS.md");
|
|
17027
16635
|
let phaseDirs = [];
|
|
17028
16636
|
try {
|
|
17029
|
-
phaseDirs = listSubDirs(phasesPath(cwd), true).map((d) => `.planning/phases/${d}`);
|
|
16637
|
+
phaseDirs = (await listSubDirs(phasesPath(cwd), true)).map((d) => `.planning/phases/${d}`);
|
|
17030
16638
|
} catch {}
|
|
17031
16639
|
let archivedMilestoneDirs = [];
|
|
17032
16640
|
try {
|
|
17033
|
-
archivedMilestoneDirs = getArchivedPhaseDirs(cwd).map((a) => a.basePath);
|
|
16641
|
+
archivedMilestoneDirs = (await getArchivedPhaseDirs(cwd)).map((a) => a.basePath);
|
|
17034
16642
|
archivedMilestoneDirs = [...new Set(archivedMilestoneDirs)];
|
|
17035
16643
|
} catch {}
|
|
17036
16644
|
const codebaseDocs = listCodebaseDocs(cwd);
|
|
@@ -17055,13 +16663,13 @@ function cmdInitCheckDrift(cwd) {
|
|
|
17055
16663
|
codebase_docs: codebaseDocs
|
|
17056
16664
|
});
|
|
17057
16665
|
}
|
|
17058
|
-
function cmdInitRealign(cwd, direction) {
|
|
17059
|
-
const config = loadConfig(cwd);
|
|
17060
|
-
const hasReport = pathExistsInternal(cwd, "
|
|
17061
|
-
const hasPlanning = pathExistsInternal(cwd
|
|
16666
|
+
async function cmdInitRealign(cwd, direction) {
|
|
16667
|
+
const config = await loadConfig(cwd);
|
|
16668
|
+
const hasReport = await pathExistsInternal(planningPath(cwd, "DRIFT-REPORT.md"));
|
|
16669
|
+
const hasPlanning = await pathExistsInternal(planningPath(cwd));
|
|
17062
16670
|
let phaseDirs = [];
|
|
17063
16671
|
try {
|
|
17064
|
-
phaseDirs = listSubDirs(phasesPath(cwd), true).map((d) => `.planning/phases/${d}`);
|
|
16672
|
+
phaseDirs = (await listSubDirs(phasesPath(cwd), true)).map((d) => `.planning/phases/${d}`);
|
|
17065
16673
|
} catch {}
|
|
17066
16674
|
const codebaseDocs = listCodebaseDocs(cwd);
|
|
17067
16675
|
return cmdOk({
|
|
@@ -17163,12 +16771,12 @@ const handleState = async (args, cwd, raw) => {
|
|
|
17163
16771
|
if (handler) return handleResult(await handler(), raw);
|
|
17164
16772
|
return handleResult(await cmdStateLoad(cwd, raw), raw);
|
|
17165
16773
|
};
|
|
17166
|
-
const handleTemplate = (args, cwd, raw) => {
|
|
16774
|
+
const handleTemplate = async (args, cwd, raw) => {
|
|
17167
16775
|
const sub = args[1];
|
|
17168
16776
|
if (sub === "select") handleResult(cmdTemplateSelect(cwd, args[2]), raw);
|
|
17169
16777
|
else if (sub === "fill") {
|
|
17170
16778
|
const f = getFlags(args, "phase", "plan", "name", "type", "wave", "fields");
|
|
17171
|
-
handleResult(cmdTemplateFill(cwd, args[2], {
|
|
16779
|
+
handleResult(await cmdTemplateFill(cwd, args[2], {
|
|
17172
16780
|
phase: f.phase ?? "",
|
|
17173
16781
|
plan: f.plan ?? void 0,
|
|
17174
16782
|
name: f.name ?? void 0,
|
|
@@ -17178,14 +16786,14 @@ const handleTemplate = (args, cwd, raw) => {
|
|
|
17178
16786
|
}), raw);
|
|
17179
16787
|
} else error("Unknown template subcommand. Available: select, fill");
|
|
17180
16788
|
};
|
|
17181
|
-
const handleFrontmatter = (args, cwd, raw) => {
|
|
16789
|
+
const handleFrontmatter = async (args, cwd, raw) => {
|
|
17182
16790
|
const sub = args[1];
|
|
17183
16791
|
const file = args[2];
|
|
17184
16792
|
const handler = sub ? {
|
|
17185
|
-
"get": () => handleResult(cmdFrontmatterGet(cwd, file, getFlag(args, "--field")), raw),
|
|
16793
|
+
"get": async () => handleResult(await cmdFrontmatterGet(cwd, file, getFlag(args, "--field")), raw),
|
|
17186
16794
|
"set": () => handleResult(cmdFrontmatterSet(cwd, file, getFlag(args, "--field"), getFlag(args, "--value") ?? void 0), raw),
|
|
17187
16795
|
"merge": () => handleResult(cmdFrontmatterMerge(cwd, file, getFlag(args, "--data")), raw),
|
|
17188
|
-
"validate": () => handleResult(cmdFrontmatterValidate(cwd, file, getFlag(args, "--schema")), raw)
|
|
16796
|
+
"validate": async () => handleResult(await cmdFrontmatterValidate(cwd, file, getFlag(args, "--schema")), raw)
|
|
17189
16797
|
}[sub] : void 0;
|
|
17190
16798
|
if (handler) return handler();
|
|
17191
16799
|
error("Unknown frontmatter subcommand. Available: get, set, merge, validate");
|
|
@@ -17193,12 +16801,12 @@ const handleFrontmatter = (args, cwd, raw) => {
|
|
|
17193
16801
|
const handleVerify = async (args, cwd, raw) => {
|
|
17194
16802
|
const sub = args[1];
|
|
17195
16803
|
const handler = sub ? {
|
|
17196
|
-
"plan-structure": () => handleResult(cmdVerifyPlanStructure(cwd, args[2]), raw),
|
|
17197
|
-
"phase-completeness": () => handleResult(cmdVerifyPhaseCompleteness(cwd, args[2]), raw),
|
|
17198
|
-
"references": () => handleResult(cmdVerifyReferences(cwd, args[2]), raw),
|
|
16804
|
+
"plan-structure": async () => handleResult(await cmdVerifyPlanStructure(cwd, args[2]), raw),
|
|
16805
|
+
"phase-completeness": async () => handleResult(await cmdVerifyPhaseCompleteness(cwd, args[2]), raw),
|
|
16806
|
+
"references": async () => handleResult(await cmdVerifyReferences(cwd, args[2]), raw),
|
|
17199
16807
|
"commits": async () => handleResult(await cmdVerifyCommits(cwd, args.slice(2)), raw),
|
|
17200
|
-
"artifacts": () => handleResult(cmdVerifyArtifacts(cwd, args[2]), raw),
|
|
17201
|
-
"key-links": () => handleResult(cmdVerifyKeyLinks(cwd, args[2]), raw)
|
|
16808
|
+
"artifacts": async () => handleResult(await cmdVerifyArtifacts(cwd, args[2]), raw),
|
|
16809
|
+
"key-links": async () => handleResult(await cmdVerifyKeyLinks(cwd, args[2]), raw)
|
|
17202
16810
|
}[sub] : void 0;
|
|
17203
16811
|
if (handler) return handler();
|
|
17204
16812
|
error("Unknown verify subcommand. Available: plan-structure, phase-completeness, references, commits, artifacts, key-links");
|
|
@@ -17257,16 +16865,16 @@ const handleMilestone = async (args, cwd, raw) => {
|
|
|
17257
16865
|
}), raw);
|
|
17258
16866
|
} else error("Unknown milestone subcommand. Available: complete");
|
|
17259
16867
|
};
|
|
17260
|
-
const handleValidate = (args, cwd, raw) => {
|
|
16868
|
+
const handleValidate = async (args, cwd, raw) => {
|
|
17261
16869
|
const sub = args[1];
|
|
17262
16870
|
const handler = sub ? {
|
|
17263
|
-
"consistency": () => handleResult(cmdValidateConsistency(cwd), raw),
|
|
17264
|
-
"health": () => handleResult(cmdValidateHealth(cwd, { repair: hasFlag(args, "repair") }), raw)
|
|
16871
|
+
"consistency": async () => handleResult(await cmdValidateConsistency(cwd), raw),
|
|
16872
|
+
"health": async () => handleResult(await cmdValidateHealth(cwd, { repair: hasFlag(args, "repair") }), raw)
|
|
17265
16873
|
}[sub] : void 0;
|
|
17266
16874
|
if (handler) return handler();
|
|
17267
16875
|
error("Unknown validate subcommand. Available: consistency, health");
|
|
17268
16876
|
};
|
|
17269
|
-
const handleDrift = (args, cwd, raw) => {
|
|
16877
|
+
const handleDrift = async (args, cwd, raw) => {
|
|
17270
16878
|
const sub = args[1];
|
|
17271
16879
|
const handler = sub ? {
|
|
17272
16880
|
"read-report": () => cmdDriftReadReport(cwd),
|
|
@@ -17276,10 +16884,10 @@ const handleDrift = (args, cwd, raw) => {
|
|
|
17276
16884
|
"write-report": () => cmdDriftWriteReport(cwd, getFlag(args, "--content"), getFlag(args, "--content-file")),
|
|
17277
16885
|
"previous-hash": () => cmdDriftPreviousHash(cwd)
|
|
17278
16886
|
}[sub] : void 0;
|
|
17279
|
-
if (handler) return handleResult(handler(), raw);
|
|
16887
|
+
if (handler) return handleResult(await handler(), raw);
|
|
17280
16888
|
error("Unknown drift subcommand. Available: read-report, extract-requirements, extract-nogos, extract-conventions, write-report, previous-hash");
|
|
17281
16889
|
};
|
|
17282
|
-
const handleInit = (args, cwd, raw) => {
|
|
16890
|
+
const handleInit = async (args, cwd, raw) => {
|
|
17283
16891
|
const workflow = args[1];
|
|
17284
16892
|
const handler = workflow ? {
|
|
17285
16893
|
"execute-phase": () => cmdInitExecutePhase(cwd, args[2]),
|
|
@@ -17303,12 +16911,12 @@ const handleInit = (args, cwd, raw) => {
|
|
|
17303
16911
|
"check-drift": () => cmdInitCheckDrift(cwd),
|
|
17304
16912
|
"realign": () => cmdInitRealign(cwd, args[2])
|
|
17305
16913
|
}[workflow] : void 0;
|
|
17306
|
-
if (handler) return handleResult(handler(), raw);
|
|
16914
|
+
if (handler) return handleResult(await handler(), raw);
|
|
17307
16915
|
error(`Unknown init workflow: ${workflow}\nAvailable: execute-phase, plan-phase, new-project, new-milestone, quick, resume, verify-work, phase-op, todos, milestone-op, map-codebase, init-existing, progress, executor, planner, researcher, verifier, debugger, check-drift, realign`);
|
|
17308
16916
|
};
|
|
17309
16917
|
const COMMANDS = {
|
|
17310
16918
|
"state": handleState,
|
|
17311
|
-
"resolve-model": (args, cwd, raw) => handleResult(cmdResolveModel(cwd, args[1], raw), raw),
|
|
16919
|
+
"resolve-model": async (args, cwd, raw) => handleResult(await cmdResolveModel(cwd, args[1], raw), raw),
|
|
17312
16920
|
"find-phase": async (args, cwd, raw) => handleResult(await cmdFindPhase(cwd, args[1]), raw),
|
|
17313
16921
|
"commit": async (args, cwd, raw) => {
|
|
17314
16922
|
const files = args.indexOf("--files") !== -1 ? args.slice(args.indexOf("--files") + 1).filter((a) => !a.startsWith("--")) : [];
|
|
@@ -17329,7 +16937,7 @@ const COMMANDS = {
|
|
|
17329
16937
|
"config-ensure-section": (_args, cwd, raw) => handleResult(cmdConfigEnsureSection(cwd, raw), raw),
|
|
17330
16938
|
"config-set": (args, cwd, raw) => handleResult(cmdConfigSet(cwd, args[1], args[2], raw), raw),
|
|
17331
16939
|
"config-get": (args, cwd, raw) => handleResult(cmdConfigGet(cwd, args[1], raw), raw),
|
|
17332
|
-
"history-digest": (_args, cwd, raw) => handleResult(cmdHistoryDigest(cwd, raw), raw),
|
|
16940
|
+
"history-digest": async (_args, cwd, raw) => handleResult(await cmdHistoryDigest(cwd, raw), raw),
|
|
17333
16941
|
"phases": handlePhases,
|
|
17334
16942
|
"roadmap": handleRoadmap,
|
|
17335
16943
|
"requirements": (args, cwd, raw) => {
|
|
@@ -17340,14 +16948,14 @@ const COMMANDS = {
|
|
|
17340
16948
|
"milestone": handleMilestone,
|
|
17341
16949
|
"validate": handleValidate,
|
|
17342
16950
|
"drift": handleDrift,
|
|
17343
|
-
"progress": (args, cwd, raw) => handleResult(cmdProgressRender(cwd, args[1] || "json", raw), raw),
|
|
16951
|
+
"progress": async (args, cwd, raw) => handleResult(await cmdProgressRender(cwd, args[1] || "json", raw), raw),
|
|
17344
16952
|
"todo": (args, cwd, raw) => {
|
|
17345
16953
|
if (args[1] === "complete") handleResult(cmdTodoComplete(cwd, args[2], raw), raw);
|
|
17346
16954
|
else error("Unknown todo subcommand. Available: complete");
|
|
17347
16955
|
},
|
|
17348
|
-
"scaffold": (args, cwd, raw) => {
|
|
16956
|
+
"scaffold": async (args, cwd, raw) => {
|
|
17349
16957
|
const f = getFlags(args, "phase", "name");
|
|
17350
|
-
handleResult(cmdScaffold(cwd, args[1], {
|
|
16958
|
+
handleResult(await cmdScaffold(cwd, args[1], {
|
|
17351
16959
|
phase: f.phase,
|
|
17352
16960
|
name: f.name ? args.slice(args.indexOf("--name") + 1).join(" ") : null
|
|
17353
16961
|
}, raw), raw);
|
|
@@ -17369,39 +16977,17 @@ const COMMANDS = {
|
|
|
17369
16977
|
freshness: f.freshness ?? void 0
|
|
17370
16978
|
}, raw), raw);
|
|
17371
16979
|
},
|
|
17372
|
-
"artefakte-read": (args, cwd, raw) => handleResult(cmdArtefakteRead(cwd, args[1], getFlag(args, "--phase") ?? void 0, raw), raw),
|
|
17373
|
-
"artefakte-write": (args, cwd, raw) => handleResult(cmdArtefakteWrite(cwd, args[1], getFlag(args, "--content") ?? void 0, getFlag(args, "--phase") ?? void 0, raw), raw),
|
|
17374
|
-
"artefakte-append": (args, cwd, raw) => handleResult(cmdArtefakteAppend(cwd, args[1], getFlag(args, "--entry") ?? void 0, getFlag(args, "--phase") ?? void 0, raw), raw),
|
|
17375
|
-
"artefakte-list": (args, cwd, raw) => handleResult(cmdArtefakteList(cwd, getFlag(args, "--phase") ?? void 0, raw), raw),
|
|
17376
|
-
"context-load": (args, cwd, raw) => handleResult(cmdContextLoad(cwd, getFlag(args, "--phase") ?? void 0, getFlag(args, "--topic") ?? void 0, hasFlag(args, "include-history")), raw),
|
|
17377
|
-
"skill-list": (_args, cwd, raw) => handleResult(cmdSkillList(cwd), raw),
|
|
16980
|
+
"artefakte-read": async (args, cwd, raw) => handleResult(await cmdArtefakteRead(cwd, args[1], getFlag(args, "--phase") ?? void 0, raw), raw),
|
|
16981
|
+
"artefakte-write": async (args, cwd, raw) => handleResult(await cmdArtefakteWrite(cwd, args[1], getFlag(args, "--content") ?? void 0, getFlag(args, "--phase") ?? void 0, raw), raw),
|
|
16982
|
+
"artefakte-append": async (args, cwd, raw) => handleResult(await cmdArtefakteAppend(cwd, args[1], getFlag(args, "--entry") ?? void 0, getFlag(args, "--phase") ?? void 0, raw), raw),
|
|
16983
|
+
"artefakte-list": async (args, cwd, raw) => handleResult(await cmdArtefakteList(cwd, getFlag(args, "--phase") ?? void 0, raw), raw),
|
|
16984
|
+
"context-load": async (args, cwd, raw) => handleResult(await cmdContextLoad(cwd, getFlag(args, "--phase") ?? void 0, getFlag(args, "--topic") ?? void 0, hasFlag(args, "include-history")), raw),
|
|
16985
|
+
"skill-list": async (_args, cwd, raw) => handleResult(await cmdSkillList(cwd), raw),
|
|
17378
16986
|
"skill-install": (args, cwd, raw) => handleResult(cmdSkillInstall(cwd, args[1]), raw),
|
|
17379
16987
|
"skill-update": (args, cwd, raw) => handleResult(cmdSkillUpdate(cwd, args[1]), raw),
|
|
17380
|
-
"start": async (args, cwd, raw) => handleResult(await cmdStart(cwd, {
|
|
17381
|
-
noBrowser: hasFlag(args, "no-browser"),
|
|
17382
|
-
networkMode: hasFlag(args, "network")
|
|
17383
|
-
}), raw),
|
|
17384
|
-
"dashboard": (args) => handleDashboard(args.slice(1)),
|
|
17385
16988
|
"start-server": async () => {
|
|
17386
16989
|
const serverPath = node_path.join(__dirname, "mcp-server.cjs");
|
|
17387
16990
|
(0, node_child_process.spawn)(process.execPath, [serverPath], { stdio: "inherit" }).on("exit", (code) => process.exit(code ?? 0));
|
|
17388
|
-
},
|
|
17389
|
-
"backend-start": async (args, cwd, raw) => {
|
|
17390
|
-
const { startBackend } = await Promise.resolve().then(() => require("./lifecycle-D8mcsEjy.cjs"));
|
|
17391
|
-
const portFlag = args.find((a) => a.startsWith("--port="))?.split("=")[1];
|
|
17392
|
-
const background = !args.includes("--foreground");
|
|
17393
|
-
output(await startBackend(cwd, {
|
|
17394
|
-
port: portFlag ? parseInt(portFlag, 10) : void 0,
|
|
17395
|
-
background
|
|
17396
|
-
}), raw);
|
|
17397
|
-
},
|
|
17398
|
-
"backend-stop": async (_args, cwd, raw) => {
|
|
17399
|
-
const { stopBackend } = await Promise.resolve().then(() => require("./lifecycle-D8mcsEjy.cjs"));
|
|
17400
|
-
output({ stopped: await stopBackend(cwd) }, raw);
|
|
17401
|
-
},
|
|
17402
|
-
"backend-status": async (_args, cwd, raw) => {
|
|
17403
|
-
const { getBackendStatus } = await Promise.resolve().then(() => require("./lifecycle-D8mcsEjy.cjs"));
|
|
17404
|
-
output(await getBackendStatus(cwd) || { running: false }, raw);
|
|
17405
16991
|
}
|
|
17406
16992
|
};
|
|
17407
16993
|
async function main() {
|
|
@@ -17442,84 +17028,7 @@ async function main() {
|
|
|
17442
17028
|
throw thrown;
|
|
17443
17029
|
}
|
|
17444
17030
|
}
|
|
17445
|
-
/**
|
|
17446
|
-
* Dashboard launch command.
|
|
17447
|
-
*
|
|
17448
|
-
* Spawns the dashboard as a detached subprocess with MAXSIM_PROJECT_CWD set.
|
|
17449
|
-
* If the dashboard is already running (detected via /api/health), prints the URL.
|
|
17450
|
-
* Supports --stop to kill a running instance.
|
|
17451
|
-
*/
|
|
17452
|
-
async function handleDashboard(args) {
|
|
17453
|
-
const networkMode = args.includes("--network");
|
|
17454
|
-
if (args.includes("--stop")) {
|
|
17455
|
-
for (let port = DEFAULT_PORT; port <= PORT_RANGE_END; port++) if (await checkHealth(port)) {
|
|
17456
|
-
console.log(`Dashboard found on port ${port} — stopping...`);
|
|
17457
|
-
killProcessOnPort(port);
|
|
17458
|
-
console.log("Dashboard stopped.");
|
|
17459
|
-
return;
|
|
17460
|
-
}
|
|
17461
|
-
console.log("No running dashboard found.");
|
|
17462
|
-
return;
|
|
17463
|
-
}
|
|
17464
|
-
const runningPort = await findRunningDashboard();
|
|
17465
|
-
if (runningPort) {
|
|
17466
|
-
console.log(`Dashboard already running at http://localhost:${runningPort}`);
|
|
17467
|
-
return;
|
|
17468
|
-
}
|
|
17469
|
-
const serverPath = resolveDashboardServer();
|
|
17470
|
-
if (!serverPath) {
|
|
17471
|
-
console.error("Could not find @maxsim/dashboard server entry point.");
|
|
17472
|
-
console.error("Ensure @maxsim/dashboard is installed and built.");
|
|
17473
|
-
process.exit(1);
|
|
17474
|
-
}
|
|
17475
|
-
const serverDir = node_path.dirname(serverPath);
|
|
17476
|
-
const dashConfig = readDashboardConfig(serverPath);
|
|
17477
|
-
console.log("Installing node-pty for terminal support...");
|
|
17478
|
-
if (!ensureNodePty(serverDir)) console.warn("node-pty installation failed — terminal will be unavailable.");
|
|
17479
|
-
console.log("Dashboard starting...");
|
|
17480
|
-
const pid = spawnDashboard({
|
|
17481
|
-
serverPath,
|
|
17482
|
-
projectCwd: dashConfig.projectCwd,
|
|
17483
|
-
networkMode
|
|
17484
|
-
});
|
|
17485
|
-
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
17486
|
-
const readyPort = await findRunningDashboard();
|
|
17487
|
-
if (readyPort) {
|
|
17488
|
-
console.log(`Dashboard ready at http://localhost:${readyPort}`);
|
|
17489
|
-
return;
|
|
17490
|
-
}
|
|
17491
|
-
console.log(`Dashboard spawned (PID ${pid}). It may take a moment to start.`);
|
|
17492
|
-
console.log(`Check http://localhost:${DEFAULT_PORT} once ready.`);
|
|
17493
|
-
}
|
|
17494
17031
|
main();
|
|
17495
17032
|
|
|
17496
17033
|
//#endregion
|
|
17497
|
-
exports.__commonJSMin = __commonJSMin;
|
|
17498
|
-
exports.__toESM = __toESM;
|
|
17499
|
-
exports.appendToStateSection = appendToStateSection;
|
|
17500
|
-
exports.cmdConfigGet = cmdConfigGet;
|
|
17501
|
-
exports.cmdConfigSet = cmdConfigSet;
|
|
17502
|
-
exports.cmdContextLoad = cmdContextLoad;
|
|
17503
|
-
exports.cmdRoadmapAnalyze = cmdRoadmapAnalyze;
|
|
17504
|
-
exports.comparePhaseNum = comparePhaseNum;
|
|
17505
|
-
exports.escapeStringRegexp = escapeStringRegexp;
|
|
17506
|
-
exports.extractFrontmatter = extractFrontmatter;
|
|
17507
|
-
exports.findPhaseInternal = findPhaseInternal;
|
|
17508
|
-
exports.generateSlugInternal = generateSlugInternal;
|
|
17509
|
-
exports.getArchivedPhaseDirs = getArchivedPhaseDirs;
|
|
17510
|
-
exports.getPhasePattern = getPhasePattern;
|
|
17511
|
-
exports.listSubDirs = listSubDirs;
|
|
17512
|
-
exports.loadConfig = loadConfig;
|
|
17513
|
-
exports.normalizePhaseName = normalizePhaseName;
|
|
17514
|
-
exports.parseTodoFrontmatter = parseTodoFrontmatter;
|
|
17515
|
-
exports.phaseAddCore = phaseAddCore;
|
|
17516
|
-
exports.phaseCompleteCore = phaseCompleteCore;
|
|
17517
|
-
exports.phaseInsertCore = phaseInsertCore;
|
|
17518
|
-
exports.phasesPath = phasesPath;
|
|
17519
|
-
exports.planningPath = planningPath;
|
|
17520
|
-
exports.safeReadFile = safeReadFile;
|
|
17521
|
-
exports.stateExtractField = stateExtractField;
|
|
17522
|
-
exports.statePath = statePath;
|
|
17523
|
-
exports.stateReplaceField = stateReplaceField;
|
|
17524
|
-
exports.todayISO = todayISO;
|
|
17525
17034
|
//# sourceMappingURL=cli.cjs.map
|