jinzd-ai-cli 0.4.285 → 0.4.286

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 (41) hide show
  1. package/dist/{batch-R563COWE.js → batch-GY3I53DE.js} +13 -10
  2. package/dist/{chat-index-TDU3S2MG.js → chat-index-DGUOUUQW.js} +2 -2
  3. package/dist/{chunk-UW33KJW5.js → chunk-2YDLBM3Z.js} +1 -1
  4. package/dist/{chunk-3LFB4YZA.js → chunk-3ZQZO5F7.js} +3 -3
  5. package/dist/chunk-53V3RQY5.js +5684 -0
  6. package/dist/{chunk-XGRZA5V6.js → chunk-6SCELZG6.js} +3 -3
  7. package/dist/{chunk-DV5D7RXZ.js → chunk-7G7RZHJI.js} +1 -1
  8. package/dist/{chunk-KLBMKONV.js → chunk-BRLLV3FX.js} +4 -4
  9. package/dist/chunk-CGLYJRFA.js +95 -0
  10. package/dist/{chunk-WBF4AOHJ.js → chunk-D7HYLMCC.js} +18 -110
  11. package/dist/{chunk-5CC5HQFW.js → chunk-EYUCJBGS.js} +30 -30
  12. package/dist/{chunk-LF6SPK7I.js → chunk-GIJL4EFA.js} +10 -2
  13. package/dist/{chunk-VLM4SKKX.js → chunk-L4FDTQ42.js} +1 -1
  14. package/dist/{chunk-DPTEC6AQ.js → chunk-LWPWBRAC.js} +12 -10
  15. package/dist/chunk-RS7SKYTS.js +45 -0
  16. package/dist/{chunk-6G7Y2VG4.js → chunk-S7ABWTDV.js} +1 -1
  17. package/dist/{chunk-PHK7QQH3.js → chunk-THUXZNJL.js} +1 -1
  18. package/dist/{chunk-AOF4K5N7.js → chunk-UKITSNSH.js} +1 -1
  19. package/dist/{ci-E4CYVEOW.js → ci-JBUIVM7P.js} +4 -4
  20. package/dist/{ci-format-7XTLOAB5.js → ci-format-B4AHV5SI.js} +2 -2
  21. package/dist/{constants-L7D3IXWV.js → constants-5FYUQLKN.js} +1 -1
  22. package/dist/constants-P75MLFV7.js +80 -0
  23. package/dist/{doctor-cli-JLROIGLO.js → doctor-cli-VLFE46PX.js} +5 -4
  24. package/dist/electron-server.js +3549 -253
  25. package/dist/git-context-VNCA2GU7.js +10 -0
  26. package/dist/{hub-7UDPLWBI.js → hub-CNORVRYW.js} +1 -1
  27. package/dist/index.js +315 -3655
  28. package/dist/{persistent-memory-CNJOZ7U2.js → persistent-memory-3KL4N27E.js} +3 -2
  29. package/dist/{persistent-memory-DRXWYBJS.js → persistent-memory-LVX2OT4L.js} +2 -2
  30. package/dist/{pr-3W5547IS.js → pr-2YUV4KII.js} +4 -4
  31. package/dist/{run-tests-LP2CI4MT.js → run-tests-ERD6X534.js} +2 -2
  32. package/dist/{run-tests-7B7N4YAE.js → run-tests-KZ2IUZHK.js} +2 -2
  33. package/dist/{semantic-FF6DDJI6.js → semantic-VPNKXKKK.js} +2 -2
  34. package/dist/{server-NIPB62XP.js → server-7VSLW446.js} +6 -5
  35. package/dist/{server-YBMWBJVG.js → server-A3OX52UC.js} +21 -15
  36. package/dist/{task-orchestrator-RYG4ZTDO.js → task-orchestrator-XAMKOFUE.js} +6 -5
  37. package/dist/{usage-YDVLCZDU.js → usage-ZXNYCAZB.js} +4 -3
  38. package/package.json +1 -1
  39. package/dist/chunk-HBAYEVVJ.js +0 -2362
  40. package/dist/{chunk-AEAYUKSY.js → chunk-7XU4BATV.js} +3 -3
  41. package/dist/{chunk-YOVHMQEJ.js → chunk-I4GQRMFV.js} +3 -3
@@ -8,13 +8,13 @@ import {
8
8
  listHooks,
9
9
  listInstalledPlugins,
10
10
  resetStats
11
- } from "./chunk-5CC5HQFW.js";
11
+ } from "./chunk-EYUCJBGS.js";
12
12
  import {
13
13
  ProviderRegistry
14
14
  } from "./chunk-UGY5SVNX.js";
15
15
  import {
16
16
  ConfigManager
17
- } from "./chunk-DV5D7RXZ.js";
17
+ } from "./chunk-7G7RZHJI.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-PHK7QQH3.js";
29
+ } from "./chunk-THUXZNJL.js";
30
30
 
