jinzd-ai-cli 0.4.233 → 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.
Files changed (35) hide show
  1. package/dist/{batch-WWNPYQ6G.js → batch-T3FRX4B6.js} +2 -2
  2. package/dist/{chat-index-O56HDGFI.js → chat-index-7HXBWQFH.js} +2 -2
  3. package/dist/{chat-index-WSI7ULRQ.js → chat-index-WYXYD7YP.js} +1 -1
  4. package/dist/{chunk-4KM53GLG.js → chunk-2QQKS56X.js} +1 -1
  5. package/dist/{chunk-ACTO5C6K.js → chunk-3KTSJ2EL.js} +1 -1
  6. package/dist/{chunk-NXYXFRPA.js → chunk-5DTEEWYC.js} +3 -3
  7. package/dist/{chunk-NVUCDUXE.js → chunk-5MYPIQ3Y.js} +11 -5
  8. package/dist/{chunk-7KS3RGZ7.js → chunk-5VPRZMZB.js} +2 -2
  9. package/dist/{chunk-FQSAK75P.js → chunk-6MJMHHRK.js} +3 -3
  10. package/dist/{chunk-M4FW2NPU.js → chunk-AFT6VFMI.js} +1 -1
  11. package/dist/{chunk-HX67JAK6.js → chunk-E5RLXMSU.js} +5 -5
  12. package/dist/{chunk-4OAV7QMB.js → chunk-ETJ5X6V7.js} +1 -1
  13. package/dist/{chunk-EZGZOK6E.js → chunk-II6RZRTF.js} +1 -1
  14. package/dist/{chunk-ZWU7FWHO.js → chunk-JMP3LJC2.js} +38 -91
  15. package/dist/chunk-KCEO2XJ4.js +420 -0
  16. package/dist/{chunk-5PKNKJYP.js → chunk-L5PNAQ6O.js} +1 -1
  17. package/dist/{chunk-TJK7AU65.js → chunk-TAXIG7HH.js} +1 -1
  18. package/dist/{chunk-LF3OUJHK.js → chunk-UO3XWZFE.js} +302 -4
  19. package/dist/{ci-V5V3JSJC.js → ci-GJ53GPLA.js} +4 -4
  20. package/dist/{ci-format-XS7LKBO5.js → ci-format-AXE4QCI6.js} +2 -2
  21. package/dist/{constants-UROQJXLY.js → constants-DC4EXFSB.js} +1 -1
  22. package/dist/{doctor-cli-BY3FIV2B.js → doctor-cli-HKREND6Q.js} +4 -4
  23. package/dist/electron-server.js +43 -96
  24. package/dist/{hub-L2QCRI5M.js → hub-LTTKRGZC.js} +2 -2
  25. package/dist/index.js +22 -22
  26. package/dist/{persist-I3JI27OK.js → persist-AMH5SQ4W.js} +3 -3
  27. package/dist/{pr-IJRUPR5C.js → pr-4VODJVRV.js} +4 -4
  28. package/dist/{run-tests-FLCVJ6TK.js → run-tests-G5BNTMWQ.js} +2 -2
  29. package/dist/{run-tests-NNXBS4EL.js → run-tests-QR2PYR2P.js} +1 -1
  30. package/dist/{server-W2X3C6GJ.js → server-64WZVZZN.js} +15 -15
  31. package/dist/{server-E6LZB72O.js → server-EO6VQHKL.js} +6 -6
  32. package/dist/{task-orchestrator-W55VKYTC.js → task-orchestrator-4INCZMLT.js} +6 -6
  33. package/dist/{usage-MZCDTJWB.js → usage-T3HFMNNV.js} +2 -2
  34. package/package.json +1 -1
  35. 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
- try {
293
- const st = fs.statSync(p);
294
- out.push({ id, path: p, mtime: st.mtimeMs });
295
- } catch {
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-FQSAK75P.js";
7
- import "./chunk-TJK7AU65.js";
6
+ } from "./chunk-6MJMHHRK.js";
7
+ import "./chunk-TAXIG7HH.js";
8
8
  import "./chunk-HLWUDRBO.js";
9
9
  import "./chunk-QYQI7ZWK.js";
10
10
  import "./chunk-O3XSFPYH.js";
11
- import "./chunk-5PKNKJYP.js";
11
+ import "./chunk-L5PNAQ6O.js";
12
12
  import "./chunk-5ULLIOVC.js";
