jinzd-ai-cli 0.4.278 → 0.4.279

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 (34) hide show
  1. package/dist/{batch-7Y4NAA6N.js → batch-6QZSWCBL.js} +2 -2
  2. package/dist/{chunk-X3722RFA.js → chunk-2BKRWTEQ.js} +1 -1
  3. package/dist/{chunk-SJCOE4C7.js → chunk-5XHEXRMN.js} +1 -1
  4. package/dist/{chunk-RFSKPCYC.js → chunk-6WMT7OQG.js} +1 -1
  5. package/dist/{chunk-JJCNNQTU.js → chunk-7L4TEK7Q.js} +239 -3
  6. package/dist/{chunk-LXXQTWT2.js → chunk-CMNXAJLH.js} +1 -1
  7. package/dist/{chunk-WOXIKQRI.js → chunk-FQJFGGKN.js} +4 -4
  8. package/dist/{chunk-L3CPM472.js → chunk-IIXZ7IPN.js} +1 -1
  9. package/dist/{chunk-LTZFUYBT.js → chunk-JLOQBYU4.js} +3 -3
  10. package/dist/{chunk-4Z6GAYB5.js → chunk-JS6VAPWM.js} +3 -3
  11. package/dist/{chunk-SB4XONS4.js → chunk-NZPHEUJM.js} +1 -1
  12. package/dist/{chunk-H7QC5VMQ.js → chunk-RJY3HJS4.js} +1 -1
  13. package/dist/{chunk-LOXEYWC3.js → chunk-SIVM2YQQ.js} +1 -1
  14. package/dist/{chunk-2BYQP6JX.js → chunk-UD3BVNC5.js} +1 -1
  15. package/dist/{ci-WDF2CYR4.js → ci-F4ESOYI5.js} +4 -4
  16. package/dist/{ci-format-7B5VAZGA.js → ci-format-AIRW3TVQ.js} +2 -2
  17. package/dist/{constants-DC3TNLTL.js → constants-3VMMZJDS.js} +1 -1
  18. package/dist/{doctor-cli-CDDG5XOY.js → doctor-cli-WVMEWMYE.js} +4 -4
  19. package/dist/electron-server.js +398 -58
  20. package/dist/{hub-TO7ODOIA.js → hub-JJCCCU3O.js} +1 -1
  21. package/dist/index.js +112 -323
  22. package/dist/{persistent-memory-BU63CSGK.js → persistent-memory-KSZKM4JG.js} +2 -2
  23. package/dist/{persistent-memory-JCENBMCJ.js → persistent-memory-QZN4Q3W4.js} +2 -2
  24. package/dist/{pr-GVSZYX6I.js → pr-GFB5JC26.js} +4 -4
  25. package/dist/{run-tests-R4IQS6IF.js → run-tests-EL54INOI.js} +2 -2
  26. package/dist/{run-tests-2Q5MJHXB.js → run-tests-HMHHIG7Y.js} +2 -2
  27. package/dist/{server-WXLE53HG.js → server-6C7GITHY.js} +5 -5
  28. package/dist/{server-KAURBKFI.js → server-WUSJWC3A.js} +187 -63
  29. package/dist/{task-orchestrator-RJ6FXYY5.js → task-orchestrator-C7RUUA2Q.js} +5 -5
  30. package/dist/{usage-V3R7DA7M.js → usage-CW6BT2UV.js} +2 -2
  31. package/dist/web/client/app.js +14 -2
  32. package/dist/web/client/app.js.br +0 -0
  33. package/dist/web/client/app.js.gz +0 -0
  34. package/package.json +1 -1
@@ -28,11 +28,11 @@ import {
28
28
  touchMemoryReferences,
29
29
  updateMemoryApproval,
30
30
  updateMemoryEntry
31
- } from "./chunk-RFSKPCYC.js";
31
+ } from "./chunk-6WMT7OQG.js";
32
32
  import "./chunk-3FEZSLGI.js";
33
33
  import "./chunk-HOSJZMQS.js";
34
34
  import "./chunk-IW3Q7AE5.js";