31
31
  // src/diagnostics/doctor-report.ts
32
32
  import { existsSync as existsSync3, statSync as statSync2 } from "fs";
@@ -11,7 +11,7 @@ import {
11
11
  CONFIG_FILE_NAME,
12
12
  HISTORY_DIR_NAME,
13
13
  PLUGINS_DIR_NAME
14
- } from "./chunk-PHK7QQH3.js";
14
+ } from "./chunk-THUXZNJL.js";
15
15
 
16
16
  // src/config/config-manager.ts
17
17
  import { readFileSync, existsSync, mkdirSync } from "fs";
@@ -11,7 +11,7 @@ import {
11
11
  searchPersistentMemories,
12
12
  touchMemoryReferences,
13
13
  updateMemoryEntry
14
- } from "./chunk-AOF4K5N7.js";
14
+ } from "./chunk-UKITSNSH.js";
15
15
  import {
16
16
  indexProject
17
17
  } from "./chunk-4DEMGCK4.js";
@@ -30,7 +30,7 @@ import {
30
30
  runHook,
31
31
  runLifecycleHooks,
32
32
  runTool
33
- } from "./chunk-5CC5HQFW.js";
33
+ } from "./chunk-EYUCJBGS.js";
34
34
  import {
35
35
  buildTruncatedArgumentsError,
36
36
  getDangerLevel,
@@ -50,14 +50,14 @@ import {
50
50
  } from "./chunk-4BKXL7SM.js";
51
51
  import {
52
52
  runTestsTool
53
- } from "./chunk-6G7Y2VG4.js";
53
+ } from "./chunk-S7ABWTDV.js";
54
54
  import {
55
55
  CONFIG_DIR_NAME,
56
56
  DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
57
57
  SUBAGENT_ALLOWED_TOOLS,
58
58
  SUBAGENT_DEFAULT_MAX_ROUNDS,
59
59
  SUBAGENT_MAX_ROUNDS_LIMIT
60
- } from "./chunk-PHK7QQH3.js";
60
+ } from "./chunk-THUXZNJL.js";
61
61
 
62
62
  // src/tools/shell-pool.ts
63
63
  import { spawn as spawn2 } from "child_process";
@@ -0,0 +1,95 @@
1
+ // src/tools/git-context.ts
2
+ import { execSync } from "child_process";
3
+ import { existsSync } from "fs";
4
+ import { join } from "path";
5
+ function runGit(cmd, cwd) {
6
+ try {
7
+ return execSync(`git ${cmd}`, {
8
+ cwd,
9
+ encoding: "utf-8",
10
+ stdio: ["pipe", "pipe", "pipe"],
11
+ timeout: 5e3
12
+ }).trim();
13
+ } catch {
14
+ return null;
15
+ }
16
+ }
17
+ function getGitRoot(cwd = process.cwd()) {
18
+ return runGit("rev-parse --show-toplevel", cwd);
19
+ }
20
+ function getGitContext(cwd = process.cwd()) {
21
+ if (!existsSync(join(cwd, ".git"))) {
22
+ const result = runGit("rev-parse --git-dir", cwd);
23
+ if (!result) return null;
24
+ }
25
+ const branch = runGit("rev-parse --abbrev-ref HEAD", cwd);
26
+ if (!branch) return null;
27
+ const statusOutput = runGit("status --porcelain", cwd) ?? "";
28
+ const statusLines = statusOutput ? statusOutput.split("\n").filter(Boolean) : [];
29
+ const stagedFiles = [];
30
+ const changedFiles = [];
31
+ for (const line of statusLines) {
32
+ const xy = line.slice(0, 2);
33
+ const file = line.slice(3).trim();
34
+ const indexStatus = xy[0];
35
+ const workStatus = xy[1];
36
+ if (indexStatus && indexStatus !== " " && indexStatus !== "?") {
37
+ stagedFiles.push(`${indexStatus} ${file}`);
38
+ }
39
+ if (workStatus && workStatus !== " ") {
40
+ changedFiles.push(`${workStatus} ${file}`);
41
+ }
42
+ }
43
+ const logOutput = runGit("log --oneline -3", cwd) ?? "";
44
+ const recentCommits = logOutput ? logOutput.split("\n").filter(Boolean) : [];
45
+ const unpushedOutput = runGit("log @{u}..HEAD --oneline", cwd);
46
+ const hasUnpushed = unpushedOutput !== null && unpushedOutput.trim().length > 0;
47
+ return {
48
+ branch,
49
+ changedFiles,
50
+ stagedFiles,
51
+ recentCommits,
52
+ hasUnpushed
53
+ };
54
+ }
55
+ function formatGitContextForPrompt(ctx) {
56
+ const lines = ["# Git Repository Status", ""];
57
+ lines.push(`- **Branch**: \`${ctx.branch}\``);
58
+ if (ctx.stagedFiles.length > 0) {
59
+ lines.push(`- **Staged** (${ctx.stagedFiles.length} files):`);
60
+ for (const f of ctx.stagedFiles.slice(0, 10)) {
61
+ lines.push(` - ${f}`);
62
+ }
63
+ if (ctx.stagedFiles.length > 10) {
64
+ lines.push(` - ... and ${ctx.stagedFiles.length - 10} more`);
65
+ }
66
+ }
67
+ if (ctx.changedFiles.length > 0) {
68
+ lines.push(`- **Modified** (${ctx.changedFiles.length} files):`);
69
+ for (const f of ctx.changedFiles.slice(0, 10)) {
70
+ lines.push(` - ${f}`);
71
+ }
72
+ if (ctx.changedFiles.length > 10) {
73
+ lines.push(` - ... and ${ctx.changedFiles.length - 10} more`);
74
+ }
75
+ }
76
+ if (ctx.stagedFiles.length === 0 && ctx.changedFiles.length === 0) {
77
+ lines.push("- **Working tree**: clean");
78
+ }
79
+ if (ctx.recentCommits.length > 0) {
80
+ lines.push("- **Recent commits**:");
81
+ for (const c of ctx.recentCommits) {
82
+ lines.push(` - ${c}`);
83
+ }
84
+ }
85
+ if (ctx.hasUnpushed) {
86
+ lines.push("- \u26A0\uFE0F Has unpushed commits");
87
+ }
88
+ return lines.join("\n");
89
+ }
90
+
91
+ export {
92
+ getGitRoot,
93
+ getGitContext,
94
+ formatGitContextForPrompt
95
+ };
@@ -2,119 +2,30 @@ import {
2
2
  DEFAULT_PATTERNS,
3
3
  redactString
4
4
  } from "./chunk-FSC6KEWU.js";
