jinzd-ai-cli 0.4.241 → 0.4.243

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 (42) hide show
  1. package/README.md +2 -2
  2. package/dist/{batch-K66BLTLJ.js → batch-CUVZUPRK.js} +2 -2
  3. package/dist/{chat-index-7HXBWQFH.js → chat-index-ALUHFJKI.js} +3 -2
  4. package/dist/{chat-index-WYXYD7YP.js → chat-index-ML5FF5L6.js} +2 -1
  5. package/dist/{chunk-SMQHEJSH.js → chunk-66CE3E6X.js} +1 -1
  6. package/dist/chunk-B5TYJO7V.js +123 -0
  7. package/dist/{chunk-PGHTAKIA.js → chunk-DJGCG7SF.js} +1 -1
  8. package/dist/{chunk-2QQKS56X.js → chunk-DT77O33T.js} +1 -1
  9. package/dist/{chunk-2LLQOMMW.js → chunk-EMFCHE2B.js} +1 -1
  10. package/dist/chunk-GEWPLNKA.js +164 -0
  11. package/dist/{chunk-LXSUPLCK.js → chunk-H3ARWBYR.js} +2 -2
  12. package/dist/{chunk-3AIR7N5M.js → chunk-HNJX3N2V.js} +5 -5
  13. package/dist/{chunk-5MYPIQ3Y.js → chunk-IGPFYNZA.js} +4 -2
  14. package/dist/{chunk-GORPFFV4.js → chunk-KILKF2VN.js} +97 -254
  15. package/dist/{chunk-JMP3LJC2.js → chunk-KWQKQVPH.js} +4 -2
  16. package/dist/{chunk-NAQPP3GZ.js → chunk-L5IRDRWG.js} +1 -1
  17. package/dist/{chunk-UO3XWZFE.js → chunk-NV63EYFL.js} +3 -119
  18. package/dist/{chunk-KCEO2XJ4.js → chunk-PJ3ONBWZ.js} +0 -119
  19. package/dist/{chunk-ZPXMT2B6.js → chunk-PLEXBFCR.js} +4 -163
  20. package/dist/chunk-PNNZRJ67.js +523 -0
  21. package/dist/{chunk-CHFFEVVT.js → chunk-QNK7GUUB.js} +3 -3
  22. package/dist/chunk-TY4FSEZS.js +432 -0
  23. package/dist/{chunk-IV6GCDVR.js → chunk-X73Y4JZI.js} +7 -1
  24. package/dist/chunk-YVTASHS5.js +121 -0
  25. package/dist/{ci-T2ABDMMQ.js → ci-3O3JR6FX.js} +4 -4
  26. package/dist/{ci-format-S2PPU27O.js → ci-format-KGWF6KOU.js} +2 -2
  27. package/dist/{constants-RS7OUU7X.js → constants-NMFRZ5LW.js} +1 -1
  28. package/dist/{doctor-cli-TGAW6RAP.js → doctor-cli-4QUHTJZ4.js} +4 -4
  29. package/dist/electron-server.js +446 -579
  30. package/dist/{hub-GL5ZU6WS.js → hub-2GXFPWOR.js} +2 -2
  31. package/dist/index.js +273 -62
  32. package/dist/{persist-AMH5SQ4W.js → persist-WGIJ6RXY.js} +4 -3
  33. package/dist/persistent-memory-VFBRMKGG.js +65 -0
  34. package/dist/persistent-memory-ZCQKLIC5.js +63 -0
  35. package/dist/{pr-TJFKUZ4B.js → pr-GIDFO4KP.js} +5 -5
  36. package/dist/{run-tests-KEI7IXTB.js → run-tests-BMH6QJN2.js} +2 -2
  37. package/dist/{run-tests-EWMU34A4.js → run-tests-WCZBWQFS.js} +2 -1
  38. package/dist/{server-UVS2D4M6.js → server-A5NGGDMP.js} +130 -47
  39. package/dist/{server-E545UIX7.js → server-FEFIFJDA.js} +8 -6
  40. package/dist/{task-orchestrator-PWXV2EBN.js → task-orchestrator-J2H6OV6R.js} +8 -6
  41. package/dist/{usage-EDJ6QOWB.js → usage-7WJC234G.js} +2 -2
  42. package/package.json +1 -1
@@ -139,7 +139,7 @@ ${content}`);
139
139
  const state = await runDiscussion(config, providers, options.topic);
140
140
  if (options.save !== false && state.messages.length > 0) {
141
141
  try {
142
- const { persistDiscussion } = await import("./persist-AMH5SQ4W.js");
142
+ const { persistDiscussion } = await import("./persist-WGIJ6RXY.js");
143
143
  const { path } = await persistDiscussion(state, configManager, defaultProvider, defaultModel);
144
144
  console.log(chalk.dim(`
145
145
  \u{1F4BE} Saved to history \u2014 open it in the Web UI and hit \u{1F3AC} to replay.
