maxsimcli 2.5.1 → 2.5.3
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.
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap"
|
|
11
11
|
rel="stylesheet"
|
|
12
12
|
/>
|
|
13
|
-
<script type="module" crossorigin src="/assets/index-
|
|
13
|
+
<script type="module" crossorigin src="/assets/index-DnL8rwuQ.js"></script>
|
|
14
14
|
<link rel="stylesheet" crossorigin href="/assets/index-SwFemGUT.css">
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
@@ -32444,7 +32444,7 @@ var require_websocket = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
32444
32444
|
const tls = require("tls");
|
|
32445
32445
|
const { randomBytes, createHash: createHash$1 } = require("crypto");
|
|
32446
32446
|
const { Duplex: Duplex$2, Readable: Readable$1 } = require("stream");
|
|
32447
|
-
const { URL } = require("url");
|
|
32447
|
+
const { URL: URL$1 } = require("url");
|
|
32448
32448
|
const PerMessageDeflate = require_permessage_deflate();
|
|
32449
32449
|
const Receiver = require_receiver();
|
|
32450
32450
|
const Sender = require_sender();
|
|
@@ -32973,9 +32973,9 @@ var require_websocket = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
32973
32973
|
websocket._closeTimeout = opts.closeTimeout;
|
|
32974
32974
|
if (!protocolVersions.includes(opts.protocolVersion)) throw new RangeError(`Unsupported protocol version: ${opts.protocolVersion} (supported versions: ${protocolVersions.join(", ")})`);
|
|
32975
32975
|
let parsedUrl;
|
|
32976
|
-
if (address instanceof URL) parsedUrl = address;
|
|
32976
|
+
if (address instanceof URL$1) parsedUrl = address;
|
|
32977
32977
|
else try {
|
|
32978
|
-
parsedUrl = new URL(address);
|
|
32978
|
+
parsedUrl = new URL$1(address);
|
|
32979
32979
|
} catch (e) {
|
|
32980
32980
|
throw new SyntaxError(`Invalid URL: ${address}`);
|
|
32981
32981
|
}
|
|
@@ -33077,7 +33077,7 @@ var require_websocket = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
33077
33077
|
req.abort();
|
|
33078
33078
|
let addr;
|
|
33079
33079
|
try {
|
|
33080
|
-
addr = new URL(location, address);
|
|
33080
|
+
addr = new URL$1(location, address);
|
|
33081
33081
|
} catch (e) {
|
|
33082
33082
|
emitErrorAndClose(websocket, /* @__PURE__ */ new SyntaxError(`Invalid URL: ${location}`));
|
|
33083
33083
|
return;
|
|
@@ -41425,12 +41425,24 @@ var SessionStore = class {
|
|
|
41425
41425
|
//#endregion
|
|
41426
41426
|
//#region src/terminal/pty-manager.ts
|
|
41427
41427
|
let pty = null;
|
|
41428
|
+
let ptyLoadError = null;
|
|
41428
41429
|
try {
|
|
41429
41430
|
pty = require("node-pty");
|
|
41430
|
-
} catch {
|
|
41431
|
+
} catch (err) {
|
|
41432
|
+
ptyLoadError = err instanceof Error ? err.message : String(err);
|
|
41433
|
+
}
|
|
41431
41434
|
const DISCONNECT_TIMEOUT_MS = 6e4;
|
|
41432
41435
|
const STATUS_INTERVAL_MS = 1e3;
|
|
41433
41436
|
const ACTIVE_THRESHOLD_MS = 2e3;
|
|
41437
|
+
const logDir$1 = node_path.join(node_path.dirname(new URL(require("url").pathToFileURL(__filename).href).pathname.replace(/^\/([A-Z]:)/i, "$1")), "..", "logs");
|
|
41438
|
+
function ptyLog(level, ...args) {
|
|
41439
|
+
try {
|
|
41440
|
+
node_fs.mkdirSync(logDir$1, { recursive: true });
|
|
41441
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
41442
|
+
const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
|
|
41443
|
+
node_fs.appendFileSync(node_path.join(logDir$1, `dashboard-${ts.slice(0, 10)}.log`), `[${ts}] [${level}] [pty-manager] ${msg}\n`);
|
|
41444
|
+
} catch {}
|
|
41445
|
+
}
|
|
41434
41446
|
var PtyManager = class PtyManager {
|
|
41435
41447
|
static instance = null;
|
|
41436
41448
|
session = null;
|
|
@@ -41443,16 +41455,21 @@ var PtyManager = class PtyManager {
|
|
|
41443
41455
|
}
|
|
41444
41456
|
spawn(opts) {
|
|
41445
41457
|
if (!pty) {
|
|
41458
|
+
ptyLog("ERROR", `node-pty not available: ${ptyLoadError}`);
|
|
41446
41459
|
this.broadcastToClients({
|
|
41447
41460
|
type: "output",
|
|
41448
|
-
data:
|
|
41461
|
+
data: `\r\n\x1b[31mTerminal unavailable: node-pty is not installed.\r\nError: ${ptyLoadError}\r\nRun: npm install node-pty\x1b[0m\r\n`
|
|
41449
41462
|
});
|
|
41450
41463
|
return;
|
|
41451
41464
|
}
|
|
41452
|
-
if (this.session)
|
|
41465
|
+
if (this.session) {
|
|
41466
|
+
ptyLog("INFO", "Killing existing session before spawn");
|
|
41467
|
+
this.kill();
|
|
41468
|
+
}
|
|
41453
41469
|
const shell = process.platform === "win32" ? "claude.cmd" : "claude";
|
|
41454
41470
|
const args = [];
|
|
41455
41471
|
if (opts.skipPermissions) args.push("--dangerously-skip-permissions");
|
|
41472
|
+
ptyLog("INFO", `Spawning: shell=${shell}, args=${JSON.stringify(args)}, cwd=${opts.cwd}, cols=${opts.cols ?? 120}, rows=${opts.rows ?? 30}`);
|
|
41456
41473
|
const proc = pty.spawn(shell, args, {
|
|
41457
41474
|
name: "xterm-256color",
|
|
41458
41475
|
cols: opts.cols ?? 120,
|
|
@@ -41460,6 +41477,7 @@ var PtyManager = class PtyManager {
|
|
|
41460
41477
|
cwd: opts.cwd,
|
|
41461
41478
|
env: process.env
|
|
41462
41479
|
});
|
|
41480
|
+
ptyLog("INFO", `Process spawned with pid=${proc.pid}`);
|
|
41463
41481
|
const store = new SessionStore();
|
|
41464
41482
|
this.session = {
|
|
41465
41483
|
process: proc,
|
|
@@ -41480,6 +41498,7 @@ var PtyManager = class PtyManager {
|
|
|
41480
41498
|
});
|
|
41481
41499
|
});
|
|
41482
41500
|
proc.onExit(({ exitCode }) => {
|
|
41501
|
+
ptyLog("INFO", `Process exited with code=${exitCode}`);
|
|
41483
41502
|
this.broadcastToClients({
|
|
41484
41503
|
type: "exit",
|
|
41485
41504
|
code: exitCode
|
|
@@ -41577,7 +41596,18 @@ var PtyManager = class PtyManager {
|
|
|
41577
41596
|
|
|
41578
41597
|
//#endregion
|
|
41579
41598
|
//#region src/server.ts
|
|
41599
|
+
const dashboardDir = node_path.dirname(new URL(require("url").pathToFileURL(__filename).href).pathname.replace(/^\/([A-Z]:)/i, "$1"));
|
|
41600
|
+
const logDir = node_path.join(dashboardDir, "logs");
|
|
41601
|
+
node_fs.mkdirSync(logDir, { recursive: true });
|
|
41602
|
+
const logFile = node_path.join(logDir, `dashboard-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.log`);
|
|
41603
|
+
const logStream = node_fs.createWriteStream(logFile, { flags: "a" });
|
|
41604
|
+
function log(level, tag, ...args) {
|
|
41605
|
+
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [${level}] [${tag}] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}\n`;
|
|
41606
|
+
logStream.write(line);
|
|
41607
|
+
if (level === "ERROR") console.error(`[${tag}]`, ...args);
|
|
41608
|
+
}
|
|
41580
41609
|
const projectCwd = process.env.MAXSIM_PROJECT_CWD || process.cwd();
|
|
41610
|
+
log("INFO", "server", `Starting dashboard server, projectCwd=${projectCwd}`);
|
|
41581
41611
|
const clientDir = node_path.join(__dirname, "client");
|
|
41582
41612
|
function isWithinPlanning(cwd, targetPath) {
|
|
41583
41613
|
const planningDir = node_path.resolve(cwd, ".planning");
|
|
@@ -41941,6 +41971,24 @@ app.get("/api/roadmap", (_req, res) => {
|
|
|
41941
41971
|
if (!data) return res.status(404).json({ error: "ROADMAP.md not found" });
|
|
41942
41972
|
return res.json(data);
|
|
41943
41973
|
});
|
|
41974
|
+
app.patch("/api/roadmap", (req, res) => {
|
|
41975
|
+
const roadmapPath = node_path.join(projectCwd, ".planning", "ROADMAP.md");
|
|
41976
|
+
if (!node_fs.existsSync(roadmapPath)) return res.status(404).json({ error: "ROADMAP.md not found" });
|
|
41977
|
+
const { phaseNumber, checked } = req.body;
|
|
41978
|
+
if (!phaseNumber || checked === void 0) return res.status(400).json({ error: "phaseNumber and checked are required" });
|
|
41979
|
+
let content = node_fs.readFileSync(roadmapPath, "utf-8");
|
|
41980
|
+
const escapedNum = phaseNumber.replace(".", "\\.");
|
|
41981
|
+
const pattern = new RegExp(`(-\\s*\\[)(x| )(\\]\\s*.*Phase\\s+${escapedNum})`, "i");
|
|
41982
|
+
if (!content.match(pattern)) return res.status(404).json({ error: `Phase ${phaseNumber} checkbox not found in ROADMAP.md` });
|
|
41983
|
+
content = content.replace(pattern, `$1${checked ? "x" : " "}$3`);
|
|
41984
|
+
suppressPath(roadmapPath);
|
|
41985
|
+
node_fs.writeFileSync(roadmapPath, content, "utf-8");
|
|
41986
|
+
return res.json({
|
|
41987
|
+
updated: true,
|
|
41988
|
+
phaseNumber,
|
|
41989
|
+
checked
|
|
41990
|
+
});
|
|
41991
|
+
});
|
|
41944
41992
|
app.get("/api/state", (_req, res) => {
|
|
41945
41993
|
const data = parseState(projectCwd);
|
|
41946
41994
|
if (!data) return res.status(404).json({ error: "STATE.md not found" });
|
|
@@ -41961,6 +42009,66 @@ app.patch("/api/state", (req, res) => {
|
|
|
41961
42009
|
field
|
|
41962
42010
|
});
|
|
41963
42011
|
});
|
|
42012
|
+
function ensureStateMd(statePath) {
|
|
42013
|
+
if (node_fs.existsSync(statePath)) return;
|
|
42014
|
+
const planningDir = node_path.dirname(statePath);
|
|
42015
|
+
node_fs.mkdirSync(planningDir, { recursive: true });
|
|
42016
|
+
const template = `# Project State
|
|
42017
|
+
|
|
42018
|
+
## Current Position
|
|
42019
|
+
|
|
42020
|
+
Phase: 1
|
|
42021
|
+
Status: In progress
|
|
42022
|
+
Last activity: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]} — State file created
|
|
42023
|
+
|
|
42024
|
+
## Accumulated Context
|
|
42025
|
+
|
|
42026
|
+
### Decisions
|
|
42027
|
+
|
|
42028
|
+
None yet.
|
|
42029
|
+
|
|
42030
|
+
### Blockers/Concerns
|
|
42031
|
+
|
|
42032
|
+
None yet.
|
|
42033
|
+
`;
|
|
42034
|
+
node_fs.writeFileSync(statePath, template, "utf-8");
|
|
42035
|
+
}
|
|
42036
|
+
function appendToStateSection(statePath, sectionPattern, entry, fallbackSection) {
|
|
42037
|
+
let content = node_fs.readFileSync(statePath, "utf-8").replace(/\r\n/g, "\n");
|
|
42038
|
+
const match = content.match(sectionPattern);
|
|
42039
|
+
if (match) {
|
|
42040
|
+
let sectionBody = match[2];
|
|
42041
|
+
sectionBody = sectionBody.replace(/None yet\.?\s*\n?/gi, "").replace(/No decisions yet\.?\s*\n?/gi, "").replace(/None\.?\s*\n?/gi, "");
|
|
42042
|
+
sectionBody = sectionBody.trimEnd() + "\n" + entry + "\n";
|
|
42043
|
+
content = content.replace(sectionPattern, (_m, header) => `${header}${sectionBody}`);
|
|
42044
|
+
} else content = content.trimEnd() + "\n\n" + fallbackSection + "\n" + entry + "\n";
|
|
42045
|
+
suppressPath(statePath);
|
|
42046
|
+
node_fs.writeFileSync(statePath, content, "utf-8");
|
|
42047
|
+
return { success: true };
|
|
42048
|
+
}
|
|
42049
|
+
app.post("/api/state/decision", (req, res) => {
|
|
42050
|
+
const statePath = node_path.join(projectCwd, ".planning", "STATE.md");
|
|
42051
|
+
ensureStateMd(statePath);
|
|
42052
|
+
const { phase, text } = req.body;
|
|
42053
|
+
if (!text?.trim()) return res.status(400).json({ error: "text is required" });
|
|
42054
|
+
const entry = `- [Phase ${phase?.trim() || "?"}]: ${text.trim()}`;
|
|
42055
|
+
appendToStateSection(statePath, /(###?\s*(?:Decisions|Decisions Made|Accumulated.*Decisions)\s*\n)([\s\S]*?)(?=\n###?|\n##[^#]|$)/i, entry, "### Decisions");
|
|
42056
|
+
return res.json({
|
|
42057
|
+
added: true,
|
|
42058
|
+
decision: entry
|
|
42059
|
+
});
|
|
42060
|
+
});
|
|
42061
|
+
app.post("/api/state/blocker", (req, res) => {
|
|
42062
|
+
const statePath = node_path.join(projectCwd, ".planning", "STATE.md");
|
|
42063
|
+
ensureStateMd(statePath);
|
|
42064
|
+
const { text } = req.body;
|
|
42065
|
+
if (!text?.trim()) return res.status(400).json({ error: "text is required" });
|
|
42066
|
+
appendToStateSection(statePath, /(###?\s*(?:Blockers|Blockers\/Concerns|Concerns)\s*\n)([\s\S]*?)(?=\n###?|\n##[^#]|$)/i, `- ${text.trim()}`, "### Blockers/Concerns");
|
|
42067
|
+
return res.json({
|
|
42068
|
+
added: true,
|
|
42069
|
+
blocker: text.trim()
|
|
42070
|
+
});
|
|
42071
|
+
});
|
|
41964
42072
|
app.get("/api/phases", (_req, res) => {
|
|
41965
42073
|
const phases = parsePhases(projectCwd);
|
|
41966
42074
|
return res.json(phases);
|
|
@@ -42078,13 +42186,18 @@ async function main() {
|
|
|
42078
42186
|
const wss = createWSS();
|
|
42079
42187
|
const terminalWss = new import_websocket_server.default({ noServer: true });
|
|
42080
42188
|
const ptyManager = PtyManager.getInstance();
|
|
42081
|
-
if (!ptyManager.isAvailable())
|
|
42189
|
+
if (!ptyManager.isAvailable()) log("WARN", "server", "node-pty not available — terminal features disabled");
|
|
42190
|
+
else log("INFO", "server", "node-pty available — terminal features enabled");
|
|
42082
42191
|
terminalWss.on("connection", (ws) => {
|
|
42192
|
+
log("INFO", "terminal-ws", "Client connected");
|
|
42083
42193
|
ptyManager.addClient(ws);
|
|
42084
|
-
if (!ptyManager.isAvailable())
|
|
42085
|
-
|
|
42086
|
-
|
|
42087
|
-
|
|
42194
|
+
if (!ptyManager.isAvailable()) {
|
|
42195
|
+
ws.send(JSON.stringify({
|
|
42196
|
+
type: "unavailable",
|
|
42197
|
+
reason: "node-pty is not installed — terminal features disabled"
|
|
42198
|
+
}));
|
|
42199
|
+
log("WARN", "terminal-ws", "Sent unavailable to client — node-pty missing");
|
|
42200
|
+
}
|
|
42088
42201
|
ws.on("message", (raw) => {
|
|
42089
42202
|
try {
|
|
42090
42203
|
const msg = JSON.parse(typeof raw === "string" ? raw : raw.toString());
|
|
@@ -42093,27 +42206,44 @@ async function main() {
|
|
|
42093
42206
|
ptyManager.write(msg.data);
|
|
42094
42207
|
break;
|
|
42095
42208
|
case "resize":
|
|
42209
|
+
log("INFO", "terminal-ws", `Resize: ${msg.cols}x${msg.rows}`);
|
|
42096
42210
|
ptyManager.resize(msg.cols, msg.rows);
|
|
42097
42211
|
break;
|
|
42098
42212
|
case "spawn":
|
|
42099
|
-
|
|
42100
|
-
|
|
42101
|
-
|
|
42102
|
-
|
|
42103
|
-
|
|
42104
|
-
|
|
42213
|
+
log("INFO", "terminal-ws", `Spawn requested: skipPermissions=${!!msg.skipPermissions}, cwd=${projectCwd}`);
|
|
42214
|
+
try {
|
|
42215
|
+
ptyManager.spawn({
|
|
42216
|
+
skipPermissions: !!msg.skipPermissions,
|
|
42217
|
+
cwd: projectCwd,
|
|
42218
|
+
cols: msg.cols,
|
|
42219
|
+
rows: msg.rows
|
|
42220
|
+
});
|
|
42221
|
+
log("INFO", "terminal-ws", `Spawn succeeded, pid=${ptyManager.getStatus()?.pid}`);
|
|
42222
|
+
} catch (err) {
|
|
42223
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
42224
|
+
log("ERROR", "terminal-ws", `Spawn failed: ${errMsg}`);
|
|
42225
|
+
ws.send(JSON.stringify({
|
|
42226
|
+
type: "output",
|
|
42227
|
+
data: `\r\n\x1b[31mFailed to start terminal: ${errMsg}\x1b[0m\r\n`
|
|
42228
|
+
}));
|
|
42229
|
+
}
|
|
42105
42230
|
break;
|
|
42106
42231
|
case "kill":
|
|
42232
|
+
log("INFO", "terminal-ws", "Kill requested");
|
|
42107
42233
|
ptyManager.kill();
|
|
42108
42234
|
break;
|
|
42235
|
+
default: log("WARN", "terminal-ws", `Unknown message type: ${msg.type}`);
|
|
42109
42236
|
}
|
|
42110
|
-
} catch {
|
|
42237
|
+
} catch (err) {
|
|
42238
|
+
log("ERROR", "terminal-ws", `Message handling error: ${err instanceof Error ? err.message : String(err)}`);
|
|
42239
|
+
}
|
|
42111
42240
|
});
|
|
42112
42241
|
ws.on("close", () => {
|
|
42242
|
+
log("INFO", "terminal-ws", "Client disconnected");
|
|
42113
42243
|
ptyManager.removeClient(ws);
|
|
42114
42244
|
});
|
|
42115
42245
|
ws.on("error", (err) => {
|
|
42116
|
-
|
|
42246
|
+
log("ERROR", "terminal-ws", `Client error: ${err.message}`);
|
|
42117
42247
|
});
|
|
42118
42248
|
});
|
|
42119
42249
|
const server = (0, node_http.createServer)(app);
|
|
@@ -42136,7 +42266,9 @@ async function main() {
|
|
|
42136
42266
|
const port = await esm_default(3333);
|
|
42137
42267
|
const url = `http://localhost:${port}`;
|
|
42138
42268
|
server.listen(port, () => {
|
|
42269
|
+
log("INFO", "server", `Dashboard ready at ${url}, log file: ${logFile}`);
|
|
42139
42270
|
console.error(`Dashboard ready at ${url}`);
|
|
42271
|
+
console.error(`Logs: ${logFile}`);
|
|
42140
42272
|
open$1(url).catch(() => {});
|
|
42141
42273
|
});
|
|
42142
42274
|
function shutdown() {
|
package/package.json
CHANGED