5
+ import {
6
+ atomicWriteFileSync
7
+ } from "./chunk-6BUTA5VW.js";
8
+ import {
9
+ getGitRoot
10
+ } from "./chunk-CGLYJRFA.js";
5
11
  import {
6
12
  MEMORY_FILE_NAME,
7
13
  MEMORY_MAX_CHARS,
8
14
  MEMORY_STORE_FILE_NAME
9
- } from "./chunk-LF6SPK7I.js";
10
- import {
11
- atomicWriteFileSync
12
- } from "./chunk-6BUTA5VW.js";
15
+ } from "./chunk-GIJL4EFA.js";
13
16
 
14
17
  // src/memory/persistent-memory.ts
15
- import { copyFileSync, existsSync as existsSync2, mkdirSync, readFileSync, statSync } from "fs";
18
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, statSync } from "fs";
16
19
  import { randomUUID, createHash } from "crypto";
17
- import { dirname, join as join2, resolve } from "path";
18
-
19
- // src/tools/git-context.ts
20
- import { execSync } from "child_process";
21
- import { existsSync } from "fs";
22
- import { join } from "path";
23
- function runGit(cmd, cwd) {
24
- try {
25
- return execSync(`git ${cmd}`, {
26
- cwd,
27
- encoding: "utf-8",
28
- stdio: ["pipe", "pipe", "pipe"],
29
- timeout: 5e3
30
- }).trim();
31
- } catch {
32
- return null;
33
- }
34
- }
35
- function getGitRoot(cwd = process.cwd()) {
36
- return runGit("rev-parse --show-toplevel", cwd);
37
- }
38
- function getGitContext(cwd = process.cwd()) {
39
- if (!existsSync(join(cwd, ".git"))) {
40
- const result = runGit("rev-parse --git-dir", cwd);
41
- if (!result) return null;
42
- }
43
- const branch = runGit("rev-parse --abbrev-ref HEAD", cwd);
44
- if (!branch) return null;
45
- const statusOutput = runGit("status --porcelain", cwd) ?? "";
46
- const statusLines = statusOutput ? statusOutput.split("\n").filter(Boolean) : [];
47
- const stagedFiles = [];
48
- const changedFiles = [];
49
- for (const line of statusLines) {
50
- const xy = line.slice(0, 2);
51
- const file = line.slice(3).trim();
52
- const indexStatus = xy[0];
53
- const workStatus = xy[1];
54
- if (indexStatus && indexStatus !== " " && indexStatus !== "?") {
55
- stagedFiles.push(`${indexStatus} ${file}`);
56
- }
57
- if (workStatus && workStatus !== " ") {
58
- changedFiles.push(`${workStatus} ${file}`);
59
- }
60
- }
61
- const logOutput = runGit("log --oneline -3", cwd) ?? "";
62
- const recentCommits = logOutput ? logOutput.split("\n").filter(Boolean) : [];
63
- const unpushedOutput = runGit("log @{u}..HEAD --oneline", cwd);
64
- const hasUnpushed = unpushedOutput !== null && unpushedOutput.trim().length > 0;
65
- return {
66
- branch,
67
- changedFiles,
68
- stagedFiles,
69
- recentCommits,
70
- hasUnpushed
71
- };
72
- }
73
- function formatGitContextForPrompt(ctx) {
74
- const lines = ["# Git Repository Status", ""];
75
- lines.push(`- **Branch**: \`${ctx.branch}\``);
76
- if (ctx.stagedFiles.length > 0) {
77
- lines.push(`- **Staged** (${ctx.stagedFiles.length} files):`);
78
- for (const f of ctx.stagedFiles.slice(0, 10)) {
79
- lines.push(` - ${f}`);
80
- }
81
- if (ctx.stagedFiles.length > 10) {
82
- lines.push(` - ... and ${ctx.stagedFiles.length - 10} more`);
83
- }
84
- }
85
- if (ctx.changedFiles.length > 0) {
86
- lines.push(`- **Modified** (${ctx.changedFiles.length} files):`);
87
- for (const f of ctx.changedFiles.slice(0, 10)) {
88
- lines.push(` - ${f}`);
89
- }
90
- if (ctx.changedFiles.length > 10) {
91
- lines.push(` - ... and ${ctx.changedFiles.length - 10} more`);
92
- }
93
- }
94
- if (ctx.stagedFiles.length === 0 && ctx.changedFiles.length === 0) {
95
- lines.push("- **Working tree**: clean");
96
- }
97
- if (ctx.recentCommits.length > 0) {
98
- lines.push("- **Recent commits**:");
99
- for (const c of ctx.recentCommits) {
100
- lines.push(` - ${c}`);
101
- }
102
- }
103
- if (ctx.hasUnpushed) {
104
- lines.push("- \u26A0\uFE0F Has unpushed commits");
105
- }
106
- return lines.join("\n");
107
- }
108
-
109
- // src/memory/persistent-memory.ts
20
+ import { dirname, join, resolve } from "path";
110
21
  function parseWritableScope(value) {
111
22
  return value === "personal" || value === "project" ? value : void 0;
112
23
  }