13
- import "./chunk-ACTO5C6K.js";
13
+ import "./chunk-3KTSJ2EL.js";
14
14
  import "./chunk-IW3Q7AE5.js";
15
15
  export {
16
16
  CI_COMMENT_MARKER,
@@ -6,8 +6,8 @@ import {
6
6
  formatCiResult,
7
7
  formatCiSarif,
8
8
  normalizeCiThresholds
9
- } from "./chunk-TJK7AU65.js";
10
- import "./chunk-ACTO5C6K.js";
9
+ } from "./chunk-TAXIG7HH.js";
10
+ import "./chunk-3KTSJ2EL.js";
11
11
  export {
12
12
  DEFAULT_CI_THRESHOLDS,
13
13
  detectCiGateSignals,
@@ -38,7 +38,7 @@ import {
38
38
  TEST_TIMEOUT,
39
39
  VERSION,
40
40
  buildUserIdentityPrompt
41
- } from "./chunk-ACTO5C6K.js";
41
+ } from "./chunk-3KTSJ2EL.js";
42
42
  export {
43
43
  AGENTIC_BEHAVIOR_GUIDELINE,
44
44
  APP_NAME,
@@ -2,14 +2,14 @@
2
2
  import {
3
3
  formatDoctorReport,
4
4
  runDoctorCli
5
- } from "./chunk-NXYXFRPA.js";
5
+ } from "./chunk-5DTEEWYC.js";
6
6
  import "./chunk-QYQI7ZWK.js";
7
- import "./chunk-EZGZOK6E.js";
7
+ import "./chunk-II6RZRTF.js";
8
8
  import "./chunk-O3XSFPYH.js";
9
- import "./chunk-5PKNKJYP.js";
9
+ import "./chunk-L5PNAQ6O.js";
10
10
  import "./chunk-5ULLIOVC.js";
11
11
  import "./chunk-HOSJZMQS.js";
12
- import "./chunk-ACTO5C6K.js";
12
+ import "./chunk-3KTSJ2EL.js";
13
13
  import "./chunk-IW3Q7AE5.js";
14
14
  export {
15
15
  formatDoctorReport,
@@ -38,7 +38,7 @@ import {
38
38
  VERSION,
39
39
  buildUserIdentityPrompt,
40
40
  runTestsTool
41
- } from "./chunk-4OAV7QMB.js";
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
- searchChatMemory
57
- } from "./chunk-LF3OUJHK.js";
60
+ searchCandidates,
61
+ searchChatMemory,
62
+ updateSessionInIndex
63
+ } from "./chunk-UO3XWZFE.js";
58
64
  import "./chunk-JV5N65KN.js";
