jinzd-ai-cli 0.4.285 → 0.4.287
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-6OH7D5YU.js} +13 -10
- package/dist/{chat-index-TDU3S2MG.js → chat-index-DGUOUUQW.js} +2 -2
- package/dist/{chunk-VLM4SKKX.js → chunk-3BHJKMPQ.js} +1 -1
- package/dist/{chunk-UW33KJW5.js → chunk-3Y5BCGD2.js} +1 -1
- package/dist/{chunk-DV5D7RXZ.js → chunk-5F7BGV72.js} +1 -1
- package/dist/{chunk-UGY5SVNX.js → chunk-ALSSNFNK.js} +94 -4
- package/dist/{chunk-KLBMKONV.js → chunk-AXSWLNCU.js} +4 -4
- package/dist/chunk-CGLYJRFA.js +95 -0
- package/dist/{chunk-LF6SPK7I.js → chunk-CYUAHF6X.js} +10 -2
- package/dist/{chunk-AOF4K5N7.js → chunk-ERDFOXYK.js} +1 -1
- package/dist/{chunk-XGRZA5V6.js → chunk-EU6NMK7G.js} +4 -4
- package/dist/{chunk-5CC5HQFW.js → chunk-HEUB5PV6.js} +30 -30
- package/dist/chunk-HNUT4STJ.js +5684 -0
- package/dist/{chunk-WBF4AOHJ.js → chunk-L625B2XV.js} +18 -110
- package/dist/{chunk-6G7Y2VG4.js → chunk-L7RAEUUN.js} +1 -1
- package/dist/{chunk-DPTEC6AQ.js → chunk-LWPWBRAC.js} +12 -10
- package/dist/chunk-RS7SKYTS.js +45 -0
- package/dist/{chunk-3LFB4YZA.js → chunk-RZVGR3KD.js} +4 -4
- package/dist/{chunk-PHK7QQH3.js → chunk-UDFK5Q52.js} +1 -1
- package/dist/{ci-E4CYVEOW.js → ci-WXCMI4ND.js} +5 -5
- package/dist/{ci-format-7XTLOAB5.js → ci-format-JXD2BQM6.js} +2 -2
- package/dist/{constants-L7D3IXWV.js → constants-2B7CN2ER.js} +1 -1
- package/dist/constants-SRRV3K5Y.js +80 -0
- package/dist/{doctor-cli-JLROIGLO.js → doctor-cli-LQYTDJ74.js} +6 -5
- package/dist/electron-server.js +3643 -257
- package/dist/git-context-VNCA2GU7.js +10 -0
- package/dist/{hub-7UDPLWBI.js → hub-Y62P5MIA.js} +1 -1
- package/dist/index.js +316 -3656
- package/dist/{persistent-memory-CNJOZ7U2.js → persistent-memory-3N2XQKJK.js} +3 -2
- package/dist/{persistent-memory-DRXWYBJS.js → persistent-memory-46JSUEYV.js} +2 -2
- package/dist/{pr-3W5547IS.js → pr-L7Y3XHGL.js} +5 -5
- package/dist/{run-tests-LP2CI4MT.js → run-tests-3ZOMRFIX.js} +2 -2
- package/dist/{run-tests-7B7N4YAE.js → run-tests-WC644BHH.js} +2 -2
- package/dist/{semantic-FF6DDJI6.js → semantic-VPNKXKKK.js} +2 -2
- package/dist/{server-NIPB62XP.js → server-L4QHJT2I.js} +6 -5
- package/dist/{server-YBMWBJVG.js → server-XWURZCAF.js} +22 -16
- package/dist/{task-orchestrator-RYG4ZTDO.js → task-orchestrator-6TVKJYKC.js} +6 -5
- package/dist/{usage-YDVLCZDU.js → usage-L2PSI2KH.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
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
loadJsonState
|
|
4
|
+
} from "./chunk-RS7SKYTS.js";
|
|
2
5
|
import {
|
|
3
6
|
ConfigManager
|
|
4
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-5F7BGV72.js";
|
|
5
8
|
import "./chunk-TU3L3PW7.js";
|
|
6
9
|
import {
|
|
7
10
|
atomicWriteFileSync
|
|
8
11
|
} from "./chunk-IW3Q7AE5.js";
|
|
9
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-UDFK5Q52.js";
|
|
10
13
|
|
|
11
14
|
// src/cli/batch.ts
|
|
12
15
|
import Anthropic from "@anthropic-ai/sdk";
|
|
@@ -64,14 +67,14 @@ function getBatchesPath(config) {
|
|
|
64
67
|
return join(config.getConfigDir(), "batches.json");
|
|
65
68
|
}
|
|
66
69
|
function loadTrackedBatches(config) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
70
|
+
return loadJsonState(getBatchesPath(config), {
|
|
71
|
+
label: "batch tracking",
|
|
72
|
+
fallback: () => [],
|
|
73
|
+
parse: (raw) => {
|
|
74
|
+
const data = raw;
|
|
75
|
+
return Array.isArray(data?.batches) ? data.batches : null;
|
|
76
|
+
}
|
|
77
|
+
}).value;
|
|
75
78
|
}
|
|
76
79
|
function saveTrackedBatches(config, batches) {
|
|
77
80
|
mkdirSync(config.getConfigDir(), { recursive: true });
|
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
getChatIndexStatus,
|
|
6
6
|
loadChatIndex,
|
|
7
7
|
searchChatMemory
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-FSC6KEWU.js";
|
|
8
|
+
} from "./chunk-I4GQRMFV.js";
|
|
10
9
|
import "./chunk-JV5N65KN.js";
|
|
10
|
+
import "./chunk-FSC6KEWU.js";
|
|
11
11
|
import "./chunk-6BUTA5VW.js";
|
|
12
12
|
export {
|
|
13
13
|
buildChatIndex,
|
|
@@ -53,9 +53,76 @@ var BaseProvider = class {
|
|
|
53
53
|
}
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
+
// src/core/network-error.ts
|
|
57
|
+
var NETWORK_CODES = /* @__PURE__ */ new Set([
|
|
58
|
+
"ECONNREFUSED",
|
|
59
|
+
// 端口没人听(代理没起来最常见)
|
|
60
|
+
"ECONNRESET",
|
|
61
|
+
// 对端断开
|
|
62
|
+
"ENOTFOUND",
|
|
63
|
+
// DNS 查不到
|
|
64
|
+
"EAI_AGAIN",
|
|
65
|
+
// DNS 临时失败
|
|
66
|
+
"ETIMEDOUT",
|
|
67
|
+
// 连接超时
|
|
68
|
+
"EHOSTUNREACH",
|
|
69
|
+
"ENETUNREACH",
|
|
70
|
+
"EPIPE",
|
|
71
|
+
"UND_ERR_SOCKET",
|
|
72
|
+
// undici:socket 意外关闭
|
|
73
|
+
"UND_ERR_CONNECT_TIMEOUT"
|
|
74
|
+
]);
|
|
75
|
+
var TRANSIENT_CODES = /* @__PURE__ */ new Set(["ECONNRESET", "UND_ERR_SOCKET", "EPIPE", "EAI_AGAIN"]);
|
|
76
|
+
function findCause(err, depth = 0) {
|
|
77
|
+
if (!err || depth > 4) return null;
|
|
78
|
+
const e = err;
|
|
79
|
+
if (typeof e.code === "string") {
|
|
80
|
+
return {
|
|
81
|
+
code: e.code,
|
|
82
|
+
address: e.address ? `${e.address}${e.port !== void 0 ? `:${e.port}` : ""}` : void 0,
|
|
83
|
+
message: e.message
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (Array.isArray(e.errors) && e.errors.length > 0) {
|
|
87
|
+
for (const inner of e.errors) {
|
|
88
|
+
const found = findCause(inner, depth + 1);
|
|
89
|
+
if (found) return found;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return findCause(e.cause, depth + 1);
|
|
93
|
+
}
|
|
94
|
+
function describeNetworkFailure(err, ctx = {}) {
|
|
95
|
+
const cause = findCause(err);
|
|
96
|
+
const topMessage = err instanceof Error ? err.message : String(err);
|
|
97
|
+
const looksNetwork = cause?.code && NETWORK_CODES.has(cause.code) || topMessage === "fetch failed" || topMessage.includes("Connection error");
|
|
98
|
+
if (!looksNetwork) return null;
|
|
99
|
+
const code = cause?.code;
|
|
100
|
+
const address = cause?.address;
|
|
101
|
+
const transient = !!code && TRANSIENT_CODES.has(code);
|
|
102
|
+
const what = code ? `${code}${address ? ` ${address}` : ""}` : cause?.message ?? "no further detail from the network layer";
|
|
103
|
+
const where = ctx.target ? ` while connecting to ${ctx.target}` : "";
|
|
104
|
+
const parts = [`Connection failed${where} (${what}).`];
|
|
105
|
+
if (ctx.proxyUrl) {
|
|
106
|
+
parts.push(`The request went through the proxy from config.proxy (${ctx.proxyUrl}).`);
|
|
107
|
+
if (code === "ECONNREFUSED") {
|
|
108
|
+
parts.push(`That address refused the connection \u2014 the proxy is probably not running. Start it, or unset config.proxy to connect directly.`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (transient) {
|
|
112
|
+
parts.push(`This usually means an idle connection was dropped by the other side \u2014 just send the message again.`);
|
|
113
|
+
} else if (code === "ENOTFOUND" || code === "EAI_AGAIN") {
|
|
114
|
+
parts.push(`DNS lookup failed \u2014 check the network connection${ctx.proxyUrl ? " and the proxy" : ""}.`);
|
|
115
|
+
} else if (code === "ETIMEDOUT" || code === "UND_ERR_CONNECT_TIMEOUT") {
|
|
116
|
+
parts.push(`The connection timed out before it was established${ctx.proxyUrl ? " \u2014 check whether the proxy can reach this host" : ""}.`);
|
|
117
|
+
}
|
|
118
|
+
return { code, address, transient, message: parts.join(" ") };
|
|
119
|
+
}
|
|
120
|
+
|
|
56
121
|
// src/providers/claude.ts
|
|
57
122
|
var CACHE_MIN_SYSTEM_CHARS = 2e3;
|
|
58
123
|
var ClaudeProvider = class extends BaseProvider {
|
|
124
|
+
/** 生效的代理(网络失败时点名它,见 core/network-error.ts)。 */
|
|
125
|
+
activeProxyUrl;
|
|
59
126
|
client;
|
|
60
127
|
info = {
|
|
61
128
|
id: "claude",
|
|
@@ -90,6 +157,7 @@ var ClaudeProvider = class extends BaseProvider {
|
|
|
90
157
|
baseURL: options?.baseUrl
|
|
91
158
|
};
|
|
92
159
|
const proxyUrl = options?.proxy;
|
|
160
|
+
this.activeProxyUrl = proxyUrl;
|
|
93
161
|
try {
|
|
94
162
|
const { Agent, ProxyAgent, fetch: undiciFetch } = await import("undici");
|
|
95
163
|
const STREAM_BODY_TIMEOUT = 30 * 60 * 1e3;
|
|
@@ -614,6 +682,8 @@ var ClaudeProvider = class extends BaseProvider {
|
|
|
614
682
|
if (err instanceof Anthropic.RateLimitError) {
|
|
615
683
|
return new RateLimitError("claude");
|
|
616
684
|
}
|
|
685
|
+
const net = describeNetworkFailure(err, { target: "api.anthropic.com", proxyUrl: this.activeProxyUrl });
|
|
686
|
+
if (net) return new ProviderError("claude", net.message, err instanceof Error ? err : void 0);
|
|
617
687
|
if (err instanceof Error) {
|
|
618
688
|
return new ProviderError("claude", err.message, err);
|
|
619
689
|
}
|
|
@@ -930,10 +1000,11 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
930
1000
|
err
|
|
931
1001
|
);
|
|
932
1002
|
}
|
|
933
|
-
|
|
1003
|
+
const net = describeNetworkFailure(err, { target: "generativelanguage.googleapis.com" });
|
|
1004
|
+
if (net || msg.includes("socket hang up")) {
|
|
934
1005
|
return new ProviderError(
|
|
935
1006
|
"gemini",
|
|
936
|
-
`Network connection failed: ${msg}
|
|
1007
|
+
`${net?.message ?? `Network connection failed: ${msg}`}
|
|
937
1008
|
Node.js does not automatically use system proxies. Try one of the following:
|
|
938
1009
|
1. Set environment variable: set HTTPS_PROXY=http://127.0.0.1:<proxy-port>
|
|
939
1010
|
2. Configure an accessible Gemini API mirror URL in config.json under customBaseUrls.gemini`,
|
|
@@ -1002,6 +1073,8 @@ function readRetryCount(headers) {
|
|
|
1002
1073
|
}
|
|
1003
1074
|
var OpenAICompatibleProvider = class extends BaseProvider {
|
|
1004
1075
|
client;
|
|
1076
|
+
/** 生效的代理(wrapError 要在网络失败时点名它);未配代理时为 undefined。 */
|
|
1077
|
+
activeProxyUrl;
|
|
1005
1078
|
defaultTimeout = 6e4;
|
|
1006
1079
|
// ms
|
|
1007
1080
|
/**
|
|
@@ -1031,13 +1104,17 @@ var OpenAICompatibleProvider = class extends BaseProvider {
|
|
|
1031
1104
|
const { Agent, ProxyAgent, fetch: undiciFetch } = await import("undici");
|
|
1032
1105
|
const STREAM_BODY_TIMEOUT = 30 * 60 * 1e3;
|
|
1033
1106
|
const STREAM_HEADERS_TIMEOUT = 5 * 60 * 1e3;
|
|
1107
|
+
const KEEP_ALIVE_TIMEOUT = 2e3;
|
|
1108
|
+
this.activeProxyUrl = proxyUrl;
|
|
1034
1109
|
const dispatcher = proxyUrl ? new ProxyAgent({
|
|
1035
1110
|
uri: proxyUrl,
|
|
1036
1111
|
bodyTimeout: STREAM_BODY_TIMEOUT,
|
|
1037
|
-
headersTimeout: STREAM_HEADERS_TIMEOUT
|
|
1112
|
+
headersTimeout: STREAM_HEADERS_TIMEOUT,
|
|
1113
|
+
keepAliveTimeout: KEEP_ALIVE_TIMEOUT
|
|
1038
1114
|
}) : new Agent({
|
|
1039
1115
|
bodyTimeout: STREAM_BODY_TIMEOUT,
|
|
1040
|
-
headersTimeout: STREAM_HEADERS_TIMEOUT
|
|
1116
|
+
headersTimeout: STREAM_HEADERS_TIMEOUT,
|
|
1117
|
+
keepAliveTimeout: KEEP_ALIVE_TIMEOUT
|
|
1041
1118
|
});
|
|
1042
1119
|
clientOptions.fetch = ((url, init) => {
|
|
1043
1120
|
const retryCount = readRetryCount(init?.headers);
|
|
@@ -1511,11 +1588,24 @@ var OpenAICompatibleProvider = class extends BaseProvider {
|
|
|
1511
1588
|
if (err instanceof OpenAI.RateLimitError) {
|
|
1512
1589
|
return new RateLimitError(this.info.id);
|
|
1513
1590
|
}
|
|
1591
|
+
const net = describeNetworkFailure(err, {
|
|
1592
|
+
target: this.hostLabel(),
|
|
1593
|
+
proxyUrl: this.activeProxyUrl
|
|
1594
|
+
});
|
|
1595
|
+
if (net) return new ProviderError(this.info.id, net.message, err instanceof Error ? err : void 0);
|
|
1514
1596
|
if (err instanceof Error) {
|
|
1515
1597
|
return new ProviderError(this.info.id, err.message, err);
|
|
1516
1598
|
}
|
|
1517
1599
|
return new ProviderError(this.info.id, String(err));
|
|
1518
1600
|
}
|
|
1601
|
+
/** 请求实际打向的主机,用于「连谁失败了」。 */
|
|
1602
|
+
hostLabel() {
|
|
1603
|
+
try {
|
|
1604
|
+
return new URL(this.info.baseUrl ?? this.defaultBaseUrl).host;
|
|
1605
|
+
} catch {
|
|
1606
|
+
return this.info.id;
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1519
1609
|
};
|
|
1520
1610
|
|
|
1521
1611
|
// src/providers/deepseek.ts
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
searchPersistentMemories,
|
|
12
12
|
touchMemoryReferences,
|
|
13
13
|
updateMemoryEntry
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-ERDFOXYK.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-HEUB5PV6.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-L7RAEUUN.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-UDFK5Q52.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
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/core/constants.ts
|
|
2
|
-
var VERSION = "0.4.
|
|
2
|
+
var VERSION = "0.4.287";
|
|
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
|
};
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
MEMORY_FILE_NAME,
|
|
14
14
|
MEMORY_MAX_CHARS,
|
|
15
15
|
MEMORY_STORE_FILE_NAME
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-UDFK5Q52.js";
|
|
17
17
|
|
|
18
18
|
// src/memory/persistent-memory.ts
|
|
19
19
|
import { copyFileSync, existsSync, mkdirSync, readFileSync, statSync } from "fs";
|
|
@@ -8,13 +8,13 @@ import {
|
|
|
8
8
|
listHooks,
|
|
9
9
|
listInstalledPlugins,
|
|
10
10
|
resetStats
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-HEUB5PV6.js";
|
|
12
12
|
import {
|
|
13
13
|
ProviderRegistry
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-ALSSNFNK.js";
|
|
15
15
|
import {
|
|
16
16
|
ConfigManager
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-5F7BGV72.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-UDFK5Q52.js";
|
|
30
30
|
|
|
31
31
|
// src/diagnostics/doctor-report.ts
|
|
32
32
|
import { existsSync as existsSync3, statSync as statSync2 } from "fs";
|
|
@@ -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-UDFK5Q52.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: [] };
|