mexus-cli 1.0.0 → 1.0.1

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.
Files changed (56) hide show
  1. package/package.json +1 -1
  2. package/packages/server/dist/cli.mjs +191 -12
  3. package/packages/server/dist/cli.mjs.map +1 -1
  4. package/packages/web/dist/assets/{_basePickBy-B0zzcSaC.js → _basePickBy-DQhOWiJk.js} +1 -1
  5. package/packages/web/dist/assets/{_baseUniq-B-4_EE7n.js → _baseUniq-DXTx6DDJ.js} +1 -1
  6. package/packages/web/dist/assets/{arc-DFOgsfTK.js → arc-D98xlvrt.js} +1 -1
  7. package/packages/web/dist/assets/{architectureDiagram-2XIMDMQ5-CNksmKJ-.js → architectureDiagram-2XIMDMQ5-BFC9xn2H.js} +1 -1
  8. package/packages/web/dist/assets/{blockDiagram-WCTKOSBZ-B1Tw0xWQ.js → blockDiagram-WCTKOSBZ-DJH8Soam.js} +1 -1
  9. package/packages/web/dist/assets/{c4Diagram-IC4MRINW-BC3Xs_CM.js → c4Diagram-IC4MRINW-w36rnsiL.js} +1 -1
  10. package/packages/web/dist/assets/channel-s9cXVaHr.js +1 -0
  11. package/packages/web/dist/assets/{chunk-4BX2VUAB-Bc_dSZCa.js → chunk-4BX2VUAB-SF13Eulk.js} +1 -1
  12. package/packages/web/dist/assets/{chunk-55IACEB6-BkpubxQa.js → chunk-55IACEB6-wMI9Klww.js} +1 -1
  13. package/packages/web/dist/assets/{chunk-FMBD7UC4-DfsMHPhA.js → chunk-FMBD7UC4-WwcC59gR.js} +1 -1
  14. package/packages/web/dist/assets/{chunk-JSJVCQXG-DQnDNPz7.js → chunk-JSJVCQXG-DvXmNU5-.js} +1 -1
  15. package/packages/web/dist/assets/{chunk-KX2RTZJC-BoujkdYL.js → chunk-KX2RTZJC-BdEEznCp.js} +1 -1
  16. package/packages/web/dist/assets/{chunk-NQ4KR5QH-BI0GEUMc.js → chunk-NQ4KR5QH-BwNAeHYs.js} +1 -1
  17. package/packages/web/dist/assets/{chunk-QZHKN3VN-Dq4w7tDq.js → chunk-QZHKN3VN-C2xATrOG.js} +1 -1
  18. package/packages/web/dist/assets/{chunk-WL4C6EOR-DSQ5ZWfk.js → chunk-WL4C6EOR-CEAL3q8O.js} +1 -1
  19. package/packages/web/dist/assets/classDiagram-VBA2DB6C-quXqjdGh.js +1 -0
  20. package/packages/web/dist/assets/classDiagram-v2-RAHNMMFH-quXqjdGh.js +1 -0
  21. package/packages/web/dist/assets/clone-BwNC5Rz2.js +1 -0
  22. package/packages/web/dist/assets/{cose-bilkent-S5V4N54A-Caq6VRnC.js → cose-bilkent-S5V4N54A-DMB9iF_s.js} +1 -1
  23. package/packages/web/dist/assets/{dagre-KLK3FWXG-D1rt0jGa.js → dagre-KLK3FWXG-B3CBp1UR.js} +1 -1
  24. package/packages/web/dist/assets/{diagram-E7M64L7V-BBrZhLH7.js → diagram-E7M64L7V-BP3gXbyt.js} +1 -1
  25. package/packages/web/dist/assets/{diagram-IFDJBPK2-BFSSudzv.js → diagram-IFDJBPK2-DiWKPyS1.js} +1 -1
  26. package/packages/web/dist/assets/{diagram-P4PSJMXO-C3oU7Ool.js → diagram-P4PSJMXO-BRwIWc-T.js} +1 -1
  27. package/packages/web/dist/assets/{erDiagram-INFDFZHY-D0cx2_2Y.js → erDiagram-INFDFZHY-CwNQ0bqL.js} +1 -1
  28. package/packages/web/dist/assets/{flowDiagram-PKNHOUZH-BXvZGiWz.js → flowDiagram-PKNHOUZH-CGwKqUfG.js} +1 -1
  29. package/packages/web/dist/assets/{ganttDiagram-A5KZAMGK-C9JOODgY.js → ganttDiagram-A5KZAMGK-CwfwEk-O.js} +1 -1
  30. package/packages/web/dist/assets/{gitGraphDiagram-K3NZZRJ6-BiIWik3M.js → gitGraphDiagram-K3NZZRJ6-BU-TCNoX.js} +1 -1
  31. package/packages/web/dist/assets/{graph-KIQcHS1V.js → graph-BpGuAB34.js} +1 -1
  32. package/packages/web/dist/assets/{index-CMzYPOPG.js → index-BQZEjwBD.js} +233 -193
  33. package/packages/web/dist/assets/{infoDiagram-LFFYTUFH-DV6kISOT.js → infoDiagram-LFFYTUFH-OgqnEPLD.js} +1 -1
  34. package/packages/web/dist/assets/{ishikawaDiagram-PHBUUO56-Dko7qIR3.js → ishikawaDiagram-PHBUUO56-C7q1YvZf.js} +1 -1
  35. package/packages/web/dist/assets/{journeyDiagram-4ABVD52K-_FLfsCtQ.js → journeyDiagram-4ABVD52K-BFTnwlYT.js} +1 -1
  36. package/packages/web/dist/assets/{kanban-definition-K7BYSVSG-Bjf_Hkam.js → kanban-definition-K7BYSVSG-BPNSFbTq.js} +1 -1
  37. package/packages/web/dist/assets/{layout-D09tLn9J.js → layout-DiHSY-T6.js} +1 -1
  38. package/packages/web/dist/assets/{linear-BnF-DuHG.js → linear-DcbEPsvj.js} +1 -1
  39. package/packages/web/dist/assets/{mindmap-definition-YRQLILUH-C4ui5Uen.js → mindmap-definition-YRQLILUH-CalG0npn.js} +1 -1
  40. package/packages/web/dist/assets/{pieDiagram-SKSYHLDU-Chjj2B6Z.js → pieDiagram-SKSYHLDU-D1PyVe3u.js} +1 -1
  41. package/packages/web/dist/assets/{quadrantDiagram-337W2JSQ-BgcnBVtA.js → quadrantDiagram-337W2JSQ-bTKx0-2j.js} +1 -1
  42. package/packages/web/dist/assets/{requirementDiagram-Z7DCOOCP-D8i7_HQl.js → requirementDiagram-Z7DCOOCP-DHyIVcFu.js} +1 -1
  43. package/packages/web/dist/assets/{sankeyDiagram-WA2Y5GQK-CE8F22pR.js → sankeyDiagram-WA2Y5GQK-CifZqZcJ.js} +1 -1
  44. package/packages/web/dist/assets/{sequenceDiagram-2WXFIKYE-BIpm8kwX.js → sequenceDiagram-2WXFIKYE-DK8qO73H.js} +1 -1
  45. package/packages/web/dist/assets/{stateDiagram-RAJIS63D-lboAMp3Q.js → stateDiagram-RAJIS63D-BoK_s4xU.js} +1 -1
  46. package/packages/web/dist/assets/stateDiagram-v2-FVOUBMTO-BKcMBcxU.js +1 -0
  47. package/packages/web/dist/assets/{timeline-definition-YZTLITO2-Dh94GN9W.js → timeline-definition-YZTLITO2-GwB8m3Pz.js} +1 -1
  48. package/packages/web/dist/assets/{treemap-KZPCXAKY-Cnfp1I4Q.js → treemap-KZPCXAKY-RvN0JaqD.js} +1 -1
  49. package/packages/web/dist/assets/{vennDiagram-LZ73GAT5-oM-IB92W.js → vennDiagram-LZ73GAT5-OnlpPkDW.js} +1 -1
  50. package/packages/web/dist/assets/{xychartDiagram-JWTSCODW-rBsEDTWK.js → xychartDiagram-JWTSCODW-Dv-KEW3d.js} +1 -1
  51. package/packages/web/dist/index.html +1 -1
  52. package/packages/web/dist/assets/channel-BolzzYH1.js +0 -1
  53. package/packages/web/dist/assets/classDiagram-VBA2DB6C-DXgRkMh7.js +0 -1
  54. package/packages/web/dist/assets/classDiagram-v2-RAHNMMFH-DXgRkMh7.js +0 -1
  55. package/packages/web/dist/assets/clone-BD_2Dvk1.js +0 -1
  56. package/packages/web/dist/assets/stateDiagram-v2-FVOUBMTO-BYDSvNCG.js +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mexus-cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Local web console for managing multiple CLI AI Agent instances in parallel",
