chatlab-cli 0.33.0 → 0.34.0
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/{chat-command-IHRNO7J4.mjs → chat-command-XPY3WURC.mjs} +9 -9
- package/dist/{chunk-KWJ5FZ74.mjs → chunk-AQPDZAWB.mjs} +385 -248
- package/dist/chunk-AQPDZAWB.mjs.map +1 -0
- package/dist/{chunk-RHA534GU.mjs → chunk-BQ3QN4QT.mjs} +3 -3
- package/dist/{chunk-NHTOSDYI.mjs → chunk-DGF3S3TZ.mjs} +2 -2
- package/dist/{chunk-4V6UP7EW.mjs → chunk-IGEHMLHM.mjs} +2 -2
- package/dist/{chunk-NSWFHMBZ.mjs → chunk-IGK6UMN2.mjs} +11 -11
- package/dist/{chunk-U4F6BNGZ.mjs → chunk-ISRLGLUL.mjs} +2 -2
- package/dist/{chunk-HGV4MUIW.mjs → chunk-JCSPDTZL.mjs} +15 -62
- package/dist/chunk-JCSPDTZL.mjs.map +1 -0
- package/dist/{chunk-S7YPBKQ3.mjs → chunk-JTOHAMIW.mjs} +2 -2
- package/dist/{chunk-C3B7RXES.mjs → chunk-OLE2USEN.mjs} +626 -318
- package/dist/chunk-OLE2USEN.mjs.map +1 -0
- package/dist/{chunk-YAQLYL52.mjs → chunk-QZCNVAH6.mjs} +2 -2
- package/dist/{chunk-YAQLYL52.mjs.map → chunk-QZCNVAH6.mjs.map} +1 -1
- package/dist/{chunk-ZERQIKI4.mjs → chunk-S5NCEESV.mjs} +3 -3
- package/dist/{chunk-ZTMZ7S7T.mjs → chunk-UO2XVFY6.mjs} +31 -20
- package/dist/chunk-UO2XVFY6.mjs.map +1 -0
- package/dist/cli.mjs +9 -9
- package/dist/contacts-worker.mjs +2 -2
- package/dist/global-insight-worker.mjs +2 -2
- package/dist/{http-Y2WC2UK4.mjs → http-HV6XWU6X.mjs} +12 -12
- package/dist/{import-4HF2UNQI.mjs → import-DP2XLZ2H.mjs} +8 -8
- package/dist/index.mjs +12 -12
- package/dist/{mcp-DJPDRFTW.mjs → mcp-QDPFBPGW.mjs} +9 -9
- package/dist/people-relationships-worker.mjs +2 -2
- package/dist/semantic-index-worker.mjs +1 -1
- package/dist/{src-R7MZLKXQ.mjs → src-B3A2QHP5.mjs} +9 -7
- package/dist/{stream-import-DX57ANUL.mjs → stream-import-KEGNP3QK.mjs} +8 -8
- package/dist/{worker-runtime-QMN7OKOZ.mjs → worker-runtime-MDYKX3BW.mjs} +6 -6
- package/dist-cli-web/assets/{ActionToolsPanel.vue_vue_type_script_setup_true_lang-hwRVh048.js → ActionToolsPanel.vue_vue_type_script_setup_true_lang-JxPR2O6b.js} +5 -5
- package/dist-cli-web/assets/{BufferResource-DwfMBlAa.js → BufferResource--dSbJb0k.js} +1 -1
- package/dist-cli-web/assets/{CanvasRenderer-q312LRsp.js → CanvasRenderer-Cm_dmJXZ.js} +1 -1
- package/dist-cli-web/assets/{DataDirCleanupNotice--ee1dY0d.js → DataDirCleanupNotice-B0s5txX3.js} +1 -1
- package/dist-cli-web/assets/{EChartWordcloud-BaMgUl0Y.js → EChartWordcloud-CwMVJLBO.js} +1 -1
- package/dist-cli-web/assets/{Filter-BOb5cLBx.js → Filter-BjYScRpK.js} +1 -1
- package/dist-cli-web/assets/LoadingState.vue_vue_type_script_setup_true_lang-BshQybD_.js +1 -0
- package/dist-cli-web/assets/{MessageExportModal-CFbovWh1.js → MessageExportModal-DAJW2mFj.js} +1 -1
- package/dist-cli-web/assets/{PageHeader-B3-W9mvh.js → PageHeader-BKAjCuqs.js} +1 -1
- package/dist-cli-web/assets/{RelationshipGalaxyCanvas-GEpsKHxV.js → RelationshipGalaxyCanvas-mlZs7k4L.js} +14 -14
- package/dist-cli-web/assets/{RelationshipGalaxyThreeCanvas-BluPHjCR.css → RelationshipGalaxyThreeCanvas-CeYJABxI.css} +1 -1
- package/dist-cli-web/assets/{RelationshipGalaxyThreeCanvas-DHOU66Gj.js → RelationshipGalaxyThreeCanvas-DgMG3jdU.js} +14 -14
- package/dist-cli-web/assets/{RenderTargetSystem-PEnnW2yb.js → RenderTargetSystem-D00Ex44y.js} +1 -1
- package/dist-cli-web/assets/{ThemeCard.vue_vue_type_script_setup_true_lang-sNw3hP4c.js → ThemeCard.vue_vue_type_script_setup_true_lang-Dsb6lzs-.js} +1 -1
- package/dist-cli-web/assets/{TimeSelect.vue_vue_type_script_setup_true_lang-BtUvMehe.js → TimeSelect.vue_vue_type_script_setup_true_lang-BfR3tlkz.js} +1 -1
- package/dist-cli-web/assets/{WebGLRenderer-BjP_1do7.js → WebGLRenderer-CTTusm2n.js} +1 -1
- package/dist-cli-web/assets/{WebGPURenderer-ldVv92u7.js → WebGPURenderer-pyv3EXor.js} +1 -1
- package/dist-cli-web/assets/{annual-summary-time-range-BHClzNvd.js → annual-summary-time-range-C_d1oZrj.js} +1 -1
- package/dist-cli-web/assets/{base-DBJ95yXf.js → base-D91aVUwM.js} +1 -1
- package/dist-cli-web/assets/{browserAll-CPoMOLKh.js → browserAll-C9fW936Y.js} +1 -1
- package/dist-cli-web/assets/{cli-web-B5VYO-Dh.js → cli-web-C7uGKz_E.js} +1 -1
- package/dist-cli-web/assets/{dateFormat-Cf2xuaE-.js → dateFormat-rY43adcv.js} +1 -1
- package/dist-cli-web/assets/{fetch-CtyVktRW.js → fetch-C6po4XYB.js} +1 -1
- package/dist-cli-web/assets/{fetch-J67jyI2k.js → fetch-CNy9OQ2g.js} +1 -1
- package/dist-cli-web/assets/{fetch-BuWxo6oK.js → fetch-CS3T-v-1.js} +1 -1
- package/dist-cli-web/assets/{fetch-C0HHT1Yn.js → fetch-CbnX5VoM.js} +1 -1
- package/dist-cli-web/assets/fetch-CrSz5KJy.js +1 -0
- package/dist-cli-web/assets/{fetch-CXIdj2-_.js → fetch-DG3AeEjW.js} +1 -1
- package/dist-cli-web/assets/{fetch-B1km2u3N.js → fetch-DYNgtIcU.js} +1 -1
- package/dist-cli-web/assets/{fetch-DGi_9my2.js → fetch-DZPC3D8R.js} +1 -1
- package/dist-cli-web/assets/{fetch-BFDKzf1P.js → fetch-Kk2knkEo.js} +1 -1
- package/dist-cli-web/assets/{fetch-Dr41uuXL.js → fetch-PLrI3V67.js} +1 -1
- package/dist-cli-web/assets/{index-BGiTw98l.js → index-2-OaYdzt.js} +1 -1
- package/dist-cli-web/assets/index-2S80bo1s.js +2 -0
- package/dist-cli-web/assets/index-3YO6RI5e.js +2 -0
- package/dist-cli-web/assets/index-BKo68Iu5.js +1 -0
- package/dist-cli-web/assets/{index-Bf3gFaid.js → index-BrkDgcJ6.js} +1 -1
- package/dist-cli-web/assets/{index-5UdyJtVU.js → index-CGI3Y8pq.js} +1 -1
- package/dist-cli-web/assets/index-CW9H_fBd.js +53 -0
- package/dist-cli-web/assets/{index-Ba21yU86.js → index-DA3Q0TGT.js} +1 -1
- package/dist-cli-web/assets/{index-B7R74Yp7.js → index-DFHYr_-u.js} +1 -1
- package/dist-cli-web/assets/index-DmwA85vG.js +173 -0
- package/dist-cli-web/assets/index-DrjoMv9s.css +1 -0
- package/dist-cli-web/assets/{index-DzQT-qXF.js → index-DsdMsKYT.js} +1 -1
- package/dist-cli-web/assets/{index-DtlTo3nt.js → index-JYfjMRb-.js} +1 -1
- package/dist-cli-web/assets/index-Jhwca9kg.css +1 -0
- package/dist-cli-web/assets/index-ZTgfCZvY.js +64 -0
- package/dist-cli-web/assets/index-vtF05fh7.css +1 -0
- package/dist-cli-web/assets/{people-page-header-BvQy1GQj.js → people-page-header-D-LWaEqn.js} +1 -1
- package/dist-cli-web/assets/{webworkerAll-DgKQKbNn.js → webworkerAll-CPOVECup.js} +1 -1
- package/dist-cli-web/index.html +2 -2
- package/package.json +1 -1
- package/dist/chunk-C3B7RXES.mjs.map +0 -1
- package/dist/chunk-HGV4MUIW.mjs.map +0 -1
- package/dist/chunk-KWJ5FZ74.mjs.map +0 -1
- package/dist/chunk-ZTMZ7S7T.mjs.map +0 -1
- package/dist-cli-web/assets/LoadingState.vue_vue_type_script_setup_true_lang-DK2z0Jrh.js +0 -1
- package/dist-cli-web/assets/fetch-80O3EH4a.js +0 -1
- package/dist-cli-web/assets/index-7jm3YI9u.js +0 -53
- package/dist-cli-web/assets/index-ByQSR8Bj.js +0 -2
- package/dist-cli-web/assets/index-CPZYydbc.js +0 -2
- package/dist-cli-web/assets/index-D8Q3U-6e.js +0 -1
- package/dist-cli-web/assets/index-DGtDxRCd.js +0 -173
- package/dist-cli-web/assets/index-DTxnpQiv.css +0 -1
- package/dist-cli-web/assets/index-gpTDI3sq.js +0 -64
- package/dist-cli-web/assets/index-lwhCMqhd.css +0 -1
- package/dist-cli-web/assets/index-qsbWn8VP.css +0 -1
- /package/dist/{chat-command-IHRNO7J4.mjs.map → chat-command-XPY3WURC.mjs.map} +0 -0
- /package/dist/{chunk-RHA534GU.mjs.map → chunk-BQ3QN4QT.mjs.map} +0 -0
- /package/dist/{chunk-NHTOSDYI.mjs.map → chunk-DGF3S3TZ.mjs.map} +0 -0
- /package/dist/{chunk-4V6UP7EW.mjs.map → chunk-IGEHMLHM.mjs.map} +0 -0
- /package/dist/{chunk-NSWFHMBZ.mjs.map → chunk-IGK6UMN2.mjs.map} +0 -0
- /package/dist/{chunk-U4F6BNGZ.mjs.map → chunk-ISRLGLUL.mjs.map} +0 -0
- /package/dist/{chunk-S7YPBKQ3.mjs.map → chunk-JTOHAMIW.mjs.map} +0 -0
- /package/dist/{chunk-ZERQIKI4.mjs.map → chunk-S5NCEESV.mjs.map} +0 -0
- /package/dist/{http-Y2WC2UK4.mjs.map → http-HV6XWU6X.mjs.map} +0 -0
- /package/dist/{import-4HF2UNQI.mjs.map → import-DP2XLZ2H.mjs.map} +0 -0
- /package/dist/{mcp-DJPDRFTW.mjs.map → mcp-QDPFBPGW.mjs.map} +0 -0
- /package/dist/{src-R7MZLKXQ.mjs.map → src-B3A2QHP5.mjs.map} +0 -0
- /package/dist/{stream-import-DX57ANUL.mjs.map → stream-import-KEGNP3QK.mjs.map} +0 -0
- /package/dist/{worker-runtime-QMN7OKOZ.mjs.map → worker-runtime-MDYKX3BW.mjs.map} +0 -0
|
@@ -27,7 +27,10 @@ var localeConfigSchema = z.object({
|
|
|
27
27
|
lang: z.string().default("")
|
|
28
28
|
});
|
|
29
29
|
var uiConfigSchema = z.object({
|
|
30
|
-
default_session_tab: z.
|
|
30
|
+
default_session_tab: z.preprocess(
|
|
31
|
+
(value) => value === "overview" ? "insights" : value,
|
|
32
|
+
z.enum(["insights", "ai-chat"]).default("insights")
|
|
33
|
+
),
|
|
31
34
|
session_gap_threshold: z.number().int().min(60).max(86400).default(1800),
|
|
32
35
|
summary_strategy: z.enum(["brief", "standard"]).default("standard")
|
|
33
36
|
});
|
|
@@ -296,9 +299,119 @@ var MigrationRunner = class {
|
|
|
296
299
|
};
|
|
297
300
|
|
|
298
301
|
// ../../packages/config/src/migrations/m001-legacy-to-multi-config.ts
|
|
302
|
+
import * as path5 from "path";
|
|
303
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
304
|
+
|
|
305
|
+
// ../../packages/config/src/atomic-json-file.ts
|
|
299
306
|
import * as fs4 from "fs";
|
|
300
307
|
import * as path4 from "path";
|
|
301
|
-
import { randomUUID } from "crypto";
|
|
308
|
+
import { createHash, randomUUID } from "crypto";
|
|
309
|
+
var LOCK_RETRY_MS = 10;
|
|
310
|
+
var LOCK_TIMEOUT_MS = 1e4;
|
|
311
|
+
var LOCK_STALE_MS = 3e4;
|
|
312
|
+
var waitBuffer = new Int32Array(new SharedArrayBuffer(4));
|
|
313
|
+
function waitForRetry() {
|
|
314
|
+
Atomics.wait(waitBuffer, 0, 0, LOCK_RETRY_MS);
|
|
315
|
+
}
|
|
316
|
+
function isProcessRunning(pid) {
|
|
317
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
318
|
+
try {
|
|
319
|
+
process.kill(pid, 0);
|
|
320
|
+
return true;
|
|
321
|
+
} catch (error) {
|
|
322
|
+
return error.code === "EPERM";
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
function getRemovableLockToken(lockPath) {
|
|
326
|
+
try {
|
|
327
|
+
const owner = fs4.readFileSync(lockPath, "utf-8");
|
|
328
|
+
const ownerPid = Number.parseInt(owner.split(":", 1)[0] || "", 10);
|
|
329
|
+
const ageMs = Date.now() - fs4.statSync(lockPath).mtimeMs;
|
|
330
|
+
if (!Number.isInteger(ownerPid) || ownerPid <= 0) {
|
|
331
|
+
return ageMs > LOCK_STALE_MS ? owner : null;
|
|
332
|
+
}
|
|
333
|
+
if (!isProcessRunning(ownerPid)) return owner;
|
|
334
|
+
return null;
|
|
335
|
+
} catch {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function tryRecoverStaleLock(lockPath, staleToken, deadline) {
|
|
340
|
+
const staleTokenHash = createHash("sha256").update(`${lockPath}\0${staleToken}`).digest("hex");
|
|
341
|
+
const recoveryPath = path4.join(path4.dirname(lockPath), `.chatlab-lock-recovery-${staleTokenHash}`);
|
|
342
|
+
const recoveryLock = acquireLockPath(recoveryPath, deadline);
|
|
343
|
+
try {
|
|
344
|
+
if (fs4.readFileSync(lockPath, "utf-8") !== staleToken) return false;
|
|
345
|
+
fs4.rmSync(lockPath, { force: true });
|
|
346
|
+
return true;
|
|
347
|
+
} catch {
|
|
348
|
+
return false;
|
|
349
|
+
} finally {
|
|
350
|
+
releaseFileLock(recoveryLock.lockPath, recoveryLock.token);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
function acquireLockPath(lockPath, deadline) {
|
|
354
|
+
const token = `${process.pid}:${randomUUID()}`;
|
|
355
|
+
fs4.mkdirSync(path4.dirname(lockPath), { recursive: true });
|
|
356
|
+
while (true) {
|
|
357
|
+
try {
|
|
358
|
+
fs4.writeFileSync(lockPath, token, { encoding: "utf-8", flag: "wx", mode: 384 });
|
|
359
|
+
return { lockPath, token };
|
|
360
|
+
} catch (error) {
|
|
361
|
+
const code = error.code;
|
|
362
|
+
if (code !== "EEXIST") throw error;
|
|
363
|
+
const removableToken = getRemovableLockToken(lockPath);
|
|
364
|
+
if (removableToken !== null && tryRecoverStaleLock(lockPath, removableToken, deadline)) {
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
if (Date.now() >= deadline) {
|
|
368
|
+
throw new Error(`Timed out waiting for configuration file lock: ${lockPath}`);
|
|
369
|
+
}
|
|
370
|
+
waitForRetry();
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
function acquireFileLock(filePath) {
|
|
375
|
+
return acquireLockPath(`${filePath}.lock`, Date.now() + LOCK_TIMEOUT_MS);
|
|
376
|
+
}
|
|
377
|
+
function releaseFileLock(lockPath, token) {
|
|
378
|
+
try {
|
|
379
|
+
if (fs4.readFileSync(lockPath, "utf-8") === token) {
|
|
380
|
+
fs4.rmSync(lockPath, { force: true });
|
|
381
|
+
}
|
|
382
|
+
} catch {
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
function withFileLock(filePath, action) {
|
|
386
|
+
const lock = acquireFileLock(filePath);
|
|
387
|
+
try {
|
|
388
|
+
return action();
|
|
389
|
+
} finally {
|
|
390
|
+
releaseFileLock(lock.lockPath, lock.token);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function readJsonFile(filePath) {
|
|
394
|
+
try {
|
|
395
|
+
return JSON.parse(fs4.readFileSync(filePath, "utf-8"));
|
|
396
|
+
} catch {
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
function writeJsonFileAtomically(filePath, data, mode) {
|
|
401
|
+
fs4.mkdirSync(path4.dirname(filePath), { recursive: true });
|
|
402
|
+
const tempPath = `${filePath}.tmp-${process.pid}-${randomUUID()}`;
|
|
403
|
+
try {
|
|
404
|
+
fs4.writeFileSync(tempPath, JSON.stringify(data, null, 2), {
|
|
405
|
+
encoding: "utf-8",
|
|
406
|
+
...mode === void 0 ? {} : { mode }
|
|
407
|
+
});
|
|
408
|
+
fs4.renameSync(tempPath, filePath);
|
|
409
|
+
} finally {
|
|
410
|
+
fs4.rmSync(tempPath, { force: true });
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// ../../packages/config/src/migrations/m001-legacy-to-multi-config.ts
|
|
302
415
|
function isLegacyFlatConfig(data) {
|
|
303
416
|
if (!data || typeof data !== "object") return false;
|
|
304
417
|
const obj = data;
|
|
@@ -309,108 +422,94 @@ var m001LegacyToMultiConfig = {
|
|
|
309
422
|
name: "legacy-to-multi-config",
|
|
310
423
|
description: "Convert legacy flat LLM config to multi-config format",
|
|
311
424
|
async up(ctx) {
|
|
312
|
-
const configPath =
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
defaultAssistant: { configId: newConfig.id, modelId: newConfig.model },
|
|
338
|
-
fastModel: null
|
|
339
|
-
};
|
|
340
|
-
fs4.writeFileSync(configPath, JSON.stringify(migrated, null, 2), "utf-8");
|
|
341
|
-
ctx.logger.info("Migration", "Legacy config migrated to multi-config format");
|
|
425
|
+
const configPath = path5.join(ctx.aiDataDir, "llm-config.json");
|
|
426
|
+
withFileLock(configPath, () => {
|
|
427
|
+
const data = readJsonFile(configPath);
|
|
428
|
+
if (!isLegacyFlatConfig(data)) return;
|
|
429
|
+
ctx.logger.info("Migration", "Converting legacy flat config to multi-config format");
|
|
430
|
+
const now = Date.now();
|
|
431
|
+
const newConfig = {
|
|
432
|
+
id: randomUUID2(),
|
|
433
|
+
name: data.provider,
|
|
434
|
+
provider: data.provider,
|
|
435
|
+
apiKey: data.apiKey || "",
|
|
436
|
+
model: data.model || "",
|
|
437
|
+
maxTokens: data.maxTokens,
|
|
438
|
+
createdAt: now,
|
|
439
|
+
updatedAt: now
|
|
440
|
+
};
|
|
441
|
+
const migrated = {
|
|
442
|
+
schemaVersion: 1,
|
|
443
|
+
configs: [newConfig],
|
|
444
|
+
defaultAssistant: { configId: newConfig.id, modelId: newConfig.model },
|
|
445
|
+
fastModel: null
|
|
446
|
+
};
|
|
447
|
+
writeJsonFileAtomically(configPath, migrated);
|
|
448
|
+
ctx.logger.info("Migration", "Legacy config migrated to multi-config format");
|
|
449
|
+
});
|
|
342
450
|
}
|
|
343
451
|
};
|
|
344
452
|
|
|
345
453
|
// ../../packages/config/src/migrations/m002-schema-v2.ts
|
|
346
|
-
import * as
|
|
347
|
-
import * as path5 from "path";
|
|
454
|
+
import * as path6 from "path";
|
|
348
455
|
var m002SchemaV2 = {
|
|
349
456
|
version: 2,
|
|
350
457
|
name: "schema-v2",
|
|
351
458
|
description: "Upgrade LLM config to schema v2 (remove deprecated fields)",
|
|
352
459
|
async up(ctx) {
|
|
353
|
-
const configPath =
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
460
|
+
const configPath = path6.join(ctx.aiDataDir, "llm-config.json");
|
|
461
|
+
withFileLock(configPath, () => {
|
|
462
|
+
const data = readJsonFile(configPath);
|
|
463
|
+
if (!data) return;
|
|
464
|
+
const schemaVersion = data.schemaVersion || 0;
|
|
465
|
+
if (schemaVersion >= 2) return;
|
|
466
|
+
ctx.logger.info("Migration", "Upgrading LLM config to schema v2");
|
|
467
|
+
const configs = data.configs || [];
|
|
468
|
+
const cleanedConfigs = configs.map((c) => {
|
|
469
|
+
const { disableThinking: _dt, isReasoningModel: _rm, ...rest } = c;
|
|
470
|
+
return rest;
|
|
471
|
+
});
|
|
472
|
+
data.configs = cleanedConfigs;
|
|
473
|
+
data.schemaVersion = 2;
|
|
474
|
+
writeJsonFileAtomically(configPath, data);
|
|
368
475
|
});
|
|
369
|
-
data.configs = cleanedConfigs;
|
|
370
|
-
data.schemaVersion = 2;
|
|
371
|
-
fs5.writeFileSync(configPath, JSON.stringify(data, null, 2), "utf-8");
|
|
372
476
|
}
|
|
373
477
|
};
|
|
374
478
|
|
|
375
479
|
// ../../packages/config/src/migrations/m003-schema-v3.ts
|
|
376
|
-
import * as
|
|
377
|
-
import * as path6 from "path";
|
|
480
|
+
import * as path7 from "path";
|
|
378
481
|
var m003SchemaV3 = {
|
|
379
482
|
version: 3,
|
|
380
483
|
name: "schema-v3-dual-slot",
|
|
381
484
|
description: "Upgrade LLM config to schema v3 (dual-slot model selection)",
|
|
382
485
|
async up(ctx) {
|
|
383
|
-
const configPath =
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
data.schemaVersion = 3;
|
|
400
|
-
delete data.activeConfigId;
|
|
401
|
-
fs6.writeFileSync(configPath, JSON.stringify(data, null, 2), "utf-8");
|
|
486
|
+
const configPath = path7.join(ctx.aiDataDir, "llm-config.json");
|
|
487
|
+
withFileLock(configPath, () => {
|
|
488
|
+
const data = readJsonFile(configPath);
|
|
489
|
+
if (!data) return;
|
|
490
|
+
const schemaVersion = data.schemaVersion || 0;
|
|
491
|
+
if (schemaVersion >= 3) return;
|
|
492
|
+
ctx.logger.info("Migration", "Upgrading LLM config to schema v3 (dual-slot)");
|
|
493
|
+
const configs = data.configs || [];
|
|
494
|
+
const activeConfigId = data.activeConfigId;
|
|
495
|
+
const resolvedConfig = activeConfigId && configs.find((c) => c.id === activeConfigId) ? configs.find((c) => c.id === activeConfigId) : configs[0] ?? null;
|
|
496
|
+
data.defaultAssistant = resolvedConfig ? { configId: resolvedConfig.id, modelId: resolvedConfig.model || "" } : null;
|
|
497
|
+
data.fastModel = data.fastModel ?? null;
|
|
498
|
+
data.schemaVersion = 3;
|
|
499
|
+
delete data.activeConfigId;
|
|
500
|
+
writeJsonFileAtomically(configPath, data);
|
|
501
|
+
});
|
|
402
502
|
}
|
|
403
503
|
};
|
|
404
504
|
|
|
405
505
|
// ../../packages/config/src/migrations/m004-encrypted-keys-to-auth-profiles.ts
|
|
406
|
-
import * as
|
|
407
|
-
import * as path9 from "path";
|
|
506
|
+
import * as path10 from "path";
|
|
408
507
|
|
|
409
508
|
// ../../packages/config/src/migrations/crypto-legacy.ts
|
|
410
|
-
import * as
|
|
509
|
+
import * as fs5 from "fs";
|
|
411
510
|
import * as os2 from "os";
|
|
412
|
-
import * as
|
|
413
|
-
import { createDecipheriv, createHash } from "crypto";
|
|
511
|
+
import * as path8 from "path";
|
|
512
|
+
import { createDecipheriv, createHash as createHash2 } from "crypto";
|
|
414
513
|
import { execSync } from "child_process";
|
|
415
514
|
var ENCRYPTED_PREFIX = "enc:";
|
|
416
515
|
var ALGORITHM = "aes-256-gcm";
|
|
@@ -421,8 +520,8 @@ function isEncrypted(value) {
|
|
|
421
520
|
}
|
|
422
521
|
function readKeyFromFile(keyPath) {
|
|
423
522
|
try {
|
|
424
|
-
if (
|
|
425
|
-
const key =
|
|
523
|
+
if (fs5.existsSync(keyPath)) {
|
|
524
|
+
const key = fs5.readFileSync(keyPath, "utf-8").trim();
|
|
426
525
|
if (key.length >= 32) return key;
|
|
427
526
|
}
|
|
428
527
|
} catch {
|
|
@@ -431,14 +530,14 @@ function readKeyFromFile(keyPath) {
|
|
|
431
530
|
}
|
|
432
531
|
function getAllDeviceKeyPaths() {
|
|
433
532
|
const home = os2.homedir();
|
|
434
|
-
const paths = [
|
|
533
|
+
const paths = [path8.join(home, ".chatlab", DEVICE_KEY_FILE)];
|
|
435
534
|
if (process.platform === "darwin") {
|
|
436
|
-
paths.push(
|
|
535
|
+
paths.push(path8.join(home, "Library", "Application Support", "ChatLab", "data", DEVICE_KEY_FILE));
|
|
437
536
|
} else if (process.platform === "win32") {
|
|
438
|
-
const appData = process.env.APPDATA ||
|
|
439
|
-
paths.push(
|
|
537
|
+
const appData = process.env.APPDATA || path8.join(home, "AppData", "Roaming");
|
|
538
|
+
paths.push(path8.join(appData, "ChatLab", "data", DEVICE_KEY_FILE));
|
|
440
539
|
} else {
|
|
441
|
-
paths.push(
|
|
540
|
+
paths.push(path8.join(home, ".config", "ChatLab", "data", DEVICE_KEY_FILE));
|
|
442
541
|
}
|
|
443
542
|
return paths;
|
|
444
543
|
}
|
|
@@ -476,16 +575,16 @@ function deriveLegacyKeys() {
|
|
|
476
575
|
machineId = raw.replace(/[\r\n\s]/g, "").toLowerCase();
|
|
477
576
|
}
|
|
478
577
|
if (machineId) {
|
|
479
|
-
const hashed =
|
|
578
|
+
const hashed = createHash2("sha256").update(machineId).digest("hex");
|
|
480
579
|
keys.push(
|
|
481
|
-
|
|
580
|
+
createHash2("sha256").update(hashed + SALT).digest()
|
|
482
581
|
);
|
|
483
582
|
}
|
|
484
583
|
}
|
|
485
584
|
} catch {
|
|
486
585
|
}
|
|
487
586
|
keys.push(
|
|
488
|
-
|
|
587
|
+
createHash2("sha256").update("chatlab-fallback-key" + SALT).digest()
|
|
489
588
|
);
|
|
490
589
|
return keys;
|
|
491
590
|
}
|
|
@@ -508,7 +607,7 @@ function tryDecryptWithKey(encrypted, key) {
|
|
|
508
607
|
function decryptApiKey(encrypted) {
|
|
509
608
|
if (!encrypted || !isEncrypted(encrypted)) return encrypted || "";
|
|
510
609
|
for (const dk of getAllDeviceKeys()) {
|
|
511
|
-
const derived =
|
|
610
|
+
const derived = createHash2("sha256").update(dk + SALT).digest();
|
|
512
611
|
const result = tryDecryptWithKey(encrypted, derived);
|
|
513
612
|
if (result !== null) return result;
|
|
514
613
|
}
|
|
@@ -520,27 +619,32 @@ function decryptApiKey(encrypted) {
|
|
|
520
619
|
}
|
|
521
620
|
|
|
522
621
|
// ../../packages/config/src/auth-profiles.ts
|
|
523
|
-
import * as
|
|
524
|
-
import * as path8 from "path";
|
|
622
|
+
import * as path9 from "path";
|
|
525
623
|
var AUTH_PROFILES_FILE = "auth-profiles.json";
|
|
624
|
+
function deriveAuthProfileName(provider, config) {
|
|
625
|
+
if (provider !== "openai-compatible") {
|
|
626
|
+
return provider.toLowerCase().replace(/\s+/g, "-");
|
|
627
|
+
}
|
|
628
|
+
if (typeof config.baseUrl === "string" && config.baseUrl) {
|
|
629
|
+
try {
|
|
630
|
+
return new URL(config.baseUrl).hostname.toLowerCase();
|
|
631
|
+
} catch {
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
if (typeof config.name === "string" && config.name) {
|
|
635
|
+
return config.name.toLowerCase().replace(/\s+/g, "-");
|
|
636
|
+
}
|
|
637
|
+
return "custom";
|
|
638
|
+
}
|
|
526
639
|
function getAuthProfilesPath() {
|
|
527
|
-
return
|
|
640
|
+
return path9.join(getConfigDir(), AUTH_PROFILES_FILE);
|
|
528
641
|
}
|
|
529
642
|
function loadAuthProfiles() {
|
|
530
|
-
const
|
|
531
|
-
if (!
|
|
532
|
-
return { version: 1, profiles: {} };
|
|
533
|
-
}
|
|
534
|
-
try {
|
|
535
|
-
const content = fs8.readFileSync(filePath, "utf-8");
|
|
536
|
-
const data = JSON.parse(content);
|
|
537
|
-
if (!data.profiles || typeof data.profiles !== "object") {
|
|
538
|
-
return { version: 1, profiles: {} };
|
|
539
|
-
}
|
|
540
|
-
return data;
|
|
541
|
-
} catch {
|
|
643
|
+
const data = readJsonFile(getAuthProfilesPath());
|
|
644
|
+
if (!data?.profiles || typeof data.profiles !== "object") {
|
|
542
645
|
return { version: 1, profiles: {} };
|
|
543
646
|
}
|
|
647
|
+
return data;
|
|
544
648
|
}
|
|
545
649
|
function getApiKeyByProfile(profileName) {
|
|
546
650
|
const data = loadAuthProfiles();
|
|
@@ -564,89 +668,72 @@ function resolveApiKey(provider, authProfile) {
|
|
|
564
668
|
return getApiKeyByProvider(provider);
|
|
565
669
|
}
|
|
566
670
|
function writeAuthProfile(name, profile) {
|
|
567
|
-
const configDir = getConfigDir();
|
|
568
|
-
if (!fs8.existsSync(configDir)) {
|
|
569
|
-
fs8.mkdirSync(configDir, { recursive: true });
|
|
570
|
-
}
|
|
571
|
-
const data = loadAuthProfiles();
|
|
572
|
-
data.profiles[name] = profile;
|
|
573
671
|
const filePath = getAuthProfilesPath();
|
|
574
|
-
|
|
672
|
+
withFileLock(filePath, () => {
|
|
673
|
+
const data = loadAuthProfiles();
|
|
674
|
+
data.profiles[name] = profile;
|
|
675
|
+
writeJsonFileAtomically(filePath, data, 384);
|
|
676
|
+
});
|
|
575
677
|
}
|
|
576
678
|
function deleteAuthProfile(name) {
|
|
577
|
-
const data = loadAuthProfiles();
|
|
578
|
-
if (!(name in data.profiles)) return false;
|
|
579
|
-
delete data.profiles[name];
|
|
580
679
|
const filePath = getAuthProfilesPath();
|
|
581
|
-
|
|
582
|
-
|
|
680
|
+
return withFileLock(filePath, () => {
|
|
681
|
+
const data = loadAuthProfiles();
|
|
682
|
+
if (!(name in data.profiles)) return false;
|
|
683
|
+
delete data.profiles[name];
|
|
684
|
+
writeJsonFileAtomically(filePath, data, 384);
|
|
685
|
+
return true;
|
|
686
|
+
});
|
|
583
687
|
}
|
|
584
688
|
|
|
585
689
|
// ../../packages/config/src/migrations/m004-encrypted-keys-to-auth-profiles.ts
|
|
586
|
-
function deriveProfileName(provider, config) {
|
|
587
|
-
if (provider !== "openai-compatible") {
|
|
588
|
-
return provider.toLowerCase().replace(/\s+/g, "-");
|
|
589
|
-
}
|
|
590
|
-
const baseUrl = config.baseUrl;
|
|
591
|
-
if (baseUrl) {
|
|
592
|
-
try {
|
|
593
|
-
return new URL(baseUrl).hostname.toLowerCase();
|
|
594
|
-
} catch {
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
const name = config.name;
|
|
598
|
-
if (name) return name.toLowerCase().replace(/\s+/g, "-");
|
|
599
|
-
return "custom";
|
|
600
|
-
}
|
|
601
690
|
var m004EncryptedKeysToAuthProfiles = {
|
|
602
691
|
version: 4,
|
|
603
692
|
name: "encrypted-keys-to-auth-profiles",
|
|
604
693
|
description: "Migrate encrypted API keys from llm-config.json to auth-profiles.json",
|
|
605
694
|
async up(ctx) {
|
|
606
|
-
const configPath =
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
if (
|
|
625
|
-
|
|
626
|
-
continue;
|
|
695
|
+
const configPath = path10.join(ctx.aiDataDir, "llm-config.json");
|
|
696
|
+
withFileLock(configPath, () => {
|
|
697
|
+
const data = readJsonFile(configPath);
|
|
698
|
+
if (!data) return;
|
|
699
|
+
const configs = data.configs || [];
|
|
700
|
+
let migrated = false;
|
|
701
|
+
const usedProfileNames = /* @__PURE__ */ new Set();
|
|
702
|
+
for (const config of configs) {
|
|
703
|
+
const apiKey = config.apiKey;
|
|
704
|
+
if (!apiKey) continue;
|
|
705
|
+
const provider = config.provider || "unknown";
|
|
706
|
+
let plainKey = null;
|
|
707
|
+
if (isEncrypted(apiKey)) {
|
|
708
|
+
plainKey = decryptApiKey(apiKey);
|
|
709
|
+
if (!plainKey) {
|
|
710
|
+
ctx.logger.warn("Migration", `Failed to decrypt API key for "${config.name}", skipping`);
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
} else if (apiKey.length > 0) {
|
|
714
|
+
plainKey = apiKey;
|
|
627
715
|
}
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
profileName
|
|
716
|
+
if (plainKey) {
|
|
717
|
+
const baseName = deriveAuthProfileName(provider, config);
|
|
718
|
+
let profileName = baseName;
|
|
719
|
+
if (usedProfileNames.has(profileName)) {
|
|
720
|
+
let i = 2;
|
|
721
|
+
while (usedProfileNames.has(`${profileName}-${i}`)) i++;
|
|
722
|
+
profileName = `${profileName}-${i}`;
|
|
723
|
+
}
|
|
724
|
+
usedProfileNames.add(profileName);
|
|
725
|
+
writeAuthProfile(profileName, { type: "api_key", provider, key: plainKey });
|
|
726
|
+
config.authProfile = profileName;
|
|
727
|
+
config.apiKey = "";
|
|
728
|
+
migrated = true;
|
|
729
|
+
ctx.logger.info("Migration", `Migrated API key \u2192 profile "${profileName}"`);
|
|
638
730
|
}
|
|
639
|
-
usedProfileNames.add(profileName);
|
|
640
|
-
writeAuthProfile(profileName, { type: "api_key", provider, key: plainKey });
|
|
641
|
-
config.apiKey = "";
|
|
642
|
-
migrated = true;
|
|
643
|
-
ctx.logger.info("Migration", `Migrated API key \u2192 profile "${profileName}"`);
|
|
644
731
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
}
|
|
732
|
+
if (migrated) {
|
|
733
|
+
writeJsonFileAtomically(configPath, data);
|
|
734
|
+
ctx.logger.info("Migration", "Cleared API keys from llm-config.json");
|
|
735
|
+
}
|
|
736
|
+
});
|
|
650
737
|
}
|
|
651
738
|
};
|
|
652
739
|
|
|
@@ -1068,6 +1155,9 @@ var BUILTIN_PROVIDERS = [
|
|
|
1068
1155
|
MINIMAX,
|
|
1069
1156
|
OPENAI_COMPATIBLE
|
|
1070
1157
|
];
|
|
1158
|
+
function getBuiltinProviderById(id) {
|
|
1159
|
+
return BUILTIN_PROVIDERS.find((p) => p.id === id) || null;
|
|
1160
|
+
}
|
|
1071
1161
|
|
|
1072
1162
|
// ../../packages/core/src/ai/model-catalog.ts
|
|
1073
1163
|
function builtin(m) {
|
|
@@ -1907,6 +1997,9 @@ var BUILTIN_MODELS = [
|
|
|
1907
1997
|
function getBuiltinModelsByProvider(providerId) {
|
|
1908
1998
|
return BUILTIN_MODELS.filter((m) => m.providerId === providerId);
|
|
1909
1999
|
}
|
|
2000
|
+
function getBuiltinModelById(providerId, modelId) {
|
|
2001
|
+
return BUILTIN_MODELS.find((m) => m.providerId === providerId && m.id === modelId) || null;
|
|
2002
|
+
}
|
|
1910
2003
|
|
|
1911
2004
|
// ../../packages/core/src/ai/content-parser.ts
|
|
1912
2005
|
var THINK_TAGS = ["think", "analysis", "reasoning", "reflection", "thought", "thinking"];
|
|
@@ -2773,6 +2866,15 @@ function getSegmentSummaries(db, options) {
|
|
|
2773
2866
|
});
|
|
2774
2867
|
}
|
|
2775
2868
|
var DEFAULT_SESSION_GAP_THRESHOLD = 1800;
|
|
2869
|
+
function hasSessionIndex(db) {
|
|
2870
|
+
if (!hasTable(db, "segment")) return false;
|
|
2871
|
+
try {
|
|
2872
|
+
const row = db.prepare("SELECT COUNT(*) as count FROM segment").get();
|
|
2873
|
+
return (row?.count ?? 0) > 0;
|
|
2874
|
+
} catch {
|
|
2875
|
+
return false;
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2776
2878
|
function getSessionIndexStats(db) {
|
|
2777
2879
|
let sessionCount = 0;
|
|
2778
2880
|
if (hasTable(db, "segment")) {
|
|
@@ -4912,6 +5014,7 @@ function getAnnualSummarySessionFacts(db, sessionId, range) {
|
|
|
4912
5014
|
function aggregateAnnualSummaryFacts(facts, range, elapsedDayCount) {
|
|
4913
5015
|
const ownerMessagesByDay = /* @__PURE__ */ new Map();
|
|
4914
5016
|
const directContactsByDay = /* @__PURE__ */ new Map();
|
|
5017
|
+
const directContactsByMonth = /* @__PURE__ */ new Map();
|
|
4915
5018
|
const directContacts = /* @__PURE__ */ new Set();
|
|
4916
5019
|
const messageTypes = /* @__PURE__ */ new Map();
|
|
4917
5020
|
const textLengths = /* @__PURE__ */ new Map();
|
|
@@ -4945,11 +5048,15 @@ function aggregateAnnualSummaryFacts(facts, range, elapsedDayCount) {
|
|
|
4945
5048
|
mergeNumberRecord(textLengths, item.textLengthCounts, Number);
|
|
4946
5049
|
for (const [date, keys] of Object.entries(item.directContactKeysByDay)) {
|
|
4947
5050
|
const daily = directContactsByDay.get(date) ?? /* @__PURE__ */ new Set();
|
|
5051
|
+
const month = date.slice(0, 7);
|
|
5052
|
+
const monthly = directContactsByMonth.get(month) ?? /* @__PURE__ */ new Set();
|
|
4948
5053
|
keys.forEach((key) => {
|
|
4949
5054
|
daily.add(key);
|
|
5055
|
+
monthly.add(key);
|
|
4950
5056
|
directContacts.add(key);
|
|
4951
5057
|
});
|
|
4952
5058
|
directContactsByDay.set(date, daily);
|
|
5059
|
+
directContactsByMonth.set(month, monthly);
|
|
4953
5060
|
}
|
|
4954
5061
|
}
|
|
4955
5062
|
const dailyActivity = [...ownerMessagesByDay.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([date, messageCount]) => ({ date, messageCount }));
|
|
@@ -4967,6 +5074,7 @@ function aggregateAnnualSummaryFacts(facts, range, elapsedDayCount) {
|
|
|
4967
5074
|
averageDirectContactsPerDay: roundAverage(dailyDirectContactTotal, elapsedDayCount)
|
|
4968
5075
|
},
|
|
4969
5076
|
monthlyActivity: buildMonthlyActivity(range, ownerMessagesByDay),
|
|
5077
|
+
monthlyDirectContacts: buildMonthlyDirectContacts(range, directContactsByMonth),
|
|
4970
5078
|
dailyActivity,
|
|
4971
5079
|
messageTypes: [...messageTypes.entries()].sort(([a], [b]) => a - b).map(([type, count]) => ({ type, count })),
|
|
4972
5080
|
textLength: buildTextLengthSummary(textLengths),
|
|
@@ -5035,6 +5143,9 @@ function buildMonthlyActivity(range, ownerMessagesByDay) {
|
|
|
5035
5143
|
}
|
|
5036
5144
|
return listMonths(range).map((month) => ({ month, messageCount: counts.get(month) ?? 0 }));
|
|
5037
5145
|
}
|
|
5146
|
+
function buildMonthlyDirectContacts(range, directContactsByMonth) {
|
|
5147
|
+
return listMonths(range).map((month) => ({ month, contactCount: directContactsByMonth.get(month)?.size ?? 0 }));
|
|
5148
|
+
}
|
|
5038
5149
|
function listMonths(range) {
|
|
5039
5150
|
if (range.mode === "year" && range.year) {
|
|
5040
5151
|
return Array.from({ length: 12 }, (_, index) => `${range.year}-${String(index + 1).padStart(2, "0")}`);
|
|
@@ -5883,13 +5994,10 @@ function getRelationshipStats(db, filter, options) {
|
|
|
5883
5994
|
totalSessions: 0,
|
|
5884
5995
|
hasSessionIndex: false,
|
|
5885
5996
|
iceBreakers: [],
|
|
5886
|
-
totalIceBreaks: 0,
|
|
5887
5997
|
responseLatency: [],
|
|
5888
5998
|
perseverance: [],
|
|
5889
|
-
totalDoubleTexts: 0,
|
|
5890
5999
|
monthlyResponseLatency: [],
|
|
5891
|
-
monthlyPerseverance: []
|
|
5892
|
-
perseveranceThreshold
|
|
6000
|
+
monthlyPerseverance: []
|
|
5893
6001
|
};
|
|
5894
6002
|
const sessionCount = db.prepare("SELECT COUNT(*) as count FROM segment").get();
|
|
5895
6003
|
if (!sessionCount || sessionCount.count === 0) return emptyResult;
|
|
@@ -5919,11 +6027,10 @@ function getRelationshipStats(db, filter, options) {
|
|
|
5919
6027
|
const memberInitTotals = /* @__PURE__ */ new Map();
|
|
5920
6028
|
const memberCloseTotals = /* @__PURE__ */ new Map();
|
|
5921
6029
|
const iceBreakMap = /* @__PURE__ */ new Map();
|
|
5922
|
-
let totalIceBreaks = 0;
|
|
5923
6030
|
let prevEndTs = null;
|
|
5924
6031
|
for (const row of segmentRows) {
|
|
5925
6032
|
const month = toLocalMonth(row.start_ts);
|
|
5926
|
-
if (!monthMap.has(month)) monthMap.set(month, { initiateMap: /* @__PURE__ */ new Map(),
|
|
6033
|
+
if (!monthMap.has(month)) monthMap.set(month, { initiateMap: /* @__PURE__ */ new Map(), totalSessions: 0 });
|
|
5927
6034
|
const ms = monthMap.get(month);
|
|
5928
6035
|
ms.totalSessions++;
|
|
5929
6036
|
if (row.initiator_id !== null) {
|
|
@@ -5931,14 +6038,12 @@ function getRelationshipStats(db, filter, options) {
|
|
|
5931
6038
|
memberInitTotals.set(row.initiator_id, (memberInitTotals.get(row.initiator_id) ?? 0) + 1);
|
|
5932
6039
|
}
|
|
5933
6040
|
if (row.closer_id !== null) {
|
|
5934
|
-
ms.closeMap.set(row.closer_id, (ms.closeMap.get(row.closer_id) ?? 0) + 1);
|
|
5935
6041
|
memberCloseTotals.set(row.closer_id, (memberCloseTotals.get(row.closer_id) ?? 0) + 1);
|
|
5936
6042
|
}
|
|
5937
6043
|
if (prevEndTs !== null && row.initiator_id !== null && row.start_ts - prevEndTs > ICE_BREAK_THRESHOLD) {
|
|
5938
6044
|
if (!iceBreakMap.has(month)) iceBreakMap.set(month, /* @__PURE__ */ new Map());
|
|
5939
6045
|
const mMap = iceBreakMap.get(month);
|
|
5940
6046
|
mMap.set(row.initiator_id, (mMap.get(row.initiator_id) ?? 0) + 1);
|
|
5941
|
-
totalIceBreaks++;
|
|
5942
6047
|
}
|
|
5943
6048
|
prevEndTs = row.end_ts;
|
|
5944
6049
|
}
|
|
@@ -5950,9 +6055,7 @@ function getRelationshipStats(db, filter, options) {
|
|
|
5950
6055
|
const ms = monthMap.get(month);
|
|
5951
6056
|
const members2 = Array.from(allMemberIds).map((memberId) => ({
|
|
5952
6057
|
memberId,
|
|
5953
|
-
|
|
5954
|
-
initiateCount: ms.initiateMap.get(memberId) ?? 0,
|
|
5955
|
-
closeCount: ms.closeMap.get(memberId) ?? 0
|
|
6058
|
+
initiateCount: ms.initiateMap.get(memberId) ?? 0
|
|
5956
6059
|
}));
|
|
5957
6060
|
return { month, members: members2, totalSessions: ms.totalSessions };
|
|
5958
6061
|
});
|
|
@@ -5978,16 +6081,13 @@ function getRelationshipStats(db, filter, options) {
|
|
|
5978
6081
|
totalSessions: segmentRows.length,
|
|
5979
6082
|
hasSessionIndex: true,
|
|
5980
6083
|
iceBreakers,
|
|
5981
|
-
|
|
5982
|
-
...msgStats,
|
|
5983
|
-
perseveranceThreshold
|
|
6084
|
+
...msgStats
|
|
5984
6085
|
};
|
|
5985
6086
|
}
|
|
5986
6087
|
function queryMessageLevelStats(db, segmentIds, memberNames, perseveranceThreshold) {
|
|
5987
6088
|
const empty = {
|
|
5988
6089
|
responseLatency: [],
|
|
5989
6090
|
perseverance: [],
|
|
5990
|
-
totalDoubleTexts: 0,
|
|
5991
6091
|
monthlyResponseLatency: [],
|
|
5992
6092
|
monthlyPerseverance: []
|
|
5993
6093
|
};
|
|
@@ -6050,14 +6150,13 @@ function queryMessageLevelStats(db, segmentIds, memberNames, perseveranceThresho
|
|
|
6050
6150
|
const responseLatency = Array.from(responseTotals.entries()).map(([memberId, { sum, count }]) => ({
|
|
6051
6151
|
memberId,
|
|
6052
6152
|
name: memberNames.get(memberId) ?? `Unknown(${memberId})`,
|
|
6053
|
-
avgResponseTime: Math.round(sum / count)
|
|
6054
|
-
totalResponses: count
|
|
6153
|
+
avgResponseTime: Math.round(sum / count)
|
|
6055
6154
|
})).sort((a, b) => a.avgResponseTime - b.avgResponseTime);
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
}).sort((a, b) => b.totalDoubleTexts - a.totalDoubleTexts);
|
|
6155
|
+
const perseverance = Array.from(dtTotals.entries()).map(([memberId, count]) => ({
|
|
6156
|
+
memberId,
|
|
6157
|
+
name: memberNames.get(memberId) ?? `Unknown(${memberId})`,
|
|
6158
|
+
totalDoubleTexts: count
|
|
6159
|
+
})).sort((a, b) => b.totalDoubleTexts - a.totalDoubleTexts);
|
|
6061
6160
|
const monthlyResponseLatency = Array.from(monthlyRespMap.entries()).sort(([a], [b]) => b.localeCompare(a)).map(([month, mMap]) => ({
|
|
6062
6161
|
month,
|
|
6063
6162
|
members: Array.from(mMap.entries()).map(([memberId, { sum, count }]) => ({
|
|
@@ -6075,13 +6174,214 @@ function queryMessageLevelStats(db, segmentIds, memberNames, perseveranceThresho
|
|
|
6075
6174
|
doubleTextCount: count
|
|
6076
6175
|
})).sort((a, b) => b.doubleTextCount - a.doubleTextCount)
|
|
6077
6176
|
}));
|
|
6078
|
-
return { responseLatency, perseverance,
|
|
6177
|
+
return { responseLatency, perseverance, monthlyResponseLatency, monthlyPerseverance };
|
|
6079
6178
|
}
|
|
6080
6179
|
function toLocalMonth(ts) {
|
|
6081
6180
|
const d = new Date(ts * 1e3);
|
|
6082
6181
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`;
|
|
6083
6182
|
}
|
|
6084
6183
|
|
|
6184
|
+
// ../../packages/core/src/query/advanced/journey.ts
|
|
6185
|
+
var SILENCE_THRESHOLD_SECONDS = 24 * 60 * 60;
|
|
6186
|
+
var EMPTY_RESULT = {
|
|
6187
|
+
range: null,
|
|
6188
|
+
hasSessionIndex: false,
|
|
6189
|
+
months: [],
|
|
6190
|
+
years: [],
|
|
6191
|
+
peakMonth: null,
|
|
6192
|
+
longestSegment: null,
|
|
6193
|
+
longestSilence: null
|
|
6194
|
+
};
|
|
6195
|
+
function getJourneyStats(db, filter) {
|
|
6196
|
+
const effectiveFilter = filter ? {
|
|
6197
|
+
startTs: filter.startTs,
|
|
6198
|
+
endTs: filter.endTs
|
|
6199
|
+
} : void 0;
|
|
6200
|
+
const monthlyRows = queryMonthlyRows(db, effectiveFilter);
|
|
6201
|
+
if (monthlyRows.length === 0) return { ...EMPTY_RESULT };
|
|
6202
|
+
const indexAvailable = hasSessionIndex(db) && hasTable(db, "message_context");
|
|
6203
|
+
const segmentRows = indexAvailable ? querySegmentRows(db, effectiveFilter) : [];
|
|
6204
|
+
const segmentCountByMonth = /* @__PURE__ */ new Map();
|
|
6205
|
+
for (const segment2 of segmentRows) {
|
|
6206
|
+
segmentCountByMonth.set(segment2.startMonth, (segmentCountByMonth.get(segment2.startMonth) ?? 0) + 1);
|
|
6207
|
+
}
|
|
6208
|
+
const firstRow = monthlyRows[0];
|
|
6209
|
+
const lastRow = monthlyRows[monthlyRows.length - 1];
|
|
6210
|
+
const monthsByKey = new Map(monthlyRows.map((row) => [row.month, row]));
|
|
6211
|
+
const months = enumerateMonths(firstRow.month, lastRow.month).map((month) => {
|
|
6212
|
+
const row = monthsByKey.get(month);
|
|
6213
|
+
return {
|
|
6214
|
+
month,
|
|
6215
|
+
messageCount: row?.messageCount ?? 0,
|
|
6216
|
+
activeDays: row?.activeDays ?? 0,
|
|
6217
|
+
segmentCount: indexAvailable ? segmentCountByMonth.get(month) ?? 0 : null
|
|
6218
|
+
};
|
|
6219
|
+
});
|
|
6220
|
+
const peakMonth = selectPeakMonth(months);
|
|
6221
|
+
const years = buildYears(months);
|
|
6222
|
+
const firstMessageTs = firstRow.firstMessageTs;
|
|
6223
|
+
const lastMessageTs = lastRow.lastMessageTs;
|
|
6224
|
+
return {
|
|
6225
|
+
range: {
|
|
6226
|
+
firstMessageTs,
|
|
6227
|
+
lastMessageTs,
|
|
6228
|
+
spanDays: Math.max(1, Math.floor((lastMessageTs - firstMessageTs) / 86400) + 1),
|
|
6229
|
+
spanMonths: months.length,
|
|
6230
|
+
activeDays: monthlyRows.reduce((sum, row) => sum + row.activeDays, 0),
|
|
6231
|
+
activeMonths: monthlyRows.length
|
|
6232
|
+
},
|
|
6233
|
+
hasSessionIndex: indexAvailable,
|
|
6234
|
+
months,
|
|
6235
|
+
years,
|
|
6236
|
+
peakMonth,
|
|
6237
|
+
longestSegment: selectLongestSegment(segmentRows),
|
|
6238
|
+
longestSilence: selectLongestSilence(segmentRows)
|
|
6239
|
+
};
|
|
6240
|
+
}
|
|
6241
|
+
function queryMonthlyRows(db, filter) {
|
|
6242
|
+
const { clause, params } = buildTimeFilter(filter, "msg");
|
|
6243
|
+
const whereClause = buildSystemMessageFilter(clause);
|
|
6244
|
+
return db.prepare(
|
|
6245
|
+
`SELECT
|
|
6246
|
+
strftime('%Y-%m', msg.ts, 'unixepoch', 'localtime') AS month,
|
|
6247
|
+
COUNT(*) AS messageCount,
|
|
6248
|
+
COUNT(DISTINCT strftime('%Y-%m-%d', msg.ts, 'unixepoch', 'localtime')) AS activeDays,
|
|
6249
|
+
MIN(msg.ts) AS firstMessageTs,
|
|
6250
|
+
MAX(msg.ts) AS lastMessageTs
|
|
6251
|
+
FROM message msg
|
|
6252
|
+
JOIN member m ON m.id = msg.sender_id
|
|
6253
|
+
${whereClause}
|
|
6254
|
+
GROUP BY month
|
|
6255
|
+
ORDER BY month ASC`
|
|
6256
|
+
).all(...params);
|
|
6257
|
+
}
|
|
6258
|
+
function querySegmentRows(db, filter) {
|
|
6259
|
+
const { clause, params } = buildTimeFilter(filter, "msg");
|
|
6260
|
+
const whereClause = buildSystemMessageFilter(clause);
|
|
6261
|
+
return db.prepare(
|
|
6262
|
+
`WITH filtered_messages AS (
|
|
6263
|
+
SELECT
|
|
6264
|
+
mc.segment_id AS segmentId,
|
|
6265
|
+
msg.id AS messageId,
|
|
6266
|
+
msg.sender_id AS senderId,
|
|
6267
|
+
msg.ts AS ts,
|
|
6268
|
+
COALESCE(m.group_nickname, m.account_name, m.platform_id) AS senderName,
|
|
6269
|
+
ROW_NUMBER() OVER (
|
|
6270
|
+
PARTITION BY mc.segment_id
|
|
6271
|
+
ORDER BY msg.ts ASC, msg.id ASC
|
|
6272
|
+
) AS rowNumber
|
|
6273
|
+
FROM message_context mc
|
|
6274
|
+
JOIN segment s ON s.id = mc.segment_id
|
|
6275
|
+
JOIN message msg ON msg.id = mc.message_id
|
|
6276
|
+
JOIN member m ON m.id = msg.sender_id
|
|
6277
|
+
${whereClause}
|
|
6278
|
+
),
|
|
6279
|
+
segment_summary AS (
|
|
6280
|
+
SELECT
|
|
6281
|
+
segmentId,
|
|
6282
|
+
MIN(ts) AS startTs,
|
|
6283
|
+
MAX(ts) AS endTs,
|
|
6284
|
+
COUNT(*) AS messageCount
|
|
6285
|
+
FROM filtered_messages
|
|
6286
|
+
GROUP BY segmentId
|
|
6287
|
+
)
|
|
6288
|
+
SELECT
|
|
6289
|
+
summary.segmentId,
|
|
6290
|
+
summary.startTs,
|
|
6291
|
+
summary.endTs,
|
|
6292
|
+
summary.messageCount,
|
|
6293
|
+
strftime('%Y-%m', summary.startTs, 'unixepoch', 'localtime') AS startMonth,
|
|
6294
|
+
firstMessage.senderId AS initiatorId,
|
|
6295
|
+
firstMessage.senderName AS initiatorName
|
|
6296
|
+
FROM segment_summary summary
|
|
6297
|
+
LEFT JOIN filtered_messages firstMessage
|
|
6298
|
+
ON firstMessage.segmentId = summary.segmentId AND firstMessage.rowNumber = 1
|
|
6299
|
+
ORDER BY summary.startTs ASC, summary.segmentId ASC`
|
|
6300
|
+
).all(...params);
|
|
6301
|
+
}
|
|
6302
|
+
function enumerateMonths(firstMonth, lastMonth) {
|
|
6303
|
+
const [firstYear, firstMonthNumber] = firstMonth.split("-").map(Number);
|
|
6304
|
+
const [lastYear, lastMonthNumber] = lastMonth.split("-").map(Number);
|
|
6305
|
+
const firstIndex = firstYear * 12 + firstMonthNumber - 1;
|
|
6306
|
+
const lastIndex = lastYear * 12 + lastMonthNumber - 1;
|
|
6307
|
+
const months = [];
|
|
6308
|
+
for (let index = firstIndex; index <= lastIndex; index++) {
|
|
6309
|
+
const year = Math.floor(index / 12);
|
|
6310
|
+
const month = index % 12 + 1;
|
|
6311
|
+
months.push(`${year}-${String(month).padStart(2, "0")}`);
|
|
6312
|
+
}
|
|
6313
|
+
return months;
|
|
6314
|
+
}
|
|
6315
|
+
function selectPeakMonth(months) {
|
|
6316
|
+
let peak = null;
|
|
6317
|
+
for (const month of months) {
|
|
6318
|
+
if (!peak || month.messageCount > peak.messageCount) peak = month;
|
|
6319
|
+
}
|
|
6320
|
+
return peak;
|
|
6321
|
+
}
|
|
6322
|
+
function buildYears(months) {
|
|
6323
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
6324
|
+
for (const month of months) {
|
|
6325
|
+
const year = Number.parseInt(month.month.slice(0, 4), 10);
|
|
6326
|
+
const values = grouped.get(year);
|
|
6327
|
+
if (values) values.push(month);
|
|
6328
|
+
else grouped.set(year, [month]);
|
|
6329
|
+
}
|
|
6330
|
+
return Array.from(grouped.entries()).map(([year, values]) => {
|
|
6331
|
+
const activeValues = values.filter((value) => value.messageCount > 0);
|
|
6332
|
+
const peak = selectPeakMonth(values);
|
|
6333
|
+
return {
|
|
6334
|
+
year,
|
|
6335
|
+
messageCount: values.reduce((sum, value) => sum + value.messageCount, 0),
|
|
6336
|
+
activeDays: values.reduce((sum, value) => sum + value.activeDays, 0),
|
|
6337
|
+
activeMonths: activeValues.length,
|
|
6338
|
+
peakMonth: peak.month,
|
|
6339
|
+
peakMonthMessageCount: peak.messageCount
|
|
6340
|
+
};
|
|
6341
|
+
});
|
|
6342
|
+
}
|
|
6343
|
+
function toJourneySegment(row) {
|
|
6344
|
+
return {
|
|
6345
|
+
segmentId: row.segmentId,
|
|
6346
|
+
startTs: row.startTs,
|
|
6347
|
+
endTs: row.endTs,
|
|
6348
|
+
durationSeconds: Math.max(0, row.endTs - row.startTs),
|
|
6349
|
+
messageCount: row.messageCount,
|
|
6350
|
+
initiator: row.initiatorId === null || row.initiatorName === null ? null : { memberId: row.initiatorId, name: row.initiatorName }
|
|
6351
|
+
};
|
|
6352
|
+
}
|
|
6353
|
+
function selectLongestSegment(rows) {
|
|
6354
|
+
let longest = null;
|
|
6355
|
+
for (const row of rows) {
|
|
6356
|
+
const candidate = toJourneySegment(row);
|
|
6357
|
+
if (!longest || candidate.durationSeconds > longest.durationSeconds || candidate.durationSeconds === longest.durationSeconds && candidate.messageCount > longest.messageCount || candidate.durationSeconds === longest.durationSeconds && candidate.messageCount === longest.messageCount && candidate.startTs < longest.startTs) {
|
|
6358
|
+
longest = candidate;
|
|
6359
|
+
}
|
|
6360
|
+
}
|
|
6361
|
+
return longest;
|
|
6362
|
+
}
|
|
6363
|
+
function selectLongestSilence(rows) {
|
|
6364
|
+
let longest = null;
|
|
6365
|
+
for (let index = 1; index < rows.length; index++) {
|
|
6366
|
+
const previous = rows[index - 1];
|
|
6367
|
+
const next = rows[index];
|
|
6368
|
+
const durationSeconds = next.startTs - previous.endTs;
|
|
6369
|
+
if (durationSeconds < SILENCE_THRESHOLD_SECONDS) continue;
|
|
6370
|
+
const candidate = {
|
|
6371
|
+
previousSegmentId: previous.segmentId,
|
|
6372
|
+
nextSegmentId: next.segmentId,
|
|
6373
|
+
startTs: previous.endTs,
|
|
6374
|
+
endTs: next.startTs,
|
|
6375
|
+
durationSeconds,
|
|
6376
|
+
reopenedBy: next.initiatorId === null || next.initiatorName === null ? null : { memberId: next.initiatorId, name: next.initiatorName }
|
|
6377
|
+
};
|
|
6378
|
+
if (!longest || candidate.durationSeconds > longest.durationSeconds || candidate.durationSeconds === longest.durationSeconds && candidate.endTs < longest.endTs) {
|
|
6379
|
+
longest = candidate;
|
|
6380
|
+
}
|
|
6381
|
+
}
|
|
6382
|
+
return longest;
|
|
6383
|
+
}
|
|
6384
|
+
|
|
6085
6385
|
// ../../packages/core/src/query/advanced/languagePreference.ts
|
|
6086
6386
|
var RE_ELLIPSIS = /\.{2,}|…+|。{2,}/g;
|
|
6087
6387
|
var RE_EXCLAMATION = /[!!]+/g;
|
|
@@ -7503,15 +7803,15 @@ function runMigrations(db, migrationsList, forceRepair = false) {
|
|
|
7503
7803
|
}
|
|
7504
7804
|
|
|
7505
7805
|
// ../../packages/node-runtime/src/ai/ai-logger.ts
|
|
7506
|
-
import * as
|
|
7507
|
-
import * as
|
|
7806
|
+
import * as fs6 from "fs";
|
|
7807
|
+
import * as path11 from "path";
|
|
7508
7808
|
var AiLogger = class {
|
|
7509
7809
|
debugMode = false;
|
|
7510
7810
|
logDir;
|
|
7511
7811
|
logFile = null;
|
|
7512
7812
|
logStream = null;
|
|
7513
7813
|
constructor(logsDir) {
|
|
7514
|
-
this.logDir =
|
|
7814
|
+
this.logDir = path11.join(logsDir, "ai");
|
|
7515
7815
|
}
|
|
7516
7816
|
setDebugMode(enabled) {
|
|
7517
7817
|
this.debugMode = enabled;
|
|
@@ -7541,14 +7841,14 @@ var AiLogger = class {
|
|
|
7541
7841
|
return this.getLogFilePath();
|
|
7542
7842
|
}
|
|
7543
7843
|
getExistingLogPath() {
|
|
7544
|
-
if (this.logFile &&
|
|
7844
|
+
if (this.logFile && fs6.existsSync(this.logFile)) {
|
|
7545
7845
|
return this.logFile;
|
|
7546
7846
|
}
|
|
7547
7847
|
return null;
|
|
7548
7848
|
}
|
|
7549
7849
|
ensureLogDir() {
|
|
7550
|
-
if (!
|
|
7551
|
-
|
|
7850
|
+
if (!fs6.existsSync(this.logDir)) {
|
|
7851
|
+
fs6.mkdirSync(this.logDir, { recursive: true });
|
|
7552
7852
|
}
|
|
7553
7853
|
}
|
|
7554
7854
|
getLogFilePath() {
|
|
@@ -7558,14 +7858,14 @@ var AiLogger = class {
|
|
|
7558
7858
|
const date = now.toISOString().split("T")[0];
|
|
7559
7859
|
const hours = String(now.getHours()).padStart(2, "0");
|
|
7560
7860
|
const minutes = String(now.getMinutes()).padStart(2, "0");
|
|
7561
|
-
this.logFile =
|
|
7861
|
+
this.logFile = path11.join(this.logDir, `ai_${date}_${hours}-${minutes}.log`);
|
|
7562
7862
|
return this.logFile;
|
|
7563
7863
|
}
|
|
7564
7864
|
getLogStream() {
|
|
7565
7865
|
if (this.logStream) return this.logStream;
|
|
7566
7866
|
const filePath = this.getLogFilePath();
|
|
7567
|
-
const isNewOrEmptyFile = !
|
|
7568
|
-
this.logStream =
|
|
7867
|
+
const isNewOrEmptyFile = !fs6.existsSync(filePath) || fs6.statSync(filePath).size === 0;
|
|
7868
|
+
this.logStream = fs6.createWriteStream(filePath, { flags: "a", encoding: "utf-8" });
|
|
7569
7869
|
if (isNewOrEmptyFile) {
|
|
7570
7870
|
this.logStream.write(`Local Path: ${filePath.replace(/ /g, "\\ ")}
|
|
7571
7871
|
|
|
@@ -7628,8 +7928,8 @@ function extractErrorStack(error, stackLines = 5) {
|
|
|
7628
7928
|
}
|
|
7629
7929
|
|
|
7630
7930
|
// ../../packages/node-runtime/src/logging/app-logger.ts
|
|
7631
|
-
import * as
|
|
7632
|
-
import * as
|
|
7931
|
+
import * as fs7 from "fs";
|
|
7932
|
+
import * as path12 from "path";
|
|
7633
7933
|
var LEVEL_ORDER = { DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3 };
|
|
7634
7934
|
var MAX_SIZE_BYTES = 10 * 1024 * 1024;
|
|
7635
7935
|
var AppLogger = class {
|
|
@@ -7637,8 +7937,8 @@ var AppLogger = class {
|
|
|
7637
7937
|
oldLogFile;
|
|
7638
7938
|
threshold;
|
|
7639
7939
|
constructor(logsDir) {
|
|
7640
|
-
this.logFile =
|
|
7641
|
-
this.oldLogFile =
|
|
7940
|
+
this.logFile = path12.join(logsDir, "app.log");
|
|
7941
|
+
this.oldLogFile = path12.join(logsDir, "app.old.log");
|
|
7642
7942
|
this.threshold = resolveThreshold();
|
|
7643
7943
|
}
|
|
7644
7944
|
debug(scope, message, data) {
|
|
@@ -7665,9 +7965,9 @@ var AppLogger = class {
|
|
|
7665
7965
|
if (tail) line += `
|
|
7666
7966
|
${tail}`;
|
|
7667
7967
|
line += "\n";
|
|
7668
|
-
ensureDir(
|
|
7968
|
+
ensureDir(path12.dirname(this.logFile));
|
|
7669
7969
|
this.rotateIfNeeded();
|
|
7670
|
-
|
|
7970
|
+
fs7.appendFileSync(this.logFile, line, "utf-8");
|
|
7671
7971
|
} catch (err) {
|
|
7672
7972
|
console.error("[AppLogger] Failed to write log:", err);
|
|
7673
7973
|
}
|
|
@@ -7676,12 +7976,12 @@ ${tail}`;
|
|
|
7676
7976
|
rotateIfNeeded() {
|
|
7677
7977
|
let size = 0;
|
|
7678
7978
|
try {
|
|
7679
|
-
size =
|
|
7979
|
+
size = fs7.statSync(this.logFile).size;
|
|
7680
7980
|
} catch {
|
|
7681
7981
|
return;
|
|
7682
7982
|
}
|
|
7683
7983
|
if (size < MAX_SIZE_BYTES) return;
|
|
7684
|
-
|
|
7984
|
+
fs7.renameSync(this.logFile, this.oldLogFile);
|
|
7685
7985
|
}
|
|
7686
7986
|
};
|
|
7687
7987
|
function resolveThreshold() {
|
|
@@ -7705,7 +8005,7 @@ ${stack}` : "");
|
|
|
7705
8005
|
}
|
|
7706
8006
|
}
|
|
7707
8007
|
function ensureDir(dir) {
|
|
7708
|
-
if (!
|
|
8008
|
+
if (!fs7.existsSync(dir)) fs7.mkdirSync(dir, { recursive: true });
|
|
7709
8009
|
}
|
|
7710
8010
|
var instance = null;
|
|
7711
8011
|
function initAppLogger(logsDir) {
|
|
@@ -7720,8 +8020,8 @@ var appLogger = {
|
|
|
7720
8020
|
};
|
|
7721
8021
|
|
|
7722
8022
|
// ../../packages/node-runtime/src/nlp/segmenter.ts
|
|
7723
|
-
import * as
|
|
7724
|
-
import * as
|
|
8023
|
+
import * as fs8 from "fs";
|
|
8024
|
+
import * as path13 from "path";
|
|
7725
8025
|
import { createRequire } from "module";
|
|
7726
8026
|
var _nlpDir = null;
|
|
7727
8027
|
var jiebaInstances = /* @__PURE__ */ new Map();
|
|
@@ -7734,14 +8034,14 @@ function getNlpDir() {
|
|
|
7734
8034
|
}
|
|
7735
8035
|
function existsDictOnDisk(dictId) {
|
|
7736
8036
|
if (!_nlpDir) return false;
|
|
7737
|
-
return
|
|
8037
|
+
return fs8.existsSync(path13.join(_nlpDir, `${dictId}.dict`));
|
|
7738
8038
|
}
|
|
7739
8039
|
function tryLoadDictFromDisk(dictId) {
|
|
7740
8040
|
if (!_nlpDir) return null;
|
|
7741
|
-
const dictPath =
|
|
7742
|
-
if (!
|
|
8041
|
+
const dictPath = path13.join(_nlpDir, `${dictId}.dict`);
|
|
8042
|
+
if (!fs8.existsSync(dictPath)) return null;
|
|
7743
8043
|
try {
|
|
7744
|
-
return
|
|
8044
|
+
return fs8.readFileSync(dictPath);
|
|
7745
8045
|
} catch {
|
|
7746
8046
|
return null;
|
|
7747
8047
|
}
|
|
@@ -7972,29 +8272,29 @@ function tokenizeQueryForFts(keywords) {
|
|
|
7972
8272
|
}
|
|
7973
8273
|
|
|
7974
8274
|
// ../../packages/node-runtime/src/migrations/electron-data-migration.ts
|
|
7975
|
-
import * as
|
|
8275
|
+
import * as fs9 from "fs";
|
|
7976
8276
|
import * as os3 from "os";
|
|
7977
|
-
import * as
|
|
8277
|
+
import * as path14 from "path";
|
|
7978
8278
|
var SYSTEM_SUBDIRS = ["ai", "settings", "cache", "logs", "nlp"];
|
|
7979
8279
|
var STORAGE_CONFIG_FILE = "storage.json";
|
|
7980
8280
|
function getElectronUserDataDir(options = {}) {
|
|
7981
8281
|
const home = options.homeDir ?? os3.homedir();
|
|
7982
8282
|
switch (options.platform ?? process.platform) {
|
|
7983
8283
|
case "darwin":
|
|
7984
|
-
return
|
|
8284
|
+
return path14.join(home, "Library", "Application Support", "ChatLab");
|
|
7985
8285
|
case "win32": {
|
|
7986
|
-
const appData = options.appDataDir ?? process.env.APPDATA ??
|
|
7987
|
-
return
|
|
8286
|
+
const appData = options.appDataDir ?? process.env.APPDATA ?? path14.join(home, "AppData", "Roaming");
|
|
8287
|
+
return path14.join(appData, "ChatLab");
|
|
7988
8288
|
}
|
|
7989
8289
|
default:
|
|
7990
|
-
return
|
|
8290
|
+
return path14.join(home, ".config", "ChatLab");
|
|
7991
8291
|
}
|
|
7992
8292
|
}
|
|
7993
8293
|
function readElectronStorageConfig(electronUserData) {
|
|
7994
|
-
const configPath =
|
|
7995
|
-
if (!
|
|
8294
|
+
const configPath = path14.join(electronUserData, STORAGE_CONFIG_FILE);
|
|
8295
|
+
if (!fs9.existsSync(configPath)) return {};
|
|
7996
8296
|
try {
|
|
7997
|
-
return JSON.parse(
|
|
8297
|
+
return JSON.parse(fs9.readFileSync(configPath, "utf-8"));
|
|
7998
8298
|
} catch {
|
|
7999
8299
|
return {};
|
|
8000
8300
|
}
|
|
@@ -8002,45 +8302,45 @@ function readElectronStorageConfig(electronUserData) {
|
|
|
8002
8302
|
function resolveElectronDataDir() {
|
|
8003
8303
|
const electronUserData = getElectronUserDataDir();
|
|
8004
8304
|
const storageConfig = readElectronStorageConfig(electronUserData);
|
|
8005
|
-
if (storageConfig.dataDir &&
|
|
8305
|
+
if (storageConfig.dataDir && path14.isAbsolute(storageConfig.dataDir)) {
|
|
8006
8306
|
return storageConfig.dataDir;
|
|
8007
8307
|
}
|
|
8008
|
-
return
|
|
8308
|
+
return path14.join(electronUserData, "data");
|
|
8009
8309
|
}
|
|
8010
8310
|
function hasDatabases(dir) {
|
|
8011
|
-
const dbDir =
|
|
8012
|
-
if (!
|
|
8311
|
+
const dbDir = path14.join(dir, "databases");
|
|
8312
|
+
if (!fs9.existsSync(dbDir)) return false;
|
|
8013
8313
|
try {
|
|
8014
|
-
return
|
|
8314
|
+
return fs9.readdirSync(dbDir).some((f) => f.endsWith(".db"));
|
|
8015
8315
|
} catch {
|
|
8016
8316
|
return false;
|
|
8017
8317
|
}
|
|
8018
8318
|
}
|
|
8019
8319
|
function ensureDir2(dirPath) {
|
|
8020
|
-
if (!
|
|
8021
|
-
|
|
8320
|
+
if (!fs9.existsSync(dirPath)) {
|
|
8321
|
+
fs9.mkdirSync(dirPath, { recursive: true });
|
|
8022
8322
|
}
|
|
8023
8323
|
}
|
|
8024
8324
|
function copyDirMerge(src, dest) {
|
|
8025
8325
|
const stats = { copied: 0, skipped: 0 };
|
|
8026
|
-
if (!
|
|
8326
|
+
if (!fs9.existsSync(src)) return stats;
|
|
8027
8327
|
ensureDir2(dest);
|
|
8028
8328
|
let entries;
|
|
8029
8329
|
try {
|
|
8030
|
-
entries =
|
|
8330
|
+
entries = fs9.readdirSync(src, { withFileTypes: true });
|
|
8031
8331
|
} catch {
|
|
8032
8332
|
return stats;
|
|
8033
8333
|
}
|
|
8034
8334
|
for (const entry of entries) {
|
|
8035
|
-
const srcPath =
|
|
8036
|
-
const destPath =
|
|
8335
|
+
const srcPath = path14.join(src, entry.name);
|
|
8336
|
+
const destPath = path14.join(dest, entry.name);
|
|
8037
8337
|
try {
|
|
8038
8338
|
if (entry.isDirectory()) {
|
|
8039
8339
|
const sub = copyDirMerge(srcPath, destPath);
|
|
8040
8340
|
stats.copied += sub.copied;
|
|
8041
8341
|
stats.skipped += sub.skipped;
|
|
8042
|
-
} else if (!
|
|
8043
|
-
|
|
8342
|
+
} else if (!fs9.existsSync(destPath)) {
|
|
8343
|
+
fs9.copyFileSync(srcPath, destPath);
|
|
8044
8344
|
stats.copied++;
|
|
8045
8345
|
} else {
|
|
8046
8346
|
stats.skipped++;
|
|
@@ -8053,22 +8353,22 @@ function copyDirMerge(src, dest) {
|
|
|
8053
8353
|
function writeMigrationLog(logDir, message) {
|
|
8054
8354
|
try {
|
|
8055
8355
|
ensureDir2(logDir);
|
|
8056
|
-
const logPath =
|
|
8356
|
+
const logPath = path14.join(logDir, "app.log");
|
|
8057
8357
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
8058
|
-
|
|
8358
|
+
fs9.appendFileSync(logPath, `[${ts}] [MIGRATION] ${message}
|
|
8059
8359
|
`, "utf-8");
|
|
8060
8360
|
} catch {
|
|
8061
8361
|
}
|
|
8062
8362
|
}
|
|
8063
8363
|
function wasElectronUsed() {
|
|
8064
8364
|
const electronUserData = getElectronUserDataDir();
|
|
8065
|
-
if (!
|
|
8066
|
-
return
|
|
8365
|
+
if (!fs9.existsSync(electronUserData)) return false;
|
|
8366
|
+
return fs9.existsSync(path14.join(electronUserData, "Preferences")) || fs9.existsSync(path14.join(electronUserData, "Local Storage")) || fs9.existsSync(path14.join(electronUserData, "Session Storage")) || fs9.existsSync(path14.join(electronUserData, "data"));
|
|
8067
8367
|
}
|
|
8068
8368
|
function verifyCliDataPath(databaseDir) {
|
|
8069
|
-
if (
|
|
8369
|
+
if (fs9.existsSync(databaseDir)) {
|
|
8070
8370
|
try {
|
|
8071
|
-
if (
|
|
8371
|
+
if (fs9.readdirSync(databaseDir).some((f) => f.endsWith(".db"))) return true;
|
|
8072
8372
|
} catch {
|
|
8073
8373
|
}
|
|
8074
8374
|
}
|
|
@@ -8086,9 +8386,9 @@ function migrateFromElectronIfNeeded(systemDir) {
|
|
|
8086
8386
|
let totalSkipped = 0;
|
|
8087
8387
|
const movedDirs = [];
|
|
8088
8388
|
for (const subDir of SYSTEM_SUBDIRS) {
|
|
8089
|
-
const srcDir =
|
|
8090
|
-
const destDir =
|
|
8091
|
-
if (!
|
|
8389
|
+
const srcDir = path14.join(electronDataDir, subDir);
|
|
8390
|
+
const destDir = path14.join(systemDir, subDir);
|
|
8391
|
+
if (!fs9.existsSync(srcDir)) continue;
|
|
8092
8392
|
const { copied, skipped } = copyDirMerge(srcDir, destDir);
|
|
8093
8393
|
if (copied > 0 || skipped > 0) {
|
|
8094
8394
|
movedDirs.push(subDir);
|
|
@@ -8098,13 +8398,13 @@ function migrateFromElectronIfNeeded(systemDir) {
|
|
|
8098
8398
|
}
|
|
8099
8399
|
}
|
|
8100
8400
|
for (const subDir of movedDirs) {
|
|
8101
|
-
const srcDir =
|
|
8401
|
+
const srcDir = path14.join(electronDataDir, subDir);
|
|
8102
8402
|
try {
|
|
8103
|
-
|
|
8403
|
+
fs9.rmSync(srcDir, { recursive: true, force: true });
|
|
8104
8404
|
} catch {
|
|
8105
8405
|
}
|
|
8106
8406
|
}
|
|
8107
|
-
const logsDir =
|
|
8407
|
+
const logsDir = path14.join(systemDir, "logs");
|
|
8108
8408
|
const summary = `CLI first-run: detected Electron data at ${electronDataDir}, pointed user_data_dir there, copied ${totalCopied} system files (${movedDirs.join(", ") || "none"})`;
|
|
8109
8409
|
writeMigrationLog(logsDir, summary);
|
|
8110
8410
|
console.log(`[Migration] ${summary}`);
|
|
@@ -8118,7 +8418,7 @@ function migrateFromElectronIfNeeded(systemDir) {
|
|
|
8118
8418
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
8119
8419
|
console.error("[Migration] Electron data migration failed:", errorMsg);
|
|
8120
8420
|
try {
|
|
8121
|
-
writeMigrationLog(
|
|
8421
|
+
writeMigrationLog(path14.join(systemDir, "logs"), `Electron migration failed: ${errorMsg}`);
|
|
8122
8422
|
} catch {
|
|
8123
8423
|
}
|
|
8124
8424
|
return { migrated: false, electronDetected: true, error: errorMsg };
|
|
@@ -8126,26 +8426,26 @@ function migrateFromElectronIfNeeded(systemDir) {
|
|
|
8126
8426
|
}
|
|
8127
8427
|
|
|
8128
8428
|
// ../../packages/node-runtime/src/cache/session-cache.ts
|
|
8129
|
-
import * as
|
|
8130
|
-
import * as
|
|
8429
|
+
import * as fs10 from "fs";
|
|
8430
|
+
import * as path15 from "path";
|
|
8131
8431
|
function getCachePath(sessionId, cacheDir) {
|
|
8132
|
-
return
|
|
8432
|
+
return path15.join(cacheDir, `${sessionId}.cache.json`);
|
|
8133
8433
|
}
|
|
8134
8434
|
function readCacheFile(cachePath) {
|
|
8135
8435
|
try {
|
|
8136
|
-
if (!
|
|
8137
|
-
return JSON.parse(
|
|
8436
|
+
if (!fs10.existsSync(cachePath)) return null;
|
|
8437
|
+
return JSON.parse(fs10.readFileSync(cachePath, "utf-8"));
|
|
8138
8438
|
} catch {
|
|
8139
8439
|
return null;
|
|
8140
8440
|
}
|
|
8141
8441
|
}
|
|
8142
8442
|
function writeCacheFile(cachePath, content) {
|
|
8143
8443
|
try {
|
|
8144
|
-
const dir =
|
|
8145
|
-
if (!
|
|
8146
|
-
|
|
8444
|
+
const dir = path15.dirname(cachePath);
|
|
8445
|
+
if (!fs10.existsSync(dir)) {
|
|
8446
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
8147
8447
|
}
|
|
8148
|
-
|
|
8448
|
+
fs10.writeFileSync(cachePath, JSON.stringify(content), "utf-8");
|
|
8149
8449
|
} catch {
|
|
8150
8450
|
}
|
|
8151
8451
|
}
|
|
@@ -8165,7 +8465,7 @@ function invalidateCache(sessionId, cacheDir, key) {
|
|
|
8165
8465
|
const cachePath = getCachePath(sessionId, cacheDir);
|
|
8166
8466
|
try {
|
|
8167
8467
|
if (!key) {
|
|
8168
|
-
if (
|
|
8468
|
+
if (fs10.existsSync(cachePath)) fs10.unlinkSync(cachePath);
|
|
8169
8469
|
} else {
|
|
8170
8470
|
const file = readCacheFile(cachePath);
|
|
8171
8471
|
if (file && file[key]) {
|
|
@@ -8179,7 +8479,7 @@ function invalidateCache(sessionId, cacheDir, key) {
|
|
|
8179
8479
|
function deleteSessionCache(sessionId, cacheDir) {
|
|
8180
8480
|
const cachePath = getCachePath(sessionId, cacheDir);
|
|
8181
8481
|
try {
|
|
8182
|
-
if (
|
|
8482
|
+
if (fs10.existsSync(cachePath)) fs10.unlinkSync(cachePath);
|
|
8183
8483
|
} catch {
|
|
8184
8484
|
}
|
|
8185
8485
|
}
|
|
@@ -8233,8 +8533,8 @@ function computeAndSetMembersCache(db, sessionId, cacheDir) {
|
|
|
8233
8533
|
}
|
|
8234
8534
|
|
|
8235
8535
|
// ../../packages/node-runtime/src/data-dir-compat.ts
|
|
8236
|
-
import
|
|
8237
|
-
import
|
|
8536
|
+
import fs11 from "fs";
|
|
8537
|
+
import path16 from "path";
|
|
8238
8538
|
var DataDirCompatibilityError = class extends Error {
|
|
8239
8539
|
code;
|
|
8240
8540
|
userDataDir;
|
|
@@ -8254,10 +8554,10 @@ var DataDirCompatibilityError = class extends Error {
|
|
|
8254
8554
|
};
|
|
8255
8555
|
function readDataDirCompatibilityMeta(userDataDir) {
|
|
8256
8556
|
const metaPath = getMetaPath(userDataDir);
|
|
8257
|
-
if (!
|
|
8557
|
+
if (!fs11.existsSync(metaPath)) return null;
|
|
8258
8558
|
let parsed;
|
|
8259
8559
|
try {
|
|
8260
|
-
parsed = JSON.parse(
|
|
8560
|
+
parsed = JSON.parse(fs11.readFileSync(metaPath, "utf-8"));
|
|
8261
8561
|
} catch (error) {
|
|
8262
8562
|
throw createInvalidMetaError(userDataDir, metaPath, "Invalid data directory compatibility meta JSON.", error);
|
|
8263
8563
|
}
|
|
@@ -8340,7 +8640,7 @@ function raiseDataDirMinRuntimeVersion(pathProvider, input) {
|
|
|
8340
8640
|
return nextMeta;
|
|
8341
8641
|
}
|
|
8342
8642
|
function getMetaPath(userDataDir) {
|
|
8343
|
-
return
|
|
8643
|
+
return path16.join(userDataDir, ".chatlab-meta.json");
|
|
8344
8644
|
}
|
|
8345
8645
|
function validateDataDirCompatibilityMeta(value, userDataDir, metaPath) {
|
|
8346
8646
|
if (!isRecord2(value)) {
|
|
@@ -8411,15 +8711,15 @@ function mergeReasons(existing, next) {
|
|
|
8411
8711
|
return [.../* @__PURE__ */ new Set([...existing, next])];
|
|
8412
8712
|
}
|
|
8413
8713
|
function writeMetaAtomic(userDataDir, metaPath, meta) {
|
|
8414
|
-
|
|
8415
|
-
const tempPath =
|
|
8714
|
+
fs11.mkdirSync(userDataDir, { recursive: true });
|
|
8715
|
+
const tempPath = path16.join(userDataDir, `.chatlab-meta.json.${process.pid}.${Date.now()}.tmp`);
|
|
8416
8716
|
try {
|
|
8417
|
-
|
|
8717
|
+
fs11.writeFileSync(tempPath, `${JSON.stringify(meta, null, 2)}
|
|
8418
8718
|
`, "utf-8");
|
|
8419
|
-
|
|
8719
|
+
fs11.renameSync(tempPath, metaPath);
|
|
8420
8720
|
} catch (error) {
|
|
8421
8721
|
try {
|
|
8422
|
-
if (
|
|
8722
|
+
if (fs11.existsSync(tempPath)) fs11.unlinkSync(tempPath);
|
|
8423
8723
|
} catch {
|
|
8424
8724
|
}
|
|
8425
8725
|
throw error;
|
|
@@ -8758,44 +9058,44 @@ function getChatDbMigrations(deps) {
|
|
|
8758
9058
|
}
|
|
8759
9059
|
|
|
8760
9060
|
// ../../packages/node-runtime/src/services/contacts/paths.ts
|
|
8761
|
-
import
|
|
9061
|
+
import path17 from "path";
|
|
8762
9062
|
var CONTACTS_DIR_NAME = "contacts";
|
|
8763
9063
|
var CONTACTS_FACTS_DIR_NAME = "facts";
|
|
8764
9064
|
function getContactsDir(userDataDir) {
|
|
8765
|
-
return
|
|
9065
|
+
return path17.join(userDataDir, CONTACTS_DIR_NAME);
|
|
8766
9066
|
}
|
|
8767
9067
|
function getContactsFactsCacheDir(userDataDir) {
|
|
8768
|
-
return
|
|
9068
|
+
return path17.join(getContactsDir(userDataDir), CONTACTS_FACTS_DIR_NAME);
|
|
8769
9069
|
}
|
|
8770
9070
|
|
|
8771
9071
|
// ../../packages/node-runtime/src/services/global-insight/paths.ts
|
|
8772
|
-
import
|
|
9072
|
+
import path18 from "path";
|
|
8773
9073
|
function getGlobalInsightDir(userDataDir) {
|
|
8774
|
-
return
|
|
9074
|
+
return path18.join(userDataDir, "insight", "annual-summary");
|
|
8775
9075
|
}
|
|
8776
9076
|
function getGlobalInsightFactsCacheDir(userDataDir) {
|
|
8777
|
-
return
|
|
9077
|
+
return path18.join(getGlobalInsightDir(userDataDir), "facts");
|
|
8778
9078
|
}
|
|
8779
9079
|
|
|
8780
9080
|
// ../../packages/node-runtime/src/services/people/relationships/paths.ts
|
|
8781
|
-
import
|
|
9081
|
+
import path19 from "path";
|
|
8782
9082
|
var PEOPLE_DIR_NAME = "people";
|
|
8783
9083
|
var RELATIONSHIPS_DIR_NAME = "relationships";
|
|
8784
9084
|
var RELATIONSHIPS_FACTS_DIR_NAME = "facts";
|
|
8785
9085
|
function getPeopleRelationshipsDir(userDataDir) {
|
|
8786
|
-
return
|
|
9086
|
+
return path19.join(userDataDir, PEOPLE_DIR_NAME, RELATIONSHIPS_DIR_NAME);
|
|
8787
9087
|
}
|
|
8788
9088
|
function getPeopleRelationshipsFactsCacheDir(userDataDir) {
|
|
8789
|
-
return
|
|
9089
|
+
return path19.join(getPeopleRelationshipsDir(userDataDir), RELATIONSHIPS_FACTS_DIR_NAME);
|
|
8790
9090
|
}
|
|
8791
9091
|
|
|
8792
9092
|
// ../../packages/node-runtime/src/database-manager.ts
|
|
8793
|
-
import * as
|
|
8794
|
-
import * as
|
|
9093
|
+
import * as fs13 from "fs";
|
|
9094
|
+
import * as path21 from "path";
|
|
8795
9095
|
|
|
8796
9096
|
// ../../packages/node-runtime/src/services/global-insight/snapshot.ts
|
|
8797
|
-
import
|
|
8798
|
-
import
|
|
9097
|
+
import fs12 from "fs";
|
|
9098
|
+
import path20 from "path";
|
|
8799
9099
|
|
|
8800
9100
|
// ../../packages/node-runtime/src/services/global-insight/time-range.ts
|
|
8801
9101
|
function normalizeAnnualSummaryRange(input, nowInput = /* @__PURE__ */ new Date()) {
|
|
@@ -8846,17 +9146,17 @@ function toAnnualSummaryLocalDate(range) {
|
|
|
8846
9146
|
// ../../packages/node-runtime/src/services/global-insight/snapshot.ts
|
|
8847
9147
|
var SNAPSHOT_TMP_PREFIX = "annual-summary.tmp-";
|
|
8848
9148
|
function getAnnualSummarySnapshotPath(snapshotDir, range) {
|
|
8849
|
-
return
|
|
9149
|
+
return path20.join(snapshotDir, `annual-summary-${toAnnualSummaryRangeKey(range)}.json`);
|
|
8850
9150
|
}
|
|
8851
9151
|
function readAnnualSummarySnapshot(snapshotDir, range, options = {}) {
|
|
8852
9152
|
const snapshotPath = getAnnualSummarySnapshotPath(snapshotDir, range);
|
|
8853
|
-
if (!
|
|
9153
|
+
if (!fs12.existsSync(snapshotPath)) return null;
|
|
8854
9154
|
try {
|
|
8855
|
-
return JSON.parse(
|
|
9155
|
+
return JSON.parse(fs12.readFileSync(snapshotPath, "utf-8"));
|
|
8856
9156
|
} catch (error) {
|
|
8857
|
-
const backupPath =
|
|
9157
|
+
const backupPath = path20.join(snapshotDir, `annual-summary.corrupt-${options.now?.() ?? Date.now()}.json`);
|
|
8858
9158
|
try {
|
|
8859
|
-
|
|
9159
|
+
fs12.renameSync(snapshotPath, backupPath);
|
|
8860
9160
|
} catch (renameError) {
|
|
8861
9161
|
appLogger.warn("global-insight", "failed to backup corrupt annual summary snapshot", renameError);
|
|
8862
9162
|
}
|
|
@@ -8865,28 +9165,28 @@ function readAnnualSummarySnapshot(snapshotDir, range, options = {}) {
|
|
|
8865
9165
|
}
|
|
8866
9166
|
}
|
|
8867
9167
|
function writeAnnualSummarySnapshot(snapshotDir, snapshot) {
|
|
8868
|
-
|
|
8869
|
-
const tmpPath =
|
|
8870
|
-
|
|
8871
|
-
|
|
9168
|
+
fs12.mkdirSync(snapshotDir, { recursive: true });
|
|
9169
|
+
const tmpPath = path20.join(snapshotDir, `${SNAPSHOT_TMP_PREFIX}${process.pid}-${Date.now()}`);
|
|
9170
|
+
fs12.writeFileSync(tmpPath, JSON.stringify(snapshot, null, 2), "utf-8");
|
|
9171
|
+
fs12.renameSync(tmpPath, getAnnualSummarySnapshotPath(snapshotDir, snapshot.range));
|
|
8872
9172
|
}
|
|
8873
9173
|
function cleanupAnnualSummarySnapshotTempFiles(snapshotDir) {
|
|
8874
|
-
if (!
|
|
8875
|
-
for (const name of
|
|
9174
|
+
if (!fs12.existsSync(snapshotDir)) return;
|
|
9175
|
+
for (const name of fs12.readdirSync(snapshotDir)) {
|
|
8876
9176
|
if (!name.startsWith(SNAPSHOT_TMP_PREFIX)) continue;
|
|
8877
9177
|
try {
|
|
8878
|
-
|
|
9178
|
+
fs12.rmSync(path20.join(snapshotDir, name), { force: true });
|
|
8879
9179
|
} catch (error) {
|
|
8880
9180
|
appLogger.warn("global-insight", "failed to remove annual summary snapshot temp file", error);
|
|
8881
9181
|
}
|
|
8882
9182
|
}
|
|
8883
9183
|
}
|
|
8884
9184
|
function deleteAnnualSummarySnapshots(snapshotDir) {
|
|
8885
|
-
if (!
|
|
8886
|
-
for (const name of
|
|
9185
|
+
if (!fs12.existsSync(snapshotDir)) return;
|
|
9186
|
+
for (const name of fs12.readdirSync(snapshotDir)) {
|
|
8887
9187
|
if (!name.startsWith("annual-summary-") && !name.startsWith("annual-summary.")) continue;
|
|
8888
9188
|
try {
|
|
8889
|
-
|
|
9189
|
+
fs12.rmSync(path20.join(snapshotDir, name), { force: true });
|
|
8890
9190
|
} catch (error) {
|
|
8891
9191
|
appLogger.warn("global-insight", "failed to remove annual summary snapshot", error);
|
|
8892
9192
|
}
|
|
@@ -8924,7 +9224,7 @@ var DatabaseManager = class {
|
|
|
8924
9224
|
return this.cache.get(sessionId);
|
|
8925
9225
|
}
|
|
8926
9226
|
const dbPath = this.getDbPath(sessionId);
|
|
8927
|
-
if (!
|
|
9227
|
+
if (!fs13.existsSync(dbPath)) return null;
|
|
8928
9228
|
this.migrateIfNeeded(dbPath);
|
|
8929
9229
|
this.assertCompatible();
|
|
8930
9230
|
const adapter = openBetterSqliteDatabase(dbPath, {
|
|
@@ -8970,7 +9270,7 @@ var DatabaseManager = class {
|
|
|
8970
9270
|
this.cache.delete(sessionId);
|
|
8971
9271
|
}
|
|
8972
9272
|
const dbPath = this.getDbPath(sessionId);
|
|
8973
|
-
if (!
|
|
9273
|
+
if (!fs13.existsSync(dbPath)) return null;
|
|
8974
9274
|
const adapter = openBetterSqliteDatabase(dbPath, {
|
|
8975
9275
|
readonly: false,
|
|
8976
9276
|
nativeBinding: this.nativeBinding
|
|
@@ -9010,8 +9310,8 @@ var DatabaseManager = class {
|
|
|
9010
9310
|
listSessionIds() {
|
|
9011
9311
|
this.assertCompatible();
|
|
9012
9312
|
const dbDir = this.pathProvider.getDatabaseDir();
|
|
9013
|
-
if (!
|
|
9014
|
-
return
|
|
9313
|
+
if (!fs13.existsSync(dbDir)) return [];
|
|
9314
|
+
return fs13.readdirSync(dbDir).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", "")).filter((id) => {
|
|
9015
9315
|
const db = this.open(id);
|
|
9016
9316
|
if (!db) return false;
|
|
9017
9317
|
return isChatSessionDb(db);
|
|
@@ -9023,8 +9323,8 @@ var DatabaseManager = class {
|
|
|
9023
9323
|
listSessionIdsReadonly() {
|
|
9024
9324
|
this.assertCompatible();
|
|
9025
9325
|
const dbDir = this.pathProvider.getDatabaseDir();
|
|
9026
|
-
if (!
|
|
9027
|
-
return
|
|
9326
|
+
if (!fs13.existsSync(dbDir)) return [];
|
|
9327
|
+
return fs13.readdirSync(dbDir).filter((fileName) => fileName.endsWith(".db")).map((fileName) => fileName.replace(".db", "")).filter((sessionId) => {
|
|
9028
9328
|
const db = this.openRawSessionDatabase(sessionId, { readonly: true });
|
|
9029
9329
|
try {
|
|
9030
9330
|
return isChatSessionDb(db);
|
|
@@ -9040,17 +9340,17 @@ var DatabaseManager = class {
|
|
|
9040
9340
|
* 获取数据库文件路径
|
|
9041
9341
|
*/
|
|
9042
9342
|
getDbPath(sessionId) {
|
|
9043
|
-
return
|
|
9343
|
+
return path21.join(this.pathProvider.getDatabaseDir(), `${sessionId}.db`);
|
|
9044
9344
|
}
|
|
9045
9345
|
openRawSessionDatabase(sessionId, options = {}) {
|
|
9046
9346
|
this.assertCompatible();
|
|
9047
9347
|
const dbPath = this.getDbPath(sessionId);
|
|
9048
|
-
if (!options.create && !
|
|
9348
|
+
if (!options.create && !fs13.existsSync(dbPath)) {
|
|
9049
9349
|
throw new Error(`Session database not found: ${sessionId}`);
|
|
9050
9350
|
}
|
|
9051
9351
|
if (!options.readonly) {
|
|
9052
9352
|
this.close(sessionId);
|
|
9053
|
-
|
|
9353
|
+
fs13.mkdirSync(path21.dirname(dbPath), { recursive: true });
|
|
9054
9354
|
}
|
|
9055
9355
|
const adapter = openBetterSqliteDatabase(dbPath, {
|
|
9056
9356
|
readonly: options.readonly ?? false,
|
|
@@ -9068,17 +9368,17 @@ var DatabaseManager = class {
|
|
|
9068
9368
|
deleteSessionDatabaseFiles(sessionId) {
|
|
9069
9369
|
this.close(sessionId);
|
|
9070
9370
|
const dbPath = this.getDbPath(sessionId);
|
|
9071
|
-
const existed = ["", "-wal", "-shm"].some((suffix) =>
|
|
9371
|
+
const existed = ["", "-wal", "-shm"].some((suffix) => fs13.existsSync(dbPath + suffix));
|
|
9072
9372
|
for (const suffix of ["", "-wal", "-shm"]) {
|
|
9073
9373
|
try {
|
|
9074
9374
|
const filePath = dbPath + suffix;
|
|
9075
|
-
if (
|
|
9375
|
+
if (fs13.existsSync(filePath)) fs13.unlinkSync(filePath);
|
|
9076
9376
|
} catch {
|
|
9077
9377
|
}
|
|
9078
9378
|
}
|
|
9079
9379
|
const cacheDir = this.pathProvider.getCacheDir();
|
|
9080
9380
|
deleteSessionCache(sessionId, cacheDir);
|
|
9081
|
-
deleteSessionCache(sessionId,
|
|
9381
|
+
deleteSessionCache(sessionId, path21.join(cacheDir, "query"));
|
|
9082
9382
|
deleteSessionCache(sessionId, getContactsFactsCacheDir(this.pathProvider.getUserDataDir()));
|
|
9083
9383
|
deleteSessionCache(sessionId, getGlobalInsightFactsCacheDir(this.pathProvider.getUserDataDir()));
|
|
9084
9384
|
deleteAnnualSummarySnapshots(getGlobalInsightDir(this.pathProvider.getUserDataDir()));
|
|
@@ -9119,12 +9419,12 @@ function shouldRepairCompatibilityGate(schemaVersion) {
|
|
|
9119
9419
|
}
|
|
9120
9420
|
|
|
9121
9421
|
// ../../packages/node-runtime/src/cache/analytics-cache.ts
|
|
9122
|
-
import * as
|
|
9422
|
+
import * as fs14 from "fs";
|
|
9123
9423
|
function getDbFileVersion(dbPath) {
|
|
9124
9424
|
const parts = [];
|
|
9125
9425
|
for (const p of [dbPath, `${dbPath}-wal`]) {
|
|
9126
9426
|
try {
|
|
9127
|
-
const st =
|
|
9427
|
+
const st = fs14.statSync(p);
|
|
9128
9428
|
parts.push(`${Math.floor(st.mtimeMs)}:${st.size}`);
|
|
9129
9429
|
} catch {
|
|
9130
9430
|
parts.push("-");
|
|
@@ -9229,6 +9529,11 @@ export {
|
|
|
9229
9529
|
writeConfigField,
|
|
9230
9530
|
ConfigSetError,
|
|
9231
9531
|
setConfigField,
|
|
9532
|
+
withFileLock,
|
|
9533
|
+
readJsonFile,
|
|
9534
|
+
writeJsonFileAtomically,
|
|
9535
|
+
deriveAuthProfileName,
|
|
9536
|
+
loadAuthProfiles,
|
|
9232
9537
|
resolveApiKey,
|
|
9233
9538
|
writeAuthProfile,
|
|
9234
9539
|
deleteAuthProfile,
|
|
@@ -9324,6 +9629,7 @@ export {
|
|
|
9324
9629
|
deleteMember,
|
|
9325
9630
|
getCatchphraseAnalysis,
|
|
9326
9631
|
getRelationshipStats,
|
|
9632
|
+
getJourneyStats,
|
|
9327
9633
|
getLanguagePreferenceAnalysis,
|
|
9328
9634
|
getDragonKingAnalysis,
|
|
9329
9635
|
getDivingAnalysis,
|
|
@@ -9338,8 +9644,10 @@ export {
|
|
|
9338
9644
|
CHART_CAPABILITY_SKILL_ID,
|
|
9339
9645
|
BUILTIN_TOOL_CATALOG,
|
|
9340
9646
|
BUILTIN_PROVIDERS,
|
|
9647
|
+
getBuiltinProviderById,
|
|
9341
9648
|
BUILTIN_MODELS,
|
|
9342
9649
|
getBuiltinModelsByProvider,
|
|
9650
|
+
getBuiltinModelById,
|
|
9343
9651
|
stripAvatarFields,
|
|
9344
9652
|
StreamingThinkTagParser,
|
|
9345
9653
|
needsStreamingThinkParsing,
|
|
@@ -9412,4 +9720,4 @@ export {
|
|
|
9412
9720
|
StaticPathProvider,
|
|
9413
9721
|
createDatabaseManagerAdapter
|
|
9414
9722
|
};
|
|
9415
|
-
//# sourceMappingURL=chunk-
|
|
9723
|
+
//# sourceMappingURL=chunk-OLE2USEN.mjs.map
|