jinzd-ai-cli 0.4.74 → 0.4.75

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,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-BT2TCINO.js";
4
+ } from "./chunk-5P4QTZBI.js";
5
5
 
6
6
  // src/tools/builtin/run-tests.ts
7
7
  import { execSync } from "child_process";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/core/constants.ts
4
- var VERSION = "0.4.74";
4
+ var VERSION = "0.4.75";
5
5
  var APP_NAME = "ai-cli";
6
6
  var CONFIG_DIR_NAME = ".aicli";
7
7
  var CONFIG_FILE_NAME = "config.json";
@@ -8,7 +8,7 @@ import {
8
8
  CONFIG_FILE_NAME,
9
9
  HISTORY_DIR_NAME,
10
10
  PLUGINS_DIR_NAME
11
- } from "./chunk-BT2TCINO.js";
11
+ } from "./chunk-5P4QTZBI.js";
12
12
 
13
13
  // src/config/config-manager.ts
14
14
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  schemaToJsonSchema,
4
4
  truncateForPersist
5
- } from "./chunk-D5ZDVEJJ.js";
5
+ } from "./chunk-MPIUYP6Q.js";
6
6
  import {
7
7
  AuthError,
8
8
  ProviderError,
@@ -18,7 +18,7 @@ import {
18
18
  MCP_PROTOCOL_VERSION,
19
19
  MCP_TOOL_PREFIX,
20
20
  VERSION
21
- } from "./chunk-BT2TCINO.js";
21
+ } from "./chunk-5P4QTZBI.js";
22
22
 
23
23
  // src/providers/claude.ts
24
24
  import Anthropic from "@anthropic-ai/sdk";
@@ -6,7 +6,7 @@ import { platform } from "os";
6
6
  import chalk from "chalk";
7
7
 
8
8
  // src/core/constants.ts
9
- var VERSION = "0.4.74";
9
+ var VERSION = "0.4.75";
10
10
  var APP_NAME = "ai-cli";
11
11
  var CONFIG_DIR_NAME = ".aicli";
12
12
  var CONFIG_FILE_NAME = "config.json";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-4BKXL7SM.js";
5
5
  import {
6
6
  runTestsTool
7
- } from "./chunk-FKVJRBPO.js";
7
+ } from "./chunk-3BHGEPIT.js";
8
8
  import {
9
9
  EnvLoader,
10
10
  NetworkError,
@@ -17,7 +17,7 @@ import {
17
17
  SUBAGENT_ALLOWED_TOOLS,
18
18
  SUBAGENT_DEFAULT_MAX_ROUNDS,
19
19
  SUBAGENT_MAX_ROUNDS_LIMIT
20
- } from "./chunk-BT2TCINO.js";
20
+ } from "./chunk-5P4QTZBI.js";
21
21
 
22
22
  // src/tools/builtin/bash.ts
23
23
  import { execSync } from "child_process";
@@ -385,7 +385,7 @@ ${content}`);
385
385
  }
386
386
  }
387
387
  async function runTaskMode(config, providers, configManager, topic) {
388
- const { TaskOrchestrator } = await import("./task-orchestrator-24UUKJW5.js");
388
+ const { TaskOrchestrator } = await import("./task-orchestrator-277NWVSE.js");
389
389
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
390
390
  let interrupted = false;
391
391
  const onSigint = () => {
package/dist/index.js CHANGED
@@ -30,10 +30,10 @@ import {
30
30
  saveDevState,
31
31
  sessionHasMeaningfulContent,
32
32
  setupProxy
33
- } from "./chunk-PLJUAA3J.js";
33
+ } from "./chunk-C4MGON2N.js";
34
34
  import {
35
35
  ConfigManager
36
- } from "./chunk-VG3MFZYG.js";
36
+ } from "./chunk-ASNDBI5R.js";
37
37
  import {
38
38
  ToolExecutor,
39
39
  ToolRegistry,
@@ -49,11 +49,11 @@ import {
49
49
  spawnAgentContext,
50
50
  theme,
51
51
  undoStack
52
- } from "./chunk-D5ZDVEJJ.js";
52
+ } from "./chunk-MPIUYP6Q.js";
53
53
  import {
54
54
  fileCheckpoints
55
55
  } from "./chunk-4BKXL7SM.js";
56
- import "./chunk-FKVJRBPO.js";
56
+ import "./chunk-3BHGEPIT.js";
57
57
  import "./chunk-2ZD3YTVM.js";
58
58
  import {
59
59
  AGENTIC_BEHAVIOR_GUIDELINE,
@@ -76,7 +76,7 @@ import {
76
76
  SKILLS_DIR_NAME,
77
77
  VERSION,
78
78
  buildUserIdentityPrompt
79
- } from "./chunk-BT2TCINO.js";
79
+ } from "./chunk-5P4QTZBI.js";
80
80
 
81
81
  // src/index.ts
82
82
  import { program } from "commander";
@@ -2392,7 +2392,7 @@ ${hint}` : "")
2392
2392
  usage: "/test [command|filter]",