59
65
  import {
60
66
  atomicWriteFileSync
@@ -3947,7 +3953,7 @@ var ProviderRegistry = class {
3947
3953
  };
3948
3954
 
3949
3955
  // src/session/session-manager.ts
3950
- import { readFileSync as readFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync, unlinkSync as unlinkSync2, openSync, readSync, closeSync, statSync } from "fs";
3956
+ import { readFileSync as readFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync, unlinkSync as unlinkSync2, statSync } from "fs";
3951
3957
  import { join as join3 } from "path";
3952
3958
  import { v4 as uuidv4 } from "uuid";
3953
3959
 
@@ -4483,19 +4489,6 @@ var Session = class _Session {
4483
4489
  };
4484
4490
 
4485
4491
  // src/session/session-manager.ts
4486
- function safeDate(value) {
4487
- const d = new Date(value);
4488
- return isNaN(d.getTime()) ? /* @__PURE__ */ new Date(0) : d;
4489
- }
4490
- function extractJsonField(header, field) {
4491
- const re = new RegExp(`"${field}"\\s*:\\s*"([^"]*)"`, "i");
4492
- const m = header.match(re);
4493
- return m ? m[1] : void 0;
4494
- }
4495
- function extractJsonNumberField(header, field) {
4496
- const m = header.match(new RegExp(`"${field}"\\s*:\\s*(\\d+)`));
4497
- return m ? Number(m[1]) : void 0;
4498
- }
4499
4492
  var SessionManager = class {
4500
4493
  _current = null;
4501
4494
  historyDir;
@@ -4553,6 +4546,18 @@ var SessionManager = class {
4553
4546
  this.lastRedactionHits = hits.length;
4554
4547
  atomicWriteFileSync(filePath, JSON.stringify(payload, null, 2));
4555
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
+ }
4556
4561
  }
4557
4562
  loadSession(id) {
4558
4563
  const filePath = join3(this.historyDir, `${id}.json`);
@@ -4571,12 +4576,16 @@ var SessionManager = class {
4571
4576
  }
4572
4577
  listSessions(opts) {
4573
4578
  if (!existsSync3(this.historyDir)) return [];
4579
+ try {
4580
+ return listFromIndex(this.historyDir, opts);
4581
+ } catch {
4582
+ }
4574
4583
  const files = readdirSync(this.historyDir).filter((f) => f.endsWith(".json"));
4575
4584
  const metas = [];
4576
4585
  for (const file of files) {
4577
4586
  try {
4578
4587
  const filePath = join3(this.historyDir, file);
4579
- const meta = this.readSessionMeta(filePath);
4588
+ const meta = readSessionMeta(filePath);
4580
4589
  if (!meta) continue;
4581
4590
  if (opts?.includeFileSize) {
4582
4591
  try {
@@ -4594,78 +4603,6 @@ var SessionManager = class {
4594
4603
  }
4595
4604
  return metas.sort((a, b) => b.updated.getTime() - a.updated.getTime());
4596
4605
  }
4597
- /**
4598
- * P1-B: Read only the first ~1KB of a session file to extract metadata fields.
4599
- * Session JSON format puts id/provider/model/created/updated/title before the
4600
- * large "messages" array, so a small header read suffices for metadata extraction.
4601
- * Falls back to full file read if header parsing fails.
4602
- */
4603
- readSessionMeta(filePath) {
4604
- const HEADER_SIZE = 1024;
4605
- let header;
4606
- try {
4607
- const fd = openSync(filePath, "r");
4608
- const buf = Buffer.alloc(HEADER_SIZE);
4609
- const bytesRead = readSync(fd, buf, 0, HEADER_SIZE, 0);
4610
- closeSync(fd);
4611
- header = buf.toString("utf-8", 0, bytesRead);
4612
- } catch {
4613
- return null;
4614
- }
4615
- const id = extractJsonField(header, "id");
4616
- const provider = extractJsonField(header, "provider");
4617
- const model = extractJsonField(header, "model");
4618
- const created = extractJsonField(header, "created");
4619
- const updated = extractJsonField(header, "updated");
4620
- const title = extractJsonField(header, "title");
4621
- if (id && provider && model) {
4622
- let messageCount = extractJsonNumberField(header, "messageCount");
4623
- if (messageCount === void 0) {
4624
- messageCount = 0;
4625
- try {
4626
- const full = readFileSync3(filePath, "utf-8");
4627
- const matches = full.match(/"role"\s*:/g);
4628
- messageCount = matches ? matches.length : 0;
4629
- } catch {
4630
- }
4631
- }
4632
- let branchCount;
4633
- let activeBranch;
4634
- try {
4635
- const brMatch = header.match(/"branches"\s*:\s*\[/);
4636
- if (brMatch) {
4637
- const brIds = header.match(/"id"\s*:\s*"[^"]*"/g);
4638
- const parentMatches = header.match(/"parentBranchId"/g);
4639
- branchCount = parentMatches ? parentMatches.length + 1 : 1;
4640
- }
4641
- activeBranch = extractJsonField(header, "activeBranchId");
4642
- } catch {
4643
- }
4644
- return {
4645
- id,
4646
- provider,
4647
- model,
4648
- messageCount,
4649
- created: safeDate(created),
4650
- updated: safeDate(updated),
4651
- title: title || void 0,
4652
- branchCount,
4653
- activeBranch
4654
- };
4655
- }
4656
- const data = JSON.parse(readFileSync3(filePath, "utf-8"));
4657
- return {
4658
- id: data.id,
4659
- provider: data.provider,
4660
- model: data.model,
4661
- messageCount: data.messages?.length ?? 0,
4662
- created: safeDate(data.created),
4663
- updated: safeDate(data.updated),
4664
- title: data.title,
4665
- branchCount: data.branches?.length ?? 1,
4666
- activeBranch: data.activeBranchId
4667
- };
4668
- }
4669
4606
  deleteSession(id) {
4670
4607
  const filePath = join3(this.historyDir, `${id}.json`);
4671
4608
  if (!existsSync3(filePath)) return false;
@@ -4674,6 +4611,10 @@ var SessionManager = class {
4674
4611
  if (this._current && this._current.id === id) {
4675
4612
  this._current = null;
4676
4613
  }
4614
+ try {
4615
+ removeSessionFromIndex(this.historyDir, id);
4616
+ } catch {
4617
+ }
4677
4618
  return true;
4678
4619
  } catch {
4679
4620
  return false;
@@ -4707,9 +4648,15 @@ var SessionManager = class {
4707
4648
  searchMessages(query, maxResults = 20) {
4708
4649
  if (!existsSync3(this.historyDir)) return [];
4709
4650
  const q = query.toLowerCase();
4710
- const files = readdirSync(this.historyDir).filter((f) => f.endsWith(".json")).map((f) => join3(this.historyDir, f));
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
+ }
4711
4658
  const results = [];
4712
- for (const filePath of files) {
4659
+ for (const filePath of filesToSearch) {
4713
4660
  if (results.length >= maxResults) break;
4714
4661
  try {
4715
4662
  const data = JSON.parse(readFileSync3(filePath, "utf-8"));
@@ -15908,7 +15855,7 @@ async function handleSecurityReview(args, ctx) {
15908
15855
  async function handleTest(args, ctx) {
15909
15856
  ctx.send({ type: "info", message: "\u{1F9EA} Running tests..." });
15910
15857
  try {
15911
- const { executeTests } = await import("./run-tests-NNXBS4EL.js");
15858
+ const { executeTests } = await import("./run-tests-QR2PYR2P.js");
15912
15859
  const argStr = args.join(" ").trim();
15913
15860
  let testArgs = {};
15914
15861
  if (argStr) {
@@ -17771,7 +17718,7 @@ ${entry.content}`;
17771
17718
  return;
17772
17719
  }
17773
17720
  try {
17774
- const { searchChatMemory: searchChatMemory2, loadChatIndex: loadChatIndex2 } = await import("./chat-index-WSI7ULRQ.js");
17721
+ const { searchChatMemory: searchChatMemory2, loadChatIndex: loadChatIndex2 } = await import("./chat-index-WYXYD7YP.js");
17775
17722
  const loaded = loadChatIndex2();
17776
17723
  if (!loaded || loaded.idx.chunks.length === 0) {
17777
17724
  this.send({ type: "memory_hits", query: q, hits: [], indexMissing: true });
@@ -17807,7 +17754,7 @@ ${entry.content}`;
17807
17754
  }
17808
17755
  async handleMemoryStatus() {
17809
17756
  try {
17810
- const { getChatIndexStatus } = await import("./chat-index-WSI7ULRQ.js");
17757
+ const { getChatIndexStatus } = await import("./chat-index-WYXYD7YP.js");
17811
17758
  const s = getChatIndexStatus();
17812
17759
  this.send({
17813
17760
  type: "memory_status",
@@ -17832,7 +17779,7 @@ ${entry.content}`;
17832
17779
  type: "info",
17833
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"
17834
17781
  });
17835
- const { buildChatIndex } = await import("./chat-index-WSI7ULRQ.js");
17782
+ const { buildChatIndex } = await import("./chat-index-WYXYD7YP.js");
17836
17783
  const stats = await buildChatIndex({
17837
17784
  full,
17838
17785
  onProgress: (p) => {
@@ -139,7 +139,7 @@ ${content}`);
139
139
  const state = await runDiscussion(config, providers, options.topic);
140
140
  if (options.save !== false && state.messages.length > 0) {
141
141
  try {
142
- const { persistDiscussion } = await import("./persist-I3JI27OK.js");
142
+ const { persistDiscussion } = await import("./persist-AMH5SQ4W.js");
143
143
  const { path } = await persistDiscussion(state, configManager, defaultProvider, defaultModel);
144
144
  console.log(chalk.dim(`
145
145
  \u{1F4BE} Saved to history \u2014 open it in the Web UI and hit \u{1F3AC} to replay.
@@ -154,7 +154,7 @@ ${content}`);
154
154
  }
155
155
  }
156
156
  async function runTaskMode(config, providers, configManager, topic) {
157
- const { TaskOrchestrator } = await import("./task-orchestrator-W55VKYTC.js");
157
+ const { TaskOrchestrator } = await import("./task-orchestrator-4INCZMLT.js");
158
158
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
159
159
  let interrupted = false;
160
160
  const onSigint = () => {