@@ -154,7 +154,7 @@ ${content}`);
154
154
  }
155
155
  }
156
156
  async function runTaskMode(config, providers, configManager, topic) {
157
- const { TaskOrchestrator } = await import("./task-orchestrator-PWXV2EBN.js");
157
+ const { TaskOrchestrator } = await import("./task-orchestrator-J2H6OV6R.js");
158
158
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
159
159
  let interrupted = false;
160
160
  const onSigint = () => {
package/dist/index.js CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ CostTracker
4
+ } from "./chunk-YVMACMXW.js";
2
5
  import {
3
6
  McpManager,
4
7
  SNAPSHOT_PROMPT,
@@ -14,7 +17,12 @@ import {
14
17
  scanProject,
15
18
  sessionHasMeaningfulContent,
16
19
  setupProxy
17
- } from "./chunk-LXSUPLCK.js";
20
+ } from "./chunk-H3ARWBYR.js";
21
+ import {
22
+ computeCost,
23
+ formatCost,
24
+ getPricing
25
+ } from "./chunk-E44DTERW.js";
18
26
  import {
19
27
  buildReviewPrompt,
20
28
  buildSecurityReviewPrompt
@@ -22,26 +30,17 @@ import {
22
30
  import {
23
31
  ToolExecutor,
24
32
  ToolRegistry,
25
- addMemoryEntry,
26
33
  askUserContext,
27
34
  cleanupAllSessions,
28
35
  cleanupRejectedTeeFile,
29
36
  clearRecentlyDeniedAutoActions,
30
- deleteMemoryEntry,
31
37
  estimateTokens,
32
- expireMemoryEntry,
33
- exportMemoryEntries,
34
- formatMemoryForPrompt,
35
38
  formatPermissionProfileWarning,
36
39
  getRecentlyDeniedAutoActions,
37
40
  googleSearchContext,
38
41
  initTheme,
39
42
  isInterrupted,
40
- isMemoryExpired,
41
43
  lastResponseStore,
42
- listMemoryEntries,
43
- memoryMarkdownPath,
44
- memoryStorePath,
45
44
  renderDiff,
46
45
  requestInterrupt,
47
46
  resetInterrupt,
@@ -50,9 +49,34 @@ import {
50
49
  setMaxOutputCap,
51
50
  spawnAgentContext,
52
51
  theme,
53
- undoStack,
54
- updateMemoryApproval
55
- } from "./chunk-GORPFFV4.js";
52
+ undoStack
53
+ } from "./chunk-KILKF2VN.js";
54
+ import {
55
+ addMemoryEntry,
56
+ backupMemoryStore,
57
+ clearMemoryEntries,
58
+ countPendingMemories,
59
+ deleteMemoryEntry,
60
+ detectStaleLegacyMarkdownEdit,
61
+ expireMemoryEntry,
62
+ exportMemoryEntries,
63
+ findSimilarMemory,
64
+ formatMemoryForPrompt,
65
+ isMemoryExpired,
66
+ isMemoryStale,
67
+ listMemoryEntries,
68
+ listOrphanedProjectMemories,
69
+ loadMemoryEntries,
70
+ memoryMarkdownPath,
71
+ memoryStorePath,
72
+ parseWritableScope,
73
+ rebindMemoryProject,
74
+ restoreMemoryEntries,
75
+ searchPersistentMemories,
76
+ touchMemoryReferences,
77
+ updateMemoryApproval,
78
+ updateMemoryEntry
79
+ } from "./chunk-TY4FSEZS.js";
56
80
  import "./chunk-K3CF65QH.js";
57
81
  import "./chunk-UUSRWSSX.js";
58
82
  import "./chunk-CKH4KQ4E.js";
@@ -60,24 +84,19 @@ import "./chunk-BXP6YZ2P.js";
60
84
  import {
61
85
  SessionManager,
62
86
  getContentText
63
- } from "./chunk-JMP3LJC2.js";
64
- import {
65
- CostTracker
66
- } from "./chunk-YVMACMXW.js";
67
- import {
68
- computeCost,
69
- formatCost,
70
- getPricing
71
- } from "./chunk-E44DTERW.js";
87
+ } from "./chunk-KWQKQVPH.js";
72
88
  import {
73
89
  buildDoctorReport,
74
90
  formatDoctorReport,
75
91
  loadContextFiles,
76
92
  writeCrashLog
77
- } from "./chunk-3AIR7N5M.js";
93
+ } from "./chunk-HNJX3N2V.js";
78
94
  import {
79
95
  ProviderRegistry
80
96
  } from "./chunk-QYQI7ZWK.js";
97
+ import {
98
+ ConfigManager
99
+ } from "./chunk-X73Y4JZI.js";
81
100
  import {
82
101
  describePlugin,
83
102
  getActivePluginAssets,
@@ -94,7 +113,7 @@ import {
94
113
  trustHook,
95
114
  trustPlugin,
96
115
  untrustHook
97
- } from "./chunk-2LLQOMMW.js";
116
+ } from "./chunk-EMFCHE2B.js";
98
117
  import {
99
118
  CONTENT_ONLY_STREAM_REMINDER,
100
119
  TEE_FINAL_USER_NUDGE,
@@ -114,9 +133,6 @@ import {
114
133
  stripToolCallReminder,
115
134
  teeStreamErrorSummary
116
135
  } from "./chunk-O3XSFPYH.js";
117
- import {
118
- ConfigManager
119
- } from "./chunk-IV6GCDVR.js";
120
136
  import {
121
137
  AuthError,
122
138
  ProviderError,
@@ -130,7 +146,7 @@ import {
130
146
  import {
131
147
  fileCheckpoints
132
148
  } from "./chunk-4BKXL7SM.js";
133
- import "./chunk-NAQPP3GZ.js";
149
+ import "./chunk-L5IRDRWG.js";
134
150
  import {
135
151
  AGENTIC_BEHAVIOR_GUIDELINE,
136
152
  AUTHOR,
@@ -149,18 +165,19 @@ import {
149
165
  SKILLS_DIR_NAME,
150
166
  VERSION,
151
167
  buildUserIdentityPrompt
152
- } from "./chunk-SMQHEJSH.js";
168
+ } from "./chunk-66CE3E6X.js";
153
169
  import {
154
170
  buildChatIndex,
155
171
  clearChatIndex,
156
172
  getChatIndexStatus,
157
173
  searchChatMemory
158
- } from "./chunk-5MYPIQ3Y.js";
174
+ } from "./chunk-IGPFYNZA.js";
159
175
  import "./chunk-KHYD3WXE.js";
176
+ import "./chunk-PJ3ONBWZ.js";
160
177
  import {
161
178
  DEFAULT_PATTERNS,
162
179
  scanString
163
- } from "./chunk-KCEO2XJ4.js";
180
+ } from "./chunk-B5TYJO7V.js";
164
181
  import {
165
182
  atomicWriteFileSync
166
183
  } from "./chunk-IW3Q7AE5.js";
@@ -1370,7 +1387,7 @@ No tools match "${filter}".
1370
1387
  const { join: join6 } = await import("path");
1371
1388
  const { existsSync: existsSync5 } = await import("fs");
1372
1389
  const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
1373
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-RS7OUU7X.js");
1390
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-NMFRZ5LW.js");
1374
1391
  const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
1375
1392
  const cwd = process.cwd();
1376
1393
  const projectRoot = getGitRoot2(cwd) ?? cwd;
@@ -2349,7 +2366,7 @@ function createReviewCommands() {
2349
2366
  usage: "/test [command|filter]",
2350
2367
  async execute(args, ctx) {
2351
2368
  try {
2352
- const { executeTests } = await import("./run-tests-KEI7IXTB.js");
2369
+ const { executeTests } = await import("./run-tests-BMH6QJN2.js");
2353
2370
  const argStr = args.join(" ").trim();
2354
2371
  let testArgs = {};
2355
2372
  if (argStr) {
@@ -2554,6 +2571,13 @@ function createMemoryCommands() {
2554
2571
  console.log(" Network : " + (ctx.config.get("networkPolicy")?.enabled ?? false ? "on" : "off"));
2555
2572
  console.log(" AutoMode : " + (ctx.getToolExecutor().sessionAutoMode ? "on" : "off"));
2556
2573
  console.log(" Hooks : " + getPendingHookTrust(mergePluginHooks(ctx.config.get("hooks") ?? void 0, ctx.config.getConfigDir()), ctx.config.getConfigDir()).length + " pending trust");
2574
+ {
2575
+ const memAll = listMemoryEntries(ctx.config.getConfigDir(), { includeExpired: true, includeRejected: true });
2576
+ const memActive = memAll.filter((m) => m.approved && !isMemoryExpired(m)).length;
2577
+ const memPending = memAll.filter((m) => !m.approved && !isMemoryExpired(m)).length;
2578
+ const pendingStr = memPending > 0 ? theme.warning(`${memPending} pending approval \u2014 /memory approve <id>`) : "0 pending";
2579
+ console.log(` Memory : ${memActive} active \xB7 ${pendingStr}`);
2580
+ }
2557
2581
  console.log(` Messages : ${session?.messages.length ?? 0}`);
2558
2582
  console.log(` Session : ${session?.id.slice(0, 8) ?? "none"}`);
2559
2583
  if (layers.length > 0) {
@@ -2698,7 +2722,7 @@ function createMemoryCommands() {
2698
2722
  {
2699
2723
  name: "memory",
2700
2724
  description: "Governed persistent memory + chat memory recall index",
2701
- usage: "/memory [show|add|approve|reject|delete|expire|export|path|rebuild|refresh|status|recall|index-clear]",
2725
+ usage: "/memory [show|add|edit|approve|reject|delete|expire|rebind|clear|backup|restore|export|path|rebuild|refresh|status|recall|index-clear]",
2702
2726
  async execute(args, ctx) {
2703
2727
  const configDir = ctx.config.getConfigDir();
2704
2728
  const sub = args[0] ?? "show";
@@ -2739,7 +2763,18 @@ function createMemoryCommands() {
2739
2763
  const pending = memories.filter((m) => !m.approved && !isMemoryExpired(m)).length;
2740
2764
  console.log(theme.heading("\n\u{1F9E0} Governed Memory"));
2741
2765
  console.log(` active : ${active}`);
2742
- console.log(` pending : ${pending}`);
2766
+ if (pending > 0) {
2767
+ console.log(theme.warning(` pending : ${pending} \u2014 run /memory show, then /memory approve <id>`));
2768
+ } else {
2769
+ console.log(` pending : 0`);
2770
+ }
2771
+ const injected = formatMemoryForPrompt(configDir, process.cwd(), ctx.config.get("memory")?.maxChars);
2772
+ if (injected) {
2773
+ const truncNote = injected.truncated ? theme.warning(` \u26A0 truncated \u2014 only newest ${injected.entryCount} of ${injected.totalCount} injected`) : "";
2774
+ console.log(` injected : ${injected.entryCount} of ${injected.totalCount} (${injected.content.length} chars)${truncNote}`);
2775
+ } else {
2776
+ console.log(` injected : 0`);
2777
+ }
2743
2778
  console.log(` store : ${memoryStorePath(configDir)}`);
2744
2779
  console.log(theme.heading("\n\u{1F9E0} Chat Memory Index"));
2745
2780
  if (!s.exists) {
@@ -2762,15 +2797,31 @@ function createMemoryCommands() {
2762
2797
  ctx.renderer.printInfo("Usage: /memory recall <query>");
2763
2798
  return;
2764
2799
  }
2800
+ const persistentHits = searchPersistentMemories(configDir, query, process.cwd(), 3);
2801
+ if (persistentHits.length > 0) {
2802
+ touchMemoryReferences(configDir, persistentHits.map((h) => h.entry.id));
2803
+ console.log(theme.heading(`
2804
+ \u{1F4DD} Persistent memory \u2014 ${persistentHits.length} hit(s):
2805
+ `));
2806
+ for (const [i, h] of persistentHits.entries()) {
2807
+ console.log(theme.accent(` [${i + 1}] id ${h.entry.id.slice(0, 8)} \xB7 ${h.entry.scope} \xB7 coverage ${h.score.toFixed(2)}`));
2808
+ console.log(theme.dim(" ") + h.entry.content.replace(/\n/g, "\n "));
2809
+ console.log();
2810
+ }
2811
+ }
2765
2812
  try {
2766
2813
  const hits = await searchChatMemory(query, { topK: 5, minScore: 0.2 });
2767
2814
  if (hits.length === 0) {
2768
- console.log(theme.warning(` No memories matched "${query}" above score 0.20.`));
2815
+ if (persistentHits.length === 0) {
2816
+ console.log(theme.warning(` No memories matched "${query}" (persistent + chat index).`));
2817
+ } else {
2818
+ console.log(theme.dim(` (no chat-history hits above score 0.20)`));
2819
+ }
2769
2820
  console.log();
2770
2821
  return;
2771
2822
  }
2772
2823
  console.log(theme.heading(`