2393
2393
  async execute(args, ctx) {
2394
2394
  try {
2395
- const { executeTests } = await import("./run-tests-HBLD2R6B.js");
2395
+ const { executeTests } = await import("./run-tests-V2JJADIU.js");
2396
2396
  const argStr = args.join(" ").trim();
2397
2397
  let testArgs = {};
2398
2398
  if (argStr) {
@@ -6264,7 +6264,7 @@ program.command("web").description("Start Web UI server with browser-based chat
6264
6264
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
6265
6265
  process.exit(1);
6266
6266
  }
6267
- const { startWebServer } = await import("./server-NMMRIWT2.js");
6267
+ const { startWebServer } = await import("./server-2XO72FRP.js");
6268
6268
  await startWebServer({ port, host: options.host });
6269
6269
  });
6270
6270
  program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | migrate <name>)").action(async (action, username) => {
@@ -6387,7 +6387,7 @@ program.command("sessions").description("List recent conversation sessions").act
6387
6387
  });
6388
6388
  program.command("batch <action> [arg] [arg2]").description("Anthropic Message Batches: submit | list | status <id> | results <id> [out] | cancel <id>").option("--dry-run", "Parse and validate input without submitting (submit only)").action(async (action, arg, arg2, options) => {
6389
6389
  try {
6390
- const batch = await import("./batch-SEO6BLMQ.js");
6390
+ const batch = await import("./batch-2RTTAHBL.js");
6391
6391
  switch (action) {
6392
6392
  case "submit":
6393
6393
  if (!arg) {
@@ -6547,7 +6547,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
6547
6547
  }),
6548
6548
  config.get("customProviders")
6549
6549
  );
6550
- const { startHub } = await import("./hub-ABCHM2OR.js");
6550
+ const { startHub } = await import("./hub-W3BF22UV.js");
6551
6551
  await startHub(
6552
6552
  {
6553
6553
  topic: topic ?? "",
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  executeTests,
3
3
  runTestsTool
4
- } from "./chunk-265H5S5H.js";
4
+ } from "./chunk-E6RP5DBU.js";
5
5
  export {
6
6
  executeTests,
7
7
  runTestsTool
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  executeTests,
4
4
  runTestsTool
5
- } from "./chunk-FKVJRBPO.js";
6
- import "./chunk-BT2TCINO.js";
5
+ } from "./chunk-3BHGEPIT.js";
6
+ import "./chunk-5P4QTZBI.js";
7
7
  export {
8
8
  executeTests,
9
9
  runTestsTool
@@ -20,13 +20,13 @@ import {
20
20
  persistToolRound,
21
21
  rebuildExtraMessages,
22
22
  setupProxy
23
- } from "./chunk-PLJUAA3J.js";
23
+ } from "./chunk-C4MGON2N.js";
24
24
  import {
25
25
  AuthManager
26
26
  } from "./chunk-BYNY5JPB.js";
27
27
  import {
28
28
  ConfigManager
29
- } from "./chunk-VG3MFZYG.js";
29
+ } from "./chunk-ASNDBI5R.js";
30
30
  import {
31
31
  ToolExecutor,
32
32
  ToolRegistry,
@@ -44,9 +44,9 @@ import {
44
44
  spawnAgentContext,
45
45
  truncateOutput,
46
46
  undoStack
47
- } from "./chunk-D5ZDVEJJ.js";
47
+ } from "./chunk-MPIUYP6Q.js";
48
48
  import "./chunk-4BKXL7SM.js";
