jinzd-ai-cli 0.4.242 → 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 (31) hide show
  1. package/dist/{batch-D3UHL432.js → batch-CUVZUPRK.js} +2 -2
  2. package/dist/{chunk-Y4CMNXZH.js → chunk-66CE3E6X.js} +1 -1
  3. package/dist/{chunk-LHINXQZF.js → chunk-DJGCG7SF.js} +1 -1
  4. package/dist/{chunk-J363BGOH.js → chunk-EMFCHE2B.js} +1 -1
  5. package/dist/{chunk-MKLPAQT6.js → chunk-GEWPLNKA.js} +1 -1
  6. package/dist/{chunk-PSP6UIKL.js → chunk-H3ARWBYR.js} +2 -2
  7. package/dist/{chunk-FRNWQIG6.js → chunk-HNJX3N2V.js} +3 -3
  8. package/dist/{chunk-FEMPCNX3.js → chunk-KILKF2VN.js} +28 -12
  9. package/dist/{chunk-6ZWNXHNH.js → chunk-L5IRDRWG.js} +1 -1
  10. package/dist/{chunk-MC2ZNPBC.js → chunk-PLEXBFCR.js} +1 -1
  11. package/dist/{chunk-UWV2NBCO.js → chunk-PNNZRJ67.js} +107 -2
  12. package/dist/{chunk-OO2PHOXD.js → chunk-QNK7GUUB.js} +3 -3
  13. package/dist/{chunk-D27TMEOV.js → chunk-TY4FSEZS.js} +107 -2
  14. package/dist/{chunk-WMAXYDCB.js → chunk-X73Y4JZI.js} +1 -1
  15. package/dist/{ci-WSED3Z6V.js → ci-3O3JR6FX.js} +4 -4
  16. package/dist/{ci-format-6AYL2X2J.js → ci-format-KGWF6KOU.js} +2 -2
  17. package/dist/{constants-FJ3L5GYO.js → constants-NMFRZ5LW.js} +1 -1
  18. package/dist/{doctor-cli-HCP56MKH.js → doctor-cli-4QUHTJZ4.js} +4 -4
  19. package/dist/electron-server.js +94 -78
  20. package/dist/{hub-K5MYSVEF.js → hub-2GXFPWOR.js} +1 -1
  21. package/dist/index.js +91 -25
  22. package/dist/{persistent-memory-EYAKL2XA.js → persistent-memory-VFBRMKGG.js} +12 -2
  23. package/dist/{persistent-memory-HWFNDQFQ.js → persistent-memory-ZCQKLIC5.js} +12 -2
  24. package/dist/{pr-OICMUN6R.js → pr-GIDFO4KP.js} +4 -4
  25. package/dist/{run-tests-DSEW5HED.js → run-tests-BMH6QJN2.js} +2 -2
  26. package/dist/{run-tests-B3FSE5NV.js → run-tests-WCZBWQFS.js} +2 -2
  27. package/dist/{server-2FS65CQZ.js → server-A5NGGDMP.js} +11 -11
  28. package/dist/{server-EDCGPEGC.js → server-FEFIFJDA.js} +5 -5
  29. package/dist/{task-orchestrator-WCZYV3TE.js → task-orchestrator-J2H6OV6R.js} +5 -5
  30. package/dist/{usage-WVUYNLOD.js → usage-7WJC234G.js} +2 -2
  31. package/package.json +1 -1
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConfigManager
4
- } from "./chunk-WMAXYDCB.js";
4
+ } from "./chunk-X73Y4JZI.js";
5
5
  import "./chunk-5ULLIOVC.js";
6
- import "./chunk-Y4CMNXZH.js";
6
+ import "./chunk-66CE3E6X.js";
7
7
  import {
8
8
  atomicWriteFileSync
9
9
  } from "./chunk-IW3Q7AE5.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/core/constants.ts
4
- var VERSION = "0.4.242";
4
+ var VERSION = "0.4.243";
5
5
  var APP_NAME = "ai-cli";
6
6
  var CONFIG_DIR_NAME = ".aicli";
7
7
  var CONFIG_FILE_NAME = "config.json";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  VERSION
