jinzd-ai-cli 0.4.72 → 0.4.74

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.
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- ConfigManager,
4
3
  HALLUCINATION_CORRECTION_MESSAGE,
5
4
  McpManager,
6
5
  ProviderRegistry,
@@ -21,10 +20,13 @@ import {
21
20
  persistToolRound,
22
21
  rebuildExtraMessages,
23
22
  setupProxy
24
- } from "./chunk-57HHY5ZX.js";
23
+ } from "./chunk-PLJUAA3J.js";
25
24
  import {
26
25
  AuthManager
27
26
  } from "./chunk-BYNY5JPB.js";
27
+ import {
28
+ ConfigManager
29
+ } from "./chunk-VG3MFZYG.js";
28
30
  import {
29
31
  ToolExecutor,
30
32
  ToolRegistry,
@@ -42,8 +44,10 @@ import {
42
44
  spawnAgentContext,
43
45
  truncateOutput,
44
46
  undoStack
45
- } from "./chunk-XH65H3BT.js";
47
+ } from "./chunk-D5ZDVEJJ.js";
46
48
  import "./chunk-4BKXL7SM.js";
49
+ import "./chunk-FKVJRBPO.js";
50
+ import "./chunk-2ZD3YTVM.js";
47
51
  import {
48
52
  AGENTIC_BEHAVIOR_GUIDELINE,
49
53
  AUTHOR,
@@ -62,7 +66,7 @@ import {
62
66
  SKILLS_DIR_NAME,
63
67
  VERSION,
64
68
  buildUserIdentityPrompt
65
- } from "./chunk-73UI5AH7.js";
69
+ } from "./chunk-BT2TCINO.js";
66
70
 
67
71
  // src/web/server.ts
68
72
  import express from "express";
@@ -1783,6 +1787,103 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
1783
1787
  }
1784
1788
  break;
1785
1789
  }
1790
+ // ── /branch ─────────────────────────────────────────────────────
1791
+ case "branch": {
1792
+ const session = this.sessions.current;
1793
+ if (!session) {
1794
+ this.send({ type: "error", message: "No active session." });
1795
+ break;
1796
+ }
1797
+ const sub = args[0]?.toLowerCase();
1798
+ if (!sub || sub === "list") {
1799
+ const branches = session.listBranches();
1800
+ const lines = [`\u{1F33F} Branches (${branches.length}):`, ""];
1801
+ for (const b of branches) {
1802
+ const marker = b.id === session.activeBranchId ? "\u25CF " : " ";
1803
+ const count = b.id === session.activeBranchId ? session.messages.length : session.getBranchMessages(b.id)?.length ?? 0;
1804
+ const parent = b.parentBranchId ? ` \u2190 ${b.parentBranchId}@${b.parentMessageIndex}` : "";
1805
+ lines.push(` ${marker}${b.id.padEnd(10)} ${b.title.padEnd(20)} (${count} msgs)${parent}`);
1806
+ }
1807
+ lines.push("");
1808
+ lines.push("Usage: /branch new <msgIndex> [title] | switch <id> | delete <id> | rename <id> <title>");
1809
+ this.send({ type: "info", message: lines.join("\n") });
1810
+ break;
1811
+ }
1812
+ if (sub === "new") {
1813
+ const idxArg = args[1];
1814
+ if (!idxArg) {
1815
+ this.send({ type: "error", message: "Usage: /branch new <msgIndex> [title]" });
1816
+ break;
1817
+ }
1818
+ const fromIndex = parseInt(idxArg, 10);
1819
+ if (isNaN(fromIndex) || fromIndex < 0 || fromIndex > session.messages.length) {
1820
+ this.send({ type: "error", message: `Invalid msgIndex: ${idxArg}. Range: 0-${session.messages.length}` });
1821
+ break;
1822
+ }
1823
+ const title = args.slice(2).join(" ").trim() || void 0;
1824
+ try {
1825
+ const newId = session.createBranch(fromIndex, title);
1826
+ await this.sessions.save();
1827
+ this.send({ type: "info", message: `\u2713 Created branch "${newId}" from message #${fromIndex}. Now active (${session.messages.length} messages).` });
1828
+ this.sendSessionMessages();
1829
+ this.sendStatus();
1830
+ } catch (err) {
1831
+ this.send({ type: "error", message: err.message });
1832
+ }
1833
+ break;
1834
+ }
1835
+ if (sub === "switch") {
1836
+ const id = args[1];
1837
+ if (!id) {
1838
+ this.send({ type: "error", message: "Usage: /branch switch <id>" });
1839
+ break;
1840
+ }
1841
+ const ok = session.switchBranch(id);
1842
+ if (ok) {
1843
+ await this.sessions.save();
1844
+ const b = session.getActiveBranch();
1845
+ this.send({ type: "info", message: `\u2713 Switched to branch "${b.id}" \u2014 ${b.title} (${session.messages.length} messages)` });
1846
+ this.sendSessionMessages();
1847
+ this.sendStatus();
1848
+ } else {
1849
+ this.send({ type: "error", message: `Cannot switch to "${id}" (not found or already active).` });
1850
+ }
1851
+ break;
1852
+ }
1853
+ if (sub === "delete") {
1854
+ const id = args[1];
1855
+ if (!id) {
1856
+ this.send({ type: "error", message: "Usage: /branch delete <id>" });
1857
+ break;
1858
+ }
1859
+ const ok = session.deleteBranch(id);
1860
+ if (ok) {
1861
+ await this.sessions.save();
1862
+ this.send({ type: "info", message: `\u2713 Deleted branch "${id}"` });
1863
+ } else {
1864
+ this.send({ type: "error", message: `Cannot delete "${id}" (not found, active, or last remaining branch).` });
1865
+ }
1866
+ break;
1867
+ }
1868
+ if (sub === "rename") {
1869
+ const id = args[1];
1870
+ const title = args.slice(2).join(" ").trim();
1871
+ if (!id || !title) {
1872
+ this.send({ type: "error", message: "Usage: /branch rename <id> <new title>" });
1873
+ break;
1874
+ }
1875
+ const ok = session.renameBranch(id, title);
1876
+ if (ok) {
1877
+ await this.sessions.save();
1878
+ this.send({ type: "info", message: `\u2713 Renamed branch "${id}" \u2192 "${title}"` });
1879
+ } else {
1880
+ this.send({ type: "error", message: `Branch "${id}" not found.` });
1881
+ }
1882
+ break;
1883
+ }
1884
+ this.send({ type: "error", message: `Unknown subcommand: ${sub}. Use list/new/switch/delete/rename.` });
1885
+ break;
1886
+ }
1786
1887
  // ── /fork ───────────────────────────────────────────────────────