113
24
  function memoryStorePath(configDir) {
114
- return join2(configDir, MEMORY_STORE_FILE_NAME);
25
+ return join(configDir, MEMORY_STORE_FILE_NAME);
115
26
  }
116
27
  function memoryMarkdownPath(configDir) {
117
- return join2(configDir, MEMORY_FILE_NAME);
28
+ return join(configDir, MEMORY_FILE_NAME);
118
29
  }
119
30
  function getProjectKey(cwd = process.cwd()) {
120
31
  return resolve(getGitRoot(cwd) ?? cwd);
@@ -155,7 +66,7 @@ function normalizeEntry(value) {
155
66
  }
156
67
  function legacyEntriesFromMarkdown(configDir) {
157
68
  const file = memoryMarkdownPath(configDir);
158
- if (!existsSync2(file)) return [];
69
+ if (!existsSync(file)) return [];
159
70
  const content = readFileSync(file, "utf-8").trim();
160
71
  if (!content) return [];
161
72
  const parts = content.split(/\n(?=##\s+\d{4}-\d{2}-\d{2})/g);
@@ -172,7 +83,7 @@ ${chunk}`).digest("hex").slice(0, 12);
172
83
  }
173
84
  function loadMemoryEntries(configDir) {
174
85
  const file = memoryStorePath(configDir);
175
- if (!existsSync2(file)) return legacyEntriesFromMarkdown(configDir);
86
+ if (!existsSync(file)) return legacyEntriesFromMarkdown(configDir);
176
87
  const text = readFileSync(file, "utf-8").trim();
177
88
  if (!text) return [];
178
89
  const entries = [];
@@ -280,8 +191,8 @@ function clearMemoryEntries(configDir) {
280
191
  const storePath = memoryStorePath(configDir);
281
192
  let backupPath = null;
282
193
  if (entries.length > 0) {
283
- const sourceFile = existsSync2(storePath) ? storePath : memoryMarkdownPath(configDir);
284
- if (existsSync2(sourceFile)) {
194
+ const sourceFile = existsSync(storePath) ? storePath : memoryMarkdownPath(configDir);
195
+ if (existsSync(sourceFile)) {
285
196
  backupPath = `${sourceFile}.bak.${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
286
197
  copyFileSync(sourceFile, backupPath);
287
198
  }
@@ -364,7 +275,7 @@ function findSimilarMemory(entries, content) {
364
275
  return null;
365
276
  }
366
277
  function listOrphanedProjectMemories(configDir) {
367
- return loadMemoryEntries(configDir).filter((entry) => entry.scope === "project" && entry.sourceProject !== void 0 && !existsSync2(entry.sourceProject));
278
+ return loadMemoryEntries(configDir).filter((entry) => entry.scope === "project" && entry.sourceProject !== void 0 && !existsSync(entry.sourceProject));
368
279
  }
369
280
  function rebindMemoryProject(configDir, idPrefix, newProjectPath) {
370
281
  const entries = loadMemoryEntries(configDir);
@@ -378,7 +289,7 @@ function rebindMemoryProject(configDir, idPrefix, newProjectPath) {
378
289
  function detectStaleLegacyMarkdownEdit(configDir) {
379
290
  const jsonlPath = memoryStorePath(configDir);
380
291
  const mdPath = memoryMarkdownPath(configDir);
381
- if (!existsSync2(jsonlPath) || !existsSync2(mdPath)) return false;
292
+ if (!existsSync(jsonlPath) || !existsSync(mdPath)) return false;
382
293
  try {
383
294
  if (!readFileSync(mdPath, "utf-8").trim()) return false;
384
295
  const jsonlMtime = statSync(jsonlPath).mtimeMs;
@@ -437,7 +348,7 @@ function backupMemoryStore(configDir, outPath) {
437
348
  const entries = loadMemoryEntries(configDir);
438
349
  if (entries.length === 0) throw new Error("memory is empty \u2014 nothing to back up");
439
350
  const storePath = memoryStorePath(configDir);
440
- if (!existsSync2(storePath)) saveMemoryEntries(configDir, entries);
351
+ if (!existsSync(storePath)) saveMemoryEntries(configDir, entries);
441
352
  const backupPath = outPath ?? `${storePath}.bak.${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
442
353
  copyFileSync(storePath, backupPath);
443
354
  return { backupPath, count: entries.length };
@@ -489,9 +400,6 @@ function restoreMemoryEntries(configDir, filePath) {
489
400
  }
490
401
 
491
402
  export {
492
- getGitRoot,
493
- getGitContext,
494
- formatGitContextForPrompt,
495
403
  parseWritableScope,
496
404
  memoryStorePath,
497
405
  memoryMarkdownPath,
@@ -1,14 +1,17 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ loadJsonState
4
+ } from "./chunk-RS7SKYTS.js";
2
5
  import {
3
6
  atomicWriteFileSync
4
7
  } from "./chunk-IW3Q7AE5.js";
5
8
  import {
6
9
  CONFIG_DIR_NAME,
7
10
  PLUGINS_DIR_NAME
8
- } from "./chunk-PHK7QQH3.js";
11
+ } from "./chunk-THUXZNJL.js";
9
12
 
10
13
  // src/diagnostics/tool-stats.ts
11
- import { existsSync, readFileSync, mkdirSync } from "fs";
14
+ import { mkdirSync } from "fs";
12
15
  import { join, dirname } from "path";
13
16
  import { homedir } from "os";
14
17
  var STATS_FILE_NAME = "tool-stats.json";
@@ -23,19 +26,16 @@ function statsFilePath() {
23
26
  return join(base, STATS_FILE_NAME);
24
27
  }
25
28
  function load() {
26
- const path = statsFilePath();
27
- if (!existsSync(path)) {
28
- return { version: STATS_VERSION, startedAt: (/* @__PURE__ */ new Date()).toISOString(), entries: {} };
29
- }
30
- try {
31
- const raw = JSON.parse(readFileSync(path, "utf-8"));
32
- if (raw.version !== STATS_VERSION || !raw.entries) {
33
- return { version: STATS_VERSION, startedAt: (/* @__PURE__ */ new Date()).toISOString(), entries: {} };
29
+ const empty = () => ({ version: STATS_VERSION, startedAt: (/* @__PURE__ */ new Date()).toISOString(), entries: {} });
30
+ return loadJsonState(statsFilePath(), {
31
+ label: "tool statistics",
32
+ fallback: empty,
33
+ parse: (raw) => {
34
+ const data = raw;
35
+ if (!data || data.version !== STATS_VERSION || !data.entries) return null;
36
+ return data;
34
37
  }
35
- return raw;
36
- } catch {
37
- return { version: STATS_VERSION, startedAt: (/* @__PURE__ */ new Date()).toISOString(), entries: {} };
38
- }
38
+ }).value;
39
39
  }
40
40
  function ensureLoaded() {
41
41
  if (state === null) state = load();
@@ -121,7 +121,7 @@ function installFlushOnExit() {
121
121
  }
122
122
 
123
123
  // src/plugins/plugin-manager.ts
124
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2, realpathSync, cpSync, rmSync, statSync } from "fs";
124
+ import { existsSync, mkdirSync as mkdirSync2, readdirSync, readFileSync, realpathSync, cpSync, rmSync, statSync } from "fs";
125
125
  import { basename, dirname as dirname2, join as join2, relative, resolve, sep } from "path";
126
126
  import { createHash } from "crypto";
127
127
  import { z } from "zod";
@@ -192,9 +192,9 @@ function statePath(configDir) {
192
192
  }
193
193
  function loadState(configDir) {
194
194
  const file = statePath(configDir);
195
- if (!existsSync2(file)) return { version: 2, plugins: [] };
195
+ if (!existsSync(file)) return { version: 2, plugins: [] };
196
196
  try {
197
- const parsed = JSON.parse(readFileSync2(file, "utf-8"));
197
+ const parsed = JSON.parse(readFileSync(file, "utf-8"));
198
198
  const rawPlugins = Array.isArray(parsed.plugins) ? parsed.plugins : [];
199
199
  return { version: 2, plugins: rawPlugins.map((p) => migrateEntry(p)) };
200
200
  } catch {
@@ -252,7 +252,7 @@ function extractCommandPaths(command, pluginDir) {
252
252
  try {
253
253
  const abs = resolve(resolvedDir, ref);
254
254
  if (!abs.startsWith(resolvedDir + sep)) continue;
255
- if (existsSync2(abs)) {
255
+ if (existsSync(abs)) {
256
256
  const real = realpathSync(abs);
257
257
  if (!real.startsWith(resolvedDir + sep)) continue;
258
258
  valid.push(relative(resolvedDir, real));
@@ -285,7 +285,7 @@ function hashPluginContent(pluginDir, manifest) {
285
285
  const sorted = [...assetRels].sort();
286
286
  const hasher = createHash("sha256");
287
287
  const manifestPath = join2(resolvedDir, MANIFEST_RELATIVE);
288
- hasher.update(normalizeForHash(readFileSync2(manifestPath)));
288
+ hasher.update(normalizeForHash(readFileSync(manifestPath)));
289
289
  for (const rel of sorted) {
290
290
  const abs = resolve(resolvedDir, rel);
291
291
  if (!abs.startsWith(resolvedDir + sep)) {
@@ -305,7 +305,7 @@ function hashPluginContent(pluginDir, manifest) {
305
305
  if (!realPath.startsWith(resolvedDir + sep)) {
306
306
  throw new Error(`plugin asset symlink escapes plugin dir: ${rel} \u2192 ${realPath}`);
307
307
  }
308
- hasher.update(normalizeForHash(readFileSync2(abs)));
308
+ hasher.update(normalizeForHash(readFileSync(abs)));
309
309
  }
310
310
  return hasher.digest("hex");
311
311
  }
@@ -313,14 +313,14 @@ function effectiveHash(entry) {
313
313
  return entry.contentHash ?? entry.hash ?? "";
314
314
  }
315
315
  function readPluginManifest(manifestPath) {
316
- return PluginManifestSchema.parse(JSON.parse(readFileSync2(manifestPath, "utf-8")));
316
+ return PluginManifestSchema.parse(JSON.parse(readFileSync(manifestPath, "utf-8")));
317
317
  }
318
318
  function findPluginSourceDir(inputPath) {
319
319
  const abs = resolve(inputPath);
320
320
  const direct = statSync(abs).isDirectory() ? abs : dirname2(abs);
321
- if (existsSync2(pluginManifestPath(direct))) return direct;
321
+ if (existsSync(pluginManifestPath(direct))) return direct;
322
322
  const nested = join2(direct, ".aicli-plugin");
323
- if (existsSync2(join2(nested, "plugin.json"))) return direct;
323
+ if (existsSync(join2(nested, "plugin.json"))) return direct;
324
324
  throw new Error(`plugin manifest not found: ${MANIFEST_RELATIVE}`);
325
325
  }
326
326
  function installPlugin(configDir, inputPath) {
@@ -328,7 +328,7 @@ function installPlugin(configDir, inputPath) {
328
328
  const manifest = readPluginManifest(pluginManifestPath(sourceDir));
329
329
  const targetDir = join2(pluginRoot(configDir), manifest.name);
330
330
  mkdirSync2(pluginRoot(configDir), { recursive: true });
331
- if (existsSync2(targetDir)) rmSync(targetDir, { recursive: true, force: true });
331
+ if (existsSync(targetDir)) rmSync(targetDir, { recursive: true, force: true });
332
332
  cpSync(sourceDir, targetDir, { recursive: true });
333
333
  const manifestPath = pluginManifestPath(targetDir);
334
334
  const contentHash = hashPluginContent(targetDir, manifest);
@@ -386,7 +386,7 @@ function getInstalledPlugin(configDir, name) {
386
386
  }
387
387
  function listInstalledPlugins(configDir) {
388
388
  const root = pluginRoot(configDir);
389
- if (!existsSync2(root)) return [];
389
+ if (!existsSync(root)) return [];
390
390
  const state2 = loadState(configDir);
391
391
  const out = [];
392
392
  for (const entry of readdirSync(root)) {
@@ -397,7 +397,7 @@ function listInstalledPlugins(configDir) {
397
397
  continue;
398
398
  }
399
399
  const manifestPath = pluginManifestPath(dir);
400
- if (!existsSync2(manifestPath)) continue;
400
+ if (!existsSync(manifestPath)) continue;
401
401
  try {
402
402
  const manifest = readPluginManifest(manifestPath);
403
403
  const contentHash = hashPluginContent(dir, manifest);
@@ -437,7 +437,7 @@ function uniqueDirs(plugin, rels) {
437
437
  for (const rel of rels) {
438
438
  const abs = resolve(plugin.dir, rel);
439
439
  if (!abs.startsWith(resolve(plugin.dir))) continue;
440
- if (existsSync2(abs)) dirs.add(statSync(abs).isDirectory() ? abs : dirname2(abs));
440
+ if (existsSync(abs)) dirs.add(statSync(abs).isDirectory() ? abs : dirname2(abs));
441
441
  }
442
442
  return [...dirs];
443
443
  }
@@ -509,7 +509,7 @@ function describePlugin(plugin) {
509
509
  // src/tools/hooks.ts
510
510
  import { execSync } from "child_process";
511
511
  import { createHash as createHash2 } from "crypto";
512
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3 } from "fs";
512
+ import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync2 } from "fs";
513
513
  import { join as join3 } from "path";
514
514
  var TRUST_FILE = "hooks-trust.json";
515
515
  var DEFAULT_TIMEOUT_MS = 5e3;
@@ -523,9 +523,9 @@ function hookTrustPath(configDir) {
523
523
  }
524
524
  function loadHookTrustStore(configDir) {
525
525
  const file = hookTrustPath(configDir);
526
- if (!existsSync3(file)) return { records: [] };
526
+ if (!existsSync2(file)) return { records: [] };
527
527
  try {
528
- const parsed = JSON.parse(readFileSync3(file, "utf-8"));
528
+ const parsed = JSON.parse(readFileSync2(file, "utf-8"));
529
529
  return { records: Array.isArray(parsed.records) ? parsed.records : [] };
530
530
  } catch {
531
531
  return { records: [] };
@@ -1,5 +1,5 @@
1
1
  // src/core/constants.ts
2
- var VERSION = "0.4.285";
2
+ var VERSION = "0.4.286";
3
3
  var APP_NAME = "ai-cli";
4
4
  var CONFIG_DIR_NAME = ".aicli";
5
5
  var CONFIG_FILE_NAME = "config.json";
@@ -14,6 +14,8 @@ var MEMORY_STORE_FILE_NAME = "memory.jsonl";
14
14
  var MEMORY_MAX_CHARS = 1e4;
15
15
  var DEV_STATE_FILE_NAME = "dev-state.md";
16
16
  var DEFAULT_MAX_TOKENS = 8192;
17
+ var DEFAULT_TEMPERATURE = 0.7;
18
+ var MAX_HISTORY_DAYS = 30;
17
19
  var DEFAULT_MAX_TOOL_ROUNDS = 200;
18
20
  var DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP = 5e5;
19
21
  var MCP_TOOL_PREFIX = "mcp__";
@@ -83,6 +85,7 @@ var SUBAGENT_ALLOWED_TOOLS = /* @__PURE__ */ new Set([
83
85
  "search_code"
84
86
  ]);
85
87
  var CONTEXT_PRESSURE_THRESHOLD = 0.8;
88
+ var CONTEXT_WARNING_THRESHOLD = 0.6;
86
89
  var TEST_TIMEOUT = 3e5;
87
90
  var AGENTIC_BEHAVIOR_GUIDELINE = `# Important Behavioral Guidelines
88
91
 
@@ -127,6 +130,7 @@ Address the user personally and adapt your communication style to their backgrou
127
130
  var AUTHOR = "Jin Zhengdong";
128
131
  var AUTHOR_EMAIL = "zhengdong.jin@gmail.com";
129
132
  var DESCRIPTION = "Cross-platform REPL-style AI conversation tool with multi-provider and agentic tool calling support";
133
+ var REPO_URL = "https://github.com/jinzhengdong/ai-cli";
130
134
 
131
135
  export {
132
136
  VERSION,
@@ -144,6 +148,8 @@ export {
144
148
  MEMORY_MAX_CHARS,
145
149
  DEV_STATE_FILE_NAME,
146
150
  DEFAULT_MAX_TOKENS,
151
+ DEFAULT_TEMPERATURE,
152
+ MAX_HISTORY_DAYS,
147
153
  DEFAULT_MAX_TOOL_ROUNDS,
148
154
  DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
149
155
  MCP_TOOL_PREFIX,
@@ -157,10 +163,12 @@ export {
157
163
  SUBAGENT_MAX_ROUNDS_LIMIT,
158
164
  SUBAGENT_ALLOWED_TOOLS,
159
165
  CONTEXT_PRESSURE_THRESHOLD,
166
+ CONTEXT_WARNING_THRESHOLD,
160
167
  TEST_TIMEOUT,
161
168
  AGENTIC_BEHAVIOR_GUIDELINE,
162
169
  buildUserIdentityPrompt,
163
170
  AUTHOR,
164
171
  AUTHOR_EMAIL,
165
- DESCRIPTION
172
+ DESCRIPTION,
173
+ REPO_URL
166
174
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TEST_TIMEOUT
3
- } from "./chunk-LF6SPK7I.js";
3
+ } from "./chunk-GIJL4EFA.js";
4
4
 
5
5
  // src/tools/builtin/run-tests.ts
6
6
  import { execSync, spawnSync } from "child_process";
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ loadJsonState
4
+ } from "./chunk-RS7SKYTS.js";
2
5
  import {
3
6
  atomicWriteFileSync
4
7
  } from "./chunk-IW3Q7AE5.js";
@@ -166,7 +169,6 @@ function currencyNote(currency = displayCurrency) {
166
169
  }
167
170
 
168
171
  // src/core/cost-tracker.ts
169
- import { existsSync, readFileSync } from "fs";
170
172
  import { join } from "path";
171
173
  var CostTracker = class _CostTracker {
172
174
  filePath;
@@ -181,16 +183,16 @@ var CostTracker = class _CostTracker {
181
183
  /** P2-PERF-04: debounce interval (ms) — coalesces multiple rapid addCost calls. */
182
184
  static SAVE_DEBOUNCE_MS = 2e3;
183
185
  load() {
184
- try {
185
- if (existsSync(this.filePath)) {
186
- const data = JSON.parse(readFileSync(this.filePath, "utf-8"));
187
- if (data.version === 1 && Array.isArray(data.records)) {
188
- this.records = [...data.records].sort((a, b) => a.date.localeCompare(b.date));
189
- }
186
+ const loaded = loadJsonState(this.filePath, {
187
+ label: "cost history",
188
+ fallback: () => [],
189
+ parse: (raw) => {
190
+ const data = raw;
191
+ if (!data || data.version !== 1 || !Array.isArray(data.records)) return null;
192
+ return [...data.records].sort((a, b) => a.date.localeCompare(b.date));
190
193
  }
191
- } catch {
192
- this.records = [];
193
- }
194
+ });
195
+ this.records = loaded.value;
194
196
  }
195
197
  /**
196
198
  * Save to disk (atomic write).
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/core/json-state.ts
4
+ import { existsSync, readFileSync, renameSync } from "fs";
5
+ function quarantinePath(filePath, now) {
6
+ const stamp = now.toISOString().replace(/[:.]/g, "-");
7
+ let candidate = `${filePath}.corrupt.${stamp}`;
8
+ let n = 1;
9
+ while (existsSync(candidate)) candidate = `${filePath}.corrupt.${stamp}-${n++}`;
10
+ return candidate;
11
+ }
12
+ function loadJsonState(filePath, opts) {
13
+ const warn = opts.warn ?? ((m) => console.error(m));
14
+ const now = opts.now ?? (() => /* @__PURE__ */ new Date());
15
+ if (!existsSync(filePath)) return { value: opts.fallback() };
16
+ let raw;
17
+ let reason;
18
+ try {
19
+ raw = JSON.parse(readFileSync(filePath, "utf-8"));
20
+ const parsed = opts.parse(raw);
21
+ if (parsed !== null) return { value: parsed };
22
+ reason = "unrecognized structure or version";
23
+ } catch (err) {
24
+ reason = err instanceof Error ? err.message : String(err);
25
+ }
26
+ let quarantinedTo;
27
+ try {
28
+ quarantinedTo = quarantinePath(filePath, now());
29
+ renameSync(filePath, quarantinedTo);
30
+ } catch (err) {
31
+ quarantinedTo = void 0;
32
+ warn(
33
+ `\u26A0 ${opts.label} file at ${filePath} is unreadable (${reason}), and it could not be moved aside (${err instanceof Error ? err.message : String(err)}). Starting empty \u2014 the next save will overwrite it.`
34
+ );
35
+ return { value: opts.fallback() };
36
+ }
37
+ warn(
38
+ `\u26A0 ${opts.label} file was unreadable (${reason}). The original was kept at ${quarantinedTo}; starting with an empty ${opts.label}.`
39
+ );
40
+ return { value: opts.fallback(), quarantinedTo };
41
+ }
42
+
43
+ export {
44
+ loadJsonState
45
+ };