2773
- \u{1F9E0} Memory recall for "${query}" \u2014 ${hits.length} hit(s):
2824
+ \u{1F9E0} Chat history recall for "${query}" \u2014 ${hits.length} hit(s):
2774
2825
  `));
2775
2826
  for (const [i, h] of hits.entries()) {
2776
2827
  const ts = h.chunk.timestamp.slice(0, 16).replace("T", " ");
@@ -2813,17 +2864,54 @@ function createMemoryCommands() {
2813
2864
  const asScope = (value) => value === "personal" || value === "project" || value === "session" || value === "team" ? value : void 0;
2814
2865
  const asSensitivity = (value) => value === "low" || value === "medium" || value === "high" ? value : void 0;
2815
2866
  if (sub === "show" || sub === "view" || sub === "list") {
2816
- const entries = listMemoryEntries(configDir, { includeExpired: true, includeRejected: true });
2867
+ const parsed = parseFlags(args.slice(1));
2868
+ const scopeFilter = asScope(parsed.flags.scope);
2869
+ const searchText = typeof parsed.flags.search === "string" ? parsed.flags.search.toLowerCase() : (parsed.text || void 0)?.toLowerCase();
2870
+ const filters = [];
2871
+ let entries;
2872
+ if (parsed.flags.orphaned === true) {
2873
+ entries = listOrphanedProjectMemories(configDir);
2874
+ filters.push("orphaned");
2875
+ } else {
2876
+ entries = listMemoryEntries(configDir, { includeExpired: true, includeRejected: true });
2877
+ }
2878
+ if (parsed.flags.pending === true) {
2879
+ entries = entries.filter((m) => !m.approved && !isMemoryExpired(m));
2880
+ filters.push("pending");
2881
+ }
2882
+ if (scopeFilter) {
2883
+ entries = entries.filter((m) => m.scope === scopeFilter);
2884
+ filters.push(`scope:${scopeFilter}`);
2885
+ }
2886
+ if (searchText) {
2887
+ entries = entries.filter((m) => m.content.toLowerCase().includes(searchText) || m.id.startsWith(searchText));
2888
+ filters.push(`search:"${searchText}"`);
2889
+ }
2890
+ const staleDays = typeof parsed.flags.stale === "string" ? Number(parsed.flags.stale) : void 0;
2891
+ if (staleDays !== void 0) {
2892
+ if (!Number.isFinite(staleDays) || staleDays <= 0) {
2893
+ ctx.renderer.renderError("Usage: /memory show --stale <days> (positive number)");
2894
+ return;
2895
+ }
2896
+ entries = entries.filter((m) => isMemoryStale(m, staleDays));
2897
+ filters.push(`stale>${staleDays}d`);
2898
+ }
2817
2899
  if (entries.length === 0) {
2818
- ctx.renderer.printInfo("Memory is empty");
2900
+ ctx.renderer.printInfo(filters.length > 0 ? `No memory entries match [${filters.join(", ")}]` : "Memory is empty");
2819
2901
  return;
2820
2902
  }
2821
- console.log(theme.heading("\n\u{1F4DD} Governed Persistent Memory:\n") + theme.dim("\u2500".repeat(72)));
2903
+ const filterNote = filters.length > 0 ? theme.dim(` (filtered: ${filters.join(", ")})`) : "";
2904
+ console.log(theme.heading("\n\u{1F4DD} Governed Persistent Memory:") + filterNote + "\n" + theme.dim("\u2500".repeat(72)));
2822
2905
  for (const entry of entries) {
2823
2906
  const status = isMemoryExpired(entry) ? "expired" : entry.approved ? "approved" : "pending";
2824
- const source = entry.sourceSession ? `session ${entry.sourceSession.slice(0, 8)}` : entry.sourceProject ? `project ${entry.sourceProject}` : "manual/tool";
2907
+ const source = [
2908
+ entry.source ?? "unknown",
2909
+ entry.sourceSession ? `session ${entry.sourceSession.slice(0, 8)}` : "",
2910
+ entry.sourceProject ? `project ${entry.sourceProject}` : ""
2911
+ ].filter(Boolean).join(" \xB7 ");
2825
2912
  console.log(theme.accent(` ${entry.id.slice(0, 8)} ${status} scope:${entry.scope} sensitivity:${entry.sensitivity}`));
2826
- console.log(theme.dim(` source: ${source} \xB7 created: ${entry.createdAt.replace("T", " ").slice(0, 19)}${entry.expiresAt ? ` \xB7 expires: ${entry.expiresAt}` : ""}`));
2913
+ const lastRef = entry.lastReferencedAt ? ` \xB7 last-referenced: ${entry.lastReferencedAt.slice(0, 10)}` : "";
2914
+ console.log(theme.dim(` source: ${source} \xB7 created: ${entry.createdAt.replace("T", " ").slice(0, 19)}${lastRef}${entry.expiresAt ? ` \xB7 expires: ${entry.expiresAt}` : ""}`));
2827
2915
  console.log(" " + entry.content.replace(/\n/g, "\n "));
2828
2916
  console.log();
2829
2917
  }
@@ -2833,12 +2921,14 @@ function createMemoryCommands() {
2833
2921
  } else if (sub === "add") {
2834
2922
  const parsed = parseFlags(args.slice(1));
2835
2923
  if (!parsed.text) {
2836
- ctx.renderer.printInfo("Usage: /memory add [--scope personal|project|session|team] [--sensitivity low|medium|high] [--expires-at ISO] <text>");
2924
+ ctx.renderer.printInfo("Usage: /memory add [--scope personal|project] [--sensitivity low|medium|high] [--expires-at ISO] <text>");
2837
2925
  return;
2838
2926
  }
2839
2927
  try {
2928
+ const similar = findSimilarMemory(loadMemoryEntries(configDir), parsed.text);
2840
2929
  const entry = addMemoryEntry(configDir, parsed.text, {
2841
- scope: asScope(parsed.flags.scope) ?? "personal",
2930
+ scope: parseWritableScope(parsed.flags.scope) ?? "personal",
2931
+ source: "manual",
2842
2932
  sensitivity: asSensitivity(parsed.flags.sensitivity),
2843
2933
  expiresAt: typeof parsed.flags["expires-at"] === "string" ? parsed.flags["expires-at"] : void 0,
2844
2934
  approved: parsed.flags.pending === true ? false : void 0,
@@ -2847,9 +2937,39 @@ function createMemoryCommands() {
2847
2937
  });
2848
2938
  const status = entry.approved ? "approved" : "pending approval";
2849
2939
  ctx.renderer.printSuccess(`Added memory ${entry.id.slice(0, 8)} (${status}, scope:${entry.scope}, sensitivity:${entry.sensitivity})`);
2940
+ if (similar) {
2941
+ ctx.renderer.printInfo(`\u26A0 Similar entry already exists: ${similar.id.slice(0, 8)} \u2014 consider /memory edit ${similar.id.slice(0, 8)} <text> or /memory delete one of them.`);
2942
+ }
2850
2943
  } catch (err) {
2851
2944
  ctx.renderer.renderError(`Failed to write memory: ${err instanceof Error ? err.message : String(err)}`);
2852
2945
  }
2946
+ } else if (sub === "edit") {
2947
+ const id = args[1];
2948
+ const newText = args.slice(2).join(" ").trim();
2949
+ if (!id || !newText) {
2950
+ ctx.renderer.printInfo("Usage: /memory edit <id> <new text>");
2951
+ return;
2952
+ }
2953
+ try {
2954
+ const entry = updateMemoryEntry(configDir, id, newText, { source: "manual", redact: true });
2955
+ const status = entry.approved ? "approved" : "pending approval \u2014 run /memory approve " + entry.id.slice(0, 8);
2956
+ ctx.renderer.printSuccess(`Updated memory ${entry.id.slice(0, 8)} (${status})`);
2957
+ } catch (err) {
2958
+ ctx.renderer.renderError(err instanceof Error ? err.message : String(err));
2959
+ }
2960
+ } else if (sub === "rebind") {
2961
+ const id = args[1];
2962
+ const newPath = args.slice(2).join(" ").trim();
2963
+ if (!id || !newPath) {
2964
+ ctx.renderer.printInfo("Usage: /memory rebind <id> <new project path> (find orphans with /memory show --orphaned)");
2965
+ return;
2966
+ }
2967
+ try {
2968
+ const entry = rebindMemoryProject(configDir, id, newPath);
2969
+ ctx.renderer.printSuccess(`Rebound memory ${entry.id.slice(0, 8)} to project ${entry.sourceProject}`);
2970
+ } catch (err) {
2971
+ ctx.renderer.renderError(err instanceof Error ? err.message : String(err));
2972
+ }
2853
2973
  } else if (sub === "approve" || sub === "reject") {
2854
2974
  const id = args[1];
2855
2975
  if (!id) {
@@ -2887,16 +3007,82 @@ function createMemoryCommands() {
2887
3007
  ctx.renderer.renderError(err instanceof Error ? err.message : String(err));
2888
3008
  }
2889
3009
  } else if (sub === "export") {
2890
- console.log(exportMemoryEntries(configDir, process.cwd()));
3010
+ const parsed = parseFlags(args.slice(1));
3011
+ const format = parsed.flags.format === "md" ? "md" : "json";
3012
+ if (parsed.flags.format && parsed.flags.format !== "md" && parsed.flags.format !== "json") {
3013
+ ctx.renderer.renderError(`Unknown format: ${parsed.flags.format}. Use --format json|md.`);
3014
+ return;
3015
+ }
3016
+ const output = exportMemoryEntries(configDir, process.cwd(), format);
3017
+ const outPath = typeof parsed.flags.out === "string" ? parsed.flags.out : void 0;
3018
+ if (outPath) {
3019
+ try {
3020
+ atomicWriteFileSync(outPath, output);
3021
+ const label = format === "md" ? "active entries (markdown)" : "all entries (json)";
3022
+ ctx.renderer.printSuccess(`Exported ${label} to ${outPath}`);
3023
+ } catch (err) {
3024
+ ctx.renderer.renderError(`Export failed: ${err instanceof Error ? err.message : String(err)}`);
3025
+ }
3026
+ } else {
3027
+ console.log(output);
3028
+ }
2891
3029
  } else if (sub === "clear") {
2892
- atomicWriteFileSync(memoryStorePath(configDir), "");
2893
- atomicWriteFileSync(memoryMarkdownPath(configDir), "");
2894
- ctx.renderer.printSuccess("Memory cleared (memory.jsonl and memory.md emptied)");
3030
+ const all = listMemoryEntries(configDir, { includeExpired: true, includeRejected: true });
3031
+ if (all.length === 0) {
3032
+ ctx.renderer.printInfo("Memory is already empty.");
3033
+ return;
3034
+ }
3035
+ console.log();
3036
+ console.log(theme.warning(` About to permanently clear ALL persistent memory (${all.length} entr${all.length > 1 ? "ies" : "y"}):`));
3037
+ for (const entry of all.slice(0, 5)) {
3038
+ const first = entry.content.split("\n")[0];
3039
+ console.log(theme.dim(` ${entry.id.slice(0, 8)} ${first.length > 60 ? first.slice(0, 60) + "\u2026" : first}`));
3040
+ }
3041
+ if (all.length > 5) console.log(theme.dim(` \u2026 and ${all.length - 5} more`));
3042
+ console.log();
3043
+ const choice = await ctx.select("Clear all persistent memory?", [
3044
+ { label: "No \u2014 keep it", value: "no" },
3045
+ { label: "Yes \u2014 clear all", value: "yes", hint: "a timestamped .bak backup is kept next to memory.jsonl" }
3046
+ ]);
3047
+ if (choice !== "yes") {
3048
+ ctx.renderer.printInfo("Cancelled \u2014 memory kept.");
3049
+ return;
3050
+ }
3051
+ const result = clearMemoryEntries(configDir);
3052
+ ctx.renderer.printSuccess(`Cleared ${result.cleared} memory entr${result.cleared > 1 ? "ies" : "y"}.`);
3053
+ if (result.backupPath) {
3054
+ ctx.renderer.printInfo(`Backup saved: ${result.backupPath}`);
3055
+ }
3056
+ } else if (sub === "backup") {
3057
+ const parsed = parseFlags(args.slice(1));
3058
+ try {
3059
+ const result = backupMemoryStore(configDir, typeof parsed.flags.out === "string" ? parsed.flags.out : void 0);
3060
+ ctx.renderer.printSuccess(`Backed up ${result.count} entr${result.count > 1 ? "ies" : "y"} to ${result.backupPath}`);
3061
+ } catch (err) {
3062
+ ctx.renderer.renderError(err instanceof Error ? err.message : String(err));
3063
+ }
3064
+ } else if (sub === "restore") {
3065
+ const file = args[1];
3066
+ if (!file) {
3067
+ ctx.renderer.printInfo("Usage: /memory restore <file> (accepts .jsonl backups or /memory export JSON)");
3068
+ return;
3069
+ }
3070
+ try {
3071
+ const result = restoreMemoryEntries(configDir, file);
3072
+ ctx.renderer.printSuccess(`Restored ${result.imported} entr${result.imported === 1 ? "y" : "ies"} (${result.skipped} duplicate${result.skipped === 1 ? "" : "s"} skipped)`);
3073
+ if (result.backupPath) ctx.renderer.printInfo(`Pre-restore backup: ${result.backupPath}`);
3074
+ const pending = countPendingMemories(configDir);
3075
+ if (pending > 0) ctx.renderer.printInfo(`${pending} entr${pending > 1 ? "ies" : "y"} pending approval \u2014 /memory show --pending`);
3076
+ } catch (err) {
3077
+ ctx.renderer.renderError(`Restore failed: ${err instanceof Error ? err.message : String(err)}`);
3078
+ }
2895
3079
  } else if (sub === "path") {
2896
3080
  console.log(theme.accent(memoryStorePath(configDir)));
2897
3081
  console.log(theme.dim(memoryMarkdownPath(configDir)));
2898
3082
  } else {
2899
- ctx.renderer.printInfo("Usage: /memory [show|add|approve|reject|delete|expire|export|path|rebuild|refresh|status|recall|index-clear]");
3083
+ ctx.renderer.printInfo(
3084
+ "Governed persistent memory: show [--pending|--orphaned|--stale <days>|--scope <s>|--search <text>] | add | edit <id> <text> | approve/reject/delete/expire <id> | rebind <id> <path> | clear | backup [--out <file>] | restore <file> | export [--format json|md] [--out <file>] | path\nChat memory index (cross-session recall): rebuild | refresh | status | recall <query> | index-clear"
3085
+ );
2900
3086
  }
2901
3087
  }
2902
3088
  },
@@ -5570,7 +5756,7 @@ var Repl = class {
5570
5756
  return { layers: result.layers, mergedContent: result.mergedContent };
5571
5757
  }
5572
5758
  loadMemoryContent() {
5573
- return formatMemoryForPrompt(this.config.getConfigDir(), process.cwd());
5759
+ return formatMemoryForPrompt(this.config.getConfigDir(), process.cwd(), this.config.get("memory")?.maxChars);
5574
5760
  }
5575
5761
  /**
5576
5762
  * 将项目上下文内容合并到 system prompt。
@@ -5952,8 +6138,21 @@ Session '${this.resumeSessionId}' not found.
5952
6138
  }
5953
6139
  const memoryInfo = this.loadMemoryContent();
5954
6140
  if (memoryInfo) {
6141
+ const truncNote = memoryInfo.truncated ? theme.warning(` \u26A0 truncated: newest ${memoryInfo.entryCount} of ${memoryInfo.totalCount} injected \u2014 /memory show to prune`) : "";
5955
6142
  process.stdout.write(
5956
- theme.dim(` \u{1F4DD} Memory loaded: ${memoryInfo.entryCount} entries (${memoryInfo.content.length} chars)
6143
+ theme.dim(` \u{1F4DD} Memory loaded: ${memoryInfo.entryCount} entries (${memoryInfo.content.length} chars)`) + truncNote + "\n"
6144
+ );
6145
+ }
6146
+ const pendingMemories = countPendingMemories(this.config.getConfigDir());
6147
+ if (pendingMemories > 0) {
6148
+ process.stdout.write(
6149
+ theme.warning(` \u26A0 ${pendingMemories} memory entr${pendingMemories > 1 ? "ies" : "y"} pending approval \u2014 run /memory show, then /memory approve <id>
6150
+ `)
6151
+ );
6152
+ }
6153
+ if (detectStaleLegacyMarkdownEdit(this.config.getConfigDir())) {
6154
+ process.stdout.write(
6155
+ theme.dim(` \u2139 memory.md was edited but is no longer read back (memory.jsonl is the source of truth) \u2014 use /memory add or /memory edit instead
5957
6156
  `)
5958
6157
  );
5959
6158
  }