5
5
  "type": "module",
6
6
  "bin": {
@@ -45,9 +45,34 @@ var init_ConfigManager = __esm({
45
45
  statusline: true,
46
46
  env: {}
47
47
  },
48
+ codex: {
49
+ bin: "codex",
50
+ continue_flag: "",
51
+ resume_flag: "",
52
+ yolo_flag: "",
53
+ statusline: false,
54
+ env: {}
55
+ },
48
56
  opencode: {
49
57
  bin: "opencode",
50
58
  continue_flag: "--continue",
59
+ resume_flag: "",
60
+ yolo_flag: "--yolo",
61
+ statusline: false,
62
+ env: {}
63
+ },
64
+ "kimi-cli": {
65
+ bin: "kimi",
66
+ continue_flag: "--continue",
67
+ resume_flag: "",
68
+ yolo_flag: "",
69
+ statusline: false,
70
+ env: {}
71
+ },
72
+ qodercli: {
73
+ bin: "qodercli",
74
+ continue_flag: "-c",
75
+ resume_flag: "-r",
51
76
  yolo_flag: "--yolo",
52
77
  statusline: false,
53
78
  env: {}
@@ -147,7 +172,7 @@ var init_ConfigManager = __esm({
147
172
  { key: "codex", bin: "codex", flag: "", statusline: false },
148
173
  { key: "opencode", bin: "opencode", flag: "--continue", statusline: false },
149
174
  { key: "kimi-cli", bin: "kimi", flag: "--continue", statusline: false },
150
- { key: "qwencode", bin: "qwen-code", flag: "--continue", statusline: false }
175
+ { key: "qodercli", bin: "qodercli", flag: "-c", statusline: false }
151
176
  ];
152
177
  const results = await Promise.allSettled(
153
178
  agentBins.map(async (agent) => {
@@ -210,7 +235,7 @@ var init_ConfigManager = __esm({
210
235
  { key: "codex", bin: "codex", installHint: "npm install -g @openai/codex" },
211
236
  { key: "opencode", bin: "opencode", installHint: "go install github.com/opencode-ai/opencode@latest" },
212
237
  { key: "kimi-cli", bin: "kimi", installHint: "pip install kimi-cli" },
213
- { key: "qwencode", bin: "qwen-code", installHint: "pip install qwen-code" }
238
+ { key: "qodercli", bin: "qodercli", installHint: "See https://docs.qoder.com/zh/cli/using-cli" }
214
239
  ];
215
240
  const checks = await Promise.allSettled(
216
241
  knownAgents.map(async (agent) => {
@@ -275,6 +300,7 @@ var KNOWN_FIELDS = {
275
300
  // Claude Code may add more fields — add them here as discovered
276
301
  };
277
302
  var MIN_KNOWN_FIELDS = 2;
303
+ var MAX_BUFFER_SIZE = 64 * 1024;
278
304
  var StatuslineParser = class {
279
305
  buffer = "";
280
306
  /**
@@ -286,6 +312,9 @@ var StatuslineParser = class {
286
312
  let meta = null;
287
313
  if (!data.includes("\n")) {
288
314
  this.buffer += data;
315
+ if (this.buffer.length > MAX_BUFFER_SIZE) {
316
+ this.buffer = "";
317
+ }
289
318
  return { cleanData: data, meta: null };
290
319
  }
291
320
  const combined = this.buffer + data;
@@ -913,9 +942,17 @@ var PtyManager = class {
913
942
  entry.stateAnalyzer.onOutput();
914
943
  entry.scrollback.push(cleanData);
915
944
  entry.scrollbackBytes += cleanData.length;
916
- while (entry.scrollbackBytes > MAX_SCROLLBACK_BYTES && entry.scrollback.length > 1) {
917
- const removed = entry.scrollback.shift();
918
- entry.scrollbackBytes -= removed.length;
945
+ if (entry.scrollbackBytes > MAX_SCROLLBACK_BYTES) {
946
+ let bytesToRemove = entry.scrollbackBytes - MAX_SCROLLBACK_BYTES;
947
+ let removeCount = 0;
948
+ while (removeCount < entry.scrollback.length - 1 && bytesToRemove > 0) {
949
+ bytesToRemove -= entry.scrollback[removeCount].length;
950
+ entry.scrollbackBytes -= entry.scrollback[removeCount].length;
951
+ removeCount++;
952
+ }
953
+ if (removeCount > 0) {
954
+ entry.scrollback.splice(0, removeCount);
955
+ }
919
956
  }
920
957
  for (const cb of entry.onDataCallbacks) {
921
958
  cb(cleanData);
@@ -1101,6 +1138,35 @@ var WorktreeManager = class {
1101
1138
  this.worktrees.set(paneId, entry);
1102
1139
  return { worktreePath, branch };
1103
1140
  }
1141
+ /**
1142
+ * Restore a worktree from a previous session.
1143
+ * If the worktree directory still exists, re-register it.
1144
+ * If not, recreate it from the existing branch.
1145
+ * Returns false if the branch no longer exists (stale config).
1146
+ */
1147
+ async restore(paneId, branch, worktreePath) {
1148
+ const baseBranch = await this.getCurrentBranch();
1149
+ try {
1150
+ await this.git.raw(["rev-parse", "--verify", branch]);
1151
+ } catch {
1152
+ return false;
1153
+ }
1154
+ if (fs3.existsSync(worktreePath)) {
1155
+ this.worktrees.set(paneId, { path: worktreePath, branch, baseBranch });
1156
+ return true;
1157
+ }
1158
+ try {
1159
+ await this.git.raw(["worktree", "prune"]).catch(() => {
1160
+ });
1161
+ fs3.mkdirSync(path3.dirname(worktreePath), { recursive: true });
1162
+ await this.git.raw(["worktree", "add", worktreePath, branch]);
1163
+ this.worktrees.set(paneId, { path: worktreePath, branch, baseBranch });
1164
+ return true;
1165
+ } catch (err) {
1166
+ console.warn(`[WorktreeManager] Failed to restore worktree for ${paneId}:`, err.message);
1167
+ return false;
1168
+ }
1169
+ }
1104
1170
  /**
1105
1171
  * Remove a worktree. Branch is kept for later merge/PR.
1106
1172
  */
@@ -1181,6 +1247,60 @@ var WorktreeManager = class {
1181
1247
  }
1182
1248
  return diffs;
1183
1249
  }
1250
+ /**
1251
+ * Merge the worktree branch into the base branch (e.g. main).
1252
+ * First commits any uncommitted changes in the worktree, then merges.
1253
+ */
1254
+ async merge(paneId) {
1255
+ const entry = this.worktrees.get(paneId);
1256
+ if (!entry) {
1257
+ return { success: false, message: "Worktree not found for this pane" };
1258
+ }
1259
+ const wtGit = simpleGit(entry.path);
1260
+ try {
1261
+ const status = await wtGit.status();
1262
+ const hasChanges = status.modified.length > 0 || status.created.length > 0 || status.deleted.length > 0 || status.staged.length > 0 || status.not_added.length > 0;
1263
+ if (hasChanges) {
1264
+ await wtGit.add("-A");
1265
+ await wtGit.commit(`nexus: auto-commit before merge (${entry.branch})`);
1266
+ }
1267
+ const log = await wtGit.log([`${entry.baseBranch}..${entry.branch}`]);
1268
+ if (log.total === 0) {
1269
+ return { success: false, message: "No changes to merge" };
1270
+ }
1271
+ await this.git.merge([entry.branch]);
1272
+ return {
1273
+ success: true,
1274
+ message: `Merged ${log.total} commit${log.total !== 1 ? "s" : ""} from ${entry.branch} into ${entry.baseBranch}`
1275
+ };
1276
+ } catch (err) {
1277
+ try {
1278
+ await this.git.merge(["--abort"]);
1279
+ } catch {
1280
+ }
1281
+ return {
1282
+ success: false,
1283
+ message: `Merge conflict: ${err.message}`
1284
+ };
1285
+ }
1286
+ }
1287
+ /**
1288
+ * Discard all changes: remove worktree and delete the branch.
1289
+ */
1290
+ async discard(paneId) {
1291
+ const entry = this.worktrees.get(paneId);
1292
+ if (!entry) {
1293
+ return { success: false, message: "Worktree not found for this pane" };
1294
+ }
1295
+ const branch = entry.branch;
1296
+ await this.forceRemoveWorktree(entry.path);
1297
+ try {
1298
+ await this.git.raw(["branch", "-D", branch]);
1299
+ } catch {
1300
+ }
1301
+ this.worktrees.delete(paneId);
1302
+ return { success: true, message: `Discarded branch ${branch}` };
1303
+ }
1184
1304
  getWorktreePath(paneId) {
1185
1305
  return this.worktrees.get(paneId)?.path;
1186
1306
  }
@@ -1494,7 +1614,7 @@ var WorkspaceManager = class {
1494
1614
  this.ptyManager = new PtyManager(configManager);
1495
1615
  this.worktreeManager = new WorktreeManager(configManager.getProjectDir());
1496
1616
  }
1497
- init() {
1617
+ async init() {
1498
1618
  const wsConfig = this.configManager.initWorkspace();
1499
1619
  this.wsName = wsConfig.name;
1500
1620
  this.wsDescription = wsConfig.description || "";
@@ -1511,8 +1631,25 @@ var WorkspaceManager = class {
1511
1631
  if (paneConfig.sessionId && paneConfig.agent !== "__shell__") {
1512
1632
  paneConfig.restore = "resume";
1513
1633
  }
1634
+ if (paneConfig.isolation === "worktree" && paneConfig.branch && paneConfig.worktreePath) {
1635
+ try {
1636
+ const restored = await this.worktreeManager.restore(paneConfig.id, paneConfig.branch, paneConfig.worktreePath);
1637
+ if (!restored) {
1638
+ console.warn(`Skipping worktree pane ${paneConfig.id} (${paneConfig.name}): branch no longer exists`);
1639
+ failCount++;
1640
+ continue;
1641
+ }
1642
+ } catch (err) {
1643
+ console.warn(`Skipping worktree pane ${paneConfig.id} (${paneConfig.name}): restore failed:`, err.message);
1644
+ failCount++;
1645
+ continue;
1646
+ }
1647
+ }
1514
1648
  try {
1515
1649
  this.spawnPane(paneConfig);
1650
+ if (paneConfig.isolation === "worktree" && paneConfig.worktreePath) {
1651
+ await this.startPaneGitService(paneConfig.id, paneConfig.worktreePath);
1652
+ }
1516
1653
  } catch (err) {
1517
1654
  console.warn(`Skipping stale pane ${paneConfig.id} (${paneConfig.name}):`, err.message);
1518
1655
  failCount++;
@@ -1605,6 +1742,28 @@ var WorkspaceManager = class {
1605
1742
  this.spawnPane(config);
1606
1743
  this.updatePaneConfigSessionId(paneId, resolvedSessionId);
1607
1744
  }
1745
+ async mergeWorktree(paneId) {
1746
+ const pane = this.panes.get(paneId);
1747
+ if (!pane || pane.isolation !== "worktree") {
1748
+ return { success: false, message: "Pane is not a worktree pane" };
1749
+ }
1750
+ return this.worktreeManager.merge(paneId);
1751
+ }
1752
+ async discardWorktree(paneId) {
1753
+ const pane = this.panes.get(paneId);
1754
+ if (!pane || pane.isolation !== "worktree") {
1755
+ return { success: false, message: "Pane is not a worktree pane" };
1756
+ }
1757
+ this.stopPaneGitService(paneId);
1758
+ const result = await this.worktreeManager.discard(paneId);
1759
+ if (result.success) {
1760
+ pane.isolation = "shared";
1761
+ pane.worktreePath = void 0;
1762
+ pane.branch = void 0;
1763
+ this.emit("onPaneDiff", paneId, []);
1764
+ }
1765
+ return result;
1766
+ }
1608
1767
  writeToPane(paneId, data) {
1609
1768
  this.ptyManager.write(paneId, data);
1610
1769
  }
@@ -1795,7 +1954,6 @@ var WorkspaceManager = class {
1795
1954
  for (const [paneId] of this.perPaneGitServices) {
1796
1955
  this.stopPaneGitService(paneId);
1797
1956
  }
1798
- await this.worktreeManager.removeAll();
1799
1957
  }
1800
1958
  };
1801
1959
 
@@ -2024,18 +2182,23 @@ function setupWsHandlers(socket, workspaceManager, gitService) {
2024
2182
  state
2025
2183
  });
2026
2184
  const SCROLLBACK_CHUNK_SIZE = 64 * 1024;
2027
- for (const pane of state.panes) {
2028
- const scrollback = workspaceManager.getScrollback(pane.id);
2029
- if (scrollback) {
2185
+ const replayScrollback = async () => {
2186
+ for (const pane of state.panes) {
2187
+ const scrollback = workspaceManager.getScrollback(pane.id);
2188
+ if (!scrollback) continue;
2030
2189
  if (scrollback.length <= SCROLLBACK_CHUNK_SIZE) {
2031
2190
  send({ type: "terminal.output", paneId: pane.id, data: scrollback });
2032
2191
  } else {
2033
2192
  for (let i = 0; i < scrollback.length; i += SCROLLBACK_CHUNK_SIZE) {
2193
+ if (socket.readyState !== socket.OPEN) return;
2034
2194
  send({ type: "terminal.output", paneId: pane.id, data: scrollback.slice(i, i + SCROLLBACK_CHUNK_SIZE) });
2195
+ await new Promise((resolve) => setImmediate(resolve));
2035
2196
  }
2036
2197
  }
2037
2198
  }
2038
- }
2199
+ };
2200
+ replayScrollback().catch(() => {
2201
+ });
2039
2202
  const paneDiffs = workspaceManager.getPaneDiffs();
2040
2203
  for (const [paneId, diffs] of paneDiffs) {
2041
2204
  if (diffs.length > 0) {
@@ -2163,6 +2326,22 @@ function setupWsHandlers(socket, workspaceManager, gitService) {
2163
2326
  });
2164
2327
  }
2165
2328
  break;
2329
+ case "pane.merge":
2330
+ workspaceManager.mergeWorktree(event.paneId).then((result) => {
2331
+ send({ type: "pane.merge.result", paneId: event.paneId, ...result });
2332
+ gitService?.refresh();
2333
+ }).catch((err) => {
2334
+ send({ type: "pane.merge.result", paneId: event.paneId, success: false, message: String(err) });
2335
+ });
2336
+ break;
2337
+ case "pane.discard":
2338
+ workspaceManager.discardWorktree(event.paneId).then((result) => {
2339
+ send({ type: "pane.merge.result", paneId: event.paneId, ...result });
2340
+ gitService?.refresh();
2341
+ }).catch((err) => {
2342
+ send({ type: "pane.merge.result", paneId: event.paneId, success: false, message: String(err) });
2343
+ });
2344
+ break;
2166
2345
  case "pane.diff.refresh":
2167
2346
  workspaceManager.refreshPaneDiff(event.paneId);
2168
2347
  break;
@@ -2742,7 +2921,7 @@ async function startServer(port, projectDir) {
2742
2921
  const configManager = new ConfigManager(projectDir);
2743
2922
  configManager.loadGlobalConfig();
2744
2923
  const workspaceManager = new WorkspaceManager(configManager);
2745
- workspaceManager.init();
2924
+ await workspaceManager.init();
2746
2925
  const agentsWriter = new AgentsYamlWriter(projectDir);
2747
2926
  workspaceManager.onEvents({
2748
2927
  onPaneAdded: () => agentsWriter.update(workspaceManager.getPanes()),