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-BwUvessa.js"></script>
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: "\r\n\x1B[31mTerminal unavailable: node-pty is not installed.\r\nRun: npm install node-pty\x1B[0m\r\n"
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) this.kill();
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()) console.error("[server] node-pty not available — terminal features disabled");
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()) ws.send(JSON.stringify({
42085
- type: "unavailable",
42086
- reason: "node-pty is not installed — terminal features disabled"
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
- ptyManager.spawn({
42100
- skipPermissions: !!msg.skipPermissions,
42101
- cwd: projectCwd,
42102
- cols: msg.cols,
42103
- rows: msg.rows
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
- console.error("[terminal-ws] Client error:", err.message);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maxsimcli",
3
- "version": "2.5.1",
3
+ "version": "2.5.3",
4
4
  "private": false,
5
5
  "description": "A meta-prompting, context engineering and spec-driven development system for Claude Code, OpenCode, Gemini and Codex by MayStudios.",
6
6
  "bin": {