4
- } from "./chunk-Y4CMNXZH.js";
4
+ } from "./chunk-66CE3E6X.js";
5
5
 
6
6
  // src/cli/ci-format.ts
7
7
  var DEFAULT_CI_THRESHOLDS = {
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  CONFIG_DIR_NAME,
4
4
  PLUGINS_DIR_NAME
5
- } from "./chunk-Y4CMNXZH.js";
5
+ } from "./chunk-66CE3E6X.js";
6
6
  import {
7
7
  atomicWriteFileSync
8
8
  } from "./chunk-IW3Q7AE5.js";
@@ -1,5 +1,5 @@
1
1
  // src/core/constants.ts
2
- var VERSION = "0.4.242";
2
+ var VERSION = "0.4.243";
3
3
  var APP_NAME = "ai-cli";
4
4
  var CONFIG_DIR_NAME = ".aicli";
5
5
  var CONFIG_FILE_NAME = "config.json";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  truncateForPersist
4
- } from "./chunk-FEMPCNX3.js";
4
+ } from "./chunk-KILKF2VN.js";
5
5
  import {
6
6
  APP_NAME,
7
7
  CONFIG_DIR_NAME,
@@ -11,7 +11,7 @@ import {
11
11
  MCP_PROTOCOL_VERSION,
12
12
  MCP_TOOL_PREFIX,
13
13
  VERSION
14
- } from "./chunk-Y4CMNXZH.js";
14
+ } from "./chunk-66CE3E6X.js";
15
15
  import {
16
16
  atomicWriteFileSync
17
17
  } from "./chunk-IW3Q7AE5.js";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-QYQI7ZWK.js";
5
5
  import {
6
6
  ConfigManager
7
- } from "./chunk-WMAXYDCB.js";
7
+ } from "./chunk-X73Y4JZI.js";
8
8
  import {
9
9
  getActivePluginAssets,
10
10
  getPendingHookTrust,
@@ -14,7 +14,7 @@ import {
14
14
  listHooks,
15
15
  listInstalledPlugins,
16
16
  resetStats
17
- } from "./chunk-J363BGOH.js";
17
+ } from "./chunk-EMFCHE2B.js";
18
18
  import {
19
19
  getGitRoot
20
20
  } from "./chunk-HOSJZMQS.js";
@@ -26,7 +26,7 @@ import {
26
26
  MCP_PROJECT_CONFIG_NAME,
27
27
  MEMORY_FILE_NAME,
28
28
  VERSION
29
- } from "./chunk-Y4CMNXZH.js";
29
+ } from "./chunk-66CE3E6X.js";
30
30
 
31
31
  // src/diagnostics/doctor-report.ts
32
32
  import { existsSync as existsSync3, statSync as statSync2 } from "fs";
@@ -4,8 +4,10 @@ import {
4
4
  findSimilarMemory,
5
5
  loadMemoryEntries,
6
6
  parseWritableScope,
7
+ searchPersistentMemories,
8
+ touchMemoryReferences,
7
9
  updateMemoryEntry
8
- } from "./chunk-D27TMEOV.js";
10
+ } from "./chunk-TY4FSEZS.js";
9
11
  import {
10
12
  indexProject
11
13
  } from "./chunk-K3CF65QH.js";
