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.
- package/dist/{batch-R563COWE.js → batch-GY3I53DE.js} +13 -10
- package/dist/{chat-index-TDU3S2MG.js → chat-index-DGUOUUQW.js} +2 -2
- package/dist/{chunk-UW33KJW5.js → chunk-2YDLBM3Z.js} +1 -1
- package/dist/{chunk-3LFB4YZA.js → chunk-3ZQZO5F7.js} +3 -3
- package/dist/chunk-53V3RQY5.js +5684 -0
- package/dist/{chunk-XGRZA5V6.js → chunk-6SCELZG6.js} +3 -3
- package/dist/{chunk-DV5D7RXZ.js → chunk-7G7RZHJI.js} +1 -1
- package/dist/{chunk-KLBMKONV.js → chunk-BRLLV3FX.js} +4 -4
- package/dist/chunk-CGLYJRFA.js +95 -0
- package/dist/{chunk-WBF4AOHJ.js → chunk-D7HYLMCC.js} +18 -110
- package/dist/{chunk-5CC5HQFW.js → chunk-EYUCJBGS.js} +30 -30
- package/dist/{chunk-LF6SPK7I.js → chunk-GIJL4EFA.js} +10 -2
- package/dist/{chunk-VLM4SKKX.js → chunk-L4FDTQ42.js} +1 -1
- package/dist/{chunk-DPTEC6AQ.js → chunk-LWPWBRAC.js} +12 -10
- package/dist/chunk-RS7SKYTS.js +45 -0
- package/dist/{chunk-6G7Y2VG4.js → chunk-S7ABWTDV.js} +1 -1
- package/dist/{chunk-PHK7QQH3.js → chunk-THUXZNJL.js} +1 -1
- package/dist/{chunk-AOF4K5N7.js → chunk-UKITSNSH.js} +1 -1
- package/dist/{ci-E4CYVEOW.js → ci-JBUIVM7P.js} +4 -4
- package/dist/{ci-format-7XTLOAB5.js → ci-format-B4AHV5SI.js} +2 -2
- package/dist/{constants-L7D3IXWV.js → constants-5FYUQLKN.js} +1 -1
- package/dist/constants-P75MLFV7.js +80 -0
- package/dist/{doctor-cli-JLROIGLO.js → doctor-cli-VLFE46PX.js} +5 -4
- package/dist/electron-server.js +3549 -253
- package/dist/git-context-VNCA2GU7.js +10 -0
- package/dist/{hub-7UDPLWBI.js → hub-CNORVRYW.js} +1 -1
- package/dist/index.js +315 -3655
- package/dist/{persistent-memory-CNJOZ7U2.js → persistent-memory-3KL4N27E.js} +3 -2
- package/dist/{persistent-memory-DRXWYBJS.js → persistent-memory-LVX2OT4L.js} +2 -2
- package/dist/{pr-3W5547IS.js → pr-2YUV4KII.js} +4 -4
- package/dist/{run-tests-LP2CI4MT.js → run-tests-ERD6X534.js} +2 -2
- package/dist/{run-tests-7B7N4YAE.js → run-tests-KZ2IUZHK.js} +2 -2
- package/dist/{semantic-FF6DDJI6.js → semantic-VPNKXKKK.js} +2 -2
- package/dist/{server-NIPB62XP.js → server-7VSLW446.js} +6 -5
- package/dist/{server-YBMWBJVG.js → server-A3OX52UC.js} +21 -15
- package/dist/{task-orchestrator-RYG4ZTDO.js → task-orchestrator-XAMKOFUE.js} +6 -5
- package/dist/{usage-YDVLCZDU.js → usage-ZXNYCAZB.js} +4 -3
- package/package.json +1 -1
- package/dist/chunk-HBAYEVVJ.js +0 -2362
- package/dist/{chunk-AEAYUKSY.js → chunk-7XU4BATV.js} +3 -3
- 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-
|
|
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-
|
|
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-
|
|
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
|
searchPersistentMemories,
|
|
12
12
|
touchMemoryReferences,
|
|
13
13
|
updateMemoryEntry
|
|
14
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
18
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, statSync } from "fs";
|
|
16
19
|
import { randomUUID, createHash } from "crypto";
|
|
17
|
-
import { dirname, join
|
|
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
|
|
25
|
+
return join(configDir, MEMORY_STORE_FILE_NAME);
|
|
115
26
|
}
|
|
116
27
|
function memoryMarkdownPath(configDir) {
|
|
117
|
-
return
|
|
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 (!
|
|
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 (!
|
|
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 =
|
|
284
|
-
if (
|
|
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 && !
|
|
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 (!
|
|
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 (!
|
|
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-
|
|
11
|
+
} from "./chunk-THUXZNJL.js";
|
|
9
12
|
|
|
10
13
|
// src/diagnostics/tool-stats.ts
|
|
11
|
-
import {
|
|
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
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return
|
|
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
|
-
|
|
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
|
|
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 (!
|
|
195
|
+
if (!existsSync(file)) return { version: 2, plugins: [] };
|
|
196
196
|
try {
|
|
197
|
-
const parsed = JSON.parse(
|
|
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 (
|
|
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(
|
|
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(
|
|
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(
|
|
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 (
|
|
321
|
+
if (existsSync(pluginManifestPath(direct))) return direct;
|
|
322
322
|
const nested = join2(direct, ".aicli-plugin");
|
|
323
|
-
if (
|
|
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 (
|
|
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 (!
|
|
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 (!
|
|
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 (
|
|
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
|
|
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 (!
|
|
526
|
+
if (!existsSync2(file)) return { records: [] };
|
|
527
527
|
try {
|
|
528
|
-
const parsed = JSON.parse(
|
|
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.
|
|
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,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
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
}
|
|
192
|
-
|
|
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
|
+
};
|