jinzd-ai-cli 0.4.89 → 0.4.91
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/README.md +6 -2
- package/README.zh-CN.md +6 -2
- package/dist/{batch-UMQYXVKG.js → batch-KZQHKPE5.js} +2 -2
- package/dist/chat-index-QKFH7ZP6.js +17 -0
- package/dist/chunk-5S3PIG5O.js +453 -0
- package/dist/{chunk-E7YC4GWV.js → chunk-AKCXRW2Q.js} +1 -1
- package/dist/{chunk-TKYNTXKB.js → chunk-IGNYJUZU.js} +1 -1
- package/dist/chunk-JV5N65KN.js +50 -0
- package/dist/{chunk-GTKJUEBS.js → chunk-MO7MWNWC.js} +6 -4
- package/dist/{chunk-FVRLRIKC.js → chunk-MYQANQ6F.js} +2 -2
- package/dist/{chunk-XMA222FQ.js → chunk-PASCDYMH.js} +17 -63
- package/dist/{chunk-3O3U3L5W.js → chunk-US6MQO6W.js} +1 -1
- package/dist/{chunk-4WVXTADR.js → chunk-XQHCCV3A.js} +1 -1
- package/dist/{chunk-ABPT6XCI.js → chunk-Z2V6EYPQ.js} +2 -2
- package/dist/electron-server.js +127 -202
- package/dist/{hub-4P2BH57W.js → hub-A66CLTFF.js} +1 -1
- package/dist/index.js +23 -16
- package/dist/{run-tests-TGGXTOFF.js → run-tests-KHJ6YCPH.js} +1 -1
- package/dist/{run-tests-5TO5G3YH.js → run-tests-MKBVRMBA.js} +2 -2
- package/dist/{semantic-MYAXLDCZ.js → semantic-3KJPAUW6.js} +3 -2
- package/dist/{server-U2BBLP4Y.js → server-B6U5GMZ7.js} +3 -3
- package/dist/{server-NG7AEAD5.js → server-J7BPHI7D.js} +112 -6
- package/dist/{task-orchestrator-ODU45UQG.js → task-orchestrator-JB5TZNBK.js} +3 -3
- package/dist/{vector-store-UR7IARXB.js → vector-store-NDUFLNGN.js} +2 -1
- package/dist/web/client/app.js +201 -0
- package/dist/web/client/index.html +24 -0
- package/package.json +1 -1
|
@@ -1,70 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import os2 from "os";
|
|
5
|
-
import crypto from "crypto";
|
|
1
|
+
import {
|
|
2
|
+
EMBEDDING_DIM
|
|
3
|
+
} from "./chunk-JV5N65KN.js";
|
|
6
4
|
|
|
7
|
-
// src/symbols/
|
|
5
|
+
// src/symbols/vector-store.ts
|
|
6
|
+
import fs from "fs";
|
|
8
7
|
import path from "path";
|
|
9
8
|
import os from "os";
|
|
10
|
-
import
|
|
11
|
-
var EMBEDDING_MODEL_ID = "Xenova/paraphrase-multilingual-MiniLM-L12-v2";
|
|
12
|
-
var EMBEDDING_DIM = 384;
|
|
13
|
-
var pipelinePromise = null;
|
|
14
|
-
function cacheDir() {
|
|
15
|
-
return path.join(os.homedir(), ".aicli", "models");
|
|
16
|
-
}
|
|
17
|
-
async function getEmbedder() {
|
|
18
|
-
if (pipelinePromise) return pipelinePromise;
|
|
19
|
-
pipelinePromise = (async () => {
|
|
20
|
-
const mod = await import("@huggingface/transformers");
|
|
21
|
-
const dir = cacheDir();
|
|
22
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
23
|
-
mod.env.cacheDir = dir;
|
|
24
|
-
mod.env.allowRemoteModels = true;
|
|
25
|
-
mod.env.allowLocalModels = true;
|
|
26
|
-
const pipe = await mod.pipeline("feature-extraction", EMBEDDING_MODEL_ID, {
|
|
27
|
-
// Keep the ONNX session in float32; int8 quantization exists but the
|
|
28
|
-
// quality drop on short code identifiers is noticeable.
|
|
29
|
-
dtype: "fp32"
|
|
30
|
-
});
|
|
31
|
-
return pipe;
|
|
32
|
-
})();
|
|
33
|
-
return pipelinePromise;
|
|
34
|
-
}
|
|
35
|
-
async function embed(texts) {
|
|
36
|
-
if (texts.length === 0) return [];
|
|
37
|
-
const pipe = await getEmbedder();
|
|
38
|
-
const out = await pipe(texts, { pooling: "mean", normalize: true });
|
|
39
|
-
const batch = texts.length;
|
|
40
|
-
const dim = EMBEDDING_DIM;
|
|
41
|
-
const rows = new Array(batch);
|
|
42
|
-
for (let i = 0; i < batch; i++) {
|
|
43
|
-
rows[i] = new Float32Array(out.data.buffer, out.data.byteOffset + i * dim * 4, dim).slice();
|
|
44
|
-
}
|
|
45
|
-
return rows;
|
|
46
|
-
}
|
|
47
|
-
async function embedOne(text) {
|
|
48
|
-
const [vec] = await embed([text]);
|
|
49
|
-
return vec;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// src/symbols/vector-store.ts
|
|
9
|
+
import crypto from "crypto";
|
|
53
10
|
var MAGIC = 1094927190;
|
|
54
11
|
var VERSION = 1;
|
|
55
12
|
var HEADER_BYTES = 16;
|
|
56
13
|
function indexDir() {
|
|
57
|
-
return
|
|
14
|
+
return path.join(os.homedir(), ".aicli", "index");
|
|
58
15
|
}
|
|
59
16
|
function projectHash(root) {
|
|
60
|
-
return crypto.createHash("sha1").update(
|
|
17
|
+
return crypto.createHash("sha1").update(path.resolve(root).toLowerCase()).digest("hex").slice(0, 16);
|
|
61
18
|
}
|
|
62
19
|
function vecPath(root) {
|
|
63
|
-
return
|
|
20
|
+
return path.join(indexDir(), `${projectHash(root)}.vec`);
|
|
64
21
|
}
|
|
65
22
|
function emptyVectorStore(root) {
|
|
66
23
|
return {
|
|
67
|
-
root:
|
|
24
|
+
root: path.resolve(root),
|
|
68
25
|
count: 0,
|
|
69
26
|
dim: EMBEDDING_DIM,
|
|
70
27
|
vectors: new Float32Array(0),
|
|
@@ -79,7 +36,7 @@ function saveVectorStore(root, indices, vectors) {
|
|
|
79
36
|
}
|
|
80
37
|
const count = indices.length;
|
|
81
38
|
const dir = indexDir();
|
|
82
|
-
|
|
39
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
83
40
|
const totalBytes = HEADER_BYTES + count * 4 + count * EMBEDDING_DIM * 4;
|
|
84
41
|
const buf = Buffer.alloc(totalBytes);
|
|
85
42
|
buf.writeUInt32LE(MAGIC, 0);
|
|
@@ -90,15 +47,15 @@ function saveVectorStore(root, indices, vectors) {
|
|
|
90
47
|
Buffer.from(vectors.buffer, vectors.byteOffset, vectors.byteLength).copy(buf, HEADER_BYTES + count * 4);
|
|
91
48
|
const target = vecPath(root);
|
|
92
49
|
const tmp = `${target}.tmp`;
|
|
93
|
-
|
|
94
|
-
|
|
50
|
+
fs.writeFileSync(tmp, buf);
|
|
51
|
+
fs.renameSync(tmp, target);
|
|
95
52
|
}
|
|
96
53
|
function loadVectorStore(root) {
|
|
97
54
|
const p = vecPath(root);
|
|
98
|
-
if (!
|
|
55
|
+
if (!fs.existsSync(p)) return null;
|
|
99
56
|
let buf;
|
|
100
57
|
try {
|
|
101
|
-
buf =
|
|
58
|
+
buf = fs.readFileSync(p);
|
|
102
59
|
} catch {
|
|
103
60
|
return null;
|
|
104
61
|
}
|
|
@@ -119,12 +76,12 @@ function loadVectorStore(root) {
|
|
|
119
76
|
buf.byteOffset + HEADER_BYTES + count * 4 + count * dim * 4
|
|
120
77
|
)
|
|
121
78
|
);
|
|
122
|
-
return { root:
|
|
79
|
+
return { root: path.resolve(root), count, dim, vectors, symbolIdx };
|
|
123
80
|
}
|
|
124
81
|
function clearVectorStore(root) {
|
|
125
82
|
const p = vecPath(root);
|
|
126
83
|
try {
|
|
127
|
-
if (
|
|
84
|
+
if (fs.existsSync(p)) fs.unlinkSync(p);
|
|
128
85
|
} catch {
|
|
129
86
|
}
|
|
130
87
|
}
|
|
@@ -156,9 +113,6 @@ function searchVectorStore(store, queryVec, k) {
|
|
|
156
113
|
}
|
|
157
114
|
|
|
158
115
|
export {
|
|
159
|
-
EMBEDDING_DIM,
|
|
160
|
-
embed,
|
|
161
|
-
embedOne,
|
|
162
116
|
emptyVectorStore,
|
|
163
117
|
saveVectorStore,
|
|
164
118
|
loadVectorStore,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from "./chunk-6VRJGH25.js";
|
|
24
24
|
import {
|
|
25
25
|
runTestsTool
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-IGNYJUZU.js";
|
|
27
27
|
import {
|
|
28
28
|
CONFIG_DIR_NAME,
|
|
29
29
|
DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
SUBAGENT_ALLOWED_TOOLS,
|
|
32
32
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
33
33
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-AKCXRW2Q.js";
|
|
35
35
|
|
|
36
36
|
// src/tools/types.ts
|
|
37
37
|
function isFileWriteTool(name) {
|
package/dist/electron-server.js
CHANGED
|
@@ -36,18 +36,21 @@ import {
|
|
|
36
36
|
VERSION,
|
|
37
37
|
buildUserIdentityPrompt,
|
|
38
38
|
runTestsTool
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-XQHCCV3A.js";
|
|
40
40
|
import {
|
|
41
41
|
hasSemanticIndex,
|
|
42
42
|
semanticSearch
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-MO7MWNWC.js";
|
|
44
44
|
import {
|
|
45
45
|
loadIndex
|
|
46
46
|
} from "./chunk-BJAT4GNC.js";
|
|
47
|
+
import "./chunk-PASCDYMH.js";
|
|
47
48
|
import {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
loadChatIndex,
|
|
50
|
+
redactJson,
|
|
51
|
+
searchChatMemory
|
|
52
|
+
} from "./chunk-5S3PIG5O.js";
|
|
53
|
+
import "./chunk-JV5N65KN.js";
|
|
51
54
|
|
|
52
55
|
// src/web/server.ts
|
|
53
56
|
import express from "express";
|
|
@@ -435,8 +438,8 @@ ${err}`
|
|
|
435
438
|
return EnvLoader.getDefaultProvider() ?? this.config.defaultProvider;
|
|
436
439
|
}
|
|
437
440
|
/** 点分路径读取配置值,如 `ui.theme` → config.ui.theme */
|
|
438
|
-
getByPath(
|
|
439
|
-
const keys =
|
|
441
|
+
getByPath(path3) {
|
|
442
|
+
const keys = path3.split(".");
|
|
440
443
|
let current = this.config;
|
|
441
444
|
for (const key of keys) {
|
|
442
445
|
if (current == null || typeof current !== "object") return void 0;
|
|
@@ -445,8 +448,8 @@ ${err}`
|
|
|
445
448
|
return current;
|
|
446
449
|
}
|
|
447
450
|
/** 点分路径写入配置值,自动类型转换(boolean/number/string)并持久化 */
|
|
448
|
-
setByPath(
|
|
449
|
-
const keys =
|
|
451
|
+
setByPath(path3, rawValue) {
|
|
452
|
+
const keys = path3.split(".");
|
|
450
453
|
if (keys.length === 0) return;
|
|
451
454
|
let value = rawValue;
|
|
452
455
|
if (rawValue === "true") value = true;
|
|
@@ -465,7 +468,7 @@ ${err}`
|
|
|
465
468
|
const result = ConfigSchema.safeParse(draft);
|
|
466
469
|
if (!result.success) {
|
|
467
470
|
const firstErr = result.error.errors[0];
|
|
468
|
-
throw new ConfigError(`Invalid config value for "${
|
|
471
|
+
throw new ConfigError(`Invalid config value for "${path3}": ${firstErr?.message ?? "validation failed"}`);
|
|
469
472
|
}
|
|
470
473
|
this.config = result.data;
|
|
471
474
|
this.save();
|
|
@@ -3057,104 +3060,6 @@ var Session = class _Session {
|
|
|
3057
3060
|
}
|
|
3058
3061
|
};
|
|
3059
3062
|
|
|
3060
|
-
// src/security/redactor.ts
|
|
3061
|
-
var DEFAULT_PATTERNS = [
|
|
3062
|
-
// password: xxx / password = xxx / password="xxx"
|
|
3063
|
-
// Covers YAML / JSON / shell-ish / env-file forms.
|
|
3064
|
-
{ kind: "password", regex: /\b(password|passwd|pwd)\s*[:=]\s*["']?([^\s"',;{}]{4,200})["']?/gi },
|
|
3065
|
-
// PGPASSWORD=xxx (explicit bash env-var form, separate rule because no quotes usually)
|
|
3066
|
-
{ kind: "pgpassword-env", regex: /\b(PGPASSWORD)=([^\s"']{4,200})/g },
|
|
3067
|
-
// JDBC/PG/MySQL/Mongo connection strings with inline credentials
|
|
3068
|
-
// postgresql://user:pass@host/db → redact pass
|
|
3069
|
-
{ kind: "db-uri-password", regex: /(\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp|mssql):\/\/[^:\s]+:)([^@\s]+)(@)/gi },
|
|
3070
|
-
// Anthropic API keys
|
|
3071
|
-
{ kind: "anthropic-key", regex: /(sk-ant-[a-zA-Z0-9_-]{90,})/g },
|
|
3072
|
-
// OpenAI / generic sk- keys — requires length ≥32 to avoid eating short identifiers
|
|
3073
|
-
{ kind: "openai-key", regex: /(sk-(?:proj-)?[a-zA-Z0-9_-]{32,})/g },
|
|
3074
|
-
// GitHub personal access tokens
|
|
3075
|
-
{ kind: "github-pat", regex: /\b(ghp_[a-zA-Z0-9]{36})\b/g },
|
|
3076
|
-
{ kind: "github-oauth", regex: /\b(gho_[a-zA-Z0-9]{36})\b/g },
|
|
3077
|
-
{ kind: "github-install", regex: /\b(ghs_[a-zA-Z0-9]{36})\b/g },
|
|
3078
|
-
// Slack tokens
|
|
3079
|
-
{ kind: "slack-bot", regex: /\b(xoxb-\d+-\d+-[a-zA-Z0-9]+)\b/g },
|
|
3080
|
-
{ kind: "slack-user", regex: /\b(xoxp-\d+-\d+-\d+-[a-zA-Z0-9]+)\b/g },
|
|
3081
|
-
// AWS access key IDs (AKIA...) and secret access keys are context-dependent;
|
|
3082
|
-
// we only catch the ID because secret key alone is indistinguishable from random base64.
|
|
3083
|
-
{ kind: "aws-access-key-id", regex: /\b(AKIA[0-9A-Z]{16})\b/g },
|
|
3084
|
-
// Google API keys
|
|
3085
|
-
{ kind: "google-api-key", regex: /\b(AIza[0-9A-Za-z_-]{35})\b/g },
|
|
3086
|
-
// Generic "api_key": "..." / "apiKey": "..." / api-key=xxx
|
|
3087
|
-
{ kind: "api-key", regex: /\b(api[_-]?key)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{16,200})["']?/gi },
|
|
3088
|
-
// Generic token: xxx (only when value looks token-shaped; avoids eating human prose)
|
|
3089
|
-
{ kind: "token", regex: /\b(token|access[_-]?token|bearer[_-]?token)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{20,300})["']?/gi },
|
|
3090
|
-
// Bearer <token> in Authorization headers
|
|
3091
|
-
{ kind: "bearer", regex: /\b(Authorization:\s*Bearer\s+)([a-zA-Z0-9_\-.=]{20,500})/g },
|
|
3092
|
-
// Private key PEM blocks — catch the header+footer together
|
|
3093
|
-
{ kind: "private-key", regex: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g }
|
|
3094
|
-
];
|
|
3095
|
-
function render(placeholder, kind) {
|
|
3096
|
-
return placeholder.replace("{kind}", kind);
|
|
3097
|
-
}
|
|
3098
|
-
function redactString(input, options) {
|
|
3099
|
-
if (!options.enabled || !input) return { redacted: input, hits: [] };
|
|
3100
|
-
const placeholder = options.placeholder ?? "[REDACTED:{kind}]";
|
|
3101
|
-
const patterns = [
|
|
3102
|
-
...options.patterns ?? DEFAULT_PATTERNS,
|
|
3103
|
-
...(options.customRegexes ?? []).flatMap((src, i) => {
|
|
3104
|
-
try {
|
|
3105
|
-
const flags = src.match(/^\/.*\/([gimsuy]*)$/)?.[1] ?? "";
|
|
3106
|
-
const body = src.replace(/^\/(.*)\/[gimsuy]*$/, "$1");
|
|
3107
|
-
const regex = new RegExp(body, flags.includes("g") ? flags : flags + "g");
|
|
3108
|
-
return [{ kind: `custom-${i}`, regex }];
|
|
3109
|
-
} catch {
|
|
3110
|
-
return [];
|
|
3111
|
-
}
|
|
3112
|
-
})
|
|
3113
|
-
];
|
|
3114
|
-
let redacted = input;
|
|
3115
|
-
const hits = [];
|
|
3116
|
-
for (const { kind, regex } of patterns) {
|
|
3117
|
-
const rx = new RegExp(regex.source, regex.flags);
|
|
3118
|
-
redacted = redacted.replace(rx, (...args) => {
|
|
3119
|
-
const match = args[0];
|
|
3120
|
-
const probe = new RegExp(rx.source).exec(match);
|
|
3121
|
-
const captureCount = probe ? probe.length - 1 : 0;
|
|
3122
|
-
const g1 = captureCount >= 1 ? args[1] : void 0;
|
|
3123
|
-
const g2 = captureCount >= 2 ? args[2] : void 0;
|
|
3124
|
-
const offset = args[1 + captureCount];
|
|
3125
|
-
if (captureCount >= 2 && typeof g2 === "string") {
|
|
3126
|
-
hits.push({ kind, start: offset + (g1?.length ?? 0), length: g2.length, secret: g2 });
|
|
3127
|
-
return `${g1}${render(placeholder, kind)}`;
|
|
3128
|
-
}
|
|
3129
|
-
hits.push({ kind, start: offset, length: match.length, secret: g1 ?? match });
|
|
3130
|
-
return render(placeholder, kind);
|
|
3131
|
-
});
|
|
3132
|
-
}
|
|
3133
|
-
return { redacted, hits };
|
|
3134
|
-
}
|
|
3135
|
-
function redactJson(value, options) {
|
|
3136
|
-
if (!options.enabled) return { value, hits: [] };
|
|
3137
|
-
const allHits = [];
|
|
3138
|
-
function walk(v) {
|
|
3139
|
-
if (typeof v === "string") {
|
|
3140
|
-
const r = redactString(v, options);
|
|
3141
|
-
allHits.push(...r.hits);
|
|
3142
|
-
return r.redacted;
|
|
3143
|
-
}
|
|
3144
|
-
if (Array.isArray(v)) return v.map(walk);
|
|
3145
|
-
if (v && typeof v === "object") {
|
|
3146
|
-
const out = {};
|
|
3147
|
-
for (const [k, vv] of Object.entries(v)) {
|
|
3148
|
-
out[k] = walk(vv);
|
|
3149
|
-
}
|
|
3150
|
-
return out;
|
|
3151
|
-
}
|
|
3152
|
-
return v;
|
|
3153
|
-
}
|
|
3154
|
-
const redacted = walk(value);
|
|
3155
|
-
return { value: redacted, hits: allHits };
|
|
3156
|
-
}
|
|
3157
|
-
|
|
3158
3063
|
// src/session/session-manager.ts
|
|
3159
3064
|
function safeDate(value) {
|
|
3160
3065
|
const d = new Date(value);
|
|
@@ -4358,8 +4263,8 @@ function checkPermission(toolName, args, dangerLevel, rules, defaultAction = "co
|
|
|
4358
4263
|
if (rule.when) {
|
|
4359
4264
|
if (rule.when.dangerLevel && rule.when.dangerLevel !== dangerLevel) continue;
|
|
4360
4265
|
if (rule.when.pathPattern) {
|
|
4361
|
-
const
|
|
4362
|
-
if (!
|
|
4266
|
+
const path3 = String(args["path"] ?? args["command"] ?? "");
|
|
4267
|
+
if (!path3.includes(rule.when.pathPattern)) continue;
|
|
4363
4268
|
}
|
|
4364
4269
|
}
|
|
4365
4270
|
return rule.action;
|
|
@@ -7859,92 +7764,6 @@ ${lines.join("\n")}`;
|
|
|
7859
7764
|
}
|
|
7860
7765
|
};
|
|
7861
7766
|
|
|
7862
|
-
// src/memory/chat-index.ts
|
|
7863
|
-
import fs2 from "fs";
|
|
7864
|
-
import path3 from "path";
|
|
7865
|
-
import os from "os";
|
|
7866
|
-
import crypto from "crypto";
|
|
7867
|
-
var MEMORY_DIR_NAME = "memory-index";
|
|
7868
|
-
var CHUNKS_FILE = "chunks.json";
|
|
7869
|
-
var VECTORS_FILE = "vectors.vec";
|
|
7870
|
-
var VEC_MAGIC = 1094929750;
|
|
7871
|
-
var VEC_VERSION = 1;
|
|
7872
|
-
var VEC_HEADER_BYTES = 16;
|
|
7873
|
-
function memoryIndexDir() {
|
|
7874
|
-
return path3.join(os.homedir(), ".aicli", MEMORY_DIR_NAME);
|
|
7875
|
-
}
|
|
7876
|
-
function chunksPath() {
|
|
7877
|
-
return path3.join(memoryIndexDir(), CHUNKS_FILE);
|
|
7878
|
-
}
|
|
7879
|
-
function vectorsPath() {
|
|
7880
|
-
return path3.join(memoryIndexDir(), VECTORS_FILE);
|
|
7881
|
-
}
|
|
7882
|
-
function readVectorsFile(expectedCount) {
|
|
7883
|
-
const p = vectorsPath();
|
|
7884
|
-
if (!fs2.existsSync(p)) return null;
|
|
7885
|
-
let buf;
|
|
7886
|
-
try {
|
|
7887
|
-
buf = fs2.readFileSync(p);
|
|
7888
|
-
} catch {
|
|
7889
|
-
return null;
|
|
7890
|
-
}
|
|
7891
|
-
if (buf.length < VEC_HEADER_BYTES) return null;
|
|
7892
|
-
const magic = buf.readUInt32LE(0);
|
|
7893
|
-
const version = buf.readUInt32LE(4);
|
|
7894
|
-
const count = buf.readUInt32LE(8);
|
|
7895
|
-
const dim = buf.readUInt32LE(12);
|
|
7896
|
-
if (magic !== VEC_MAGIC || version !== VEC_VERSION || dim !== EMBEDDING_DIM) return null;
|
|
7897
|
-
if (count !== expectedCount) return null;
|
|
7898
|
-
const expected = VEC_HEADER_BYTES + count * dim * 4;
|
|
7899
|
-
if (buf.length !== expected) return null;
|
|
7900
|
-
return new Float32Array(
|
|
7901
|
-
buf.buffer.slice(buf.byteOffset + VEC_HEADER_BYTES, buf.byteOffset + expected)
|
|
7902
|
-
);
|
|
7903
|
-
}
|
|
7904
|
-
function readIndexFile() {
|
|
7905
|
-
const p = chunksPath();
|
|
7906
|
-
if (!fs2.existsSync(p)) return null;
|
|
7907
|
-
try {
|
|
7908
|
-
const raw = fs2.readFileSync(p, "utf-8");
|
|
7909
|
-
const data = JSON.parse(raw);
|
|
7910
|
-
if (data.version !== 1) return null;
|
|
7911
|
-
return data;
|
|
7912
|
-
} catch {
|
|
7913
|
-
return null;
|
|
7914
|
-
}
|
|
7915
|
-
}
|
|
7916
|
-
function loadChatIndex() {
|
|
7917
|
-
const idx = readIndexFile();
|
|
7918
|
-
if (!idx) return null;
|
|
7919
|
-
const vectors = readVectorsFile(idx.chunks.length);
|
|
7920
|
-
if (!vectors) return null;
|
|
7921
|
-
return { idx, vectors };
|
|
7922
|
-
}
|
|
7923
|
-
async function searchChatMemory(query, options = {}) {
|
|
7924
|
-
const topK = options.topK ?? 5;
|
|
7925
|
-
const minScore = options.minScore ?? 0.25;
|
|
7926
|
-
const loaded = loadChatIndex();
|
|
7927
|
-
if (!loaded || loaded.idx.chunks.length === 0) return [];
|
|
7928
|
-
const { idx, vectors } = loaded;
|
|
7929
|
-
const { redacted } = redactString(query, { enabled: true });
|
|
7930
|
-
const qvec = await embedOne(redacted);
|
|
7931
|
-
const candidates = [];
|
|
7932
|
-
for (let i = 0; i < idx.chunks.length; i++) {
|
|
7933
|
-
const c = idx.chunks[i];
|
|
7934
|
-
if (options.sessionId && c.sessionId !== options.sessionId) continue;
|
|
7935
|
-
if (options.excludeSessionId && c.sessionId === options.excludeSessionId) continue;
|
|
7936
|
-
let score = 0;
|
|
7937
|
-
const base = i * EMBEDDING_DIM;
|
|
7938
|
-
for (let d = 0; d < EMBEDDING_DIM; d++) {
|
|
7939
|
-
score += vectors[base + d] * qvec[d];
|
|
7940
|
-
}
|
|
7941
|
-
if (score < minScore) continue;
|
|
7942
|
-
candidates.push({ chunk: c, score });
|
|
7943
|
-
}
|
|
7944
|
-
candidates.sort((a, b) => b.score - a.score);
|
|
7945
|
-
return candidates.slice(0, topK);
|
|
7946
|
-
}
|
|
7947
|
-
|
|
7948
7767
|
// src/tools/builtin/recall-memory.ts
|
|
7949
7768
|
function formatHit(h, i) {
|
|
7950
7769
|
const ts = h.chunk.timestamp.slice(0, 16).replace("T", " ");
|
|
@@ -9240,9 +9059,9 @@ function getDevStatePath() {
|
|
|
9240
9059
|
return join10(homedir4(), CONFIG_DIR_NAME, DEV_STATE_FILE_NAME);
|
|
9241
9060
|
}
|
|
9242
9061
|
function loadDevState() {
|
|
9243
|
-
const
|
|
9244
|
-
if (!existsSync17(
|
|
9245
|
-
const content = readFileSync11(
|
|
9062
|
+
const path3 = getDevStatePath();
|
|
9063
|
+
if (!existsSync17(path3)) return null;
|
|
9064
|
+
const content = readFileSync11(path3, "utf-8").trim();
|
|
9246
9065
|
return content || null;
|
|
9247
9066
|
}
|
|
9248
9067
|
|
|
@@ -9795,6 +9614,12 @@ var SessionHandler = class _SessionHandler {
|
|
|
9795
9614
|
}
|
|
9796
9615
|
return;
|
|
9797
9616
|
}
|
|
9617
|
+
case "memory_search":
|
|
9618
|
+
return this.handleMemorySearch(msg.query, msg.topK, msg.minScore, msg.excludeCurrentSession);
|
|
9619
|
+
case "memory_status_request":
|
|
9620
|
+
return this.handleMemoryStatus();
|
|
9621
|
+
case "memory_rebuild":
|
|
9622
|
+
return this.handleMemoryRebuild(Boolean(msg.full));
|
|
9798
9623
|
case "auto_pause_response": {
|
|
9799
9624
|
const resolve6 = this.pendingAutoPause.get(msg.requestId);
|
|
9800
9625
|
if (resolve6) {
|
|
@@ -11168,7 +10993,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11168
10993
|
const root = process.cwd();
|
|
11169
10994
|
const { loadIndex: loadIndex2, clearIndex } = await import("./store-247B3TAU.js");
|
|
11170
10995
|
const { indexProject: indexProject2 } = await import("./indexer-O5FCGFBJ.js");
|
|
11171
|
-
const { loadVectorStore, clearVectorStore } = await import("./vector-store-
|
|
10996
|
+
const { loadVectorStore, clearVectorStore } = await import("./vector-store-NDUFLNGN.js");
|
|
11172
10997
|
if (sub === "status") {
|
|
11173
10998
|
const idx = loadIndex2(root);
|
|
11174
10999
|
const vec = loadVectorStore(root);
|
|
@@ -11217,7 +11042,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11217
11042
|
message: `Building semantic index for ${idx.symbolCount} symbols\u2026 (first run downloads ~117 MB model)`
|
|
11218
11043
|
});
|
|
11219
11044
|
try {
|
|
11220
|
-
const { rebuildSemanticIndex } = await import("./semantic-
|
|
11045
|
+
const { rebuildSemanticIndex } = await import("./semantic-3KJPAUW6.js");
|
|
11221
11046
|
const stats = await rebuildSemanticIndex(root);
|
|
11222
11047
|
const first = stats.modelFirstLoadMs ? ` (model load+first batch ${stats.modelFirstLoadMs}ms)` : "";
|
|
11223
11048
|
this.send({
|
|
@@ -11404,7 +11229,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11404
11229
|
case "test": {
|
|
11405
11230
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
11406
11231
|
try {
|
|
11407
|
-
const { executeTests } = await import("./run-tests-
|
|
11232
|
+
const { executeTests } = await import("./run-tests-KHJ6YCPH.js");
|
|
11408
11233
|
const argStr = args.join(" ").trim();
|
|
11409
11234
|
let testArgs = {};
|
|
11410
11235
|
if (argStr) {
|
|
@@ -11918,6 +11743,106 @@ Add .md files to create commands.` });
|
|
|
11918
11743
|
this.send({ type: "error", message: `Failed to clear memory: ${err.message}` });
|
|
11919
11744
|
}
|
|
11920
11745
|
}
|
|
11746
|
+
// ── B4 chat memory recall (v0.4.90+) ──────────────────────────────
|
|
11747
|
+
// Lazy-imported so the 117 MB embedder stays out of the load path for
|
|
11748
|
+
// clients that never open the Memory panel.
|
|
11749
|
+
async handleMemorySearch(query, topK, minScore, excludeCurrent) {
|
|
11750
|
+
const q = (query ?? "").trim();
|
|
11751
|
+
if (!q) {
|
|
11752
|
+
this.send({ type: "error", message: "Memory search: query is empty." });
|
|
11753
|
+
return;
|
|
11754
|
+
}
|
|
11755
|
+
try {
|
|
11756
|
+
const { searchChatMemory: searchChatMemory2, loadChatIndex: loadChatIndex2 } = await import("./chat-index-QKFH7ZP6.js");
|
|
11757
|
+
const loaded = loadChatIndex2();
|
|
11758
|
+
if (!loaded || loaded.idx.chunks.length === 0) {
|
|
11759
|
+
this.send({ type: "memory_hits", query: q, hits: [], indexMissing: true });
|
|
11760
|
+
return;
|
|
11761
|
+
}
|
|
11762
|
+
const hits = await searchChatMemory2(q, {
|
|
11763
|
+
topK: topK ?? 8,
|
|
11764
|
+
minScore: minScore ?? 0.2,
|
|
11765
|
+
excludeSessionId: excludeCurrent ? this.sessions.current?.id : void 0
|
|
11766
|
+
});
|
|
11767
|
+
this.send({
|
|
11768
|
+
type: "memory_hits",
|
|
11769
|
+
query: q,
|
|
11770
|
+
hits: hits.map((h) => ({
|
|
11771
|
+
id: h.chunk.id,
|
|
11772
|
+
sessionId: h.chunk.sessionId,
|
|
11773
|
+
sessionTitle: h.chunk.sessionTitle,
|
|
11774
|
+
provider: h.chunk.provider,
|
|
11775
|
+
model: h.chunk.model,
|
|
11776
|
+
timestamp: h.chunk.timestamp,
|
|
11777
|
+
score: h.score,
|
|
11778
|
+
text: h.chunk.text,
|
|
11779
|
+
startMessageIdx: h.chunk.startMessageIdx,
|
|
11780
|
+
endMessageIdx: h.chunk.endMessageIdx
|
|
11781
|
+
}))
|
|
11782
|
+
});
|
|
11783
|
+
} catch (err) {
|
|
11784
|
+
this.send({
|
|
11785
|
+
type: "error",
|
|
11786
|
+
message: `Memory search failed: ${err instanceof Error ? err.message : String(err)}`
|
|
11787
|
+
});
|
|
11788
|
+
}
|
|
11789
|
+
}
|
|
11790
|
+
async handleMemoryStatus() {
|
|
11791
|
+
try {
|
|
11792
|
+
const { getChatIndexStatus } = await import("./chat-index-QKFH7ZP6.js");
|
|
11793
|
+
const s = getChatIndexStatus();
|
|
11794
|
+
this.send({
|
|
11795
|
+
type: "memory_status",
|
|
11796
|
+
exists: s.exists,
|
|
11797
|
+
chunks: s.chunks,
|
|
11798
|
+
sessions: s.sessions,
|
|
11799
|
+
built: s.built,
|
|
11800
|
+
model: s.model,
|
|
11801
|
+
vecFileSizeBytes: s.vecFileSizeBytes,
|
|
11802
|
+
chunksFileSizeBytes: s.chunksFileSizeBytes
|
|
11803
|
+
});
|
|
11804
|
+
} catch (err) {
|
|
11805
|
+
this.send({
|
|
11806
|
+
type: "error",
|
|
11807
|
+
message: `Memory status failed: ${err instanceof Error ? err.message : String(err)}`
|
|
11808
|
+
});
|
|
11809
|
+
}
|
|
11810
|
+
}
|
|
11811
|
+
async handleMemoryRebuild(full) {
|
|
11812
|
+
try {
|
|
11813
|
+
this.send({
|
|
11814
|
+
type: "info",
|
|
11815
|
+
message: full ? "\u{1F9E0} Rebuilding chat memory index (this may take a while on first run \u2014 ~117 MB embedder)." : "\u{1F9E0} Refreshing chat memory index (incremental)\u2026"
|
|
11816
|
+
});
|
|
11817
|
+
const { buildChatIndex } = await import("./chat-index-QKFH7ZP6.js");
|
|
11818
|
+
const stats = await buildChatIndex({
|
|
11819
|
+
full,
|
|
11820
|
+
onProgress: (p) => {
|
|
11821
|
+
this.send({
|
|
11822
|
+
type: "memory_rebuild_progress",
|
|
11823
|
+
stage: p.stage,
|
|
11824
|
+
processed: p.processed,
|
|
11825
|
+
total: p.total
|
|
11826
|
+
});
|
|
11827
|
+
}
|
|
11828
|
+
});
|
|
11829
|
+
this.send({
|
|
11830
|
+
type: "memory_rebuild_done",
|
|
11831
|
+
chunksTotal: stats.chunksTotal,
|
|
11832
|
+
chunksAdded: stats.chunksAdded,
|
|
11833
|
+
chunksRemoved: stats.chunksRemoved,
|
|
11834
|
+
sessionsIndexed: stats.sessionsIndexed,
|
|
11835
|
+
sessionsSkipped: stats.sessionsSkipped,
|
|
11836
|
+
durationMs: stats.durationMs
|
|
11837
|
+
});
|
|
11838
|
+
await this.handleMemoryStatus();
|
|
11839
|
+
} catch (err) {
|
|
11840
|
+
this.send({
|
|
11841
|
+
type: "error",
|
|
11842
|
+
message: `Memory rebuild failed: ${err instanceof Error ? err.message : String(err)}`
|
|
11843
|
+
});
|
|
11844
|
+
}
|
|
11845
|
+
}
|
|
11921
11846
|
sendSessionMessages() {
|
|
11922
11847
|
const session = this.sessions.current;
|
|
11923
11848
|
if (!session) return;
|
|
@@ -385,7 +385,7 @@ ${content}`);
|
|
|
385
385
|
}
|
|
386
386
|
}
|
|
387
387
|
async function runTaskMode(config, providers, configManager, topic) {
|
|
388
|
-
const { TaskOrchestrator } = await import("./task-orchestrator-
|
|
388
|
+
const { TaskOrchestrator } = await import("./task-orchestrator-JB5TZNBK.js");
|
|
389
389
|
const orchestrator = new TaskOrchestrator(config, providers, configManager);
|
|
390
390
|
let interrupted = false;
|
|
391
391
|
const onSigint = () => {
|