@@ -6012,14 +6211,26 @@ Session '${this.resumeSessionId}' not found.
6012
6211
  })();
6013
6212
  void (async () => {
6014
6213
  try {
6015
- const { getChatIndexStatus: getChatIndexStatus2, buildChatIndex: buildChatIndex2 } = await import("./chat-index-7HXBWQFH.js");
6214
+ const { getChatIndexStatus: getChatIndexStatus2, buildChatIndex: buildChatIndex2 } = await import("./chat-index-ALUHFJKI.js");
6016
6215
  const initial = getChatIndexStatus2();
6017
6216
  this.chatMemoryStatus = {
6018
6217
  exists: initial.exists,
6019
6218
  chunks: initial.chunks,
6020
6219
  sessions: initial.sessions
6021
6220
  };
6022
- if (!initial.exists) return;
6221
+ if (!initial.exists) {
6222
+ try {
6223
+ const sessionCount = this.sessions.listSessions().length;
6224
+ if (sessionCount >= 5) {
6225
+ process.stdout.write(theme.dim(
6226
+ ` \u{1F4A1} ${sessionCount} past sessions have no memory index \u2014 run /memory rebuild to enable cross-session recall (first run downloads ~117 MB)
6227
+ `
6228
+ ));
6229
+ }
6230
+ } catch {
6231
+ }
6232
+ return;
6233
+ }
6023
6234
  const stats = await buildChatIndex2({ full: false });
6024
6235
  const after = getChatIndexStatus2();
6025
6236
  this.chatMemoryStatus = {
@@ -7803,7 +8014,7 @@ program.command("web").description("Start Web UI server with browser-based chat
7803
8014
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
7804
8015
  process.exit(1);
7805
8016
  }
7806
- const { startWebServer } = await import("./server-UVS2D4M6.js");
8017
+ const { startWebServer } = await import("./server-A5NGGDMP.js");
7807
8018
  await startWebServer({ port, host: options.host });
7808
8019
  });
7809
8020
  program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | logout-all <name> | migrate <name>)").action(async (action, username) => {
@@ -7970,11 +8181,11 @@ program.command("sessions").description("List recent conversation sessions").opt
7970
8181
  console.log(footer + "\n");
7971
8182
  });