@@ -21,7 +23,7 @@ import {
21
23
  runHook,
22
24
  runLifecycleHooks,
23
25
  runTool
24
- } from "./chunk-J363BGOH.js";
26
+ } from "./chunk-EMFCHE2B.js";
25
27
  import {
26
28
  getDangerLevel,
27
29
  isFileWriteTool,
@@ -37,14 +39,14 @@ import {
37
39
  } from "./chunk-4BKXL7SM.js";
38
40
  import {
39
41
  runTestsTool
40
- } from "./chunk-6ZWNXHNH.js";
42
+ } from "./chunk-L5IRDRWG.js";
41
43
  import {
42
44
  CONFIG_DIR_NAME,
43
45
  DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
44
46
  SUBAGENT_ALLOWED_TOOLS,
45
47
  SUBAGENT_DEFAULT_MAX_ROUNDS,
46
48
  SUBAGENT_MAX_ROUNDS_LIMIT
47
- } from "./chunk-Y4CMNXZH.js";
49
+ } from "./chunk-66CE3E6X.js";
48
50
  import {
49
51
  loadChatIndex,
50
52
  searchChatMemory
@@ -6576,6 +6578,8 @@ ${lines.join("\n")}`;
6576
6578
  };
6577
6579
 
6578
6580
  // src/tools/builtin/recall-memory.ts
6581
+ import { join as join8 } from "path";
6582
+ import { homedir as homedir5 } from "os";
6579
6583
  function formatHit(h, i) {
6580
6584
  const ts = h.chunk.timestamp.slice(0, 16).replace("T", " ");
6581
6585
  const title = h.chunk.sessionTitle ? ` \xB7 ${h.chunk.sessionTitle}` : "";
@@ -6588,7 +6592,7 @@ function formatHit(h, i) {
6588
6592
  var recallMemoryTool = {
6589
6593
  definition: {
6590
6594
  name: "recall_memory",
6591
- description: 'Semantic search over past chat sessions. Call this whenever the user references something that may have been discussed before ("last time", "remember", "\u4E4B\u524D", "\u4E0A\u6B21"), when context is ambiguous and continuity matters, or when you want to check what decisions or preferences have been established across prior conversations. Returns up to `topK` relevant snippets with session id, timestamp, and cosine similarity score. Prefer this over asking the user "can you remind me".',
6595
+ description: 'Search long-term memory: governed persistent memory entries (keyword match) plus semantic search over past chat sessions. Call this whenever the user references something that may have been discussed before ("last time", "remember", "\u4E4B\u524D", "\u4E0A\u6B21"), when context is ambiguous and continuity matters, or when you want to check what decisions or preferences have been established across prior conversations \u2014 including memories that were dropped from the injected system prompt by the size budget. Returns persistent-memory hits first, then up to `topK` chat snippets with session id, timestamp, and cosine similarity score. Prefer this over asking the user "can you remind me".',
6592
6596
  parameters: {
6593
6597
  query: {
6594
6598
  type: "string",
@@ -6625,9 +6629,21 @@ var recallMemoryTool = {
6625
6629
  const excludeCurrent = Boolean(args["excludeCurrentSession"]);
6626
6630
  const currentId = args["currentSessionId"] ? String(args["currentSessionId"]) : void 0;
6627
6631
  const minScore = args["minScore"] !== void 0 ? Number(args["minScore"]) : 0.25;
6632
+ const configDir = join8(homedir5(), CONFIG_DIR_NAME);
6633
+ let persistentSection = "";
6634
+ try {
6635
+ const persistentHits = searchPersistentMemories(configDir, query, process.cwd(), 3);
6636
+ if (persistentHits.length > 0) {
6637
+ touchMemoryReferences(configDir, persistentHits.map((h) => h.entry.id));
6638
+ persistentSection = `\u2500\u2500 Persistent memory (${persistentHits.length} hit(s)) \u2500\u2500
6639
+ ` + persistentHits.map((h) => `[id ${h.entry.id.slice(0, 8)} \xB7 ${h.entry.scope} \xB7 coverage ${h.score.toFixed(2)}]
6640
+ ${h.entry.content}`).join("\n\n") + "\n\n";
6641
+ }
6642
+ } catch {
6643
+ }
6628
6644
  const status = loadChatIndex();
6629
6645
  if (!status) {
6630
- return "No chat memory index found. The index is built on REPL startup, or run `/memory rebuild` manually. If you have no past sessions yet, this is expected.";
6646
+ return persistentSection + "No chat memory index found. The index is built on REPL startup, or run `/memory rebuild` manually. If you have no past sessions yet, this is expected.";
6631
6647
  }
6632
6648
  const hits = await searchChatMemory(query, {
6633
6649
  topK,
@@ -6635,11 +6651,11 @@ var recallMemoryTool = {
6635
6651
  excludeSessionId: excludeCurrent ? currentId : void 0
6636
6652
  });
6637
6653
  if (hits.length === 0) {
6638
- return `No memories matched "${query}" above score ${minScore}. Index has ${status.idx.chunks.length} chunks across ${Object.keys(status.idx.sessionMtimes).length} sessions. Consider lowering minScore to 0.15 or rephrasing the query.`;
6654
+ return persistentSection + `No chat-history memories matched "${query}" above score ${minScore}. Index has ${status.idx.chunks.length} chunks across ${Object.keys(status.idx.sessionMtimes).length} sessions. Consider lowering minScore to 0.15 or rephrasing the query.`;
6639
6655
  }
6640
- const header = `Found ${hits.length} memory hit(s) for "${query}" (min-score ${minScore}):
6656
+ const header = `Found ${hits.length} chat-history hit(s) for "${query}" (min-score ${minScore}):
6641
6657
  `;
6642
- return header + "\n" + hits.map(formatHit).join("\n\n");
6658
+ return persistentSection + header + "\n" + hits.map(formatHit).join("\n\n");
6643
6659
  }
