jinzd-ai-cli 0.4.87 → 0.4.89
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-FNHSLCMV.js → batch-UMQYXVKG.js} +2 -2
- package/dist/chat-index-W2UZ34ZI.js +18 -0
- package/dist/{chunk-PFYAAX2S.js → chunk-2DXY7UGF.js} +16 -63
- package/dist/{chunk-Y75YPB5F.js → chunk-3O3U3L5W.js} +19 -1
- package/dist/{chunk-AQX3GYRD.js → chunk-4WVXTADR.js} +1 -1
- package/dist/{chunk-SP6RFAKW.js → chunk-ABPT6XCI.js} +76 -3
- package/dist/chunk-ANYYM4CF.js +460 -0
- package/dist/{chunk-BAOIXQHD.js → chunk-E7YC4GWV.js} +1 -1
- package/dist/{chunk-3DGNN4RM.js → chunk-FVRLRIKC.js} +28 -3
- package/dist/chunk-KHYD3WXE.js +52 -0
- package/dist/{chunk-CQQQFNND.js → chunk-KJLJPUY2.js} +6 -4
- package/dist/{chunk-TFLBQRQM.js → chunk-TKYNTXKB.js} +1 -1
- package/dist/electron-server.js +310 -14
- package/dist/{hub-HEC4GYKR.js → hub-4P2BH57W.js} +1 -1
- package/dist/index.js +247 -17
- package/dist/{run-tests-7PTRRO4D.js → run-tests-5TO5G3YH.js} +2 -2
- package/dist/{run-tests-P7GIZ6UH.js → run-tests-TGGXTOFF.js} +1 -1
- package/dist/{semantic-ICJ536BG.js → semantic-YDRPPVWK.js} +3 -2
- package/dist/{server-TRTN3RVO.js → server-NG7AEAD5.js} +15 -13
- package/dist/{server-GJRBVTTQ.js → server-U2BBLP4Y.js} +7 -5
- package/dist/{task-orchestrator-36SFPCP7.js → task-orchestrator-ODU45UQG.js} +7 -5
- package/dist/{vector-store-YTVHACBV.js → vector-store-QARQ2P6D.js} +2 -1
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ConfigManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3O3U3L5W.js";
|
|
5
5
|
import "./chunk-2ZD3YTVM.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-E7YC4GWV.js";
|
|
7
7
|
|
|
8
8
|
// src/cli/batch.ts
|
|
9
9
|
import Anthropic from "@anthropic-ai/sdk";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
buildChatIndex,
|
|
4
|
+
chunkSession,
|
|
5
|
+
clearChatIndex,
|
|
6
|
+
getChatIndexStatus,
|
|
7
|
+
loadChatIndex,
|
|
8
|
+
searchChatMemory
|
|
9
|
+
} from "./chunk-ANYYM4CF.js";
|
|
10
|
+
import "./chunk-KHYD3WXE.js";
|
|
11
|
+
export {
|
|
12
|
+
buildChatIndex,
|
|
13
|
+
chunkSession,
|
|
14
|
+
clearChatIndex,
|
|
15
|
+
getChatIndexStatus,
|
|
16
|
+
loadChatIndex,
|
|
17
|
+
searchChatMemory
|
|
18
|
+
};
|
|
@@ -1,72 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
EMBEDDING_DIM
|
|
4
|
+
} from "./chunk-KHYD3WXE.js";
|
|
2
5
|
|
|
3
6
|
// src/symbols/vector-store.ts
|
|
4
|
-
import
|
|
5
|
-
import path2 from "path";
|
|
6
|
-
import os2 from "os";
|
|
7
|
-
import crypto from "crypto";
|
|
8
|
-
|
|
9
|
-
// src/symbols/embedder.ts
|
|
7
|
+
import fs from "fs";
|
|
10
8
|
import path from "path";
|
|
11
9
|
import os from "os";
|
|
12
|
-
import
|
|
13
|
-
var EMBEDDING_MODEL_ID = "Xenova/paraphrase-multilingual-MiniLM-L12-v2";
|
|
14
|
-
var EMBEDDING_DIM = 384;
|
|
15
|
-
var pipelinePromise = null;
|
|
16
|
-
function cacheDir() {
|
|
17
|
-
return path.join(os.homedir(), ".aicli", "models");
|
|
18
|
-
}
|
|
19
|
-
async function getEmbedder() {
|
|
20
|
-
if (pipelinePromise) return pipelinePromise;
|
|
21
|
-
pipelinePromise = (async () => {
|
|
22
|
-
const mod = await import("@huggingface/transformers");
|
|
23
|
-
const dir = cacheDir();
|
|
24
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
25
|
-
mod.env.cacheDir = dir;
|
|
26
|
-
mod.env.allowRemoteModels = true;
|
|
27
|
-
mod.env.allowLocalModels = true;
|
|
28
|
-
const pipe = await mod.pipeline("feature-extraction", EMBEDDING_MODEL_ID, {
|
|
29
|
-
// Keep the ONNX session in float32; int8 quantization exists but the
|
|
30
|
-
// quality drop on short code identifiers is noticeable.
|
|
31
|
-
dtype: "fp32"
|
|
32
|
-
});
|
|
33
|
-
return pipe;
|
|
34
|
-
})();
|
|
35
|
-
return pipelinePromise;
|
|
36
|
-
}
|
|
37
|
-
async function embed(texts) {
|
|
38
|
-
if (texts.length === 0) return [];
|
|
39
|
-
const pipe = await getEmbedder();
|
|
40
|
-
const out = await pipe(texts, { pooling: "mean", normalize: true });
|
|
41
|
-
const batch = texts.length;
|
|
42
|
-
const dim = EMBEDDING_DIM;
|
|
43
|
-
const rows = new Array(batch);
|
|
44
|
-
for (let i = 0; i < batch; i++) {
|
|
45
|
-
rows[i] = new Float32Array(out.data.buffer, out.data.byteOffset + i * dim * 4, dim).slice();
|
|
46
|
-
}
|
|
47
|
-
return rows;
|
|
48
|
-
}
|
|
49
|
-
async function embedOne(text) {
|
|
50
|
-
const [vec] = await embed([text]);
|
|
51
|
-
return vec;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// src/symbols/vector-store.ts
|
|
10
|
+
import crypto from "crypto";
|
|
55
11
|
var MAGIC = 1094927190;
|
|
56
12
|
var VERSION = 1;
|
|
57
13
|
var HEADER_BYTES = 16;
|
|
58
14
|
function indexDir() {
|
|
59
|
-
return
|
|
15
|
+
return path.join(os.homedir(), ".aicli", "index");
|
|
60
16
|
}
|
|
61
17
|
function projectHash(root) {
|
|
62
|
-
return crypto.createHash("sha1").update(
|
|
18
|
+
return crypto.createHash("sha1").update(path.resolve(root).toLowerCase()).digest("hex").slice(0, 16);
|
|
63
19
|
}
|
|
64
20
|
function vecPath(root) {
|
|
65
|
-
return
|
|
21
|
+
return path.join(indexDir(), `${projectHash(root)}.vec`);
|
|
66
22
|
}
|
|
67
23
|
function emptyVectorStore(root) {
|
|
68
24
|
return {
|
|
69
|
-
root:
|
|
25
|
+
root: path.resolve(root),
|
|
70
26
|
count: 0,
|
|
71
27
|
dim: EMBEDDING_DIM,
|
|
72
28
|
vectors: new Float32Array(0),
|
|
@@ -81,7 +37,7 @@ function saveVectorStore(root, indices, vectors) {
|
|
|
81
37
|
}
|
|
82
38
|
const count = indices.length;
|
|
83
39
|
const dir = indexDir();
|
|
84
|
-
|
|
40
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
85
41
|
const totalBytes = HEADER_BYTES + count * 4 + count * EMBEDDING_DIM * 4;
|
|
86
42
|
const buf = Buffer.alloc(totalBytes);
|
|
87
43
|
buf.writeUInt32LE(MAGIC, 0);
|
|
@@ -92,15 +48,15 @@ function saveVectorStore(root, indices, vectors) {
|
|
|
92
48
|
Buffer.from(vectors.buffer, vectors.byteOffset, vectors.byteLength).copy(buf, HEADER_BYTES + count * 4);
|
|
93
49
|
const target = vecPath(root);
|
|
94
50
|
const tmp = `${target}.tmp`;
|
|
95
|
-
|
|
96
|
-
|
|
51
|
+
fs.writeFileSync(tmp, buf);
|
|
52
|
+
fs.renameSync(tmp, target);
|
|
97
53
|
}
|
|
98
54
|
function loadVectorStore(root) {
|
|
99
55
|
const p = vecPath(root);
|
|
100
|
-
if (!
|
|
56
|
+
if (!fs.existsSync(p)) return null;
|
|
101
57
|
let buf;
|
|
102
58
|
try {
|
|
103
|
-
buf =
|
|
59
|
+
buf = fs.readFileSync(p);
|
|
104
60
|
} catch {
|
|
105
61
|
return null;
|
|
106
62
|
}
|
|
@@ -121,12 +77,12 @@ function loadVectorStore(root) {
|
|
|
121
77
|
buf.byteOffset + HEADER_BYTES + count * 4 + count * dim * 4
|
|
122
78
|
)
|
|
123
79
|
);
|
|
124
|
-
return { root:
|
|
80
|
+
return { root: path.resolve(root), count, dim, vectors, symbolIdx };
|
|
125
81
|
}
|
|
126
82
|
function clearVectorStore(root) {
|
|
127
83
|
const p = vecPath(root);
|
|
128
84
|
try {
|
|
129
|
-
if (
|
|
85
|
+
if (fs.existsSync(p)) fs.unlinkSync(p);
|
|
130
86
|
} catch {
|
|
131
87
|
}
|
|
132
88
|
}
|
|
@@ -158,9 +114,6 @@ function searchVectorStore(store, queryVec, k) {
|
|
|
158
114
|
}
|
|
159
115
|
|
|
160
116
|
export {
|
|
161
|
-
EMBEDDING_DIM,
|
|
162
|
-
embed,
|
|
163
|
-
embedOne,
|
|
164
117
|
emptyVectorStore,
|
|
165
118
|
saveVectorStore,
|
|
166
119
|
loadVectorStore,
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
CONFIG_FILE_NAME,
|
|
9
9
|
HISTORY_DIR_NAME,
|
|
10
10
|
PLUGINS_DIR_NAME
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-E7YC4GWV.js";
|
|
12
12
|
|
|
13
13
|
// src/config/config-manager.ts
|
|
14
14
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
@@ -179,6 +179,24 @@ var ConfigSchema = z.object({
|
|
|
179
179
|
// 必须确认插件来源可信后,再设为 true 启用。
|
|
180
180
|
// 可通过 /config 命令或直接编辑 ~/.aicli/config.json 开启。
|
|
181
181
|
allowPlugins: z.boolean().default(false),
|
|
182
|
+
// 敏感信息脱敏(v0.4.88+,2026-04 凭据泄漏事件后引入)
|
|
183
|
+
// 会话保存到磁盘 / 发送给 Provider 前,自动将 API key、密码、PEM 私钥等
|
|
184
|
+
// 按正则替换为 [REDACTED:kind] 占位符。模式定义在 src/security/redactor.ts。
|
|
185
|
+
//
|
|
186
|
+
// redactOnSave 默认 true:保存到 ~/.aicli/history/*.json 时脱敏(推荐开启)
|
|
187
|
+
// redactOnSend 默认 false:发送到 Provider 时脱敏(激进,可能影响工具结果)
|
|
188
|
+
// mode:
|
|
189
|
+
// 'default' — 使用内置 13 条模式(推荐)
|
|
190
|
+
// 'strict' — 同 default,但阈值更低(更激进,可能误报)
|
|
191
|
+
// 'off' — 禁用所有模式(等同 redactOnSave=false)
|
|
192
|
+
// customPatterns — 用户补充正则字符串(支持 /pattern/flags 形式),
|
|
193
|
+
// 无效正则会静默跳过,不会中断保存。
|
|
194
|
+
security: z.object({
|
|
195
|
+
redactOnSave: z.boolean().default(true),
|
|
196
|
+
redactOnSend: z.boolean().default(false),
|
|
197
|
+
mode: z.enum(["default", "strict", "off"]).default("default"),
|
|
198
|
+
customPatterns: z.array(z.string()).default([])
|
|
199
|
+
}).default({}),
|
|
182
200
|
// 智能模型路由(v0.4.68+)
|
|
183
201
|
// 按用户每轮输入的内容/标签/长度动态选择模型,在同一 provider 内切换,
|
|
184
202
|
// 例:短问题走 haiku(省钱),planning 走 opus(质量)。
|
|
@@ -7,19 +7,23 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
fileCheckpoints
|
|
9
9
|
} from "./chunk-4BKXL7SM.js";
|
|
10
|
+
import {
|
|
11
|
+
loadChatIndex,
|
|
12
|
+
searchChatMemory
|
|
13
|
+
} from "./chunk-ANYYM4CF.js";
|
|
10
14
|
import {
|
|
11
15
|
indexProject
|
|
12
16
|
} from "./chunk-NHNWUBXB.js";
|
|
13
17
|
import {
|
|
14
18
|
hasSemanticIndex,
|
|
15
19
|
semanticSearch
|
|
16
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-KJLJPUY2.js";
|
|
17
21
|
import {
|
|
18
22
|
loadIndex
|
|
19
23
|
} from "./chunk-6VRJGH25.js";
|
|
20
24
|
import {
|
|
21
25
|
runTestsTool
|
|
22
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-TKYNTXKB.js";
|
|
23
27
|
import {
|
|
24
28
|
CONFIG_DIR_NAME,
|
|
25
29
|
DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
|
|
@@ -27,7 +31,7 @@ import {
|
|
|
27
31
|
SUBAGENT_ALLOWED_TOOLS,
|
|
28
32
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
29
33
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
30
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-E7YC4GWV.js";
|
|
31
35
|
|
|
32
36
|
// src/tools/types.ts
|
|
33
37
|
function isFileWriteTool(name) {
|
|
@@ -4578,6 +4582,74 @@ ${lines.join("\n")}`;
|
|
|
4578
4582
|
}
|
|
4579
4583
|
};
|
|
4580
4584
|
|
|
4585
|
+
// src/tools/builtin/recall-memory.ts
|
|
4586
|
+
function formatHit(h, i) {
|
|
4587
|
+
const ts = h.chunk.timestamp.slice(0, 16).replace("T", " ");
|
|
4588
|
+
const title = h.chunk.sessionTitle ? ` \xB7 ${h.chunk.sessionTitle}` : "";
|
|
4589
|
+
const sid = h.chunk.sessionId.slice(0, 8);
|
|
4590
|
+
const score = h.score.toFixed(3);
|
|
4591
|
+
const body = h.chunk.text.length > 600 ? h.chunk.text.slice(0, 600) + "\u2026" : h.chunk.text;
|
|
4592
|
+
return `\u2500\u2500\u2500 Hit ${i + 1} (score ${score}, session ${sid}${title}, ${ts}) \u2500\u2500\u2500
|
|
4593
|
+
` + body;
|
|
4594
|
+
}
|
|
4595
|
+
var recallMemoryTool = {
|
|
4596
|
+
definition: {
|
|
4597
|
+
name: "recall_memory",
|
|
4598
|
+
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".',
|
|
4599
|
+
parameters: {
|
|
4600
|
+
query: {
|
|
4601
|
+
type: "string",
|
|
4602
|
+
description: "Natural-language description of what to recall. Chinese or English both work.",
|
|
4603
|
+
required: true
|
|
4604
|
+
},
|
|
4605
|
+
topK: {
|
|
4606
|
+
type: "number",
|
|
4607
|
+
description: "Max number of snippets to return (default 5, max 20).",
|
|
4608
|
+
required: false
|
|
4609
|
+
},
|
|
4610
|
+
excludeCurrentSession: {
|
|
4611
|
+
type: "boolean",
|
|
4612
|
+
description: "If true, exclude the current session from results (avoid echoing what you just said). Default false.",
|
|
4613
|
+
required: false
|
|
4614
|
+
},
|
|
4615
|
+
currentSessionId: {
|
|
4616
|
+
type: "string",
|
|
4617
|
+
description: "Session ID to exclude when excludeCurrentSession=true. Usually the active session.",
|
|
4618
|
+
required: false
|
|
4619
|
+
},
|
|
4620
|
+
minScore: {
|
|
4621
|
+
type: "number",
|
|
4622
|
+
description: "Drop hits below this cosine score. Default 0.25. Raise to 0.35+ for stricter matches.",
|
|
4623
|
+
required: false
|
|
4624
|
+
}
|
|
4625
|
+
},
|
|
4626
|
+
dangerous: false
|
|
4627
|
+
},
|
|
4628
|
+
async execute(args) {
|
|
4629
|
+
const query = String(args["query"] ?? "").trim();
|
|
4630
|
+
if (!query) throw new ToolError("recall_memory", "query is required");
|
|
4631
|
+
const topK = Math.max(1, Math.min(20, Number(args["topK"] ?? 5)));
|
|
4632
|
+
const excludeCurrent = Boolean(args["excludeCurrentSession"]);
|
|
4633
|
+
const currentId = args["currentSessionId"] ? String(args["currentSessionId"]) : void 0;
|
|
4634
|
+
const minScore = args["minScore"] !== void 0 ? Number(args["minScore"]) : 0.25;
|
|
4635
|
+
const status = loadChatIndex();
|
|
4636
|
+
if (!status) {
|
|
4637
|
+
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.";
|
|
4638
|
+
}
|
|
4639
|
+
const hits = await searchChatMemory(query, {
|
|
4640
|
+
topK,
|
|
4641
|
+
minScore,
|
|
4642
|
+
excludeSessionId: excludeCurrent ? currentId : void 0
|
|
4643
|
+
});
|
|
4644
|
+
if (hits.length === 0) {
|
|
4645
|
+
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.`;
|
|
4646
|
+
}
|
|
4647
|
+
const header = `Found ${hits.length} memory hit(s) for "${query}" (min-score ${minScore}):
|
|
4648
|
+
`;
|
|
4649
|
+
return header + "\n" + hits.map(formatHit).join("\n\n");
|
|
4650
|
+
}
|
|
4651
|
+
};
|
|
4652
|
+
|
|
4581
4653
|
// src/core/token-estimator.ts
|
|
4582
4654
|
var CJK_REGEX = /[\u2E80-\u9FFF\uA000-\uA4FF\uAC00-\uD7FF\uF900-\uFAFF\uFE30-\uFE4F\uFF00-\uFFEF]/g;
|
|
4583
4655
|
function estimateTokens(text) {
|
|
@@ -4637,6 +4709,7 @@ var ToolRegistry = class {
|
|
|
4637
4709
|
this.register(getOutlineTool);
|
|
4638
4710
|
this.register(findReferencesTool);
|
|
4639
4711
|
this.register(searchCodeTool);
|
|
4712
|
+
this.register(recallMemoryTool);
|
|
4640
4713
|
}
|
|
4641
4714
|
register(tool) {
|
|
4642
4715
|
this.tools.set(tool.definition.name, tool);
|