49
- import "./chunk-FKVJRBPO.js";
49
+ import "./chunk-3BHGEPIT.js";
50
50
  import "./chunk-2ZD3YTVM.js";
51
51
  import {
52
52
  AGENTIC_BEHAVIOR_GUIDELINE,
@@ -66,7 +66,7 @@ import {
66
66
  SKILLS_DIR_NAME,
67
67
  VERSION,
68
68
  buildUserIdentityPrompt
69
- } from "./chunk-BT2TCINO.js";
69
+ } from "./chunk-5P4QTZBI.js";
70
70
 
71
71
  // src/web/server.ts
72
72
  import express from "express";
@@ -563,6 +563,15 @@ var SessionHandler = class _SessionHandler {
563
563
  models: p.info.models.map((m) => ({ id: m.id, name: m.displayName ?? m.id }))
564
564
  }));
565
565
  const costUsd = computeCost(this.currentProvider, this.currentModel, this.sessionTokenUsage);
566
+ const sess = this.sessions.current;
567
+ const branches = sess ? sess.listBranches().map((b) => ({
568
+ id: b.id,
569
+ title: b.title,
570
+ parentBranchId: b.parentBranchId,
571
+ parentMessageIndex: b.parentMessageIndex,
572
+ created: b.created.toISOString(),
573
+ messageCount: b.id === sess.activeBranchId ? sess.messages.length : sess.getBranchMessages(b.id)?.length ?? 0
574
+ })) : [];
566
575
  this.send({
567
576
  type: "status",
568
577
  provider: this.currentProvider,
@@ -574,7 +583,9 @@ var SessionHandler = class _SessionHandler {
574
583
  thinkingMode: this.runtimeThinking ?? false,
575
584
  tokenUsage: { ...this.sessionTokenUsage },
576
585
  costUsd,
577
- providers: providerList
586
+ providers: providerList,
587
+ branches,
588
+ activeBranchId: sess?.activeBranchId ?? "main"
578
589
  });
579
590
  }
