jinzd-ai-cli 0.4.242 → 0.4.244

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-GLB7ES6K.js} +2 -2
  2. package/dist/{chunk-6ZWNXHNH.js → chunk-6IAVHU3I.js} +1 -1
  3. package/dist/{chunk-WMAXYDCB.js → chunk-ACU6T7B3.js} +1 -1
  4. package/dist/{chunk-Y4CMNXZH.js → chunk-B7KTFHK2.js} +1 -1
  5. package/dist/{chunk-D27TMEOV.js → chunk-BKTCOL5D.js} +107 -2
  6. package/dist/{chunk-J363BGOH.js → chunk-BO5UU3TY.js} +1 -1
  7. package/dist/{chunk-FRNWQIG6.js → chunk-HN4FU37T.js} +3 -3
  8. package/dist/{chunk-UWV2NBCO.js → chunk-M7XY5AK5.js} +107 -2
  9. package/dist/{chunk-MC2ZNPBC.js → chunk-MCC5BEZG.js} +1 -1
  10. package/dist/{chunk-PSP6UIKL.js → chunk-OYFDGRYD.js} +2 -2
  11. package/dist/{chunk-OO2PHOXD.js → chunk-P6AUULT2.js} +3 -3
  12. package/dist/{chunk-FEMPCNX3.js → chunk-WF7FD7WS.js} +49 -27
  13. package/dist/{chunk-LHINXQZF.js → chunk-XZI4ULXF.js} +1 -1
  14. package/dist/{chunk-MKLPAQT6.js → chunk-ZQGCX4QD.js} +1 -1
  15. package/dist/{ci-WSED3Z6V.js → ci-V7RGDIER.js} +4 -4
  16. package/dist/{ci-format-6AYL2X2J.js → ci-format-HSUEHAM2.js} +2 -2
  17. package/dist/{constants-FJ3L5GYO.js → constants-OQ6FVQ23.js} +1 -1
  18. package/dist/{doctor-cli-HCP56MKH.js → doctor-cli-LABZF3XG.js} +4 -4
  19. package/dist/electron-server.js +115 -93
  20. package/dist/{hub-K5MYSVEF.js → hub-RTFICY6M.js} +1 -1
  21. package/dist/index.js +91 -25
  22. package/dist/{persistent-memory-HWFNDQFQ.js → persistent-memory-OWXDBSZY.js} +12 -2
  23. package/dist/{persistent-memory-EYAKL2XA.js → persistent-memory-P6LU5KDG.js} +12 -2
  24. package/dist/{pr-OICMUN6R.js → pr-HXJ6ML6M.js} +4 -4
  25. package/dist/{run-tests-B3FSE5NV.js → run-tests-EFWAH43I.js} +2 -2
  26. package/dist/{run-tests-DSEW5HED.js → run-tests-XJ44FWIK.js} +2 -2
  27. package/dist/{server-2FS65CQZ.js → server-6OPGWJ7S.js} +11 -11
  28. package/dist/{server-EDCGPEGC.js → server-B6WJWV3T.js} +5 -5
  29. package/dist/{task-orchestrator-WCZYV3TE.js → task-orchestrator-KHJYQXWU.js} +5 -5
  30. package/dist/{usage-WVUYNLOD.js → usage-NW2ZXN6N.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-ACU6T7B3.js";
5
5
  import "./chunk-5ULLIOVC.js";
6
- import "./chunk-Y4CMNXZH.js";
6
+ import "./chunk-B7KTFHK2.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
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-Y4CMNXZH.js";
4
+ } from "./chunk-B7KTFHK2.js";
5
5
 
6
6
  // src/tools/builtin/run-tests.ts
7
7
  import { execSync, spawnSync } from "child_process";
@@ -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-B7KTFHK2.js";
12
12
  import {
13
13
  atomicWriteFileSync
14
14
  } 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.244";
5
5
  var APP_NAME = "ai-cli";
6
6
  var CONFIG_DIR_NAME = ".aicli";
7
7
  var CONFIG_FILE_NAME = "config.json";
@@ -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-B7KTFHK2.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
  };