35
- import "./chunk-X3722RFA.js";
35
+ import "./chunk-2BKRWTEQ.js";
36
36
  export {
37
37
  addMemoryEntry,
38
38
  backupMemoryStore,
@@ -27,9 +27,9 @@ import {
27
27
  touchMemoryReferences,
28
28
  updateMemoryApproval,
29
29
  updateMemoryEntry
30
- } from "./chunk-LXXQTWT2.js";
30
+ } from "./chunk-CMNXAJLH.js";
31
31
  import "./chunk-FSC6KEWU.js";
32
- import "./chunk-SJCOE4C7.js";
32
+ import "./chunk-5XHEXRMN.js";
33
33
  import "./chunk-6BUTA5VW.js";
34
34
  export {
35
35
  addMemoryEntry,
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  countSeverity,
4
4
  runCi
5
- } from "./chunk-4Z6GAYB5.js";
6
- import "./chunk-H7QC5VMQ.js";
5
+ } from "./chunk-JS6VAPWM.js";
6
+ import "./chunk-RJY3HJS4.js";
7
7
  import {
8
8
  buildReviewPrompt,
9
9
  buildSecurityReviewPrompt,
@@ -17,13 +17,13 @@ import {
17
17
  } from "./chunk-UGY5SVNX.js";
18
18
  import {
19
19
  ConfigManager
20
- } from "./chunk-2BYQP6JX.js";
20
+ } from "./chunk-UD3BVNC5.js";
21
21
  import "./chunk-TEXT4DAT.js";
22
22
  import "./chunk-TU3L3PW7.js";
23
23
  import "./chunk-IW3Q7AE5.js";
24
24
  import {
25
25
  VERSION
26
- } from "./chunk-X3722RFA.js";
26
+ } from "./chunk-2BKRWTEQ.js";
27
27
 
28
28
  // src/cli/pr.ts
29
29
  import { execFileSync } from "child_process";
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  executeTests,
4
4
  runTestsTool
5
- } from "./chunk-SB4XONS4.js";
6
- import "./chunk-X3722RFA.js";
5
+ } from "./chunk-NZPHEUJM.js";
6
+ import "./chunk-2BKRWTEQ.js";
7
7
  export {
8
8
  executeTests,
9
9
  runTestsTool
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  executeTests,
3
3
  runTestsTool
4
- } from "./chunk-LOXEYWC3.js";
5
- import "./chunk-SJCOE4C7.js";
4
+ } from "./chunk-SIVM2YQQ.js";
5
+ import "./chunk-5XHEXRMN.js";
6
6
  export {
7
7
  executeTests,
8
8
  runTestsTool
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ToolRegistry
4
- } from "./chunk-WOXIKQRI.js";
4
+ } from "./chunk-FQJFGGKN.js";
5
5
  import "./chunk-GHWZVPUV.js";
6
- import "./chunk-RFSKPCYC.js";
6
+ import "./chunk-6WMT7OQG.js";
7
7
  import "./chunk-4DEMGCK4.js";
8
8
  import "./chunk-UUSRWSSX.js";
9
9
  import "./chunk-CKH4KQ4E.js";
@@ -14,7 +14,7 @@ import "./chunk-NYNSYLFY.js";
14
14
  import "./chunk-3FEZSLGI.js";
15
15
  import {
16
16
  runTool
17
- } from "./chunk-L3CPM472.js";
17
+ } from "./chunk-IIXZ7IPN.js";
18
18
  import {
19
19
  getDangerLevel,
20
20
  schemaToJsonSchema
@@ -23,10 +23,10 @@ import "./chunk-TU3L3PW7.js";
23
23
  import "./chunk-HOSJZMQS.js";
24
24
  import "./chunk-IW3Q7AE5.js";
25
25
  import "./chunk-4BKXL7SM.js";
26
- import "./chunk-SB4XONS4.js";
26
+ import "./chunk-NZPHEUJM.js";
27
27
  import {
28
28
  VERSION
29
- } from "./chunk-X3722RFA.js";
29
+ } from "./chunk-2BKRWTEQ.js";
30
30
 
31
31
  // src/mcp/server.ts
32
32
  import { createInterface } from "readline";