1787
1888
  case "fork": {
1788
1889
  const session = this.sessions.current;
@@ -1948,7 +2049,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
1948
2049
  case "test": {
1949
2050
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
1950
2051
  try {
1951
- const { executeTests } = await import("./run-tests-4565WOUK.js");
2052
+ const { executeTests } = await import("./run-tests-HBLD2R6B.js");
1952
2053
  const argStr = args.join(" ").trim();
1953
2054
  let testArgs = {};
1954
2055
  if (argStr) {
@@ -4,11 +4,13 @@ import {
4
4
  getDangerLevel,
5
5
  googleSearchContext,
6
6
  truncateOutput
7
- } from "./chunk-XH65H3BT.js";
7
+ } from "./chunk-D5ZDVEJJ.js";
8
8
  import "./chunk-4BKXL7SM.js";
9
+ import "./chunk-FKVJRBPO.js";
10
+ import "./chunk-2ZD3YTVM.js";
9
11
  import {
10
12
  SUBAGENT_ALLOWED_TOOLS
11
- } from "./chunk-73UI5AH7.js";
13
+ } from "./chunk-BT2TCINO.js";
12
14
 
13
15
  // src/hub/task-orchestrator.ts
14
16
  import { createInterface } from "readline";
@@ -1044,7 +1044,10 @@ function renderFilteredSessions(filter) {
1044
1044
  }
1045
1045
 
1046
1046
  // ── Session Replay (B1) ─────────────────────────────────
1047
+ let _replaySessionId = null; // session shown in the replay modal
1048
+
1047
1049
  async function openReplay(sessionId) {
1050
+ _replaySessionId = sessionId;
1048
1051
  const modal = document.getElementById('replay-modal');
1049
1052
  const metaEl = document.getElementById('replay-meta');
1050
1053
  const usageEl = document.getElementById('replay-usage');
@@ -1092,6 +1095,34 @@ function renderReplay(session, metaEl, usageEl, timelineEl) {
1092
1095
 
1093
1096
  const messages = Array.isArray(session.messages) ? session.messages : [];
1094
1097
  timelineEl.innerHTML = messages.map((m, i) => renderReplayStep(m, i)).join('');
1098
+
1099
+ // Wire 🌿 fork-from-here buttons.
1100
+ timelineEl.querySelectorAll('.replay-fork-btn').forEach((btn) => {
1101
+ btn.addEventListener('click', (e) => {
1102
+ e.stopPropagation();
1103
+ const idx = parseInt(btn.dataset.msgIndex || '0', 10);
1104
+ forkFromReplay(idx);
1105
+ });
1106
+ });
1107
+ }
1108
+
1109
+ function forkFromReplay(msgIndex) {
1110
+ if (!_replaySessionId) return;
1111
+ const activeSid = sessionTabs[activeTabIdx]?.sessionId;
1112
+ const title = prompt(`New branch title (forking at message #${msgIndex}):`, '');
1113
+ if (title === null) return; // cancelled
1114
+ const args = ['new', String(msgIndex), ...(title.trim() ? [title.trim()] : [])];
1115
+ if (activeSid && activeSid === _replaySessionId) {
1116
+ // Replayed session is already active — just branch.
1117
+ send({ type: 'command', name: 'branch', args });
1118
+ } else {
1119
+ // Load the replayed session first, then branch.
1120
+ send({ type: 'command', name: 'session', args: ['load', _replaySessionId] });
1121
+ // Small delay to let the load settle before branching.
1122
+ setTimeout(() => send({ type: 'command', name: 'branch', args }), 400);
1123
+ }
1124
+ const modal = document.getElementById('replay-modal');
1125
+ if (modal && typeof modal.close === 'function') modal.close();
1095
1126
  }
1096
1127
 
1097
1128
  function renderReplayStep(m, idx) {
@@ -1142,6 +1173,7 @@ function renderReplayStep(m, idx) {
1142
1173
  <span class="role-tag">${escapeHtml(roleTag)}</span>
1143
1174
  <span class="opacity-50">${ts}</span>
1144
1175
  ${m.toolCallId ? `<span class="opacity-40">↳ ${escapeHtml(m.toolCallId)}</span>` : ''}
1176
+ <button class="replay-fork-btn opacity-60 hover:opacity-100 text-xs ml-auto" data-msg-index="${idx + 1}" title="Fork a new branch from this point">🌿 fork here</button>
1145
1177
  </div>
1146
1178
  ${body || '<div class="opacity-40 text-xs">(empty)</div>'}
1147
1179
  </div>`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.4.72",
3
+ "version": "0.4.74",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",