@@ -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-B7KTFHK2.js";
6
6
  import {
7
7
  atomicWriteFileSync
8
8
  } 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-ACU6T7B3.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-BO5UU3TY.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-B7KTFHK2.js";
30
30
 
31
31
  // src/diagnostics/doctor-report.ts
32
32
  import { existsSync as existsSync3, statSync as statSync2 } from "fs";
@@ -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-ZQGCX4QD.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
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TEST_TIMEOUT
3
- } from "./chunk-MKLPAQT6.js";
3
+ } from "./chunk-ZQGCX4QD.js";
4
4
 
5
5
  // src/tools/builtin/run-tests.ts
6
6
  import { execSync, spawnSync } from "child_process";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  truncateForPersist
4
- } from "./chunk-FEMPCNX3.js";
4
+ } from "./chunk-WF7FD7WS.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-B7KTFHK2.js";
15
15
  import {
16
16
  atomicWriteFileSync
17
17
  } from "./chunk-IW3Q7AE5.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  evaluateCiGate,
4
4
  normalizeCiThresholds
5
- } from "./chunk-LHINXQZF.js";
5
+ } from "./chunk-XZI4ULXF.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-ACU6T7B3.js";
17
17
  import {
18
18
  VERSION
19
- } from "./chunk-Y4CMNXZH.js";
19
+ } from "./chunk-B7KTFHK2.js";
20
20
 
21
21
  // src/cli/ci.ts
22
22
  import { execFileSync } from "child_process";
@@ -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-BKTCOL5D.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-BO5UU3TY.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-6IAVHU3I.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-B7KTFHK2.js";
48
50
  import {
49
51
  loadChatIndex,
50
52
  searchChatMemory
@@ -556,6 +558,10 @@ Important rules:
556
558
  [The user pressed Ctrl+C while this command was running. Stop the current task, summarize what was done so far, and wait for the user's next instruction. Do NOT retry this command or continue with further tool calls unless explicitly asked.]`
557
559
  );
558
560
  }