580
591
  async handleMessage(raw) {
@@ -1860,6 +1871,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
1860
1871
  if (ok) {
1861
1872
  await this.sessions.save();
1862
1873
  this.send({ type: "info", message: `\u2713 Deleted branch "${id}"` });
1874
+ this.sendStatus();
1863
1875
  } else {
1864
1876
  this.send({ type: "error", message: `Cannot delete "${id}" (not found, active, or last remaining branch).` });
1865
1877
  }
@@ -1876,6 +1888,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
1876
1888
  if (ok) {
1877
1889
  await this.sessions.save();
1878
1890
  this.send({ type: "info", message: `\u2713 Renamed branch "${id}" \u2192 "${title}"` });
1891
+ this.sendStatus();
1879
1892
  } else {
1880
1893
  this.send({ type: "error", message: `Branch "${id}" not found.` });
1881
1894
  }
@@ -2049,7 +2062,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
2049
2062
  case "test": {
2050
2063
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
2051
2064
  try {
2052
- const { executeTests } = await import("./run-tests-HBLD2R6B.js");
2065
+ const { executeTests } = await import("./run-tests-V2JJADIU.js");
2053
2066
  const argStr = args.join(" ").trim();
2054
2067
  let testArgs = {};
2055
2068
  if (argStr) {
@@ -4,13 +4,13 @@ import {
4
4
  getDangerLevel,
5
5
  googleSearchContext,
6
6
  truncateOutput
7
- } from "./chunk-D5ZDVEJJ.js";
7
+ } from "./chunk-MPIUYP6Q.js";
8
8
  import "./chunk-4BKXL7SM.js";
9
- import "./chunk-FKVJRBPO.js";
9
+ import "./chunk-3BHGEPIT.js";
10
10
  import "./chunk-2ZD3YTVM.js";
11
11
  import {
12
12
  SUBAGENT_ALLOWED_TOOLS
13
- } from "./chunk-BT2TCINO.js";
13
+ } from "./chunk-5P4QTZBI.js";
14
14
 
15
15
  // src/hub/task-orchestrator.ts
16
16
  import { createInterface } from "readline";
@@ -519,6 +519,17 @@ function handleStatus(msg) {
519
519
  }
520
520
  if (msg.tokenUsage) targetTab.tokenUsage = msg.tokenUsage;
521
521
 
522
+ // B2: stash branch data on the tab so tab-switch keeps the picker in sync.
523
+ if (Array.isArray(msg.branches)) {
524
+ targetTab.branches = msg.branches;
525
+ targetTab.activeBranchId = msg.activeBranchId || 'main';
526
+ }
527
+
528
+ if (isActiveTarget) {
529
+ // Re-render the branches panel whenever the active tab gets a status.
530
+ renderBranchPanel(msg.branches || [], msg.activeBranchId || 'main', msg.sessionId || '');
531
+ }
532
+
522
533
  if (isActiveTarget) {
523
534
  // Active tab: full UI reflection
524
535
  btnThink.classList.toggle('btn-active-toggle', msg.thinkingMode);
@@ -1179,6 +1190,137 @@ function renderReplayStep(m, idx) {
1179
1190
  </div>`;
1180
1191
  }
1181
1192
 
1193
+ // ── B2: Branch sidebar panel ─────────────────────────────
1194
+ let _cachedBranches = [];
1195
+ let _cachedActiveBranchId = 'main';
1196
+
1197
+ function renderBranchPanel(branches, activeId, sessionId) {
1198
+ _cachedBranches = branches;
1199
+ _cachedActiveBranchId = activeId;
1200
+ const listEl = document.getElementById('branch-list');
1201
+ const headerEl = document.getElementById('branches-header');
1202
+ if (!listEl) return;
1203
+
1204
+ if (!sessionId) {
1205
+ if (headerEl) headerEl.textContent = 'No session';
1206
+ listEl.innerHTML = '<div class="text-xs opacity-40 text-center py-4">Load a session to see branches</div>';
1207
+ return;
1208
+ }
1209
+ if (headerEl) {
1210
+ headerEl.textContent = `Session ${sessionId.slice(0, 8)} · ${branches.length} branch${branches.length === 1 ? '' : 'es'}`;
1211
+ }
1212
+ if (branches.length === 0) {
1213
+ listEl.innerHTML = '<div class="text-xs opacity-40 text-center py-4">No branches</div>';
1214
+ return;
1215
+ }
1216
+
1217
+ // Build tree: compute depth by walking parent chain.
1218
+ const byId = Object.fromEntries(branches.map(b => [b.id, b]));
1219
+ function depthOf(b) {
1220
+ let d = 0, cur = b;
1221
+ while (cur && cur.parentBranchId && byId[cur.parentBranchId]) {
1222
+ d++;
1223
+ cur = byId[cur.parentBranchId];
1224
+ if (d > 100) break; // safety
1225
+ }
1226
+ return d;
1227
+ }
1228
+ // Depth-first order: roots first, then children in order.
1229
+ const ordered = [];
1230
+ const visited = new Set();
1231
+ function visit(b) {
1232
+ if (visited.has(b.id)) return;
1233
+ visited.add(b.id);
1234
+ ordered.push(b);
1235
+ for (const c of branches) {
1236
+ if (c.parentBranchId === b.id) visit(c);
1237
+ }
1238
+ }
1239
+ for (const b of branches) {
1240
+ if (!b.parentBranchId || !byId[b.parentBranchId]) visit(b);
1241
+ }
1242
+ // Any remaining (orphaned) — append at end.
1243
+ for (const b of branches) if (!visited.has(b.id)) visit(b);
1244
+
1245
+ listEl.innerHTML = ordered.map(b => {
1246
+ const depth = depthOf(b);
1247
+ const indent = depth === 0 ? '' : '│ '.repeat(depth - 1) + '└─ ';
1248
+ const isActive = b.id === activeId;
1249
+ const marker = isActive ? '●' : '○';
1250
+ const parentTag = b.parentBranchId
1251
+ ? `<span class="branch-count">← ${escapeHtml(b.parentBranchId)}@${b.parentMessageIndex}</span>`
1252
+ : '';
1253
+ return `
1254
+ <div class="branch-item${isActive ? ' active' : ''}" data-branch-id="${escapeHtml(b.id)}" data-branch-active="${isActive ? '1' : '0'}">
1255
+ <span class="branch-indent">${indent}</span>
1256
+ <span class="branch-marker">${marker}</span>
1257
+ <span class="branch-title" title="${escapeHtml(b.title)}">${escapeHtml(b.title)}</span>
1258
+ <span class="branch-id">${escapeHtml(b.id)}</span>
1259
+ <span class="branch-count">${b.messageCount}m</span>
1260
+ ${parentTag}
1261
+ <span class="branch-actions">
1262
+ <button data-branch-action="rename" title="Rename">✎</button>
1263
+ <button data-branch-action="delete" title="Delete">×</button>
1264
+ </span>
1265
+ </div>`;
1266
+ }).join('');
1267
+
1268
+ // Wire click handlers.
1269
+ listEl.querySelectorAll('.branch-item').forEach(el => {
1270
+ el.addEventListener('click', (e) => {
1271
+ const actionBtn = e.target.closest('button[data-branch-action]');
1272
+ const id = el.dataset.branchId;
1273
+ if (!id) return;
1274
+ if (actionBtn) {
1275
+ e.stopPropagation();
1276
+ const action = actionBtn.dataset.branchAction;
1277
+ if (action === 'rename') {
1278
+ const cur = byId[id];
1279
+ const title = prompt('New branch title:', cur?.title || '');
1280
+ if (title && title.trim() && title.trim() !== cur?.title) {
1281
+ send({ type: 'command', name: 'branch', args: ['rename', id, title.trim()] });
1282
+ }
1283
+ } else if (action === 'delete') {
1284
+ if (id === activeId) {
1285
+ alert('Cannot delete the active branch. Switch to another branch first.');
1286
+ return;
1287
+ }
1288
+ if (confirm(`Delete branch "${id}"? Its messages will be lost.`)) {
1289
+ send({ type: 'command', name: 'branch', args: ['delete', id] });
1290
+ }
1291
+ }
1292
+ return;
1293
+ }
1294
+ // Plain click → switch branch.
1295
+ if (el.dataset.branchActive !== '1') {
1296
+ send({ type: 'command', name: 'branch', args: ['switch', id] });
1297
+ }
1298
+ });
1299
+ });
1300
+ }
1301
+
1302
+ // "+ Fork" button — fork the active branch at its current tip.
1303
+ document.getElementById('btn-branch-new')?.addEventListener('click', () => {
1304
+ const activeTab = sessionTabs[activeTabIdx];
1305
+ if (!activeTab || !activeTab.sessionId) {
1306
+ alert('Load a session first.');
1307
+ return;
1308
+ }
1309
+ const activeBranch = _cachedBranches.find(b => b.id === _cachedActiveBranchId);
1310
+ const tip = activeBranch?.messageCount ?? 0;
1311
+ const raw = prompt(`Fork from message # (0–${tip}, default ${tip}):`, String(tip));
1312
+ if (raw === null) return;
1313
+ const idx = parseInt(raw.trim() || String(tip), 10);
1314
+ if (isNaN(idx) || idx < 0 || idx > tip) {
1315
+ alert(`Invalid index. Range: 0–${tip}`);
1316
+ return;
1317
+ }
1318
+ const title = prompt('New branch title (optional):', '');
1319
+ if (title === null) return;
1320
+ const args = ['new', String(idx), ...(title.trim() ? [title.trim()] : [])];
1321
+ send({ type: 'command', name: 'branch', args });
1322
+ });
1323
+
1182
1324
  function startSessionRename(itemEl, titleEl) {
1183
1325
  const sessionId = itemEl.dataset.sessionId;
1184
1326
  const currentTitle = titleEl.textContent.trim();
@@ -105,6 +105,7 @@
105
105
  <!-- Sidebar tabs -->
106
106
  <div class="flex border-b border-base-content/10 flex-shrink-0">
107
107
  <button class="sidebar-tab active flex-1 text-xs font-semibold py-2 px-1 text-center" data-tab="sessions">📋 Sessions</button>
108
+ <button class="sidebar-tab flex-1 text-xs font-semibold py-2 px-1 text-center" data-tab="branches" title="Conversation branches (B2)">🌿 Branches</button>
108
109
  <button class="sidebar-tab flex-1 text-xs font-semibold py-2 px-1 text-center" data-tab="tools">🔧 Tools</button>
109
110
  <button class="sidebar-tab flex-1 text-xs font-semibold py-2 px-1 text-center" data-tab="files">📁 Files</button>
110
111
  </div>
@@ -127,6 +128,17 @@
127
128
  <div class="text-xs opacity-40 text-center py-4">No sessions yet</div>
128
129
  </div>
129
130
  </div>
131
+ <!-- Branches tab (B2) -->
132
+ <div id="tab-branches" class="sidebar-tab-content flex flex-col flex-1 overflow-hidden hidden">
133
+ <div class="p-2 border-b border-base-content/10 flex items-center gap-1">
134
+ <span class="text-xs opacity-60 flex-1 truncate" id="branches-header">No session</span>
135
+ <button id="btn-branch-new" class="btn btn-xs btn-primary btn-outline flex-shrink-0 whitespace-nowrap" title="Fork at current tip">+ Fork</button>
136
+ </div>
137
+ <div id="branch-list" class="flex-1 overflow-y-auto p-2 flex flex-col gap-1 text-sm">
138
+ <div class="text-xs opacity-40 text-center py-4">Load a session to see branches</div>
139
+ </div>
140
+ </div>
141
+
130
142
  <!-- Tools tab -->
131
143
  <div id="tab-tools" class="sidebar-tab-content flex flex-col flex-1 overflow-hidden hidden">
132
144
  <div class="p-2 border-b border-base-content/10">
@@ -903,3 +903,74 @@ button, a, .session-item, .file-tree-row, .template-item, .tool-item, .mcp-serve
903
903
  max-height: 12rem;
904
904
  overflow-y: auto;
905
905
  }
906
+
907
+ /* ── B2 Branch picker (sidebar) ─────────────────────────── */
908
+ .branch-item {
909
+ display: flex;
910
+ align-items: center;
911
+ gap: 0.35rem;
912
+ padding: 0.35rem 0.5rem;
913
+ border-radius: 0.35rem;
914
+ cursor: pointer;
915
+ border: 1px solid transparent;
916
+ transition: background 0.1s, border-color 0.1s;
917
+ font-size: 0.78rem;
918
+ line-height: 1.25;
919
+ position: relative;
920
+ }
921
+ .branch-item:hover {
922
+ background: rgba(128, 128, 128, 0.12);
923
+ }
924
+ .branch-item.active {
925
+ background: rgba(34, 197, 94, 0.12);
926
+ border-color: rgba(34, 197, 94, 0.45);
927
+ }
928
+ .branch-item .branch-marker {
929
+ flex-shrink: 0;
930
+ width: 0.8rem;
931
+ color: rgb(34, 197, 94);
932
+ }
933
+ .branch-item .branch-title {
934
+ flex: 1;
935
+ min-width: 0;
936
+ overflow: hidden;
937
+ text-overflow: ellipsis;
938
+ white-space: nowrap;
939
+ }
940
+ .branch-item .branch-id {
941
+ flex-shrink: 0;
942
+ opacity: 0.5;
943
+ font-family: ui-monospace, SFMono-Regular, monospace;
944
+ font-size: 0.7rem;
945
+ }
946
+ .branch-item .branch-count {
947
+ flex-shrink: 0;
948
+ opacity: 0.55;
949
+ font-size: 0.7rem;
950
+ }
951
+ .branch-item .branch-actions {
952
+ display: none;
953
+ gap: 0.15rem;
954
+ flex-shrink: 0;
955
+ }
956
+ .branch-item:hover .branch-actions {
957
+ display: flex;
958
+ }
959
+ .branch-item .branch-actions button {
960
+ background: transparent;
961
+ border: none;
962
+ padding: 0 0.2rem;
963
+ font-size: 0.72rem;
964
+ cursor: pointer;
965
+ opacity: 0.7;
966
+ }
967
+ .branch-item .branch-actions button:hover {
968
+ opacity: 1;
969
+ }
970
+ .branch-item .branch-indent {
971
+ flex-shrink: 0;
972
+ color: rgba(128, 128, 128, 0.5);
973
+ font-family: ui-monospace, SFMono-Regular, monospace;
974
+ font-size: 0.72rem;
975
+ white-space: pre;
976
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.4.74",
3
+ "version": "0.4.75",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",