7972
8183
  program.command("usage").description("Show token + cost usage grouped by provider/model (cross-session)").option("--days <n>", "Only the last N days (inclusive of today)").option("--month <ym>", "Only a specific month, format YYYY-MM (e.g. 2026-06)").option("--json", "Output as JSON (for scripting)").action(async (options) => {
7973
- const { runUsageCli } = await import("./usage-EDJ6QOWB.js");
8184
+ const { runUsageCli } = await import("./usage-7WJC234G.js");
7974
8185
  await runUsageCli(options);
7975
8186
  });
7976
8187
  program.command("doctor").description("Health check: API keys, config, MCP, recent crashes, tool usage, disk usage").option("--json", "Output as JSON (for scripting)").option("--reset-stats", "Reset accumulated tool usage statistics").action(async (options) => {
7977
- const { runDoctorCli } = await import("./doctor-cli-TGAW6RAP.js");
8188
+ const { runDoctorCli } = await import("./doctor-cli-4QUHTJZ4.js");
7978
8189
  const argv = process.argv.slice(2);
7979
8190
  await runDoctorCli({
7980
8191
  json: !!options.json || argv.includes("--json"),
@@ -7983,7 +8194,7 @@ program.command("doctor").description("Health check: API keys, config, MCP, rece
7983
8194
  });
7984
8195
  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) => {
7985
8196
  try {
7986
- const batch = await import("./batch-K66BLTLJ.js");
8197
+ const batch = await import("./batch-CUVZUPRK.js");
7987
8198
  switch (action) {
7988
8199
  case "submit":
7989
8200
  if (!arg) {
@@ -8026,7 +8237,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
8026
8237
  }
8027
8238
  });
8028
8239
  program.command("mcp-serve").description("Start an MCP server over STDIO, exposing aicli's built-in tools to Claude Desktop / Cursor / other MCP clients").option("--allow-destructive", "Allow bash / run_interactive / task_create (always destructive in MCP mode)").option("--allow-outside-cwd", "Allow tool path arguments to escape the sandbox root \u2014 disabled by default").option("--tools <list>", "Comma-separated whitelist of tools to expose (default: all eligible tools)").option("--cwd <path>", "Working directory AND sandbox root (default: current directory)").action(async (options) => {
8029
- const { startMcpServer } = await import("./server-E545UIX7.js");
8240
+ const { startMcpServer } = await import("./server-FEFIFJDA.js");
8030
8241
  await startMcpServer({
8031
8242
  allowDestructive: !!options.allowDestructive,
8032
8243
  allowOutsideCwd: !!options.allowOutsideCwd,
@@ -8039,7 +8250,7 @@ program.command("pr <action> [target]").description("PR review helpers: review |
8039
8250
  console.error(`Unknown pr action: ${action}. Use review | security-review | summarize.`);
8040
8251
  process.exit(1);
8041
8252
  }
8042
- const { runPrCli } = await import("./pr-TJFKUZ4B.js");
8253
+ const { runPrCli } = await import("./pr-GIDFO4KP.js");
8043
8254
  const result = await runPrCli({
8044
8255
  action,
8045
8256
  target,
@@ -8059,8 +8270,8 @@ program.command("pr <action> [target]").description("PR review helpers: review |
8059
8270
  process.exit(result.exitCode);
8060
8271
  });
8061
8272
  program.command("ci").description("Headless PR review (code + security) \u2014 reads git/gh diff, optionally posts to PR. Designed for GitHub Actions.").option("--pr <num>", "PR number or URL; diff fetched via gh pr diff <value>", (v) => /^#?\d+$/.test(v) ? parseInt(v.replace(/^#/, ""), 10) : v).option("--base <ref>", "Base ref for git diff <ref>...HEAD (ignored when --pr set)").option("--post", "Post review as a PR comment (requires gh CLI + GH_TOKEN, needs --pr)").option("--no-update", "Always create a new comment instead of updating the previous aicli review").option("--skip-code", "Skip the code review section").option("--skip-security", "Skip the security review section").option("--detailed", "Use the detailed code-review prompt").option("--max-diff <n>", "Max diff chars sent to the model (default 30000)", (v) => parseInt(v, 10)).option("--provider <id>", "Override provider (default: config.defaultProvider)").option("--model <id>", "Override model").option("--dry-run", "Print result to stdout instead of posting (overrides --post)").option("--json", "Output a structured JSON report").option("--markdown", "Output Markdown report (default)").option("--sarif", "Output SARIF 2.1.0 for code scanning artifacts").option("--fail-on-security-high", "Fail when the security review contains HIGH/CRITICAL findings (default)").option("--no-fail-on-security-high", "Do not fail on security HIGH/CRITICAL findings").option("--fail-on-test-failure", "Fail when the report mentions test failures (default)").option("--no-fail-on-test-failure", "Do not fail on test failure findings").option("--fail-on-lint-failure", "Fail when the report mentions lint/typecheck failures (default)").option("--no-fail-on-lint-failure", "Do not fail on lint/typecheck failure findings").action(async (options) => {
8062
- const { runCi } = await import("./ci-T2ABDMMQ.js");
8063
- const { formatCiResult } = await import("./ci-format-S2PPU27O.js");
8273
+ const { runCi } = await import("./ci-3O3JR6FX.js");
8274
+ const { formatCiResult } = await import("./ci-format-KGWF6KOU.js");
8064
8275
  const formats = [options.json, options.markdown, options.sarif].filter(Boolean).length;
8065
8276
  if (formats > 1) {
8066
8277
  console.error("Choose only one output format: --json, --markdown, or --sarif.");
@@ -8218,7 +8429,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
8218
8429
  config.get("customProviders"),
8219
8430
  config.getConfigDir()
8220
8431
  );
8221
- const { startHub } = await import("./hub-GL5ZU6WS.js");
8432
+ const { startHub } = await import("./hub-2GXFPWOR.js");
8222
8433
  await startHub(
8223
8434
  {
8224
8435
  topic: topic ?? "",
@@ -2,9 +2,10 @@
2
2
  import {
3
3
  discussionToMessages,
4
4
  persistDiscussion
5
- } from "./chunk-2QQKS56X.js";
6
- import "./chunk-JMP3LJC2.js";
7
- import "./chunk-KCEO2XJ4.js";
5
+ } from "./chunk-DT77O33T.js";
6
+ import "./chunk-KWQKQVPH.js";
7
+ import "./chunk-PJ3ONBWZ.js";
8
+ import "./chunk-B5TYJO7V.js";
8
9
  import "./chunk-IW3Q7AE5.js";
9
10
  export {
10
11
  discussionToMessages,