561
+ if (timedOut) {
562
+ pushBashUndoEntries(beforeSnapshot, parsedTargetsBefore, effectiveCwd);
563
+ throw new ToolError("bash", formatTimeoutMessage(timeout, MAX_TIMEOUT));
564
+ }
559
565
  if (status !== 0 || timedOut) {
560
566
  const poolStdout = (stdout ?? "").trim();
561
567
  const poolStderr = (stderr ?? "").trim();
@@ -617,21 +623,7 @@ ${combined || formatFailureFallback(status)}
617
623
  const execErr = err;
618
624
  const isTimeout = execErr.code === "ETIMEDOUT" || execErr.status == null && execErr.signal === "SIGTERM" || /ETIMEDOUT/i.test(execErr.message ?? "");
619
625
  if (isTimeout) {
620
- const seconds = Math.round(timeout / 1e3);
621
- throw new ToolError(
622
- "bash",
623
- `Command timed out after ${seconds}s.
624
-
625
- The previous command ran for longer than the timeout limit and was killed. This usually means it is scanning a large filesystem tree (recursive Get-ChildItem / find), compressing a big archive, or waiting on a network request.
626
-
627
- How to recover (pick ONE \u2014 do NOT retry the same command):
628
- 1. Pass an explicit longer timeout, e.g. timeout: ${Math.min(timeout * 2, MAX_TIMEOUT)}
629
- 2. Use a non-recursive / narrower alternative (e.g. 'Get-ChildItem -File' without -Recurse, or limit depth with -Depth 1)
630
- 3. Split the work into smaller batches (process subdirectories one at a time)
631
- 4. For size/count queries, use '(Get-ChildItem X).Count' per directory instead of one giant pipeline
632
-
633
- [Do NOT retry the identical command \u2014 it will time out again.]`
634
- );
626
+ throw new ToolError("bash", formatTimeoutMessage(timeout, MAX_TIMEOUT));
635
627
  }
636
628
  if ("status" in execErr && execErr.status !== void 0) {
637
629
  const stderr = IS_WINDOWS3 && Buffer.isBuffer(execErr.stderr) ? decodeWindowsBuffer(execErr.stderr).trim() : execErr.stderr?.toString().trim() ?? "";
@@ -656,6 +648,22 @@ ${combined || execErr.message || formatFailureFallback(execErr.status)}
656
648
  function formatFailureHeader(status) {
657
649
  return typeof status === "number" ? `Exit code ${status}:` : "Command failed before exit code could be determined:";
658
650
  }
651
+ function formatTimeoutMessage(timeout, maxTimeout) {
652
+ const seconds = Math.round(timeout / 1e3);
653
+ return [
654
+ `Command timed out after ${seconds}s.`,
655
+ "",
656
+ "The previous command ran for longer than the timeout limit and was killed. This usually means it is scanning a large filesystem tree (recursive Get-ChildItem / find), compressing a big archive, or waiting on a network request.",
657
+ "",
658
+ "How to recover (pick ONE \u2014 do NOT retry the same command):",
659
+ ` 1. Pass an explicit longer timeout, e.g. timeout: ${Math.min(timeout * 2, maxTimeout)}`,
660
+ " 2. Use a non-recursive / narrower alternative (e.g. 'Get-ChildItem -File' without -Recurse, or limit depth with -Depth 1)",
661
+ " 3. Split the work into smaller batches (process subdirectories one at a time)",
662
+ " 4. For size/count queries, use '(Get-ChildItem X).Count' per directory instead of one giant pipeline",
663
+ "",
664
+ "[Do NOT retry the identical command \u2014 it will time out again.]"
665
+ ].join(String.fromCharCode(10));
666
+ }
659
667
  function formatFailureFallback(status) {
660
668
  return typeof status === "number" ? `exit ${status}` : "The shell process ended before reporting a numeric exit code.";
661
669
  }
@@ -6576,6 +6584,8 @@ ${lines.join("\n")}`;
6576
6584
  };
6577
6585
 
6578
6586
  // src/tools/builtin/recall-memory.ts
6587
+ import { join as join8 } from "path";
6588
+ import { homedir as homedir5 } from "os";
6579
6589
  function formatHit(h, i) {
6580
6590
  const ts = h.chunk.timestamp.slice(0, 16).replace("T", " ");
6581
6591
  const title = h.chunk.sessionTitle ? ` \xB7 ${h.chunk.sessionTitle}` : "";
@@ -6588,7 +6598,7 @@ function formatHit(h, i) {
6588
6598
  var recallMemoryTool = {
6589
6599
  definition: {
6590
6600
  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".',
6601
+ 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
6602
  parameters: {
6593
6603
  query: {
6594
6604
  type: "string",
@@ -6625,9 +6635,21 @@ var recallMemoryTool = {
6625
6635
  const excludeCurrent = Boolean(args["excludeCurrentSession"]);
6626
6636
  const currentId = args["currentSessionId"] ? String(args["currentSessionId"]) : void 0;
6627
6637
  const minScore = args["minScore"] !== void 0 ? Number(args["minScore"]) : 0.25;
6638
+ const configDir = join8(homedir5(), CONFIG_DIR_NAME);
6639
+ let persistentSection = "";
6640
+ try {
6641
+ const persistentHits = searchPersistentMemories(configDir, query, process.cwd(), 3);
6642
+ if (persistentHits.length > 0) {
6643
+ touchMemoryReferences(configDir, persistentHits.map((h) => h.entry.id));
6644
+ persistentSection = `\u2500\u2500 Persistent memory (${persistentHits.length} hit(s)) \u2500\u2500
6645
+ ` + persistentHits.map((h) => `[id ${h.entry.id.slice(0, 8)} \xB7 ${h.entry.scope} \xB7 coverage ${h.score.toFixed(2)}]
6646
+ ${h.entry.content}`).join("\n\n") + "\n\n";
6647
+ }
6648
+ } catch {
6649
+ }
6628
6650
  const status = loadChatIndex();
6629
6651
  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.";
6652
+ 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
6653
  }
6632
6654
  const hits = await searchChatMemory(query, {
6633
6655
  topK,
@@ -6635,11 +6657,11 @@ var recallMemoryTool = {
6635
6657
  excludeSessionId: excludeCurrent ? currentId : void 0
6636
6658
  });
6637
6659
  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.`;
6660
+ 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
6661
  }
6640
- const header = `Found ${hits.length} memory hit(s) for "${query}" (min-score ${minScore}):
6662
+ const header = `Found ${hits.length} chat-history hit(s) for "${query}" (min-score ${minScore}):
6641
6663
  `;
6642
- return header + "\n" + hits.map(formatHit).join("\n\n");
6664
+ return persistentSection + header + "\n" + hits.map(formatHit).join("\n\n");
6643
6665
  }
6644
6666
  };
6645
6667
 
@@ -6668,7 +6690,7 @@ function estimateToolDefinitionTokens(def) {
6668
6690
  // src/tools/registry.ts
6669
6691
  import { pathToFileURL } from "url";
6670
6692
  import { existsSync as existsSync14, mkdirSync as mkdirSync3, readdirSync as readdirSync7 } from "fs";
6671
- import { join as join8 } from "path";
6693
+ import { join as join9 } from "path";
6672
6694
  var ToolRegistry = class {
6673
6695
  tools = /* @__PURE__ */ new Map();
6674
6696
  pluginToolNames = /* @__PURE__ */ new Set();
@@ -6855,12 +6877,12 @@ var ToolRegistry = class {
6855
6877
  process.stderr.write(
6856
6878
  `
6857
6879
  [plugins] \u26A0 Loading ${files.length} plugin(s) with FULL system privileges:
6858
- ` + files.map((f) => ` + ${join8(pluginsDir, f)}`).join("\n") + "\n\n"
6880
+ ` + files.map((f) => ` + ${join9(pluginsDir, f)}`).join("\n") + "\n\n"
6859
6881
  );