@@ -30,22 +30,32 @@ import {
30
30
  estimateConversationTokens,
31
31
  evaluateContextPressure,
32
32
  filterMemoryEntries,
33
+ formatSessionSummaryLine,
33
34
  loadDevState,
35
+ parseBatchDeleteArgs,
36
+ parseCleanArgs,
34
37
  parseMemoryShowFilters,
35
38
  parseModelCommand,
36
39
  parseRouteCommand,
40
+ parseSessionListArgs,
37
41
  persistToolRound,
38
42
  readGitDiff,
39
43
  resolveModelSwitch,
40
44
  resolveProviderSwitch,
45
+ resolveSessionRef,
41
46
  routeDecisionRows,
42
47
  routingEmptyRulesNote,
43
48
  scanDirTree,
44
49
  scanProject,
50
+ selectSessions,
51
+ selectStaleSessions,
52
+ sessionListJsonRow,
53
+ sessionListNeedsFileSize,
54
+ sessionListSummary,
45
55
  setupProxy,
46
56
  snapshotFile,
47
57
  stripRoutingTags
48
- } from "./chunk-JJCNNQTU.js";
58
+ } from "./chunk-7L4TEK7Q.js";
49
59
  import {
50
60
  CNY_PER_USD,
51
61
  CostTracker,
@@ -87,7 +97,7 @@ import {
87
97
  spawnAgentContext,
88
98
  truncateOutput,
89
99
  undoStack
90
- } from "./chunk-WOXIKQRI.js";
100
+ } from "./chunk-FQJFGGKN.js";
91
101
  import {
92
102
  buildReviewPrompt,
93
103
  buildSecurityReviewPrompt
@@ -114,7 +124,7 @@ import {
114
124
  restoreMemoryEntries,
115
125
  updateMemoryApproval,
116
126
  updateMemoryEntry
117
- } from "./chunk-RFSKPCYC.js";
127
+ } from "./chunk-6WMT7OQG.js";
118
128
  import "./chunk-4DEMGCK4.js";
119
129
  import "./chunk-UUSRWSSX.js";
120
130
  import "./chunk-CKH4KQ4E.js";
@@ -133,7 +143,7 @@ import {
133
143
  buildDoctorReport,
134
144
  formatDoctorReport,
135
145
  loadContextFiles
136
- } from "./chunk-LTZFUYBT.js";
146
+ } from "./chunk-JLOQBYU4.js";
137
147
  import {
138
148
  describePlugin,
139
149
  getActivePluginAssets,
@@ -148,13 +158,13 @@ import {
148
158
  runTool,
149
159
  setPluginEnabled,
150
160
  trustPlugin
151
- } from "./chunk-L3CPM472.js";
161
+ } from "./chunk-IIXZ7IPN.js";
152
162
  import {
153
163
  ProviderRegistry
154
164
  } from "./chunk-UGY5SVNX.js";
