maxsimcli 3.11.0 → 3.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/assets/CHANGELOG.md +19 -0
- package/dist/assets/dashboard/client/assets/index-CxFKStBk.css +32 -0
- package/dist/assets/dashboard/client/assets/{index-CZ8WC97G.js → index-wtQDvXzr.js} +64 -64
- package/dist/assets/dashboard/client/index.html +2 -2
- package/dist/assets/templates/agents/AGENTS.md +82 -0
- package/dist/assets/templates/commands/maxsim/settings.md +1 -1
- package/dist/assets/templates/skills/code-review/SKILL.md +151 -0
- package/dist/assets/templates/skills/memory-management/SKILL.md +174 -0
- package/dist/assets/templates/skills/simplify/SKILL.md +137 -0
- package/dist/assets/templates/skills/using-maxsim/SKILL.md +115 -0
- package/dist/assets/templates/templates/config.json +1 -1
- package/dist/assets/templates/workflows/add-tests.md +3 -3
- package/dist/assets/templates/workflows/complete-milestone.md +1 -1
- package/dist/assets/templates/workflows/execute-phase.md +4 -14
- package/dist/assets/templates/workflows/init-existing.md +7 -3
- package/dist/assets/templates/workflows/new-milestone.md +4 -0
- package/dist/assets/templates/workflows/new-project.md +6 -2
- package/dist/assets/templates/workflows/plan-phase.md +2 -2
- package/dist/assets/templates/workflows/settings.md +8 -4
- package/dist/assets/templates/workflows/verify-work.md +1 -1
- package/dist/cli.cjs +265 -161
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +73 -204
- package/dist/cli.js.map +1 -1
- package/dist/core/commands.d.ts.map +1 -1
- package/dist/core/commands.js +4 -1
- package/dist/core/commands.js.map +1 -1
- package/dist/core/core.d.ts +18 -0
- package/dist/core/core.d.ts.map +1 -1
- package/dist/core/core.js +43 -13
- package/dist/core/core.js.map +1 -1
- package/dist/core/dashboard-launcher.d.ts +56 -0
- package/dist/core/dashboard-launcher.d.ts.map +1 -0
- package/dist/core/dashboard-launcher.js +243 -0
- package/dist/core/dashboard-launcher.js.map +1 -0
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +20 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/init.d.ts +0 -1
- package/dist/core/init.d.ts.map +1 -1
- package/dist/core/init.js +0 -1
- package/dist/core/init.js.map +1 -1
- package/dist/core/phase.d.ts.map +1 -1
- package/dist/core/phase.js +7 -1
- package/dist/core/phase.js.map +1 -1
- package/dist/core/roadmap.d.ts.map +1 -1
- package/dist/core/roadmap.js +1 -0
- package/dist/core/roadmap.js.map +1 -1
- package/dist/core/state.d.ts.map +1 -1
- package/dist/core/state.js +7 -5
- package/dist/core/state.js.map +1 -1
- package/dist/core/types.d.ts +1 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +1 -2
- package/dist/core/types.js.map +1 -1
- package/dist/install/adapters.d.ts +15 -0
- package/dist/install/adapters.d.ts.map +1 -0
- package/dist/install/adapters.js +203 -0
- package/dist/install/adapters.js.map +1 -0
- package/dist/install/copy.d.ts +15 -0
- package/dist/install/copy.d.ts.map +1 -0
- package/dist/install/copy.js +191 -0
- package/dist/install/copy.js.map +1 -0
- package/dist/install/dashboard.d.ts +16 -0
- package/dist/install/dashboard.d.ts.map +1 -0
- package/dist/install/dashboard.js +273 -0
- package/dist/install/dashboard.js.map +1 -0
- package/dist/install/hooks.d.ts +32 -0
- package/dist/install/hooks.d.ts.map +1 -0
- package/dist/install/hooks.js +285 -0
- package/dist/install/hooks.js.map +1 -0
- package/dist/install/index.d.ts +2 -0
- package/dist/install/index.d.ts.map +1 -0
- package/dist/install/index.js +598 -0
- package/dist/install/index.js.map +1 -0
- package/dist/install/manifest.d.ts +20 -0
- package/dist/install/manifest.d.ts.map +1 -0
- package/dist/install/manifest.js +135 -0
- package/dist/install/manifest.js.map +1 -0
- package/dist/install/patches.d.ts +11 -0
- package/dist/install/patches.d.ts.map +1 -0
- package/dist/install/patches.js +136 -0
- package/dist/install/patches.js.map +1 -0
- package/dist/install/shared.d.ts +50 -0
- package/dist/install/shared.d.ts.map +1 -0
- package/dist/install/shared.js +142 -0
- package/dist/install/shared.js.map +1 -0
- package/dist/install/uninstall.d.ts +6 -0
- package/dist/install/uninstall.d.ts.map +1 -0
- package/dist/install/uninstall.js +280 -0
- package/dist/install/uninstall.js.map +1 -0
- package/dist/install.cjs +763 -709
- package/dist/install.cjs.map +1 -1
- package/dist/mcp-server.cjs.map +1 -1
- package/package.json +1 -1
- package/dist/assets/dashboard/client/assets/index-DzJChB-D.css +0 -32
- package/dist/install.d.ts +0 -2
- package/dist/install.d.ts.map +0 -1
- package/dist/install.js +0 -1841
- package/dist/install.js.map +0 -1
package/dist/cli.cjs
CHANGED
|
@@ -31,10 +31,9 @@ let node_fs = require("node:fs");
|
|
|
31
31
|
node_fs = __toESM(node_fs);
|
|
32
32
|
let node_path = require("node:path");
|
|
33
33
|
node_path = __toESM(node_path);
|
|
34
|
+
let node_child_process = require("node:child_process");
|
|
34
35
|
let node_os = require("node:os");
|
|
35
36
|
node_os = __toESM(node_os);
|
|
36
|
-
let node_child_process = require("node:child_process");
|
|
37
|
-
let node_module = require("node:module");
|
|
38
37
|
let node_buffer = require("node:buffer");
|
|
39
38
|
let child_process = require("child_process");
|
|
40
39
|
let node_events = require("node:events");
|
|
@@ -42,6 +41,7 @@ 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);
|
|
44
|
+
let node_module = require("node:module");
|
|
45
45
|
|
|
46
46
|
//#region src/core/types.ts
|
|
47
47
|
const PLANNING_CONFIG_DEFAULTS = {
|
|
@@ -53,9 +53,8 @@ const PLANNING_CONFIG_DEFAULTS = {
|
|
|
53
53
|
milestone_branch_template: "maxsim/{milestone}-{slug}",
|
|
54
54
|
workflow: {
|
|
55
55
|
research: true,
|
|
56
|
-
|
|
57
|
-
verifier: true
|
|
58
|
-
nyquist_validation: false
|
|
56
|
+
plan_checker: true,
|
|
57
|
+
verifier: true
|
|
59
58
|
},
|
|
60
59
|
parallelization: true,
|
|
61
60
|
brave_search: false
|
|
@@ -594,7 +593,7 @@ var require_has_flag = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
594
593
|
//#endregion
|
|
595
594
|
//#region ../../node_modules/supports-color/index.js
|
|
596
595
|
var require_supports_color = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
597
|
-
const os$
|
|
596
|
+
const os$5 = require("os");
|
|
598
597
|
const tty$2 = require("tty");
|
|
599
598
|
const hasFlag = require_has_flag();
|
|
600
599
|
const { env } = process;
|
|
@@ -621,7 +620,7 @@ var require_supports_color = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
621
620
|
const min = forceColor || 0;
|
|
622
621
|
if (env.TERM === "dumb") return min;
|
|
623
622
|
if (process.platform === "win32") {
|
|
624
|
-
const osRelease = os$
|
|
623
|
+
const osRelease = os$5.release().split(".");
|
|
625
624
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
626
625
|
return 1;
|
|
627
626
|
}
|
|
@@ -4711,21 +4710,47 @@ const MODEL_PROFILES = {
|
|
|
4711
4710
|
tokenburner: "opus"
|
|
4712
4711
|
}
|
|
4713
4712
|
};
|
|
4713
|
+
/** Thrown by output() to signal successful command completion. */
|
|
4714
|
+
var CliOutput = class {
|
|
4715
|
+
result;
|
|
4716
|
+
raw;
|
|
4717
|
+
rawValue;
|
|
4718
|
+
constructor(result, raw, rawValue) {
|
|
4719
|
+
this.result = result;
|
|
4720
|
+
this.raw = raw ?? false;
|
|
4721
|
+
this.rawValue = rawValue;
|
|
4722
|
+
}
|
|
4723
|
+
};
|
|
4724
|
+
/** Thrown by error() to signal a command error. */
|
|
4725
|
+
var CliError = class {
|
|
4726
|
+
message;
|
|
4727
|
+
constructor(message) {
|
|
4728
|
+
this.message = message;
|
|
4729
|
+
}
|
|
4730
|
+
};
|
|
4714
4731
|
function output(result, raw, rawValue) {
|
|
4715
|
-
|
|
4732
|
+
throw new CliOutput(result, raw, rawValue);
|
|
4733
|
+
}
|
|
4734
|
+
function error(message) {
|
|
4735
|
+
throw new CliError(message);
|
|
4736
|
+
}
|
|
4737
|
+
/** Re-throw CliOutput/CliError signals so catch blocks don't intercept them */
|
|
4738
|
+
function rethrowCliSignals(e) {
|
|
4739
|
+
if (e instanceof CliOutput || e instanceof CliError) throw e;
|
|
4740
|
+
}
|
|
4741
|
+
/**
|
|
4742
|
+
* Handle a CliOutput by writing to stdout. Extracted so cli.ts can use it.
|
|
4743
|
+
*/
|
|
4744
|
+
function writeOutput(out) {
|
|
4745
|
+
if (out.raw && out.rawValue !== void 0) process.stdout.write(String(out.rawValue));
|
|
4716
4746
|
else {
|
|
4717
|
-
const json = JSON.stringify(result, null, 2);
|
|
4747
|
+
const json = JSON.stringify(out.result, null, 2);
|
|
4718
4748
|
if (json.length > 5e4) {
|
|
4719
4749
|
const tmpPath = node_path.default.join(node_os.default.tmpdir(), `maxsim-${Date.now()}.json`);
|
|
4720
4750
|
node_fs.default.writeFileSync(tmpPath, json, "utf-8");
|
|
4721
4751
|
process.stdout.write("@file:" + tmpPath);
|
|
4722
4752
|
} else process.stdout.write(json);
|
|
4723
4753
|
}
|
|
4724
|
-
process.exit(0);
|
|
4725
|
-
}
|
|
4726
|
-
function error(message) {
|
|
4727
|
-
process.stderr.write("Error: " + message + "\n");
|
|
4728
|
-
process.exit(1);
|
|
4729
4754
|
}
|
|
4730
4755
|
/** Today's date as YYYY-MM-DD. */
|
|
4731
4756
|
function todayISO() {
|
|
@@ -4833,6 +4858,9 @@ function loadConfig(cwd) {
|
|
|
4833
4858
|
field: "research"
|
|
4834
4859
|
}) ?? defaults.research,
|
|
4835
4860
|
plan_checker: get("plan_checker", {
|
|
4861
|
+
section: "workflow",
|
|
4862
|
+
field: "plan_checker"
|
|
4863
|
+
}) ?? get("plan_checker", {
|
|
4836
4864
|
section: "workflow",
|
|
4837
4865
|
field: "plan_check"
|
|
4838
4866
|
}) ?? defaults.plan_checker,
|
|
@@ -12079,7 +12107,7 @@ function cmdStateLoad(cwd, raw) {
|
|
|
12079
12107
|
};
|
|
12080
12108
|
if (raw) {
|
|
12081
12109
|
const c = config;
|
|
12082
|
-
|
|
12110
|
+
output(result, true, [
|
|
12083
12111
|
`model_profile=${c.model_profile}`,
|
|
12084
12112
|
`commit_docs=${c.commit_docs}`,
|
|
12085
12113
|
`branching_strategy=${c.branching_strategy}`,
|
|
@@ -12092,9 +12120,7 @@ function cmdStateLoad(cwd, raw) {
|
|
|
12092
12120
|
`config_exists=${configExists}`,
|
|
12093
12121
|
`roadmap_exists=${roadmapExists}`,
|
|
12094
12122
|
`state_exists=${stateExists}`
|
|
12095
|
-
];
|
|
12096
|
-
process.stdout.write(lines.join("\n"));
|
|
12097
|
-
process.exit(0);
|
|
12123
|
+
].join("\n"));
|
|
12098
12124
|
}
|
|
12099
12125
|
output(result);
|
|
12100
12126
|
}
|
|
@@ -12120,7 +12146,8 @@ function cmdStateGet(cwd, section, raw) {
|
|
|
12120
12146
|
return;
|
|
12121
12147
|
}
|
|
12122
12148
|
output({ error: `Section or field "${section}" not found` }, raw, "");
|
|
12123
|
-
} catch {
|
|
12149
|
+
} catch (e) {
|
|
12150
|
+
rethrowCliSignals(e);
|
|
12124
12151
|
error("STATE.md not found");
|
|
12125
12152
|
}
|
|
12126
12153
|
}
|
|
@@ -12142,7 +12169,8 @@ function cmdStatePatch(cwd, patches, raw) {
|
|
|
12142
12169
|
}
|
|
12143
12170
|
if (results.updated.length > 0) node_fs.default.writeFileSync(statePath$3, content, "utf-8");
|
|
12144
12171
|
output(results, raw, results.updated.length > 0 ? "true" : "false");
|
|
12145
|
-
} catch {
|
|
12172
|
+
} catch (e) {
|
|
12173
|
+
rethrowCliSignals(e);
|
|
12146
12174
|
error("STATE.md not found");
|
|
12147
12175
|
}
|
|
12148
12176
|
}
|
|
@@ -12161,7 +12189,8 @@ function cmdStateUpdate(cwd, field, value) {
|
|
|
12161
12189
|
updated: false,
|
|
12162
12190
|
reason: `Field "${field}" not found in STATE.md`
|
|
12163
12191
|
});
|
|
12164
|
-
} catch {
|
|
12192
|
+
} catch (e) {
|
|
12193
|
+
rethrowCliSignals(e);
|
|
12165
12194
|
output({
|
|
12166
12195
|
updated: false,
|
|
12167
12196
|
reason: "STATE.md not found"
|
|
@@ -12555,6 +12584,7 @@ function cmdRoadmapGetPhase(cwd, phaseNum, raw) {
|
|
|
12555
12584
|
section
|
|
12556
12585
|
}, raw, section);
|
|
12557
12586
|
} catch (e) {
|
|
12587
|
+
rethrowCliSignals(e);
|
|
12558
12588
|
error("Failed to read ROADMAP.md: " + e.message);
|
|
12559
12589
|
}
|
|
12560
12590
|
}
|
|
@@ -13327,7 +13357,8 @@ function cmdVerifyPathExists(cwd, targetPath, raw) {
|
|
|
13327
13357
|
exists: true,
|
|
13328
13358
|
type: stats.isDirectory() ? "directory" : stats.isFile() ? "file" : "other"
|
|
13329
13359
|
}, raw, "true");
|
|
13330
|
-
} catch {
|
|
13360
|
+
} catch (e) {
|
|
13361
|
+
rethrowCliSignals(e);
|
|
13331
13362
|
output({
|
|
13332
13363
|
exists: false,
|
|
13333
13364
|
type: null
|
|
@@ -13408,6 +13439,7 @@ function cmdHistoryDigest(cwd, raw) {
|
|
|
13408
13439
|
};
|
|
13409
13440
|
output(outputDigest, raw);
|
|
13410
13441
|
} catch (e) {
|
|
13442
|
+
rethrowCliSignals(e);
|
|
13411
13443
|
error("Failed to generate history digest: " + e.message);
|
|
13412
13444
|
}
|
|
13413
13445
|
}
|
|
@@ -13580,6 +13612,7 @@ async function cmdWebsearch(query, options, raw) {
|
|
|
13580
13612
|
results
|
|
13581
13613
|
}, raw, results.map((r) => `${r.title}\n${r.url}\n${r.description}`).join("\n\n"));
|
|
13582
13614
|
} catch (err) {
|
|
13615
|
+
rethrowCliSignals(err);
|
|
13583
13616
|
output({
|
|
13584
13617
|
available: false,
|
|
13585
13618
|
error: err.message
|
|
@@ -14597,6 +14630,7 @@ function cmdPhasesList(cwd, options, raw) {
|
|
|
14597
14630
|
count: dirs.length
|
|
14598
14631
|
}, raw, dirs.join("\n"));
|
|
14599
14632
|
} catch (e) {
|
|
14633
|
+
rethrowCliSignals(e);
|
|
14600
14634
|
error("Failed to list phases: " + e.message);
|
|
14601
14635
|
}
|
|
14602
14636
|
}
|
|
@@ -14637,6 +14671,7 @@ function cmdPhaseNextDecimal(cwd, basePhase, raw) {
|
|
|
14637
14671
|
existing: existingDecimals
|
|
14638
14672
|
}, raw, nextDecimal);
|
|
14639
14673
|
} catch (e) {
|
|
14674
|
+
rethrowCliSignals(e);
|
|
14640
14675
|
error("Failed to calculate next decimal phase: " + e.message);
|
|
14641
14676
|
}
|
|
14642
14677
|
}
|
|
@@ -14674,7 +14709,8 @@ function cmdFindPhase(cwd, phase, raw) {
|
|
|
14674
14709
|
summaries
|
|
14675
14710
|
};
|
|
14676
14711
|
output(result, raw, result.directory);
|
|
14677
|
-
} catch {
|
|
14712
|
+
} catch (e) {
|
|
14713
|
+
rethrowCliSignals(e);
|
|
14678
14714
|
output(notFound, raw, "");
|
|
14679
14715
|
}
|
|
14680
14716
|
}
|
|
@@ -14756,6 +14792,7 @@ function cmdPhaseAdd(cwd, description, raw) {
|
|
|
14756
14792
|
directory: result.directory
|
|
14757
14793
|
}, raw, result.padded);
|
|
14758
14794
|
} catch (e) {
|
|
14795
|
+
rethrowCliSignals(e);
|
|
14759
14796
|
error(e.message);
|
|
14760
14797
|
}
|
|
14761
14798
|
}
|
|
@@ -14771,6 +14808,7 @@ function cmdPhaseInsert(cwd, afterPhase, description, raw) {
|
|
|
14771
14808
|
directory: result.directory
|
|
14772
14809
|
}, raw, result.phase_number);
|
|
14773
14810
|
} catch (e) {
|
|
14811
|
+
rethrowCliSignals(e);
|
|
14774
14812
|
error(e.message);
|
|
14775
14813
|
}
|
|
14776
14814
|
}
|
|
@@ -14954,6 +14992,7 @@ function cmdPhaseComplete(cwd, phaseNum, raw) {
|
|
|
14954
14992
|
state_updated: result.state_updated
|
|
14955
14993
|
}, raw);
|
|
14956
14994
|
} catch (e) {
|
|
14995
|
+
rethrowCliSignals(e);
|
|
14957
14996
|
error(e.message);
|
|
14958
14997
|
}
|
|
14959
14998
|
}
|
|
@@ -15179,6 +15218,155 @@ function cmdTemplateFill(cwd, templateType, options, raw) {
|
|
|
15179
15218
|
}, raw, relPath);
|
|
15180
15219
|
}
|
|
15181
15220
|
|
|
15221
|
+
//#endregion
|
|
15222
|
+
//#region src/core/dashboard-launcher.ts
|
|
15223
|
+
/**
|
|
15224
|
+
* Dashboard Launcher — Shared dashboard lifecycle utilities
|
|
15225
|
+
*
|
|
15226
|
+
* Used by both cli.ts (tool-router) and install.ts (npx entry point).
|
|
15227
|
+
*/
|
|
15228
|
+
const DEFAULT_PORT = 3333;
|
|
15229
|
+
const PORT_RANGE_END = 3343;
|
|
15230
|
+
const HEALTH_TIMEOUT_MS = 1500;
|
|
15231
|
+
/**
|
|
15232
|
+
* Check if a dashboard health endpoint is responding on the given port.
|
|
15233
|
+
*/
|
|
15234
|
+
async function checkHealth(port, timeoutMs = HEALTH_TIMEOUT_MS) {
|
|
15235
|
+
try {
|
|
15236
|
+
const controller = new AbortController();
|
|
15237
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
15238
|
+
const res = await fetch(`http://localhost:${port}/api/health`, { signal: controller.signal });
|
|
15239
|
+
clearTimeout(timer);
|
|
15240
|
+
if (res.ok) return (await res.json()).status === "ok";
|
|
15241
|
+
return false;
|
|
15242
|
+
} catch {
|
|
15243
|
+
return false;
|
|
15244
|
+
}
|
|
15245
|
+
}
|
|
15246
|
+
/**
|
|
15247
|
+
* Scan the port range for a running dashboard instance.
|
|
15248
|
+
* Returns the port number if found, null otherwise.
|
|
15249
|
+
*/
|
|
15250
|
+
async function findRunningDashboard(timeoutMs = HEALTH_TIMEOUT_MS) {
|
|
15251
|
+
for (let port = DEFAULT_PORT; port <= PORT_RANGE_END; port++) if (await checkHealth(port, timeoutMs)) return port;
|
|
15252
|
+
return null;
|
|
15253
|
+
}
|
|
15254
|
+
/**
|
|
15255
|
+
* Kill processes listening on the given port. Cross-platform.
|
|
15256
|
+
*/
|
|
15257
|
+
function killProcessOnPort(port) {
|
|
15258
|
+
if (process.platform === "win32") try {
|
|
15259
|
+
const lines = (0, node_child_process.execSync)(`netstat -ano | findstr :${port} | findstr LISTENING`, { encoding: "utf-8" }).trim().split("\n");
|
|
15260
|
+
const pids = /* @__PURE__ */ new Set();
|
|
15261
|
+
for (const line of lines) {
|
|
15262
|
+
const parts = line.trim().split(/\s+/);
|
|
15263
|
+
const pid = parts[parts.length - 1];
|
|
15264
|
+
if (pid && pid !== "0") pids.add(pid);
|
|
15265
|
+
}
|
|
15266
|
+
for (const pid of pids) try {
|
|
15267
|
+
(0, node_child_process.execSync)(`taskkill /PID ${pid} /F`, { stdio: "ignore" });
|
|
15268
|
+
} catch {}
|
|
15269
|
+
} catch {}
|
|
15270
|
+
else try {
|
|
15271
|
+
(0, node_child_process.execSync)(`lsof -i :${port} -t | xargs kill -SIGTERM 2>/dev/null`, { stdio: "ignore" });
|
|
15272
|
+
} catch {}
|
|
15273
|
+
}
|
|
15274
|
+
/**
|
|
15275
|
+
* Resolve the dashboard server entry point path.
|
|
15276
|
+
* Tries: local project install, global install, @maxsim/dashboard package, monorepo walk.
|
|
15277
|
+
*/
|
|
15278
|
+
function resolveDashboardServer() {
|
|
15279
|
+
const localDashboard = node_path.default.join(process.cwd(), ".claude", "dashboard", "server.js");
|
|
15280
|
+
if (node_fs.default.existsSync(localDashboard)) return localDashboard;
|
|
15281
|
+
const globalDashboard = node_path.default.join(node_os.default.homedir(), ".claude", "dashboard", "server.js");
|
|
15282
|
+
if (node_fs.default.existsSync(globalDashboard)) return globalDashboard;
|
|
15283
|
+
try {
|
|
15284
|
+
const pkgPath = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href).resolve("@maxsim/dashboard/package.json");
|
|
15285
|
+
const pkgDir = node_path.default.dirname(pkgPath);
|
|
15286
|
+
const serverJs = node_path.default.join(pkgDir, "server.js");
|
|
15287
|
+
if (node_fs.default.existsSync(serverJs)) return serverJs;
|
|
15288
|
+
const serverTs = node_path.default.join(pkgDir, "server.ts");
|
|
15289
|
+
if (node_fs.default.existsSync(serverTs)) return serverTs;
|
|
15290
|
+
} catch {}
|
|
15291
|
+
try {
|
|
15292
|
+
let dir = node_path.default.dirname(new URL(require("url").pathToFileURL(__filename).href).pathname);
|
|
15293
|
+
if (process.platform === "win32" && dir.startsWith("/")) dir = dir.slice(1);
|
|
15294
|
+
for (let i = 0; i < 5; i++) {
|
|
15295
|
+
const candidate = node_path.default.join(dir, "packages", "dashboard", "server.ts");
|
|
15296
|
+
if (node_fs.default.existsSync(candidate)) return candidate;
|
|
15297
|
+
const candidateJs = node_path.default.join(dir, "packages", "dashboard", "server.js");
|
|
15298
|
+
if (node_fs.default.existsSync(candidateJs)) return candidateJs;
|
|
15299
|
+
dir = node_path.default.dirname(dir);
|
|
15300
|
+
}
|
|
15301
|
+
} catch {}
|
|
15302
|
+
return null;
|
|
15303
|
+
}
|
|
15304
|
+
/**
|
|
15305
|
+
* Ensure node-pty is installed in the dashboard directory.
|
|
15306
|
+
* Returns true if node-pty is available after this call.
|
|
15307
|
+
*/
|
|
15308
|
+
function ensureNodePty(serverDir) {
|
|
15309
|
+
const ptyModulePath = node_path.default.join(serverDir, "node_modules", "node-pty");
|
|
15310
|
+
if (node_fs.default.existsSync(ptyModulePath)) return true;
|
|
15311
|
+
const dashPkgPath = node_path.default.join(serverDir, "package.json");
|
|
15312
|
+
if (!node_fs.default.existsSync(dashPkgPath)) node_fs.default.writeFileSync(dashPkgPath, "{\"private\":true}\n");
|
|
15313
|
+
try {
|
|
15314
|
+
(0, node_child_process.execSync)("npm install node-pty --save-optional --no-audit --no-fund --loglevel=error", {
|
|
15315
|
+
cwd: serverDir,
|
|
15316
|
+
stdio: "inherit",
|
|
15317
|
+
timeout: 12e4
|
|
15318
|
+
});
|
|
15319
|
+
return true;
|
|
15320
|
+
} catch {
|
|
15321
|
+
return false;
|
|
15322
|
+
}
|
|
15323
|
+
}
|
|
15324
|
+
/**
|
|
15325
|
+
* Read dashboard.json config from the parent directory of the dashboard dir.
|
|
15326
|
+
*/
|
|
15327
|
+
function readDashboardConfig(serverPath) {
|
|
15328
|
+
const dashboardDir = node_path.default.dirname(serverPath);
|
|
15329
|
+
const dashboardConfigPath = node_path.default.join(node_path.default.dirname(dashboardDir), "dashboard.json");
|
|
15330
|
+
let projectCwd = process.cwd();
|
|
15331
|
+
let networkMode = false;
|
|
15332
|
+
if (node_fs.default.existsSync(dashboardConfigPath)) try {
|
|
15333
|
+
const config = JSON.parse(node_fs.default.readFileSync(dashboardConfigPath, "utf8"));
|
|
15334
|
+
if (config.projectCwd) projectCwd = config.projectCwd;
|
|
15335
|
+
networkMode = config.networkMode ?? false;
|
|
15336
|
+
} catch {}
|
|
15337
|
+
return {
|
|
15338
|
+
projectCwd,
|
|
15339
|
+
networkMode
|
|
15340
|
+
};
|
|
15341
|
+
}
|
|
15342
|
+
/**
|
|
15343
|
+
* Spawn the dashboard server as a detached background process.
|
|
15344
|
+
* Returns the child process PID, or null if spawn failed.
|
|
15345
|
+
*/
|
|
15346
|
+
function spawnDashboard(options) {
|
|
15347
|
+
const { serverPath, projectCwd, networkMode = false, nodeEnv = "production" } = options;
|
|
15348
|
+
const serverDir = node_path.default.dirname(serverPath);
|
|
15349
|
+
const isTsFile = serverPath.endsWith(".ts");
|
|
15350
|
+
const child = (0, node_child_process.spawn)("node", isTsFile ? [
|
|
15351
|
+
"--import",
|
|
15352
|
+
"tsx",
|
|
15353
|
+
serverPath
|
|
15354
|
+
] : [serverPath], {
|
|
15355
|
+
cwd: serverDir,
|
|
15356
|
+
detached: true,
|
|
15357
|
+
stdio: "ignore",
|
|
15358
|
+
env: {
|
|
15359
|
+
...process.env,
|
|
15360
|
+
MAXSIM_PROJECT_CWD: projectCwd,
|
|
15361
|
+
MAXSIM_NETWORK_MODE: networkMode ? "1" : "0",
|
|
15362
|
+
NODE_ENV: isTsFile ? "development" : nodeEnv
|
|
15363
|
+
},
|
|
15364
|
+
...process.platform === "win32" ? { shell: true } : {}
|
|
15365
|
+
});
|
|
15366
|
+
child.unref();
|
|
15367
|
+
return child.pid ?? null;
|
|
15368
|
+
}
|
|
15369
|
+
|
|
15182
15370
|
//#endregion
|
|
15183
15371
|
//#region src/core/init.ts
|
|
15184
15372
|
/**
|
|
@@ -15258,7 +15446,6 @@ function cmdInitPlanPhase(cwd, phase, raw) {
|
|
|
15258
15446
|
checker_model: resolveModelInternal(cwd, "maxsim-plan-checker"),
|
|
15259
15447
|
research_enabled: config.research,
|
|
15260
15448
|
plan_checker_enabled: config.plan_checker,
|
|
15261
|
-
nyquist_validation_enabled: false,
|
|
15262
15449
|
commit_docs: config.commit_docs,
|
|
15263
15450
|
phase_found: !!phaseInfo,
|
|
15264
15451
|
phase_dir: phaseInfo?.directory ?? null,
|
|
@@ -15946,30 +16133,42 @@ const COMMANDS = {
|
|
|
15946
16133
|
}
|
|
15947
16134
|
};
|
|
15948
16135
|
async function main() {
|
|
15949
|
-
|
|
15950
|
-
|
|
15951
|
-
|
|
15952
|
-
|
|
15953
|
-
|
|
15954
|
-
|
|
15955
|
-
|
|
15956
|
-
|
|
15957
|
-
|
|
15958
|
-
|
|
15959
|
-
|
|
15960
|
-
|
|
15961
|
-
|
|
15962
|
-
|
|
15963
|
-
|
|
15964
|
-
|
|
15965
|
-
|
|
15966
|
-
|
|
15967
|
-
|
|
15968
|
-
|
|
15969
|
-
|
|
15970
|
-
|
|
15971
|
-
|
|
15972
|
-
|
|
16136
|
+
try {
|
|
16137
|
+
const args = process.argv.slice(2);
|
|
16138
|
+
let cwd = process.cwd();
|
|
16139
|
+
const cwdEqArg = args.find((arg) => arg.startsWith("--cwd="));
|
|
16140
|
+
const cwdIdx = args.indexOf("--cwd");
|
|
16141
|
+
if (cwdEqArg) {
|
|
16142
|
+
const value = cwdEqArg.slice(6).trim();
|
|
16143
|
+
if (!value) error("Missing value for --cwd");
|
|
16144
|
+
args.splice(args.indexOf(cwdEqArg), 1);
|
|
16145
|
+
cwd = node_path.resolve(value);
|
|
16146
|
+
} else if (cwdIdx !== -1) {
|
|
16147
|
+
const value = args[cwdIdx + 1];
|
|
16148
|
+
if (!value || value.startsWith("--")) error("Missing value for --cwd");
|
|
16149
|
+
args.splice(cwdIdx, 2);
|
|
16150
|
+
cwd = node_path.resolve(value);
|
|
16151
|
+
}
|
|
16152
|
+
if (!node_fs.existsSync(cwd) || !node_fs.statSync(cwd).isDirectory()) error(`Invalid --cwd: ${cwd}`);
|
|
16153
|
+
const rawIndex = args.indexOf("--raw");
|
|
16154
|
+
const raw = rawIndex !== -1;
|
|
16155
|
+
if (rawIndex !== -1) args.splice(rawIndex, 1);
|
|
16156
|
+
const command = args[0];
|
|
16157
|
+
if (!command) error(`Usage: maxsim-tools <command> [args] [--raw] [--cwd <path>]\nCommands: ${Object.keys(COMMANDS).join(", ")}`);
|
|
16158
|
+
const handler = COMMANDS[command];
|
|
16159
|
+
if (!handler) error(`Unknown command: ${command}`);
|
|
16160
|
+
await handler(args, cwd, raw);
|
|
16161
|
+
} catch (thrown) {
|
|
16162
|
+
if (thrown instanceof CliOutput) {
|
|
16163
|
+
writeOutput(thrown);
|
|
16164
|
+
process.exit(0);
|
|
16165
|
+
}
|
|
16166
|
+
if (thrown instanceof CliError) {
|
|
16167
|
+
process.stderr.write("Error: " + thrown.message + "\n");
|
|
16168
|
+
process.exit(1);
|
|
16169
|
+
}
|
|
16170
|
+
throw thrown;
|
|
16171
|
+
}
|
|
15973
16172
|
}
|
|
15974
16173
|
/**
|
|
15975
16174
|
* Dashboard launch command.
|
|
@@ -15979,40 +16178,20 @@ async function main() {
|
|
|
15979
16178
|
* Supports --stop to kill a running instance.
|
|
15980
16179
|
*/
|
|
15981
16180
|
async function handleDashboard(args) {
|
|
15982
|
-
const DEFAULT_PORT = 3333;
|
|
15983
|
-
const PORT_RANGE_END = 3343;
|
|
15984
|
-
const HEALTH_TIMEOUT_MS = 1500;
|
|
15985
16181
|
const networkMode = args.includes("--network");
|
|
15986
16182
|
if (args.includes("--stop")) {
|
|
15987
|
-
for (let port = DEFAULT_PORT; port <= PORT_RANGE_END; port++) if (await checkHealth(port
|
|
15988
|
-
console.log(`Dashboard found on port ${port} —
|
|
15989
|
-
|
|
15990
|
-
console.log(
|
|
15991
|
-
try {
|
|
15992
|
-
if (process.platform === "win32") {
|
|
15993
|
-
const lines = (0, node_child_process.execSync)(`netstat -ano | findstr :${port} | findstr LISTENING`, { encoding: "utf-8" }).trim().split("\n");
|
|
15994
|
-
const pids = /* @__PURE__ */ new Set();
|
|
15995
|
-
for (const line of lines) {
|
|
15996
|
-
const parts = line.trim().split(/\s+/);
|
|
15997
|
-
const pid = parts[parts.length - 1];
|
|
15998
|
-
if (pid && pid !== "0") pids.add(pid);
|
|
15999
|
-
}
|
|
16000
|
-
for (const pid of pids) try {
|
|
16001
|
-
(0, node_child_process.execSync)(`taskkill /PID ${pid} /F`, { stdio: "ignore" });
|
|
16002
|
-
console.log(`Killed process ${pid}`);
|
|
16003
|
-
} catch {}
|
|
16004
|
-
} else (0, node_child_process.execSync)(`lsof -i :${port} -t | xargs kill -SIGTERM 2>/dev/null`, { stdio: "ignore" });
|
|
16005
|
-
console.log("Dashboard stopped.");
|
|
16006
|
-
} catch {
|
|
16007
|
-
console.log("Could not automatically stop the dashboard. Kill the process manually.");
|
|
16008
|
-
}
|
|
16183
|
+
for (let port = DEFAULT_PORT; port <= PORT_RANGE_END; port++) if (await checkHealth(port)) {
|
|
16184
|
+
console.log(`Dashboard found on port ${port} — stopping...`);
|
|
16185
|
+
killProcessOnPort(port);
|
|
16186
|
+
console.log("Dashboard stopped.");
|
|
16009
16187
|
return;
|
|
16010
16188
|
}
|
|
16011
16189
|
console.log("No running dashboard found.");
|
|
16012
16190
|
return;
|
|
16013
16191
|
}
|
|
16014
|
-
|
|
16015
|
-
|
|
16192
|
+
const runningPort = await findRunningDashboard();
|
|
16193
|
+
if (runningPort) {
|
|
16194
|
+
console.log(`Dashboard already running at http://localhost:${runningPort}`);
|
|
16016
16195
|
return;
|
|
16017
16196
|
}
|
|
16018
16197
|
const serverPath = resolveDashboardServer();
|
|
@@ -16021,100 +16200,25 @@ async function handleDashboard(args) {
|
|
|
16021
16200
|
console.error("Ensure @maxsim/dashboard is installed and built.");
|
|
16022
16201
|
process.exit(1);
|
|
16023
16202
|
}
|
|
16024
|
-
const isTsFile = serverPath.endsWith(".ts");
|
|
16025
|
-
const runner = "node";
|
|
16026
|
-
const runnerArgs = isTsFile ? [
|
|
16027
|
-
"--import",
|
|
16028
|
-
"tsx",
|
|
16029
|
-
serverPath
|
|
16030
|
-
] : [serverPath];
|
|
16031
16203
|
const serverDir = node_path.dirname(serverPath);
|
|
16032
|
-
|
|
16033
|
-
|
|
16034
|
-
if (
|
|
16035
|
-
const config = JSON.parse(node_fs.readFileSync(dashboardConfigPath, "utf8"));
|
|
16036
|
-
if (config.projectCwd) projectCwd = config.projectCwd;
|
|
16037
|
-
} catch {}
|
|
16038
|
-
const ptyModulePath = node_path.join(serverDir, "node_modules", "node-pty");
|
|
16039
|
-
if (!node_fs.existsSync(ptyModulePath)) {
|
|
16040
|
-
console.log("Installing node-pty for terminal support...");
|
|
16041
|
-
try {
|
|
16042
|
-
(0, node_child_process.execSync)("npm install node-pty --save-optional --no-audit --no-fund --loglevel=error", {
|
|
16043
|
-
cwd: serverDir,
|
|
16044
|
-
stdio: "inherit",
|
|
16045
|
-
timeout: 12e4
|
|
16046
|
-
});
|
|
16047
|
-
} catch {
|
|
16048
|
-
console.warn("node-pty installation failed — terminal will be unavailable.");
|
|
16049
|
-
}
|
|
16050
|
-
}
|
|
16204
|
+
const dashConfig = readDashboardConfig(serverPath);
|
|
16205
|
+
console.log("Installing node-pty for terminal support...");
|
|
16206
|
+
if (!ensureNodePty(serverDir)) console.warn("node-pty installation failed — terminal will be unavailable.");
|
|
16051
16207
|
console.log("Dashboard starting...");
|
|
16052
|
-
const
|
|
16053
|
-
|
|
16054
|
-
|
|
16055
|
-
|
|
16056
|
-
env: {
|
|
16057
|
-
...process.env,
|
|
16058
|
-
MAXSIM_PROJECT_CWD: projectCwd,
|
|
16059
|
-
NODE_ENV: isTsFile ? "development" : "production",
|
|
16060
|
-
...networkMode ? { MAXSIM_NETWORK_MODE: "1" } : {}
|
|
16061
|
-
},
|
|
16062
|
-
...process.platform === "win32" ? { shell: true } : {}
|
|
16208
|
+
const pid = spawnDashboard({
|
|
16209
|
+
serverPath,
|
|
16210
|
+
projectCwd: dashConfig.projectCwd,
|
|
16211
|
+
networkMode
|
|
16063
16212
|
});
|
|
16064
|
-
child.unref();
|
|
16065
16213
|
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
16066
|
-
|
|
16067
|
-
|
|
16214
|
+
const readyPort = await findRunningDashboard();
|
|
16215
|
+
if (readyPort) {
|
|
16216
|
+
console.log(`Dashboard ready at http://localhost:${readyPort}`);
|
|
16068
16217
|
return;
|
|
16069
16218
|
}
|
|
16070
|
-
console.log(`Dashboard spawned (PID ${
|
|
16219
|
+
console.log(`Dashboard spawned (PID ${pid}). It may take a moment to start.`);
|
|
16071
16220
|
console.log(`Check http://localhost:${DEFAULT_PORT} once ready.`);
|
|
16072
16221
|
}
|
|
16073
|
-
/**
|
|
16074
|
-
* Check if a dashboard health endpoint is responding on the given port.
|
|
16075
|
-
*/
|
|
16076
|
-
async function checkHealth(port, timeoutMs) {
|
|
16077
|
-
try {
|
|
16078
|
-
const controller = new AbortController();
|
|
16079
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
16080
|
-
const res = await fetch(`http://localhost:${port}/api/health`, { signal: controller.signal });
|
|
16081
|
-
clearTimeout(timer);
|
|
16082
|
-
if (res.ok) return (await res.json()).status === "ok";
|
|
16083
|
-
return false;
|
|
16084
|
-
} catch {
|
|
16085
|
-
return false;
|
|
16086
|
-
}
|
|
16087
|
-
}
|
|
16088
|
-
/**
|
|
16089
|
-
* Resolve the dashboard server entry point path.
|
|
16090
|
-
* Tries: built server.js first, then source server.ts for dev mode.
|
|
16091
|
-
*/
|
|
16092
|
-
function resolveDashboardServer() {
|
|
16093
|
-
const localDashboard = node_path.join(process.cwd(), ".claude", "dashboard", "server.js");
|
|
16094
|
-
if (node_fs.existsSync(localDashboard)) return localDashboard;
|
|
16095
|
-
const globalDashboard = node_path.join(node_os.homedir(), ".claude", "dashboard", "server.js");
|
|
16096
|
-
if (node_fs.existsSync(globalDashboard)) return globalDashboard;
|
|
16097
|
-
try {
|
|
16098
|
-
const pkgPath = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href).resolve("@maxsim/dashboard/package.json");
|
|
16099
|
-
const pkgDir = node_path.dirname(pkgPath);
|
|
16100
|
-
const serverJs = node_path.join(pkgDir, "server.js");
|
|
16101
|
-
if (node_fs.existsSync(serverJs)) return serverJs;
|
|
16102
|
-
const serverTs = node_path.join(pkgDir, "server.ts");
|
|
16103
|
-
if (node_fs.existsSync(serverTs)) return serverTs;
|
|
16104
|
-
} catch {}
|
|
16105
|
-
try {
|
|
16106
|
-
let dir = node_path.dirname(new URL(require("url").pathToFileURL(__filename).href).pathname);
|
|
16107
|
-
if (process.platform === "win32" && dir.startsWith("/")) dir = dir.slice(1);
|
|
16108
|
-
for (let i = 0; i < 5; i++) {
|
|
16109
|
-
const candidate = node_path.join(dir, "packages", "dashboard", "server.ts");
|
|
16110
|
-
if (node_fs.existsSync(candidate)) return candidate;
|
|
16111
|
-
const candidateJs = node_path.join(dir, "packages", "dashboard", "server.js");
|
|
16112
|
-
if (node_fs.existsSync(candidateJs)) return candidateJs;
|
|
16113
|
-
dir = node_path.dirname(dir);
|
|
16114
|
-
}
|
|
16115
|
-
} catch {}
|
|
16116
|
-
return null;
|
|
16117
|
-
}
|
|
16118
16222
|
main();
|
|
16119
16223
|
|
|
16120
16224
|
//#endregion
|