jinzd-ai-cli 0.4.232 → 0.4.234
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-D6XYKHHA.js → batch-T3FRX4B6.js} +2 -2
- package/dist/{chat-index-O56HDGFI.js → chat-index-7HXBWQFH.js} +2 -2
- package/dist/{chat-index-WSI7ULRQ.js → chat-index-WYXYD7YP.js} +1 -1
- package/dist/{chunk-4KM53GLG.js → chunk-2QQKS56X.js} +1 -1
- package/dist/{chunk-EPDW73H7.js → chunk-3KTSJ2EL.js} +1 -1
- package/dist/{chunk-KIQ2ICMV.js → chunk-5DTEEWYC.js} +4 -4
- package/dist/{chunk-NVUCDUXE.js → chunk-5MYPIQ3Y.js} +11 -5
- package/dist/{chunk-YDGKT6RI.js → chunk-5VPRZMZB.js} +2 -2
- package/dist/{chunk-RRMLRCPW.js → chunk-6MJMHHRK.js} +4 -4
- package/dist/{chunk-2FZACYUE.js → chunk-AFT6VFMI.js} +1 -1
- package/dist/{chunk-TJVM535A.js → chunk-E5RLXMSU.js} +6 -6
- package/dist/{chunk-XVR4YKRC.js → chunk-ETJ5X6V7.js} +1 -1
- package/dist/{chunk-6VSAKQTN.js → chunk-II6RZRTF.js} +1 -1
- package/dist/{chunk-ZWU7FWHO.js → chunk-JMP3LJC2.js} +38 -91
- package/dist/chunk-KCEO2XJ4.js +420 -0
- package/dist/{chunk-LKTYTDEJ.js → chunk-L5PNAQ6O.js} +1 -1
- package/dist/{chunk-ODYTXQ26.js → chunk-O3XSFPYH.js} +35 -3
- package/dist/{chunk-62R7CACG.js → chunk-QYQI7ZWK.js} +1 -1
- package/dist/{chunk-2HWL45PG.js → chunk-TAXIG7HH.js} +1 -1
- package/dist/{chunk-LF3OUJHK.js → chunk-UO3XWZFE.js} +302 -4
- package/dist/{ci-OR57Z7QF.js → ci-GJ53GPLA.js} +6 -6
- package/dist/{ci-format-DMMS2ZFK.js → ci-format-AXE4QCI6.js} +2 -2
- package/dist/{constants-7GZKINR5.js → constants-DC4EXFSB.js} +1 -1
- package/dist/{doctor-cli-ZD37GAZD.js → doctor-cli-HKREND6Q.js} +6 -6
- package/dist/electron-server.js +78 -99
- package/dist/{hub-VFYFUSM6.js → hub-LTTKRGZC.js} +2 -2
- package/dist/index.js +24 -24
- package/dist/{persist-I3JI27OK.js → persist-AMH5SQ4W.js} +3 -3
- package/dist/{pr-YF6TXJYE.js → pr-4VODJVRV.js} +6 -6
- package/dist/{run-tests-HEDDC6DJ.js → run-tests-G5BNTMWQ.js} +2 -2
- package/dist/{run-tests-BNZZDCTU.js → run-tests-QR2PYR2P.js} +1 -1
- package/dist/{server-HCDI2EID.js → server-64WZVZZN.js} +17 -17
- package/dist/{server-C52P6IDO.js → server-EO6VQHKL.js} +7 -7
- package/dist/{task-orchestrator-QIEHYRGK.js → task-orchestrator-4INCZMLT.js} +7 -7
- package/dist/{usage-4AAMJBBM.js → usage-T3HFMNNV.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-B5TYJO7V.js +0 -123
|
@@ -128,6 +128,293 @@ function scanString(input, options) {
|
|
|
128
128
|
return hits;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
// src/session/session-index.ts
|
|
132
|
+
import { existsSync, readFileSync as readFileSync2, readdirSync, statSync } from "fs";
|
|
133
|
+
import { join } from "path";
|
|
134
|
+
|
|
135
|
+
// src/session/session-meta.ts
|
|
136
|
+
import { readFileSync, openSync, readSync, closeSync } from "fs";
|
|
137
|
+
function safeDate(value) {
|
|
138
|
+
const d = new Date(value);
|
|
139
|
+
return isNaN(d.getTime()) ? /* @__PURE__ */ new Date(0) : d;
|
|
140
|
+
}
|
|
141
|
+
function extractJsonField(header, field) {
|
|
142
|
+
const re = new RegExp(`"${field}"\\s*:\\s*"([^"]*)"`, "i");
|
|
143
|
+
const m = header.match(re);
|
|
144
|
+
return m ? m[1] : void 0;
|
|
145
|
+
}
|
|
146
|
+
function extractJsonNumberField(header, field) {
|
|
147
|
+
const m = header.match(new RegExp(`"${field}"\\s*:\\s*(\\d+)`));
|
|
148
|
+
return m ? Number(m[1]) : void 0;
|
|
149
|
+
}
|
|
150
|
+
function readSessionMeta(filePath) {
|
|
151
|
+
const HEADER_SIZE = 1024;
|
|
152
|
+
let header;
|
|
153
|
+
try {
|
|
154
|
+
const fd = openSync(filePath, "r");
|
|
155
|
+
const buf = Buffer.alloc(HEADER_SIZE);
|
|
156
|
+
const bytesRead = readSync(fd, buf, 0, HEADER_SIZE, 0);
|
|
157
|
+
closeSync(fd);
|
|
158
|
+
header = buf.toString("utf-8", 0, bytesRead);
|
|
159
|
+
} catch {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
const id = extractJsonField(header, "id");
|
|
163
|
+
const provider = extractJsonField(header, "provider");
|
|
164
|
+
const model = extractJsonField(header, "model");
|
|
165
|
+
const created = extractJsonField(header, "created");
|
|
166
|
+
const updated = extractJsonField(header, "updated");
|
|
167
|
+
const title = extractJsonField(header, "title");
|
|
168
|
+
if (id && provider && model) {
|
|
169
|
+
let messageCount = extractJsonNumberField(header, "messageCount");
|
|
170
|
+
if (messageCount === void 0) {
|
|
171
|
+
messageCount = 0;
|
|
172
|
+
try {
|
|
173
|
+
const full = readFileSync(filePath, "utf-8");
|
|
174
|
+
const matches = full.match(/"role"\s*:/g);
|
|
175
|
+
messageCount = matches ? matches.length : 0;
|
|
176
|
+
} catch {
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
let branchCount;
|
|
180
|
+
let activeBranch;
|
|
181
|
+
try {
|
|
182
|
+
const brMatch = header.match(/"branches"\s*:\s*\[/);
|
|
183
|
+
if (brMatch) {
|
|
184
|
+
const parentMatches = header.match(/"parentBranchId"/g);
|
|
185
|
+
branchCount = parentMatches ? parentMatches.length + 1 : 1;
|
|
186
|
+
}
|
|
187
|
+
activeBranch = extractJsonField(header, "activeBranchId");
|
|
188
|
+
} catch {
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
id,
|
|
192
|
+
provider,
|
|
193
|
+
model,
|
|
194
|
+
messageCount,
|
|
195
|
+
created: safeDate(created),
|
|
196
|
+
updated: safeDate(updated),
|
|
197
|
+
title: title || void 0,
|
|
198
|
+
branchCount,
|
|
199
|
+
activeBranch
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
const data = JSON.parse(readFileSync(filePath, "utf-8"));
|
|
203
|
+
return {
|
|
204
|
+
id: data.id,
|
|
205
|
+
provider: data.provider,
|
|
206
|
+
model: data.model,
|
|
207
|
+
messageCount: data.messages?.length ?? 0,
|
|
208
|
+
created: safeDate(data.created),
|
|
209
|
+
updated: safeDate(data.updated),
|
|
210
|
+
title: data.title,
|
|
211
|
+
branchCount: data.branches?.length ?? 1,
|
|
212
|
+
activeBranch: data.activeBranchId
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/session/session-index.ts
|
|
217
|
+
var INDEX_FILE = "sessions.index.json";
|
|
218
|
+
function indexFilePath(historyDir2) {
|
|
219
|
+
return join(historyDir2, INDEX_FILE);
|
|
220
|
+
}
|
|
221
|
+
function loadIndex(historyDir2) {
|
|
222
|
+
const fp = indexFilePath(historyDir2);
|
|
223
|
+
if (!existsSync(fp)) return null;
|
|
224
|
+
try {
|
|
225
|
+
const data = JSON.parse(readFileSync2(fp, "utf-8"));
|
|
226
|
+
if (data?.version === 1 && data.sessions && data.invertedIndex) {
|
|
227
|
+
return data;
|
|
228
|
+
}
|
|
229
|
+
return null;
|
|
230
|
+
} catch {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function saveIndex(historyDir2, idx) {
|
|
235
|
+
idx.built = (/* @__PURE__ */ new Date()).toISOString();
|
|
236
|
+
const fp = indexFilePath(historyDir2);
|
|
237
|
+
atomicWriteFileSync(fp, JSON.stringify(idx));
|
|
238
|
+
}
|
|
239
|
+
function rebuildIndex(historyDir2) {
|
|
240
|
+
if (!existsSync(historyDir2)) {
|
|
241
|
+
const empty = { version: 1, built: (/* @__PURE__ */ new Date()).toISOString(), sessions: {}, invertedIndex: {} };
|
|
242
|
+
return empty;
|
|
243
|
+
}
|
|
244
|
+
const files = readdirSync(historyDir2).filter((f) => f.endsWith(".json"));
|
|
245
|
+
const sessions = {};
|
|
246
|
+
const invertedIndex = /* @__PURE__ */ new Map();
|
|
247
|
+
for (const file of files) {
|
|
248
|
+
const filePath = join(historyDir2, file);
|
|
249
|
+
const meta = readSessionMeta(filePath);
|
|
250
|
+
if (!meta) continue;
|
|
251
|
+
let fileSize = 0;
|
|
252
|
+
try {
|
|
253
|
+
fileSize = statSync(filePath).size;
|
|
254
|
+
} catch {
|
|
255
|
+
}
|
|
256
|
+
let mtimeMs = 0;
|
|
257
|
+
try {
|
|
258
|
+
mtimeMs = statSync(filePath).mtimeMs;
|
|
259
|
+
} catch {
|
|
260
|
+
}
|
|
261
|
+
const entry = {
|
|
262
|
+
id: meta.id,
|
|
263
|
+
provider: meta.provider,
|
|
264
|
+
model: meta.model,
|
|
265
|
+
title: meta.title,
|
|
266
|
+
messageCount: meta.messageCount,
|
|
267
|
+
fileSize,
|
|
268
|
+
created: meta.created.toISOString(),
|
|
269
|
+
updated: meta.updated.toISOString(),
|
|
270
|
+
branchCount: meta.branchCount,
|
|
271
|
+
activeBranch: meta.activeBranch,
|
|
272
|
+
_mtimeMs: mtimeMs
|
|
273
|
+
};
|
|
274
|
+
sessions[meta.id] = entry;
|
|
275
|
+
addTokensToIndex(invertedIndex, meta.title ?? "", meta.id);
|
|
276
|
+
}
|
|
277
|
+
const serializedIndex = {};
|
|
278
|
+
for (const [token, ids] of invertedIndex) {
|
|
279
|
+
serializedIndex[token] = [...ids];
|
|
280
|
+
}
|
|
281
|
+
const idx = {
|
|
282
|
+
version: 1,
|
|
283
|
+
built: (/* @__PURE__ */ new Date()).toISOString(),
|
|
284
|
+
sessions,
|
|
285
|
+
invertedIndex: serializedIndex
|
|
286
|
+
};
|
|
287
|
+
saveIndex(historyDir2, idx);
|
|
288
|
+
return idx;
|
|
289
|
+
}
|
|
290
|
+
function updateSessionInIndex(historyDir2, meta, filePath) {
|
|
291
|
+
let idx = loadIndex(historyDir2);
|
|
292
|
+
if (!idx) {
|
|
293
|
+
rebuildIndex(historyDir2);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
let fileSize = 0;
|
|
297
|
+
try {
|
|
298
|
+
fileSize = statSync(filePath).size;
|
|
299
|
+
} catch {
|
|
300
|
+
}
|
|
301
|
+
let mtimeMs = 0;
|
|
302
|
+
try {
|
|
303
|
+
mtimeMs = statSync(filePath).mtimeMs;
|
|
304
|
+
} catch {
|
|
305
|
+
}
|
|
306
|
+
const id = meta.id;
|
|
307
|
+
for (const [token, ids] of Object.entries(idx.invertedIndex)) {
|
|
308
|
+
const filtered = ids.filter((sid) => sid !== id);
|
|
309
|
+
if (filtered.length === 0) {
|
|
310
|
+
delete idx.invertedIndex[token];
|
|
311
|
+
} else {
|
|
312
|
+
idx.invertedIndex[token] = filtered;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
idx.sessions[id] = {
|
|
316
|
+
id,
|
|
317
|
+
provider: meta.provider,
|
|
318
|
+
model: meta.model,
|
|
319
|
+
title: meta.title,
|
|
320
|
+
messageCount: meta.messageCount,
|
|
321
|
+
fileSize,
|
|
322
|
+
created: meta.created.toISOString(),
|
|
323
|
+
updated: meta.updated.toISOString(),
|
|
324
|
+
_mtimeMs: mtimeMs
|
|
325
|
+
};
|
|
326
|
+
const tokens = tokenize(meta.title ?? "");
|
|
327
|
+
for (const token of tokens) {
|
|
328
|
+
const existing = idx.invertedIndex[token] ?? [];
|
|
329
|
+
if (!existing.includes(id)) {
|
|
330
|
+
existing.push(id);
|
|
331
|
+
idx.invertedIndex[token] = existing;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
saveIndex(historyDir2, idx);
|
|
335
|
+
}
|
|
336
|
+
function removeSessionFromIndex(historyDir2, id) {
|
|
337
|
+
const idx = loadIndex(historyDir2);
|
|
338
|
+
if (!idx) return;
|
|
339
|
+
delete idx.sessions[id];
|
|
340
|
+
for (const [token, ids] of Object.entries(idx.invertedIndex)) {
|
|
341
|
+
const filtered = ids.filter((sid) => sid !== id);
|
|
342
|
+
if (filtered.length === 0) {
|
|
343
|
+
delete idx.invertedIndex[token];
|
|
344
|
+
} else {
|
|
345
|
+
idx.invertedIndex[token] = filtered;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
saveIndex(historyDir2, idx);
|
|
349
|
+
}
|
|
350
|
+
function listFromIndex(historyDir2, opts) {
|
|
351
|
+
let idx = loadIndex(historyDir2);
|
|
352
|
+
if (!idx) {
|
|
353
|
+
idx = rebuildIndex(historyDir2);
|
|
354
|
+
}
|
|
355
|
+
return Object.values(idx.sessions).map((entry) => ({
|
|
356
|
+
id: entry.id,
|
|
357
|
+
provider: entry.provider,
|
|
358
|
+
model: entry.model,
|
|
359
|
+
title: entry.title,
|
|
360
|
+
messageCount: entry.messageCount,
|
|
361
|
+
created: new Date(entry.created),
|
|
362
|
+
updated: new Date(entry.updated),
|
|
363
|
+
fileSize: opts?.includeFileSize ? entry.fileSize : void 0,
|
|
364
|
+
branchCount: entry.branchCount,
|
|
365
|
+
activeBranch: entry.activeBranch
|
|
366
|
+
})).sort((a, b) => b.updated.getTime() - a.updated.getTime());
|
|
367
|
+
}
|
|
368
|
+
function searchCandidates(historyDir2, query) {
|
|
369
|
+
const idx = loadIndex(historyDir2);
|
|
370
|
+
if (!idx) return null;
|
|
371
|
+
const queryTokens = tokenize(query.toLowerCase());
|
|
372
|
+
if (queryTokens.length === 0) return null;
|
|
373
|
+
const scoreMap = /* @__PURE__ */ new Map();
|
|
374
|
+
for (const token of queryTokens) {
|
|
375
|
+
const matchingIds = idx.invertedIndex[token];
|
|
376
|
+
if (!matchingIds) continue;
|
|
377
|
+
for (const sid of matchingIds) {
|
|
378
|
+
scoreMap.set(sid, (scoreMap.get(sid) ?? 0) + 1);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
const candidates = [...scoreMap.entries()].filter(([, score]) => score > 0).sort((a, b) => {
|
|
382
|
+
const scoreDiff = b[1] - a[1];
|
|
383
|
+
if (scoreDiff !== 0) return scoreDiff;
|
|
384
|
+
const aMeta = idx.sessions[a[0]];
|
|
385
|
+
const bMeta = idx.sessions[b[0]];
|
|
386
|
+
return (bMeta?.updated ?? "").localeCompare(aMeta?.updated ?? "");
|
|
387
|
+
}).map(([sid]) => sid);
|
|
388
|
+
return candidates.length > 0 ? candidates : null;
|
|
389
|
+
}
|
|
390
|
+
function getIndexMtimeMap(historyDir2) {
|
|
391
|
+
const idx = loadIndex(historyDir2);
|
|
392
|
+
if (!idx) return null;
|
|
393
|
+
const map = {};
|
|
394
|
+
for (const entry of Object.values(idx.sessions)) {
|
|
395
|
+
map[entry.id] = entry._mtimeMs;
|
|
396
|
+
}
|
|
397
|
+
return map;
|
|
398
|
+
}
|
|
399
|
+
function addTokensToIndex(invertedIndex, text, sessionId) {
|
|
400
|
+
for (const token of tokenize(text)) {
|
|
401
|
+
const s = invertedIndex.get(token) ?? /* @__PURE__ */ new Set();
|
|
402
|
+
s.add(sessionId);
|
|
403
|
+
invertedIndex.set(token, s);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
function tokenize(text) {
|
|
407
|
+
const tokens = /* @__PURE__ */ new Set();
|
|
408
|
+
const cjkOnly = text.replace(/[^\u4e00-\u9fff\u3400-\u4dbf]/g, "");
|
|
409
|
+
for (let i = 0; i < cjkOnly.length - 1; i++) {
|
|
410
|
+
tokens.add(cjkOnly.slice(i, i + 2));
|
|
411
|
+
}
|
|
412
|
+
const english = text.replace(/[\u4e00-\u9fff\u3400-\u4dbf]/g, " ").toLowerCase();
|
|
413
|
+
const words = english.split(/[^a-z0-9]+/).filter((w) => w.length >= 2);
|
|
414
|
+
for (const w of words) tokens.add(w);
|
|
415
|
+
return [...tokens];
|
|
416
|
+
}
|
|
417
|
+
|
|
131
418
|
// src/memory/chat-index.ts
|
|
132
419
|
var MEMORY_DIR_NAME = "memory-index";
|
|
133
420
|
var CHUNKS_FILE = "chunks.json";
|
|
@@ -285,14 +572,19 @@ function listSessionFiles() {
|
|
|
285
572
|
const dir = historyDir();
|
|
286
573
|
if (!fs.existsSync(dir)) return [];
|
|
287
574
|
const out = [];
|
|
575
|
+
const indexMtimes = getIndexMtimeMap(dir);
|
|
288
576
|
for (const name of fs.readdirSync(dir)) {
|
|
289
577
|
if (!name.endsWith(".json")) continue;
|
|
290
578
|
const id = name.replace(/\.json$/, "");
|
|
291
579
|
const p = path.join(dir, name);
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
580
|
+
if (indexMtimes && indexMtimes[id] !== void 0) {
|
|
581
|
+
out.push({ id, path: p, mtime: indexMtimes[id] });
|
|
582
|
+
} else {
|
|
583
|
+
try {
|
|
584
|
+
const st = fs.statSync(p);
|
|
585
|
+
out.push({ id, path: p, mtime: st.mtimeMs });
|
|
586
|
+
} catch {
|
|
587
|
+
}
|
|
296
588
|
}
|
|
297
589
|
}
|
|
298
590
|
return out;
|
|
@@ -461,6 +753,12 @@ export {
|
|
|
461
753
|
redactString,
|
|
462
754
|
redactJson,
|
|
463
755
|
scanString,
|
|
756
|
+
safeDate,
|
|
757
|
+
readSessionMeta,
|
|
758
|
+
updateSessionInIndex,
|
|
759
|
+
removeSessionFromIndex,
|
|
760
|
+
listFromIndex,
|
|
761
|
+
searchCandidates,
|
|
464
762
|
chunkSession,
|
|
465
763
|
loadChatIndex,
|
|
466
764
|
clearChatIndex,
|
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
CI_COMMENT_MARKER,
|
|
4
4
|
countSeverity,
|
|
5
5
|
runCi
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-6MJMHHRK.js";
|
|
7
|
+
import "./chunk-TAXIG7HH.js";
|
|
8
8
|
import "./chunk-HLWUDRBO.js";
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-QYQI7ZWK.js";
|
|
10
|
+
import "./chunk-O3XSFPYH.js";
|
|
11
|
+
import "./chunk-L5PNAQ6O.js";
|
|
12
12
|
import "./chunk-5ULLIOVC.js";
|
|
13
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-3KTSJ2EL.js";
|
|
14
14
|
import "./chunk-IW3Q7AE5.js";
|
|
15
15
|
export {
|
|
16
16
|
CI_COMMENT_MARKER,
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import {
|
|
3
3
|
formatDoctorReport,
|
|
4
4
|
runDoctorCli
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-5DTEEWYC.js";
|
|
6
|
+
import "./chunk-QYQI7ZWK.js";
|
|
7
|
+
import "./chunk-II6RZRTF.js";
|
|
8
|
+
import "./chunk-O3XSFPYH.js";
|
|
9
|
+
import "./chunk-L5PNAQ6O.js";
|
|
10
10
|
import "./chunk-5ULLIOVC.js";
|
|
11
11
|
import "./chunk-HOSJZMQS.js";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-3KTSJ2EL.js";
|
|
13
13
|
import "./chunk-IW3Q7AE5.js";
|
|
14
14
|
export {
|
|
15
15
|
formatDoctorReport,
|
package/dist/electron-server.js
CHANGED
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
VERSION,
|
|
39
39
|
buildUserIdentityPrompt,
|
|
40
40
|
runTestsTool
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-ETJ5X6V7.js";
|
|
42
42
|
import {
|
|
43
43
|
hasSemanticIndex,
|
|
44
44
|
semanticSearch
|
|
@@ -49,12 +49,18 @@ import {
|
|
|
49
49
|
import "./chunk-IEQAE3QG.js";
|
|
50
50
|
import {
|
|
51
51
|
DEFAULT_PATTERNS,
|
|
52
|
+
listFromIndex,
|
|
52
53
|
loadChatIndex,
|
|
54
|
+
readSessionMeta,
|
|
53
55
|
redactJson,
|
|
54
56
|
redactString,
|
|
57
|
+
removeSessionFromIndex,
|
|
58
|
+
safeDate,
|
|
55
59
|
scanString,
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
searchCandidates,
|
|
61
|
+
searchChatMemory,
|
|
62
|
+
updateSessionInIndex
|
|
63
|
+
} from "./chunk-UO3XWZFE.js";
|
|
58
64
|
import "./chunk-JV5N65KN.js";
|
|
59
65
|
import {
|
|
60
66
|
atomicWriteFileSync
|
|
@@ -2053,7 +2059,10 @@ function peelMetaNarration(content) {
|
|
|
2053
2059
|
var META_NARRATION_HARD_MARKERS = [
|
|
2054
2060
|
/\[⚠️\s*CONTENT GENERATION MODE\]/,
|
|
2055
2061
|
/CONTENT_ONLY_STREAM_REMINDER\b/,
|
|
2056
|
-
/<system-reminder>/i
|
|
2062
|
+
/<system-reminder>/i,
|
|
2063
|
+
// → `path` — AI wraps content with "已写好 → `file.md`" before the document body.
|
|
2064
|
+
// Documents never use this conversational file-path-pointer syntax.
|
|
2065
|
+
/→\s*`[^`]{2,}`/u
|
|
2057
2066
|
];
|
|
2058
2067
|
var META_NARRATION_HEURISTICS = [
|
|
2059
2068
|
/\bthe user (?:is asking me|wants me|is requesting|expects me)\b/i,
|
|
@@ -2064,7 +2073,24 @@ var META_NARRATION_HEURISTICS = [
|
|
|
2064
2073
|
/\bActually,?\s+I\b/i,
|
|
2065
2074
|
/\bI need to be honest with the user\b/i,
|
|
2066
2075
|
/\bI(?:'m| am) in a special mode\b/i,
|
|
2067
|
-
/\bGiven that I cannot\b/i
|
|
2076
|
+
/\bGiven that I cannot\b/i,
|
|
2077
|
+
// ── 中文 ── (need 2+ total hits across all patterns to trigger)
|
|
2078
|
+
/(?:已经?|已)\s*(?:写[好完]|生成[好完]|创建[好完]|准备[好完]|搞[好定]|弄[好完])[了啦]?/u,
|
|
2079
|
+
/(?:需要你|请你|麻烦你|还要你|你看)\s*(?:确认|决定|选择|帮忙|看[一看下]|过目)/u,
|
|
2080
|
+
/(?:总结|概括|归纳|整理)[一下]?(?:核心|主要|关键)?(?:思路|要点|内容|设计)/u,
|
|
2081
|
+
/(?:随时|有问题|有需要|需要调整|需要修改|需要补充)\s*(?:联系|找我|告诉|沟通|调整|修改|补充|说)/u,
|
|
2082
|
+
/^(?:.{0,40})(?:好的[,,,!\s]|嗯[,,,!\s]|收到[了]?[,,,!\s]|了解[了]?[,,,!\s]|明白[了]?[,,,!\s])/mu,
|
|
2083
|
+
/(?:我来|让我|容我)\s*(?:整理|梳理|归纳|想想|看看|重新|检查|核实)/u,
|
|
2084
|
+
// 过渡语(需要 2+ hits):"以下是:" / "如下:" 作为独立行。文档中可作小节标题,
|
|
2085
|
+
// 但配合另一个对话模式(如"好的")时是典型的 AI 内容包装。
|
|
2086
|
+
/^.{0,60}(?:以下是|下面是|如下)\s*[::,,]\s*$/mu
|
|
2087
|
+
];
|
|
2088
|
+
var CHINESE_TAIL_CLOSING_MARKERS = [
|
|
2089
|
+
/(?:需要你|请你|麻烦你|你看)\s*(?:确认|决定|选择|帮忙|看[一看下]|过目|觉得|认为)/u,
|
|
2090
|
+
/(?:随时|有问题|有需要|需要调整|需要修改)\s*(?:联系|找我|告诉|沟通|调整|修改)/u,
|
|
2091
|
+
/(?:如果|假如|假设)\s*(?:有[没缺][有]?|需要|觉得|认为).{0,30}?(?:随时|可以|直接|尽管)\s*(?:联系|找我|告诉|说|调整|修改)/u,
|
|
2092
|
+
/(?:以上|先这样|暂时|目前).{0,10}$/mu,
|
|
2093
|
+
/(?:几个|一些|以下)\s*(?:关键)?(?:问题|疑问|想法|建议).{0,30}$/mu
|
|
2068
2094
|
];
|
|
2069
2095
|
function detectMetaNarration(content) {
|
|
2070
2096
|
if (!content) return null;
|
|
@@ -2072,7 +2098,19 @@ function detectMetaNarration(content) {
|
|
|
2072
2098
|
for (const re of META_NARRATION_HARD_MARKERS) {
|
|
2073
2099
|
if (re.test(head)) return re.source;
|
|
2074
2100
|
}
|
|
2075
|
-
if (
|
|
2101
|
+
if (content.length > 500) {
|
|
2102
|
+
const tail = content.slice(-500);
|
|
2103
|
+
let tailHits = 0;
|
|
2104
|
+
let tailFirst = "";
|
|
2105
|
+
for (const re of CHINESE_TAIL_CLOSING_MARKERS) {
|
|
2106
|
+
if (re.test(tail)) {
|
|
2107
|
+
tailHits++;
|
|
2108
|
+
if (!tailFirst) tailFirst = re.source;
|
|
2109
|
+
if (tailHits >= 2) return `meta-narration-tail:${tailFirst}`;
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
if (/^#{1,3}\s+\S/m.test(content.slice(0, 200))) return null;
|
|
2076
2114
|
let hits = 0;
|
|
2077
2115
|
let firstMatch = "";
|
|
2078
2116
|
for (const re of META_NARRATION_HEURISTICS) {
|
|
@@ -3915,7 +3953,7 @@ var ProviderRegistry = class {
|
|
|
3915
3953
|
};
|
|
3916
3954
|
|
|
3917
3955
|
// src/session/session-manager.ts
|
|
3918
|
-
import { readFileSync as readFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync, unlinkSync as unlinkSync2,
|
|
3956
|
+
import { readFileSync as readFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync, unlinkSync as unlinkSync2, statSync } from "fs";
|
|
3919
3957
|
import { join as join3 } from "path";
|
|
3920
3958
|
import { v4 as uuidv4 } from "uuid";
|
|
3921
3959
|
|
|
@@ -4451,19 +4489,6 @@ var Session = class _Session {
|
|
|
4451
4489
|
};
|
|
4452
4490
|
|
|
4453
4491
|
// src/session/session-manager.ts
|
|
4454
|
-
function safeDate(value) {
|
|
4455
|
-
const d = new Date(value);
|
|
4456
|
-
return isNaN(d.getTime()) ? /* @__PURE__ */ new Date(0) : d;
|
|
4457
|
-
}
|
|
4458
|
-
function extractJsonField(header, field) {
|
|
4459
|
-
const re = new RegExp(`"${field}"\\s*:\\s*"([^"]*)"`, "i");
|
|
4460
|
-
const m = header.match(re);
|
|
4461
|
-
return m ? m[1] : void 0;
|
|
4462
|
-
}
|
|
4463
|
-
function extractJsonNumberField(header, field) {
|
|
4464
|
-
const m = header.match(new RegExp(`"${field}"\\s*:\\s*(\\d+)`));
|
|
4465
|
-
return m ? Number(m[1]) : void 0;
|
|
4466
|
-
}
|
|
4467
4492
|
var SessionManager = class {
|
|
4468
4493
|
_current = null;
|
|
4469
4494
|
historyDir;
|
|
@@ -4521,6 +4546,18 @@ var SessionManager = class {
|
|
|
4521
4546
|
this.lastRedactionHits = hits.length;
|
|
4522
4547
|
atomicWriteFileSync(filePath, JSON.stringify(payload, null, 2));
|
|
4523
4548
|
this._current.dirty = false;
|
|
4549
|
+
try {
|
|
4550
|
+
updateSessionInIndex(this.historyDir, {
|
|
4551
|
+
id: this._current.id,
|
|
4552
|
+
provider: this._current.provider,
|
|
4553
|
+
model: this._current.model,
|
|
4554
|
+
title: this._current.title,
|
|
4555
|
+
messageCount: this._current.messages.length,
|
|
4556
|
+
created: this._current.created,
|
|
4557
|
+
updated: this._current.updated
|
|
4558
|
+
}, filePath);
|
|
4559
|
+
} catch {
|
|
4560
|
+
}
|
|
4524
4561
|
}
|
|
4525
4562
|
loadSession(id) {
|
|
4526
4563
|
const filePath = join3(this.historyDir, `${id}.json`);
|
|
@@ -4539,12 +4576,16 @@ var SessionManager = class {
|
|
|
4539
4576
|
}
|
|
4540
4577
|
listSessions(opts) {
|
|
4541
4578
|
if (!existsSync3(this.historyDir)) return [];
|
|
4579
|
+
try {
|
|
4580
|
+
return listFromIndex(this.historyDir, opts);
|
|
4581
|
+
} catch {
|
|
4582
|
+
}
|
|
4542
4583
|
const files = readdirSync(this.historyDir).filter((f) => f.endsWith(".json"));
|
|
4543
4584
|
const metas = [];
|
|
4544
4585
|
for (const file of files) {
|
|
4545
4586
|
try {
|
|
4546
4587
|
const filePath = join3(this.historyDir, file);
|
|
4547
|
-
const meta =
|
|
4588
|
+
const meta = readSessionMeta(filePath);
|
|
4548
4589
|
if (!meta) continue;
|
|
4549
4590
|
if (opts?.includeFileSize) {
|
|
4550
4591
|
try {
|
|
@@ -4562,78 +4603,6 @@ var SessionManager = class {
|
|
|
4562
4603
|
}
|
|
4563
4604
|
return metas.sort((a, b) => b.updated.getTime() - a.updated.getTime());
|
|
4564
4605
|
}
|
|
4565
|
-
/**
|
|
4566
|
-
* P1-B: Read only the first ~1KB of a session file to extract metadata fields.
|
|
4567
|
-
* Session JSON format puts id/provider/model/created/updated/title before the
|
|
4568
|
-
* large "messages" array, so a small header read suffices for metadata extraction.
|
|
4569
|
-
* Falls back to full file read if header parsing fails.
|
|
4570
|
-
*/
|
|
4571
|
-
readSessionMeta(filePath) {
|
|
4572
|
-
const HEADER_SIZE = 1024;
|
|
4573
|
-
let header;
|
|
4574
|
-
try {
|
|
4575
|
-
const fd = openSync(filePath, "r");
|
|
4576
|
-
const buf = Buffer.alloc(HEADER_SIZE);
|
|
4577
|
-
const bytesRead = readSync(fd, buf, 0, HEADER_SIZE, 0);
|
|
4578
|
-
closeSync(fd);
|
|
4579
|
-
header = buf.toString("utf-8", 0, bytesRead);
|
|
4580
|
-
} catch {
|
|
4581
|
-
return null;
|
|
4582
|
-
}
|
|
4583
|
-
const id = extractJsonField(header, "id");
|
|
4584
|
-
const provider = extractJsonField(header, "provider");
|
|
4585
|
-
const model = extractJsonField(header, "model");
|
|
4586
|
-
const created = extractJsonField(header, "created");
|
|
4587
|
-
const updated = extractJsonField(header, "updated");
|
|
4588
|
-
const title = extractJsonField(header, "title");
|
|
4589
|
-
if (id && provider && model) {
|
|
4590
|
-
let messageCount = extractJsonNumberField(header, "messageCount");
|
|
4591
|
-
if (messageCount === void 0) {
|
|
4592
|
-
messageCount = 0;
|
|
4593
|
-
try {
|
|
4594
|
-
const full = readFileSync3(filePath, "utf-8");
|
|
4595
|
-
const matches = full.match(/"role"\s*:/g);
|
|
4596
|
-
messageCount = matches ? matches.length : 0;
|
|
4597
|
-
} catch {
|
|
4598
|
-
}
|
|
4599
|
-
}
|
|
4600
|
-
let branchCount;
|
|
4601
|
-
let activeBranch;
|
|
4602
|
-
try {
|
|
4603
|
-
const brMatch = header.match(/"branches"\s*:\s*\[/);
|
|
4604
|
-
if (brMatch) {
|
|
4605
|
-
const brIds = header.match(/"id"\s*:\s*"[^"]*"/g);
|
|
4606
|
-
const parentMatches = header.match(/"parentBranchId"/g);
|
|
4607
|
-
branchCount = parentMatches ? parentMatches.length + 1 : 1;
|
|
4608
|
-
}
|
|
4609
|
-
activeBranch = extractJsonField(header, "activeBranchId");
|
|
4610
|
-
} catch {
|
|
4611
|
-
}
|
|
4612
|
-
return {
|
|
4613
|
-
id,
|
|
4614
|
-
provider,
|
|
4615
|
-
model,
|
|
4616
|
-
messageCount,
|
|
4617
|
-
created: safeDate(created),
|
|
4618
|
-
updated: safeDate(updated),
|
|
4619
|
-
title: title || void 0,
|
|
4620
|
-
branchCount,
|
|
4621
|
-
activeBranch
|
|
4622
|
-
};
|
|
4623
|
-
}
|
|
4624
|
-
const data = JSON.parse(readFileSync3(filePath, "utf-8"));
|
|
4625
|
-
return {
|
|
4626
|
-
id: data.id,
|
|
4627
|
-
provider: data.provider,
|
|
4628
|
-
model: data.model,
|
|
4629
|
-
messageCount: data.messages?.length ?? 0,
|
|
4630
|
-
created: safeDate(data.created),
|
|
4631
|
-
updated: safeDate(data.updated),
|
|
4632
|
-
title: data.title,
|
|
4633
|
-
branchCount: data.branches?.length ?? 1,
|
|
4634
|
-
activeBranch: data.activeBranchId
|
|
4635
|
-
};
|
|
4636
|
-
}
|
|
4637
4606
|
deleteSession(id) {
|
|
4638
4607
|
const filePath = join3(this.historyDir, `${id}.json`);
|
|
4639
4608
|
if (!existsSync3(filePath)) return false;
|
|
@@ -4642,6 +4611,10 @@ var SessionManager = class {
|
|
|
4642
4611
|
if (this._current && this._current.id === id) {
|
|
4643
4612
|
this._current = null;
|
|
4644
4613
|
}
|
|
4614
|
+
try {
|
|
4615
|
+
removeSessionFromIndex(this.historyDir, id);
|
|
4616
|
+
} catch {
|
|
4617
|
+
}
|
|
4645
4618
|
return true;
|
|
4646
4619
|
} catch {
|
|
4647
4620
|
return false;
|
|
@@ -4675,9 +4648,15 @@ var SessionManager = class {
|
|
|
4675
4648
|
searchMessages(query, maxResults = 20) {
|
|
4676
4649
|
if (!existsSync3(this.historyDir)) return [];
|
|
4677
4650
|
const q = query.toLowerCase();
|
|
4678
|
-
const
|
|
4651
|
+
const candidateIds = searchCandidates(this.historyDir, q);
|
|
4652
|
+
let filesToSearch;
|
|
4653
|
+
if (candidateIds !== null) {
|
|
4654
|
+
filesToSearch = candidateIds.map((id) => join3(this.historyDir, `${id}.json`)).filter((fp) => existsSync3(fp));
|
|
4655
|
+
} else {
|
|
4656
|
+
filesToSearch = readdirSync(this.historyDir).filter((f) => f.endsWith(".json")).map((f) => join3(this.historyDir, f));
|
|
4657
|
+
}
|
|
4679
4658
|
const results = [];
|
|
4680
|
-
for (const filePath of
|
|
4659
|
+
for (const filePath of filesToSearch) {
|
|
4681
4660
|
if (results.length >= maxResults) break;
|
|
4682
4661
|
try {
|
|
4683
4662
|
const data = JSON.parse(readFileSync3(filePath, "utf-8"));
|
|
@@ -15876,7 +15855,7 @@ async function handleSecurityReview(args, ctx) {
|
|
|
15876
15855
|
async function handleTest(args, ctx) {
|
|
15877
15856
|
ctx.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
15878
15857
|
try {
|
|
15879
|
-
const { executeTests } = await import("./run-tests-
|
|
15858
|
+
const { executeTests } = await import("./run-tests-QR2PYR2P.js");
|
|
15880
15859
|
const argStr = args.join(" ").trim();
|
|
15881
15860
|
let testArgs = {};
|
|
15882
15861
|
if (argStr) {
|
|
@@ -17739,7 +17718,7 @@ ${entry.content}`;
|
|
|
17739
17718
|
return;
|
|
17740
17719
|
}
|
|
17741
17720
|
try {
|
|
17742
|
-
const { searchChatMemory: searchChatMemory2, loadChatIndex: loadChatIndex2 } = await import("./chat-index-
|
|
17721
|
+
const { searchChatMemory: searchChatMemory2, loadChatIndex: loadChatIndex2 } = await import("./chat-index-WYXYD7YP.js");
|
|
17743
17722
|
const loaded = loadChatIndex2();
|
|
17744
17723
|
if (!loaded || loaded.idx.chunks.length === 0) {
|
|
17745
17724
|
this.send({ type: "memory_hits", query: q, hits: [], indexMissing: true });
|
|
@@ -17775,7 +17754,7 @@ ${entry.content}`;
|
|
|
17775
17754
|
}
|
|
17776
17755
|
async handleMemoryStatus() {
|
|
17777
17756
|
try {
|
|
17778
|
-
const { getChatIndexStatus } = await import("./chat-index-
|
|
17757
|
+
const { getChatIndexStatus } = await import("./chat-index-WYXYD7YP.js");
|
|
17779
17758
|
const s = getChatIndexStatus();
|
|
17780
17759
|
this.send({
|
|
17781
17760
|
type: "memory_status",
|
|
@@ -17800,7 +17779,7 @@ ${entry.content}`;
|
|
|
17800
17779
|
type: "info",
|
|
17801
17780
|
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"
|
|
17802
17781
|
});
|
|
17803
|
-
const { buildChatIndex } = await import("./chat-index-
|
|
17782
|
+
const { buildChatIndex } = await import("./chat-index-WYXYD7YP.js");
|
|
17804
17783
|
const stats = await buildChatIndex({
|
|
17805
17784
|
full,
|
|
17806
17785
|
onProgress: (p) => {
|