6860
6882
  let loaded = 0;
6861
6883
  for (const file of files) {
6862
6884
  try {
6863
- const fileUrl = pathToFileURL(join8(pluginsDir, file)).href;
6885
+ const fileUrl = pathToFileURL(join9(pluginsDir, file)).href;
6864
6886
  const mod = await import(fileUrl);
6865
6887
  const tool = mod.tool ?? mod.default?.tool ?? mod.default;
6866
6888
  if (!tool || typeof tool.execute !== "function" || !tool.definition?.name) {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  VERSION
4
- } from "./chunk-Y4CMNXZH.js";
4
+ } from "./chunk-B7KTFHK2.js";
5
5
 
6
6
  // src/cli/ci-format.ts
7
7
  var DEFAULT_CI_THRESHOLDS = {
@@ -1,5 +1,5 @@
1
1
  // src/core/constants.ts
2
- var VERSION = "0.4.242";
2
+ var VERSION = "0.4.244";
3
3
  var APP_NAME = "ai-cli";
4
4
  var CONFIG_DIR_NAME = ".aicli";
5
5
  var CONFIG_FILE_NAME = "config.json";
@@ -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-P6AUULT2.js";
7
+ import "./chunk-XZI4ULXF.js";
8
8
  import "./chunk-HLWUDRBO.js";
9
9
  import "./chunk-QYQI7ZWK.js";
10
- import "./chunk-WMAXYDCB.js";
10
+ import "./chunk-ACU6T7B3.js";
11
11
  import "./chunk-O3XSFPYH.js";
12
12
  import "./chunk-5ULLIOVC.js";
13
- import "./chunk-Y4CMNXZH.js";
13
+ import "./chunk-B7KTFHK2.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-XZI4ULXF.js";
10
+ import "./chunk-B7KTFHK2.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-B7KTFHK2.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-HN4FU37T.js";
6
6
  import "./chunk-QYQI7ZWK.js";
7
- import "./chunk-WMAXYDCB.js";
8
- import "./chunk-J363BGOH.js";
7
+ import "./chunk-ACU6T7B3.js";
8
+ import "./chunk-BO5UU3TY.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-B7KTFHK2.js";
13
13
  import "./chunk-IW3Q7AE5.js";
14
14
  export {
15
15
  formatDoctorReport,