155
165
  import {
156
166
  ConfigManager
157
- } from "./chunk-2BYQP6JX.js";
167
+ } from "./chunk-UD3BVNC5.js";
158
168
  import {
159
169
  CONTENT_ONLY_STREAM_REMINDER,
160
170
  TEE_FINAL_USER_NUDGE,
@@ -184,7 +194,7 @@ import {
184
194
  maskConfigSecrets
185
195
  } from "./chunk-XNFIYS7G.js";
186
196
  import "./chunk-4BKXL7SM.js";
187
- import "./chunk-SB4XONS4.js";
197
+ import "./chunk-NZPHEUJM.js";
188
198
  import {
189
199
  AGENTIC_BEHAVIOR_GUIDELINE,
190
200
  AUTHOR,
@@ -200,7 +210,7 @@ import {
200
210
  SKILLS_DIR_NAME,
201
211
  VERSION,
202
212
  buildUserIdentityPrompt
203
- } from "./chunk-X3722RFA.js";
213
+ } from "./chunk-2BKRWTEQ.js";
204
214
 
205
215
  // src/web/server.ts
206
216
  import express from "express";
@@ -954,7 +964,7 @@ Cache: write=${cacheCreate} read=${cacheRead}` : "";
954
964
  Cost: ${formatCost(cost)}` : "";
955
965
  let memoryLine = "";
956
966
  try {
957
- const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-BU63CSGK.js");
967
+ const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-KSZKM4JG.js");
958
968
  const pending = countPendingMemories2(ctx.config.getConfigDir());
959
969
  if (pending > 0) memoryLine = `
960
970
  Memory: \u26A0 ${pending} pending approval \u2014 see the Memory panel or /memory`;
@@ -997,11 +1007,17 @@ async function handleSession(args, ctx) {
997
1007
  ctx.sendSessionList();
998
1008
  return;
999
1009
  }
1000
- const list = ctx.sessions.listSessions();
1001
- const found = list.find((s) => s.id.startsWith(targetId));
1002
- if (found) {
1010
+ const ref = resolveSessionRef(ctx.sessions.listSessions(), targetId, "most-recent");
1011
+ if (ref.status === "ok") {
1012
+ const found = ref.match;
1003
1013
  ctx.sessions.loadSession(found.id);
1004
1014
  ctx.resetWebSessionUsage();
1015
+ if (ref.message) {
1016
+ ctx.send({
1017
+ type: "info",
1018
+ message: [ref.message, ...ref.ambiguousWith.slice(0, 5).map((m) => ` ${formatSessionSummaryLine(m)}`)].join("\n")
1019
+ });
1020
+ }
1005
1021
  ctx.send({ type: "info", message: `Loaded session: ${found.id.slice(0, 8)} "${found.title ?? ""}" (${found.messageCount} messages)` });
1006
1022
  const loadedSession = ctx.sessions.current;
1007
1023
  if (loadedSession && loadedSession.messages.length > 0) {
@@ -1031,52 +1047,81 @@ async function handleSession(args, ctx) {
1031
1047
  return;
1032
1048
  }
1033
1049
  if (sub === "list") {
1034
- ctx.sendSessionList();
1050
+ if (args.length <= 1) {
1051
+ ctx.sendSessionList();
1052
+ return;
1053
+ }
1054
+ const opts = parseSessionListArgs(args);
1055
+ const all = ctx.sessions.listSessions({ includeFileSize: sessionListNeedsFileSize(opts) });
1056
+ if (all.length === 0) {
1057
+ ctx.send({ type: "info", message: "No saved sessions." });
1058
+ return;
1059
+ }
1060
+ const view = selectSessions(all, opts);
1061
+ if (view.totalCount === 0) {
1062
+ ctx.send({
1063
+ type: "info",
1064
+ message: [...opts.warnings.map((w) => `\u26A0 ${w}`), "No sessions match the filter criteria."].join("\n")
1065
+ });
1066
+ return;
1067
+ }
1068
+ if (opts.json) {
1069
+ ctx.send({
1070
+ type: "info",
1071
+ message: JSON.stringify(view.shown.map((s) => sessionListJsonRow(s, view.needsFileSize)), null, 2)
1072
+ });
1073
+ return;
1074
+ }
1075
+ const lines = [
1076
+ ...opts.warnings.map((w) => `\u26A0 ${w}`),
1077
+ ...view.shown.map((s) => formatSessionSummaryLine(s)),
1078
+ `\u2500\u2500 ${sessionListSummary(view)}`
1079
+ ];
1080
+ if (view.shown.length < view.totalCount) lines.push("Use --all to show all, or --limit N to change count.");
1081
+ ctx.send({ type: "info", message: lines.join("\n") });
1035
1082
  return;
1036
1083
  }
1037
1084
  if (sub === "delete" && args[1]) {
1038
1085
  const targetId = args[1];
1039
1086
  if (targetId === "--filter") {
1040
- let filterMessages;
1041
- for (let i = 1; i < args.length; i++) {
1042
- if (args[i] === "--filter" && i + 1 < args.length) {
1043
- const val = args[i + 1];
1044
- i++;
1045
- const eq = val.indexOf("=");
1046
- if (eq > 0) {
1047
- const key = val.slice(0, eq);
1048
- const vals = val.slice(eq + 1).split(",").map((s) => s.trim().toLowerCase());
1049
- if (key === "messages") {
1050
- const n = Number(vals[0]);
1051
- if (Number.isFinite(n) && n >= 0) filterMessages = n;
1052
- }
1053
- }
1054
- }
1055
- }
1056
- if (filterMessages === void 0) {
1057
- ctx.send({ type: "error", message: "Usage: /session delete --filter messages=N" });
1087
+ const opts = parseBatchDeleteArgs(args);
1088
+ if (opts.error) {
1089
+ ctx.send({ type: "error", message: opts.error });
1058
1090
  return;
1059
1091
  }
1060
- const list2 = ctx.sessions.listSessions();
1061
- const matches = list2.filter((s) => s.messageCount === filterMessages);
1092
+ const matches = ctx.sessions.listSessions().filter((s) => s.messageCount === opts.messages);
1062
1093
  if (matches.length === 0) {
1063
- ctx.send({ type: "info", message: `No sessions with ${filterMessages} message(s) found.` });
1094
+ ctx.send({ type: "info", message: `No sessions with ${opts.messages} message(s) found.` });
1095
+ return;
1096
+ }
1097
+ const preview = [
1098
+ `Found ${matches.length} session(s) with ${opts.messages} message(s):`,
1099
+ ...matches.slice(0, 20).map((s) => ` ${formatSessionSummaryLine(s)}`),
1100
+ ...matches.length > 20 ? [` ... and ${matches.length - 20} more`] : []
1101
+ ];
1102
+ if (opts.dryRun) {
1103
+ ctx.send({
1104
+ type: "info",
1105
+ message: [...preview, "--dry-run: no sessions were deleted. Remove --dry-run to actually delete."].join("\n")
1106
+ });
1064
1107
  return;
1065
1108
  }
1066
1109
  let deleted = 0;
1067
1110
  let failed = 0;
1068
1111
  for (const s of matches) {
1069
- if (ctx.sessions.deleteSession(s.id)) {
1070
- deleted++;
1071
- } else {
1072
- failed++;
1073
- }
1112
+ if (ctx.sessions.deleteSession(s.id)) deleted++;
1113
+ else failed++;
1074
1114
  }
1075
1115
  if (!ctx.sessions.current) {
1076
- ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
1116
+ const created = ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
1117
+ ctx.unsavedSessions.set(created.id, created);
1077
1118
  ctx.resetWebSessionUsage();
1078
1119
  }
1079
- ctx.send({ type: "info", message: `Deleted ${deleted} session(s) with ${filterMessages} message(s)${failed > 0 ? `, ${failed} failed` : ""}.` });
1120
+ ctx.send({
1121
+ type: "info",
1122
+ message: [...preview, `Deleted ${deleted} session(s)${failed > 0 ? `, ${failed} failed` : ""}.`].join("\n")
1123
+ });
1124
+ ctx.sendStatus();
1080
1125
  ctx.sendSessionList();
1081
1126
  return;
1082
1127
  }
@@ -1085,20 +1130,79 @@ async function handleSession(args, ctx) {
1085
1130
  ctx.unsavedSessions.delete(cachedKey);
1086
1131
  if (ctx.sessions.current?.id === cachedKey) {
1087
1132
  ctx.sessions.clearCurrent();
1133
+ const created = ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
1134
+ ctx.unsavedSessions.set(created.id, created);
1135
+ ctx.resetWebSessionUsage();
1136
+ ctx.sendStatus();
1088
1137
  }
1089
1138
  ctx.send({ type: "info", message: `Deleted session: ${cachedKey.slice(0, 8)}` });
1090
1139
  ctx.sendSessionList();
1091
1140
  return;
1092
1141
  }
1093
- const list = ctx.sessions.listSessions();
1094
- const found = list.find((s) => s.id.startsWith(targetId));
1095
- if (found) {
1096
- ctx.sessions.deleteSession(found.id);
1097
- ctx.send({ type: "info", message: `Deleted session: ${found.id.slice(0, 8)}` });
1098
- ctx.sendSessionList();
1099
- } else {
1142
+ const ref = resolveSessionRef(ctx.sessions.listSessions(), targetId, "strict");
1143
+ if (ref.status === "not-found") {
1100
1144
  ctx.send({ type: "error", message: `Session not found: ${targetId}` });
1145
+ return;
1146
+ }
1147
+ if (ref.status === "ambiguous") {
1148
+ ctx.send({
1149
+ type: "error",
1150
+ message: [ref.message, ...ref.matches.slice(0, 10).map((m) => ` ${formatSessionSummaryLine(m)}`)].join("\n")
1151
+ });
1152
+ return;
1153
+ }
1154
+ const wasCurrent = ctx.sessions.current?.id === ref.match.id;
1155
+ if (!ctx.sessions.deleteSession(ref.match.id)) {
1156
+ ctx.send({ type: "error", message: "Delete failed \u2014 session file not found on disk." });
1157
+ return;
1158
+ }
1159
+ ctx.send({ type: "info", message: `Deleted session: ${ref.match.id.slice(0, 8)}` });
1160
+ if (wasCurrent) {
1161
+ const created = ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
1162
+ ctx.unsavedSessions.set(created.id, created);
1163
+ ctx.resetWebSessionUsage();
1164
+ ctx.send({ type: "info", message: "Current session was deleted \u2014 started a fresh session." });
1165
+ ctx.sendStatus();
1166
+ }
1167
+ ctx.sendSessionList();
1168
+ return;
1169
+ }
1170
+ if (sub === "clean") {
1171
+ const opts = parseCleanArgs(args);
1172
+ const stale = selectStaleSessions(ctx.sessions.listSessions(), opts.staleDays);
1173
+ if (stale.length === 0) {
1174
+ ctx.send({ type: "info", message: `No sessions older than ${opts.staleDays} days found.` });
1175
+ return;
1176
+ }
1177
+ const preview = [
1178
+ `Found ${stale.length} session(s) not updated in ${opts.staleDays}+ days:`,
1179
+ ...stale.slice(0, 20).map((s) => ` ${formatSessionSummaryLine(s)}`),
1180
+ ...stale.length > 20 ? [` ... and ${stale.length - 20} more`] : []
1181
+ ];
1182
+ if (opts.dryRun) {
1183
+ ctx.send({
1184
+ type: "info",
1185
+ message: [...preview, "--dry-run: no sessions were deleted. Remove --dry-run to actually delete."].join("\n")
1186
+ });
1187
+ return;
1188
+ }
1189
+ let deleted = 0;
1190
+ let failed = 0;
1191
+ for (const s of stale) {
1192
+ if (ctx.sessions.deleteSession(s.id)) deleted++;
1193
+ else failed++;
1194
+ }
1195
+ if (!ctx.sessions.current) {
1196
+ const created = ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
1197
+ ctx.unsavedSessions.set(created.id, created);
1198
+ ctx.resetWebSessionUsage();
1199
+ ctx.sendStatus();
1101
1200
  }
1201
+ ctx.send({
1202
+ type: "info",
1203
+ message: [...preview, `Cleaned up: ${deleted} deleted${failed > 0 ? `, ${failed} failed` : ""}.`].join("\n")
1204
+ });
1205
+ ctx.sendSessionList();
1102
1206
  return;
1103
1207
  }
1104
1208
  if (sub === "batch-delete") {
@@ -1122,6 +1226,12 @@ async function handleSession(args, ctx) {
1122
1226
  deleted++;
1123
1227
  }
1124
1228
  }
1229
+ if (!ctx.sessions.current) {
1230
+ const created = ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
1231
+ ctx.unsavedSessions.set(created.id, created);
1232
+ ctx.resetWebSessionUsage();
1233
+ ctx.sendStatus();
1234
+ }
1125
1235
  ctx.send({ type: "info", message: `Deleted ${deleted} session(s).` });
1126
1236
  ctx.sendSessionList();
1127
1237
  return;
@@ -1135,26 +1245,40 @@ async function handleSession(args, ctx) {
1135
1245
  }
1136
1246
  const cachedKey = ctx.unsavedSessions.has(targetId) ? targetId : [...ctx.unsavedSessions.keys()].find((k) => k.startsWith(targetId));
1137
1247
  if (cachedKey) {
1138
- const session = ctx.unsavedSessions.get(cachedKey);
1139
- session.title = newTitle;
1248
+ const session2 = ctx.unsavedSessions.get(cachedKey);
1249
+ session2.title = newTitle;
1140
1250
  ctx.send({ type: "info", message: `Renamed session: "${newTitle}"` });
1141
1251
  ctx.sendSessionList();
1142
1252
  return;
1143
1253
  }
1144
- const list = ctx.sessions.listSessions();
1145
- const found = list.find((s) => s.id.startsWith(targetId));
1146
- if (found) {
1147
- const session = ctx.sessions.loadSession(found.id);
1148
- session.title = newTitle;
1149
- ctx.sessions.save();
1150
- ctx.send({ type: "info", message: `Renamed session: "${newTitle}"` });
1151
- ctx.sendSessionList();
1152
- } else {
1254
+ const ref = resolveSessionRef(ctx.sessions.listSessions(), targetId, "strict");
1255
+ if (ref.status === "not-found") {
1153
1256
  ctx.send({ type: "error", message: `Session not found: ${targetId}` });
1257
+ return;
1258
+ }
1259
+ if (ref.status === "ambiguous") {
1260
+ ctx.send({
1261
+ type: "error",
1262
+ message: [ref.message, ...ref.matches.slice(0, 10).map((m) => ` ${formatSessionSummaryLine(m)}`)].join("\n")
1263
+ });
1264
+ return;
1154
1265
  }
1266
+ const priorId = ctx.sessions.current?.id ?? null;
1267
+ const isCurrent = priorId === ref.match.id;
1268
+ const session = isCurrent ? ctx.sessions.current : ctx.sessions.loadSession(ref.match.id);
1269
+ session.title = newTitle;
1270
+ ctx.sessions.save();
1271
+ if (!isCurrent && priorId) {
1272
+ ctx.sessions.loadSession(priorId);
1273
+ }
1274
+ ctx.send({ type: "info", message: `Renamed session: "${newTitle}"` });
1275
+ ctx.sendSessionList();
1155
1276
  return;
1156
1277
  }
1157
- ctx.send({ type: "info", message: "Usage: /session new | list | load <id> | delete <id> | delete --filter messages=N | rename <id> <title>" });
1278
+ ctx.send({
1279
+ type: "info",
1280
+ message: "Usage: /session new | list [--filter k=v] [--search kw] [--limit N|--all] [--sort f[:o]] [--json] | load <id> | delete <id> | delete --filter messages=N [--dry-run] | clean --stale N [--dry-run] | rename <id> <title>"
1281
+ });
1158
1282
  }
1159
1283
  async function handleExport(args, ctx) {
1160
1284
  const format = args[0] === "json" ? "json" : "md";
@@ -1767,7 +1891,7 @@ async function handleTest(args, ctx) {
1767
1891
  const isCommand = argStr.includes(" ") || /^(mvn|gradle|npm|pytest|cargo|go)\b/.test(argStr);
1768
1892
  testArgs = isCommand ? { command: argStr } : { filter: argStr };
1769
1893
  }
1770
- const runTests = ctx.runTests ?? (await import("./run-tests-R4IQS6IF.js")).executeTests;
1894
+ const runTests = ctx.runTests ?? (await import("./run-tests-EL54INOI.js")).executeTests;
1771
1895
  const report = await runTests(testArgs);
1772
1896
  ctx.send({ type: "info", message: report });
1773
1897
  } catch (err) {
@@ -2103,7 +2227,7 @@ async function handleMemory(args, ctx) {
2103
2227
  ctx.handleMemoryManage(sub, args[1], sub === "expire" ? args[2] : void 0);
2104
2228
  } else if (sub === "export") {
2105
2229
  if (args[1] === "md") {
2106
- const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-BU63CSGK.js");
2230
+ const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-KSZKM4JG.js");
2107
2231
  ctx.send({
2108
2232
  type: "export_data",
2109
2233
  format: "md",
@@ -2359,7 +2483,7 @@ async function handleHelp(_args, ctx) {
2359
2483
  " /think [on|off] \u2014 Toggle extended thinking mode",
2360
2484
  " /plan [execute|exit|status] \u2014 Read-only planning mode (bare /plan enters it)",
2361
2485
  " /route [on|off|show|test <msg>] \u2014 Smart model routing",
2362
- " /session new|list|load|delete <id> \u2014 Session management",
2486
+ " /session new|list [filters]|load <id>|delete <id>|delete --filter messages=N [--dry-run]|clean --stale N [--dry-run]|rename <id> <title> \u2014 Session management",
2363
2487
  " /system [prompt|clear] \u2014 Set/view/reset system prompt",
2364
2488
  " /context [status|reload] \u2014 Show/reload context layers",
2365
2489
  " /status \u2014 Show session info & token usage",
@@ -4,9 +4,9 @@ import {
4
4
  googleSearchContext,
5
5
  isToolCapableProvider,
6
6
  truncateOutput
7
- } from "./chunk-WOXIKQRI.js";
7
+ } from "./chunk-FQJFGGKN.js";
8
8
  import "./chunk-GHWZVPUV.js";
9
- import "./chunk-RFSKPCYC.js";
9
+ import "./chunk-6WMT7OQG.js";
10
10
  import "./chunk-4DEMGCK4.js";
11
11
  import "./chunk-UUSRWSSX.js";
12
12
  import "./chunk-CKH4KQ4E.js";
@@ -17,7 +17,7 @@ import "./chunk-NYNSYLFY.js";
17
17
  import "./chunk-3FEZSLGI.js";
18
18
  import {
19
19
  runTool
20
- } from "./chunk-L3CPM472.js";
20
+ } from "./chunk-IIXZ7IPN.js";
21
21
  import {
22
22
  getDangerLevel,
23
23
  runLeanAgentLoop
@@ -28,10 +28,10 @@ import {
28
28
  atomicWriteFileSync
29
29
  } from "./chunk-IW3Q7AE5.js";
30
30
  import "./chunk-4BKXL7SM.js";
31
- import "./chunk-SB4XONS4.js";
31
+ import "./chunk-NZPHEUJM.js";
32
32
  import {
33
33
  SUBAGENT_ALLOWED_TOOLS
34
- } from "./chunk-X3722RFA.js";
34
+ } from "./chunk-2BKRWTEQ.js";
35
35
 
36
36
  // src/hub/task-orchestrator.ts
37
37
  import { createInterface } from "readline";
@@ -8,10 +8,10 @@ import {
8
8
  } from "./chunk-DPTEC6AQ.js";
9
9
  import {
10
10
  ConfigManager
11
- } from "./chunk-2BYQP6JX.js";
11
+ } from "./chunk-UD3BVNC5.js";
12
12
  import "./chunk-TU3L3PW7.js";
13
13
  import "./chunk-IW3Q7AE5.js";
14
- import "./chunk-X3722RFA.js";
14
+ import "./chunk-2BKRWTEQ.js";
15
15
 
16
16
  // src/cli/usage.ts
17
17
  function classifyRowCost(row) {
@@ -481,9 +481,21 @@ function handleStatus(msg) {
481
481
  }
482
482
  }
483
483
 
484
+ if (targetIdx < 0 && msg.sessionId && sessionTabs.length > 0) {
485
+ // 没有任何标签认领这个 sessionId,也没人在等待绑定——最常见的成因是**服务端换了会话**:
486
+ // 服务器重启后本页重连,或历史标签从 localStorage 恢复而服务端早已新建了会话。
487
+ // 此前这里直接静默丢弃,于是 plan/think 指示灯、token 用量与成本从此不再更新,
488
+ // 而页面看上去一切正常(P2-02 第 3 批实测发现,第 4 批修)。
489
+ //
490
+ // 一个 WebSocket 只对应服务端一个 SessionHandler、一个 current session,所以这一帧
491
+ // 只可能属于当前活跃标签——把新 id 认领过来,而不是把帧扔掉。
492
+ targetIdx = activeTabIdx >= 0 ? activeTabIdx : 0;
493
+ sessionTabs[targetIdx].sessionId = msg.sessionId;
494
+ sessionTabs[targetIdx].pendingBind = false;
495
+ }
496
+
484
497
  if (targetIdx < 0) {
485
- // Stale response — the tab that asked for it was closed before the
486
- // server responded. Drop silently.
498
+ // 连一个标签都没有(页面正在重建)——这一帧确实无处可去。
487
499
  return;
488
500
  }
489
501
 
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.4.278",
3
+ "version": "0.4.279",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",