6644
6660
  };
6645
6661
 
@@ -6668,7 +6684,7 @@ function estimateToolDefinitionTokens(def) {
6668
6684
  // src/tools/registry.ts
6669
6685
  import { pathToFileURL } from "url";
6670
6686
  import { existsSync as existsSync14, mkdirSync as mkdirSync3, readdirSync as readdirSync7 } from "fs";
6671
- import { join as join8 } from "path";
6687
+ import { join as join9 } from "path";
6672
6688
  var ToolRegistry = class {
6673
6689
  tools = /* @__PURE__ */ new Map();
6674
6690
  pluginToolNames = /* @__PURE__ */ new Set();
@@ -6855,12 +6871,12 @@ var ToolRegistry = class {
6855
6871
  process.stderr.write(
6856
6872
  `
6857
6873
  [plugins] \u26A0 Loading ${files.length} plugin(s) with FULL system privileges:
6858
- ` + files.map((f) => ` + ${join8(pluginsDir, f)}`).join("\n") + "\n\n"
6874
+ ` + files.map((f) => ` + ${join9(pluginsDir, f)}`).join("\n") + "\n\n"
6859
6875
  );
6860
6876
  let loaded = 0;
6861
6877
  for (const file of files) {
6862
6878
  try {
6863
- const fileUrl = pathToFileURL(join8(pluginsDir, file)).href;
6879
+ const fileUrl = pathToFileURL(join9(pluginsDir, file)).href;
6864
6880
  const mod = await import(fileUrl);
6865
6881
  const tool = mod.tool ?? mod.default?.tool ?? mod.default;
6866
6882
  if (!tool || typeof tool.execute !== "function" || !tool.definition?.name) {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-Y4CMNXZH.js";
4
+ } from "./chunk-66CE3E6X.js";
5
5
 
6
6
  // src/tools/builtin/run-tests.ts
7
7
  import { execSync, spawnSync } from "child_process";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TEST_TIMEOUT
3
- } from "./chunk-MKLPAQT6.js";
3
+ } from "./chunk-GEWPLNKA.js";
4
4
 
5
5
  // src/tools/builtin/run-tests.ts
6
6
  import { execSync, spawnSync } from "child_process";
@@ -6,7 +6,7 @@ import {
6
6
  MEMORY_FILE_NAME,
7
7
  MEMORY_MAX_CHARS,
8
8
  MEMORY_STORE_FILE_NAME
9
- } from "./chunk-MKLPAQT6.js";
9
+ } from "./chunk-GEWPLNKA.js";
10
10
  import {
11
11
  atomicWriteFileSync
12
12
  } from "./chunk-6BUTA5VW.js";
@@ -147,6 +147,7 @@ function normalizeEntry(value) {
147
147
  createdAt,
148
148
  updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : createdAt,
149
149
  expiresAt: typeof raw.expiresAt === "string" && raw.expiresAt ? raw.expiresAt : void 0,
150
+ lastReferencedAt: typeof raw.lastReferencedAt === "string" && raw.lastReferencedAt ? raw.lastReferencedAt : void 0,
150
151
  sensitivity: isValidSensitivity(raw.sensitivity) ? raw.sensitivity : "low",
151
152
  approved: raw.approved === true,
152
153
  redactedKinds: Array.isArray(raw.redactedKinds) ? raw.redactedKinds.filter((x) => typeof x === "string") : void 0
@@ -387,6 +388,105 @@ function detectStaleLegacyMarkdownEdit(configDir) {
387
388
  return false;
388
389
  }
389
390
  }
391
+ function touchMemoryReferences(configDir, ids) {
392
+ if (ids.length === 0) return;
393
+ const wanted = new Set(ids);
394
+ const entries = loadMemoryEntries(configDir);
395
+ let changed = false;
396
+ const ts = nowIso();
397
+ for (const entry of entries) {
398
+ if (wanted.has(entry.id)) {
399
+ entry.lastReferencedAt = ts;
400
+ changed = true;
401
+ }
402
+ }
403
+ if (changed) saveMemoryEntries(configDir, entries);
404
+ }
405
+ function isMemoryStale(entry, days, at = /* @__PURE__ */ new Date()) {
406
+ const reference = Date.parse(entry.lastReferencedAt ?? entry.updatedAt);
407
+ if (!Number.isFinite(reference)) return false;
408
+ return at.getTime() - reference > days * 864e5;
409
+ }
410
+ function tokenizeQuery(query) {
411
+ const tokens = [];
412
+ for (const word of query.toLowerCase().split(/\s+/).filter(Boolean)) {
413
+ const cjkRuns = word.match(/[一-鿿぀-ヿ가-힯]+/g) ?? [];
414
+ const nonCjk = word.replace(/[一-鿿぀-ヿ가-힯]+/g, " ").split(/\s+/).filter((t) => t.length >= 2);
415
+ tokens.push(...nonCjk);
416
+ for (const run of cjkRuns) {
417
+ if (run.length === 1) tokens.push(run);
418
+ for (let i = 0; i + 2 <= run.length; i++) tokens.push(run.slice(i, i + 2));
419
+ }
420
+ }
421
+ return [...new Set(tokens)];
422
+ }
423
+ function searchPersistentMemories(configDir, query, cwd = process.cwd(), limit = 3) {
424
+ const tokens = tokenizeQuery(query);
425
+ if (tokens.length === 0) return [];
426
+ const entries = listMemoryEntries(configDir, { cwd }).filter((entry) => entry.approved && !isMemoryExpired(entry));
427
+ const hits = [];
428
+ for (const entry of entries) {
429
+ const haystack = entry.content.toLowerCase();
430
+ const matched = tokens.filter((token) => haystack.includes(token)).length;
431
+ const score = matched / tokens.length;
432
+ if (score >= 0.34) hits.push({ entry, score });
433
+ }
434
+ return hits.sort((a, b) => b.score - a.score).slice(0, limit);
435
+ }
436
+ function backupMemoryStore(configDir, outPath) {
437
+ const entries = loadMemoryEntries(configDir);
438
+ if (entries.length === 0) throw new Error("memory is empty \u2014 nothing to back up");
439
+ const storePath = memoryStorePath(configDir);
440
+ if (!existsSync2(storePath)) saveMemoryEntries(configDir, entries);
441
+ const backupPath = outPath ?? `${storePath}.bak.${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
442
+ copyFileSync(storePath, backupPath);
443
+ return { backupPath, count: entries.length };
444
+ }
445
+ function restoreMemoryEntries(configDir, filePath) {
446
+ const text = readFileSync(filePath, "utf-8").trim();
447
+ if (!text) throw new Error(`restore file is empty: ${filePath}`);
448
+ let rawItems;
449
+ try {
450
+ const parsed = JSON.parse(text);
451
+ rawItems = Array.isArray(parsed) ? parsed : [parsed];
452
+ } catch {
453
+ rawItems = text.split("\n").map((line) => {
454
+ try {
455
+ return JSON.parse(line.trim());
456
+ } catch {
457
+ return null;
458
+ }
459
+ }).filter((x) => x !== null);
460
+ }
461
+ const candidates = rawItems.map((item) => normalizeEntry(item)).filter((entry) => Boolean(entry));
462
+ if (candidates.length === 0) throw new Error(`no valid memory entries found in ${filePath}`);
463
+ const existing = loadMemoryEntries(configDir);
464
+ const existingIds = new Set(existing.map((entry) => entry.id));
465
+ let backupPath = null;
466
+ if (existing.length > 0) {
467
+ backupPath = backupMemoryStore(configDir).backupPath;
468
+ }
469
+ let imported = 0;
470
+ let skipped = 0;
471
+ for (const candidate of candidates) {
472
+ if (existingIds.has(candidate.id)) {
473
+ skipped++;
474
+ continue;
475
+ }
476
+ const redacted = redactString(candidate.content, { enabled: true, patterns: DEFAULT_PATTERNS });
477
+ if (redacted.hits.length > 0) {
478
+ candidate.content = redacted.redacted.trim();
479
+ candidate.sensitivity = "high";
480
+ candidate.approved = false;
481
+ candidate.redactedKinds = [...new Set(redacted.hits.map((hit) => hit.kind))];
482
+ }
483
+ existing.push(candidate);
484
+ existingIds.add(candidate.id);
485
+ imported++;
486
+ }
487
+ saveMemoryEntries(configDir, existing);
488
+ return { imported, skipped, backupPath };
489
+ }
390
490
 
391
491
  export {
392
492
  getGitRoot,
@@ -414,5 +514,10 @@ export {
414
514
  findSimilarMemory,
415
515
  listOrphanedProjectMemories,
416
516
  rebindMemoryProject,
417
- detectStaleLegacyMarkdownEdit
517
+ detectStaleLegacyMarkdownEdit,
518
+ touchMemoryReferences,
519
+ isMemoryStale,
520
+ searchPersistentMemories,
521
+ backupMemoryStore,
522
+ restoreMemoryEntries
418
523
  };
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  evaluateCiGate,
4
4
  normalizeCiThresholds
5
- } from "./chunk-LHINXQZF.js";
5
+ } from "./chunk-DJGCG7SF.js";
6
6
  import {
7
7
  buildReviewPrompt,
8
8
  buildSecurityReviewPrompt,
@@ -13,10 +13,10 @@ import {
13
13
  } from "./chunk-QYQI7ZWK.js";
14
14
  import {
15
15
  ConfigManager
16
- } from "./chunk-WMAXYDCB.js";
16
+ } from "./chunk-X73Y4JZI.js";
17
17
  import {
18
18
  VERSION
19
- } from "./chunk-Y4CMNXZH.js";
19
+ } from "./chunk-66CE3E6X.js";
20
20
 
21
21
  // src/cli/ci.ts
22
22
  import { execFileSync } from "child_process";
@@ -6,7 +6,7 @@ import {
6
6
  MEMORY_FILE_NAME,
7
7
  MEMORY_MAX_CHARS,
8
8
  MEMORY_STORE_FILE_NAME
9
- } from "./chunk-Y4CMNXZH.js";
9
+ } from "./chunk-66CE3E6X.js";
10
10
  import {
11
11
  DEFAULT_PATTERNS,
12
12
  redactString
@@ -59,6 +59,7 @@ function normalizeEntry(value) {
59
59
  createdAt,
60
60
  updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : createdAt,
61
61
  expiresAt: typeof raw.expiresAt === "string" && raw.expiresAt ? raw.expiresAt : void 0,
62
+ lastReferencedAt: typeof raw.lastReferencedAt === "string" && raw.lastReferencedAt ? raw.lastReferencedAt : void 0,
62
63
  sensitivity: isValidSensitivity(raw.sensitivity) ? raw.sensitivity : "low",
63
64
  approved: raw.approved === true,
64
65
  redactedKinds: Array.isArray(raw.redactedKinds) ? raw.redactedKinds.filter((x) => typeof x === "string") : void 0
@@ -299,6 +300,105 @@ function detectStaleLegacyMarkdownEdit(configDir) {
299
300
  return false;
300
301
  }
301
302
  }
303
+ function touchMemoryReferences(configDir, ids) {
304
+ if (ids.length === 0) return;
305
+ const wanted = new Set(ids);
306
+ const entries = loadMemoryEntries(configDir);
307
+ let changed = false;
308
+ const ts = nowIso();
309
+ for (const entry of entries) {
310
+ if (wanted.has(entry.id)) {
311
+ entry.lastReferencedAt = ts;
312
+ changed = true;
313
+ }
314
+ }
315
+ if (changed) saveMemoryEntries(configDir, entries);
316
+ }
317
+ function isMemoryStale(entry, days, at = /* @__PURE__ */ new Date()) {
318
+ const reference = Date.parse(entry.lastReferencedAt ?? entry.updatedAt);
319
+ if (!Number.isFinite(reference)) return false;
320
+ return at.getTime() - reference > days * 864e5;
321
+ }
322
+ function tokenizeQuery(query) {
323
+ const tokens = [];
324
+ for (const word of query.toLowerCase().split(/\s+/).filter(Boolean)) {
325
+ const cjkRuns = word.match(/[一-鿿぀-ヿ가-힯]+/g) ?? [];
326
+ const nonCjk = word.replace(/[一-鿿぀-ヿ가-힯]+/g, " ").split(/\s+/).filter((t) => t.length >= 2);
327
+ tokens.push(...nonCjk);
328
+ for (const run of cjkRuns) {
329
+ if (run.length === 1) tokens.push(run);
330
+ for (let i = 0; i + 2 <= run.length; i++) tokens.push(run.slice(i, i + 2));
331
+ }
332
+ }
333
+ return [...new Set(tokens)];
334
+ }
335
+ function searchPersistentMemories(configDir, query, cwd = process.cwd(), limit = 3) {
336
+ const tokens = tokenizeQuery(query);
337
+ if (tokens.length === 0) return [];
338
+ const entries = listMemoryEntries(configDir, { cwd }).filter((entry) => entry.approved && !isMemoryExpired(entry));
339
+ const hits = [];
340
+ for (const entry of entries) {
341
+ const haystack = entry.content.toLowerCase();
342
+ const matched = tokens.filter((token) => haystack.includes(token)).length;
343
+ const score = matched / tokens.length;
344
+ if (score >= 0.34) hits.push({ entry, score });
345
+ }
346
+ return hits.sort((a, b) => b.score - a.score).slice(0, limit);
347
+ }
348
+ function backupMemoryStore(configDir, outPath) {
349
+ const entries = loadMemoryEntries(configDir);
350
+ if (entries.length === 0) throw new Error("memory is empty \u2014 nothing to back up");
351
+ const storePath = memoryStorePath(configDir);
352
+ if (!existsSync(storePath)) saveMemoryEntries(configDir, entries);
353
+ const backupPath = outPath ?? `${storePath}.bak.${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
354
+ copyFileSync(storePath, backupPath);
355
+ return { backupPath, count: entries.length };
356
+ }
357
+ function restoreMemoryEntries(configDir, filePath) {
358
+ const text = readFileSync(filePath, "utf-8").trim();
359
+ if (!text) throw new Error(`restore file is empty: ${filePath}`);
360
+ let rawItems;
361
+ try {
362
+ const parsed = JSON.parse(text);
363
+ rawItems = Array.isArray(parsed) ? parsed : [parsed];
364
+ } catch {
365
+ rawItems = text.split("\n").map((line) => {
366
+ try {
367
+ return JSON.parse(line.trim());
368
+ } catch {
369
+ return null;
370
+ }
371
+ }).filter((x) => x !== null);
372
+ }
373
+ const candidates = rawItems.map((item) => normalizeEntry(item)).filter((entry) => Boolean(entry));
374
+ if (candidates.length === 0) throw new Error(`no valid memory entries found in ${filePath}`);
375
+ const existing = loadMemoryEntries(configDir);
376
+ const existingIds = new Set(existing.map((entry) => entry.id));
377
+ let backupPath = null;
378
+ if (existing.length > 0) {
379
+ backupPath = backupMemoryStore(configDir).backupPath;
380
+ }
381
+ let imported = 0;
382
+ let skipped = 0;
383
+ for (const candidate of candidates) {
384
+ if (existingIds.has(candidate.id)) {
385
+ skipped++;
386
+ continue;
387
+ }
388
+ const redacted = redactString(candidate.content, { enabled: true, patterns: DEFAULT_PATTERNS });
389
+ if (redacted.hits.length > 0) {
390
+ candidate.content = redacted.redacted.trim();
391
+ candidate.sensitivity = "high";
392
+ candidate.approved = false;
393
+ candidate.redactedKinds = [...new Set(redacted.hits.map((hit) => hit.kind))];
394
+ }
395
+ existing.push(candidate);
396
+ existingIds.add(candidate.id);
397
+ imported++;
398
+ }
399
+ saveMemoryEntries(configDir, existing);
400
+ return { imported, skipped, backupPath };
401
+ }
302
402
 
303
403
  export {
304
404
  parseWritableScope,
@@ -323,5 +423,10 @@ export {
323
423
  findSimilarMemory,
324
424
  listOrphanedProjectMemories,
325
425
  rebindMemoryProject,
326
- detectStaleLegacyMarkdownEdit
426
+ detectStaleLegacyMarkdownEdit,
427
+ touchMemoryReferences,
428
+ isMemoryStale,
429
+ searchPersistentMemories,
430
+ backupMemoryStore,
431
+ restoreMemoryEntries
327
432
  };
@@ -8,7 +8,7 @@ import {
8
8
  CONFIG_FILE_NAME,
9
9
  HISTORY_DIR_NAME,
10
10
  PLUGINS_DIR_NAME
11
- } from "./chunk-Y4CMNXZH.js";
11
+ } from "./chunk-66CE3E6X.js";
12
12
  import {
13
13
  atomicWriteFileSync
14
14
  } from "./chunk-IW3Q7AE5.js";
@@ -3,14 +3,14 @@ import {
3
3
  CI_COMMENT_MARKER,
4
4
  countSeverity,
5
5
  runCi
6
- } from "./chunk-OO2PHOXD.js";
7
- import "./chunk-LHINXQZF.js";
6
+ } from "./chunk-QNK7GUUB.js";
7
+ import "./chunk-DJGCG7SF.js";
8
8
  import "./chunk-HLWUDRBO.js";
9
9
  import "./chunk-QYQI7ZWK.js";
10
- import "./chunk-WMAXYDCB.js";
10
+ import "./chunk-X73Y4JZI.js";
11
11
  import "./chunk-O3XSFPYH.js";
12
12
  import "./chunk-5ULLIOVC.js";
13
- import "./chunk-Y4CMNXZH.js";
13
+ import "./chunk-66CE3E6X.js";
14
14
  import "./chunk-IW3Q7AE5.js";
15
15
  export {
16
16
  CI_COMMENT_MARKER,
@@ -6,8 +6,8 @@ import {
6
6
  formatCiResult,
7
7
  formatCiSarif,
8
8
  normalizeCiThresholds
9
- } from "./chunk-LHINXQZF.js";
10
- import "./chunk-Y4CMNXZH.js";
9
+ } from "./chunk-DJGCG7SF.js";
10
+ import "./chunk-66CE3E6X.js";
11
11
  export {
12
12
  DEFAULT_CI_THRESHOLDS,
13
13
  detectCiGateSignals,
@@ -38,7 +38,7 @@ import {
38
38
  TEST_TIMEOUT,
39
39
  VERSION,
40
40
  buildUserIdentityPrompt
41
- } from "./chunk-Y4CMNXZH.js";
41
+ } from "./chunk-66CE3E6X.js";
42
42
  export {
43
43
  AGENTIC_BEHAVIOR_GUIDELINE,
44
44
  APP_NAME,
@@ -2,14 +2,14 @@
2
2
  import {
3
3
  formatDoctorReport,
4
4
  runDoctorCli
5
- } from "./chunk-FRNWQIG6.js";
5
+ } from "./chunk-HNJX3N2V.js";
6
6
  import "./chunk-QYQI7ZWK.js";
7
- import "./chunk-WMAXYDCB.js";
8
- import "./chunk-J363BGOH.js";
7
+ import "./chunk-X73Y4JZI.js";
8
+ import "./chunk-EMFCHE2B.js";
9
9
  import "./chunk-O3XSFPYH.js";
10
10
  import "./chunk-5ULLIOVC.js";
11
11
  import "./chunk-HOSJZMQS.js";
12
- import "./chunk-Y4CMNXZH.js";
12
+ import "./chunk-66CE3E6X.js";
13
13
  import "./chunk-IW3Q7AE5.js";
14
14
  export {
15
15
  formatDoctorReport,