chatlab-cli 0.33.0 → 0.34.1

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 (113) hide show
  1. package/dist/{chat-command-IHRNO7J4.mjs → chat-command-OWKJJ736.mjs} +9 -9
  2. package/dist/{chunk-C3B7RXES.mjs → chunk-3RWYALUP.mjs} +629 -319
  3. package/dist/chunk-3RWYALUP.mjs.map +1 -0
  4. package/dist/{chunk-4V6UP7EW.mjs → chunk-GHZFNAMF.mjs} +2 -2
  5. package/dist/{chunk-NHTOSDYI.mjs → chunk-J7HAIT3T.mjs} +15 -9
  6. package/dist/chunk-J7HAIT3T.mjs.map +1 -0
  7. package/dist/{chunk-HGV4MUIW.mjs → chunk-MPHFZYB7.mjs} +15 -62
  8. package/dist/chunk-MPHFZYB7.mjs.map +1 -0
  9. package/dist/{chunk-U4F6BNGZ.mjs → chunk-OHFVX2HH.mjs} +2 -2
  10. package/dist/{chunk-YAQLYL52.mjs → chunk-QZCNVAH6.mjs} +2 -2
  11. package/dist/{chunk-YAQLYL52.mjs.map → chunk-QZCNVAH6.mjs.map} +1 -1
  12. package/dist/{chunk-ZTMZ7S7T.mjs → chunk-RMW3524R.mjs} +46 -66
  13. package/dist/chunk-RMW3524R.mjs.map +1 -0
  14. package/dist/{chunk-KWJ5FZ74.mjs → chunk-RRC6U56Y.mjs} +640 -296
  15. package/dist/chunk-RRC6U56Y.mjs.map +1 -0
  16. package/dist/{chunk-NSWFHMBZ.mjs → chunk-VTCZM2JS.mjs} +11 -11
  17. package/dist/{chunk-S7YPBKQ3.mjs → chunk-XEGEOU2D.mjs} +2 -2
  18. package/dist/{chunk-RHA534GU.mjs → chunk-YRCFDZ5Q.mjs} +3 -3
  19. package/dist/{chunk-ZERQIKI4.mjs → chunk-ZM5DSHFF.mjs} +95 -5
  20. package/dist/chunk-ZM5DSHFF.mjs.map +1 -0
  21. package/dist/cli.mjs +9 -9
  22. package/dist/contacts-worker.mjs +2 -2
  23. package/dist/global-insight-worker.mjs +2 -2
  24. package/dist/{http-Y2WC2UK4.mjs → http-X55S6MTO.mjs} +12 -12
  25. package/dist/{import-4HF2UNQI.mjs → import-4AX6IX57.mjs} +8 -8
  26. package/dist/index.mjs +12 -12
  27. package/dist/{mcp-DJPDRFTW.mjs → mcp-GWC52AWE.mjs} +9 -9
  28. package/dist/people-relationships-worker.mjs +2 -2
  29. package/dist/semantic-index-worker.mjs +1 -1
  30. package/dist/{src-R7MZLKXQ.mjs → src-DLLM4SEO.mjs} +11 -7
  31. package/dist/{stream-import-DX57ANUL.mjs → stream-import-K24HWAAZ.mjs} +8 -8
  32. package/dist/{worker-runtime-QMN7OKOZ.mjs → worker-runtime-6KKR55TD.mjs} +6 -6
  33. package/dist-cli-web/assets/{ActionToolsPanel.vue_vue_type_script_setup_true_lang-hwRVh048.js → ActionToolsPanel.vue_vue_type_script_setup_true_lang-D1BiZuQL.js} +5 -5
  34. package/dist-cli-web/assets/{BufferResource-DwfMBlAa.js → BufferResource-IPkSmPao.js} +1 -1
  35. package/dist-cli-web/assets/{CanvasRenderer-q312LRsp.js → CanvasRenderer-OAQy65em.js} +1 -1
  36. package/dist-cli-web/assets/{DataDirCleanupNotice--ee1dY0d.js → DataDirCleanupNotice-jEI-YjFp.js} +1 -1
  37. package/dist-cli-web/assets/{EChartWordcloud-BaMgUl0Y.js → EChartWordcloud-Pi48JdN2.js} +1 -1
  38. package/dist-cli-web/assets/{Filter-BOb5cLBx.js → Filter-FQD30cRE.js} +1 -1
  39. package/dist-cli-web/assets/LoadingState.vue_vue_type_script_setup_true_lang-CCK5yTju.js +1 -0
  40. package/dist-cli-web/assets/{MessageExportModal-CFbovWh1.js → MessageExportModal-CZn3LbeY.js} +1 -1
  41. package/dist-cli-web/assets/{PageHeader-B3-W9mvh.js → PageHeader-B9B9K9by.js} +1 -1
  42. package/dist-cli-web/assets/{RelationshipGalaxyCanvas-GEpsKHxV.js → RelationshipGalaxyCanvas-CbTmpnZ6.js} +14 -14
  43. package/dist-cli-web/assets/{RelationshipGalaxyThreeCanvas-BluPHjCR.css → RelationshipGalaxyThreeCanvas-CeYJABxI.css} +1 -1
  44. package/dist-cli-web/assets/{RelationshipGalaxyThreeCanvas-DHOU66Gj.js → RelationshipGalaxyThreeCanvas-Cu6NmKOq.js} +14 -14
  45. package/dist-cli-web/assets/{RenderTargetSystem-PEnnW2yb.js → RenderTargetSystem-DnptJCQ0.js} +1 -1
  46. package/dist-cli-web/assets/{ThemeCard.vue_vue_type_script_setup_true_lang-sNw3hP4c.js → ThemeCard.vue_vue_type_script_setup_true_lang-JXMFY6aD.js} +1 -1
  47. package/dist-cli-web/assets/{TimeSelect.vue_vue_type_script_setup_true_lang-BtUvMehe.js → TimeSelect.vue_vue_type_script_setup_true_lang-QAZFwx5S.js} +1 -1
  48. package/dist-cli-web/assets/{WebGLRenderer-BjP_1do7.js → WebGLRenderer-BmjIF5se.js} +1 -1
  49. package/dist-cli-web/assets/{WebGPURenderer-ldVv92u7.js → WebGPURenderer-DkNcKkqj.js} +1 -1
  50. package/dist-cli-web/assets/{annual-summary-time-range-BHClzNvd.js → annual-summary-time-range-DJ0HWI_t.js} +1 -1
  51. package/dist-cli-web/assets/{base-DBJ95yXf.js → base-CnuE0ss0.js} +1 -1
  52. package/dist-cli-web/assets/{browserAll-CPoMOLKh.js → browserAll-C_NnyNBz.js} +1 -1
  53. package/dist-cli-web/assets/{cli-web-B5VYO-Dh.js → cli-web-t1gabACJ.js} +1 -1
  54. package/dist-cli-web/assets/{dateFormat-Cf2xuaE-.js → dateFormat-p6nibkgt.js} +1 -1
  55. package/dist-cli-web/assets/{fetch-J67jyI2k.js → fetch-BBUvWvOM.js} +1 -1
  56. package/dist-cli-web/assets/{fetch-BuWxo6oK.js → fetch-BfYranz7.js} +1 -1
  57. package/dist-cli-web/assets/{fetch-CXIdj2-_.js → fetch-Bsm5YQ_7.js} +1 -1
  58. package/dist-cli-web/assets/{fetch-Dr41uuXL.js → fetch-C4KJ7tGz.js} +1 -1
  59. package/dist-cli-web/assets/fetch-CMhV3TYQ.js +1 -0
  60. package/dist-cli-web/assets/{fetch-C0HHT1Yn.js → fetch-Ch4IMKin.js} +1 -1
  61. package/dist-cli-web/assets/{fetch-B1km2u3N.js → fetch-DajjPQtq.js} +1 -1
  62. package/dist-cli-web/assets/{fetch-BFDKzf1P.js → fetch-WElo3Vix.js} +1 -1
  63. package/dist-cli-web/assets/{fetch-DGi_9my2.js → fetch-WIOgRPd9.js} +1 -1
  64. package/dist-cli-web/assets/{fetch-CtyVktRW.js → fetch-_Hb-KRSr.js} +3 -3
  65. package/dist-cli-web/assets/index-B8I5Pax_.js +2 -0
  66. package/dist-cli-web/assets/index-BE4nd1aX.js +1 -0
  67. package/dist-cli-web/assets/{index-B7R74Yp7.js → index-Bb6EtLMB.js} +1 -1
  68. package/dist-cli-web/assets/{index-DzQT-qXF.js → index-BcWaPFz7.js} +1 -1
  69. package/dist-cli-web/assets/index-CKkIHbie.js +64 -0
  70. package/dist-cli-web/assets/index-CbacXZN3.js +2 -0
  71. package/dist-cli-web/assets/{index-DtlTo3nt.js → index-CjoTcSEc.js} +1 -1
  72. package/dist-cli-web/assets/index-CsX1Wt8l.js +173 -0
  73. package/dist-cli-web/assets/{index-BGiTw98l.js → index-CsyURmWU.js} +1 -1
  74. package/dist-cli-web/assets/{index-5UdyJtVU.js → index-DLnlRLCx.js} +1 -1
  75. package/dist-cli-web/assets/index-DrjoMv9s.css +1 -0
  76. package/dist-cli-web/assets/index-Jhwca9kg.css +1 -0
  77. package/dist-cli-web/assets/index-YzfjPohq.js +53 -0
  78. package/dist-cli-web/assets/{index-Bf3gFaid.js → index-dObiAHg6.js} +1 -1
  79. package/dist-cli-web/assets/index-vtF05fh7.css +1 -0
  80. package/dist-cli-web/assets/{index-Ba21yU86.js → index-x74lBtei.js} +1 -1
  81. package/dist-cli-web/assets/{people-page-header-BvQy1GQj.js → people-page-header-BW5cNPl7.js} +1 -1
  82. package/dist-cli-web/assets/{webworkerAll-DgKQKbNn.js → webworkerAll-8AFsQkH1.js} +1 -1
  83. package/dist-cli-web/index.html +2 -2
  84. package/package.json +1 -1
  85. package/dist/chunk-C3B7RXES.mjs.map +0 -1
  86. package/dist/chunk-HGV4MUIW.mjs.map +0 -1
  87. package/dist/chunk-KWJ5FZ74.mjs.map +0 -1
  88. package/dist/chunk-NHTOSDYI.mjs.map +0 -1
  89. package/dist/chunk-ZERQIKI4.mjs.map +0 -1
  90. package/dist/chunk-ZTMZ7S7T.mjs.map +0 -1
  91. package/dist-cli-web/assets/LoadingState.vue_vue_type_script_setup_true_lang-DK2z0Jrh.js +0 -1
  92. package/dist-cli-web/assets/fetch-80O3EH4a.js +0 -1
  93. package/dist-cli-web/assets/index-7jm3YI9u.js +0 -53
  94. package/dist-cli-web/assets/index-ByQSR8Bj.js +0 -2
  95. package/dist-cli-web/assets/index-CPZYydbc.js +0 -2
  96. package/dist-cli-web/assets/index-D8Q3U-6e.js +0 -1
  97. package/dist-cli-web/assets/index-DGtDxRCd.js +0 -173
  98. package/dist-cli-web/assets/index-DTxnpQiv.css +0 -1
  99. package/dist-cli-web/assets/index-gpTDI3sq.js +0 -64
  100. package/dist-cli-web/assets/index-lwhCMqhd.css +0 -1
  101. package/dist-cli-web/assets/index-qsbWn8VP.css +0 -1
  102. /package/dist/{chat-command-IHRNO7J4.mjs.map → chat-command-OWKJJ736.mjs.map} +0 -0
  103. /package/dist/{chunk-4V6UP7EW.mjs.map → chunk-GHZFNAMF.mjs.map} +0 -0
  104. /package/dist/{chunk-U4F6BNGZ.mjs.map → chunk-OHFVX2HH.mjs.map} +0 -0
  105. /package/dist/{chunk-NSWFHMBZ.mjs.map → chunk-VTCZM2JS.mjs.map} +0 -0
  106. /package/dist/{chunk-S7YPBKQ3.mjs.map → chunk-XEGEOU2D.mjs.map} +0 -0
  107. /package/dist/{chunk-RHA534GU.mjs.map → chunk-YRCFDZ5Q.mjs.map} +0 -0
  108. /package/dist/{http-Y2WC2UK4.mjs.map → http-X55S6MTO.mjs.map} +0 -0
  109. /package/dist/{import-4HF2UNQI.mjs.map → import-4AX6IX57.mjs.map} +0 -0
  110. /package/dist/{mcp-DJPDRFTW.mjs.map → mcp-GWC52AWE.mjs.map} +0 -0
  111. /package/dist/{src-R7MZLKXQ.mjs.map → src-DLLM4SEO.mjs.map} +0 -0
  112. /package/dist/{stream-import-DX57ANUL.mjs.map → stream-import-K24HWAAZ.mjs.map} +0 -0
  113. /package/dist/{worker-runtime-QMN7OKOZ.mjs.map → worker-runtime-6KKR55TD.mjs.map} +0 -0
@@ -9,7 +9,7 @@ import {
9
9
  createEmptyContactsDiagnostics,
10
10
  normalizeContactsTimeRangePreset,
11
11
  resolveContactsTimeRange
12
- } from "./chunk-4V6UP7EW.mjs";
12
+ } from "./chunk-GHZFNAMF.mjs";
13
13
  import {
14
14
  PEOPLE_RELATIONSHIPS_ALGORITHM_VERSION,
15
15
  buildPeopleRelationshipsNeighborhoodGraph,
@@ -18,10 +18,10 @@ import {
18
18
  computePeopleRelationshipsSnapshot,
19
19
  normalizePeopleRelationshipsTimeRangePreset,
20
20
  resolvePeopleRelationshipsTimeRange
21
- } from "./chunk-S7YPBKQ3.mjs";
21
+ } from "./chunk-XEGEOU2D.mjs";
22
22
  import {
23
23
  ANNUAL_SUMMARY_ALGORITHM_VERSION
24
- } from "./chunk-YAQLYL52.mjs";
24
+ } from "./chunk-QZCNVAH6.mjs";
25
25
  import {
26
26
  BUILTIN_MODELS,
27
27
  BUILTIN_PROVIDERS,
@@ -51,11 +51,14 @@ import {
51
51
  deleteAuthProfile,
52
52
  deleteMember,
53
53
  deleteMembers,
54
+ deriveAuthProfileName,
54
55
  generateIncrementalSessionIndex,
55
56
  generateMessageKey,
56
57
  generateSessionIndex,
57
58
  getAnnualSummarySnapshotPath,
59
+ getBuiltinModelById,
58
60
  getBuiltinModelsByProvider,
61
+ getBuiltinProviderById,
59
62
  getChatSessionList,
60
63
  getContactsDir,
61
64
  getContactsFactsCacheDir,
@@ -80,6 +83,7 @@ import {
80
83
  isNameMatchPlatform,
81
84
  isReasoningModel,
82
85
  isSupportedChatLabFormatVersion,
86
+ loadAuthProfiles,
83
87
  matchOwnerProfile,
84
88
  mergeConfirmedNames,
85
89
  mergeMembers,
@@ -88,6 +92,7 @@ import {
88
92
  normalizeBuiltinToolNames,
89
93
  openBetterSqliteDatabase,
90
94
  readAnnualSummarySnapshot,
95
+ readJsonFile,
91
96
  renameSession,
92
97
  resolveApiKey,
93
98
  saveSegmentSummary,
@@ -100,10 +105,12 @@ import {
100
105
  truncateToolResultText,
101
106
  updateMemberAliases,
102
107
  updateSessionOwnerId,
108
+ withFileLock,
103
109
  writeAnnualSummarySnapshot,
104
110
  writeAuthProfile,
111
+ writeJsonFileAtomically,
105
112
  writeParseResultToDb
106
- } from "./chunk-C3B7RXES.mjs";
113
+ } from "./chunk-3RWYALUP.mjs";
107
114
  import {
108
115
  __commonJS,
109
116
  __export,
@@ -1461,7 +1468,7 @@ var require_pend = __commonJS({
1461
1468
  var require_fd_slicer = __commonJS({
1462
1469
  "../../packages/node-runtime/node_modules/yauzl/fd-slicer.js"(exports) {
1463
1470
  "use strict";
1464
- var fs37 = __require("fs");
1471
+ var fs36 = __require("fs");
1465
1472
  var util = __require("util");
1466
1473
  var stream = __require("stream");
1467
1474
  var Readable = stream.Readable;
@@ -1481,7 +1488,7 @@ var require_fd_slicer = __commonJS({
1481
1488
  FdSlicer.prototype.read = function(buffer, offset, length, position, callback) {
1482
1489
  var self = this;
1483
1490
  self.pend.go(function(cb) {
1484
- fs37.read(self.fd, buffer, offset, length, position, function(err, bytesRead, buffer2) {
1491
+ fs36.read(self.fd, buffer, offset, length, position, function(err, bytesRead, buffer2) {
1485
1492
  cb();
1486
1493
  callback(err, bytesRead, buffer2);
1487
1494
  });
@@ -1498,7 +1505,7 @@ var require_fd_slicer = __commonJS({
1498
1505
  self.refCount -= 1;
1499
1506
  if (self.refCount < 0) throw new Error("invalid unref");
1500
1507
  if (self.refCount > 0) return;
1501
- fs37.close(self.fd, onCloseDone);
1508
+ fs36.close(self.fd, onCloseDone);
1502
1509
  function onCloseDone(err) {
1503
1510
  if (err) {
1504
1511
  self.emit("error", err);
@@ -1530,7 +1537,7 @@ var require_fd_slicer = __commonJS({
1530
1537
  }
1531
1538
  self.context.pend.go(function(cb) {
1532
1539
  var buffer = Buffer.allocUnsafe(toRead);
1533
- fs37.read(self.context.fd, buffer, 0, toRead, self.pos, function(err, bytesRead) {
1540
+ fs36.read(self.context.fd, buffer, 0, toRead, self.pos, function(err, bytesRead) {
1534
1541
  if (err) {
1535
1542
  self.destroy(err);
1536
1543
  } else if (bytesRead === 0) {
@@ -1892,7 +1899,7 @@ var require_crc32 = __commonJS({
1892
1899
  var require_yauzl = __commonJS({
1893
1900
  "../../packages/node-runtime/node_modules/yauzl/index.js"(exports) {
1894
1901
  "use strict";
1895
- var fs37 = __require("fs");
1902
+ var fs36 = __require("fs");
1896
1903
  var zlib = __require("zlib");
1897
1904
  var fd_slicer = require_fd_slicer();
1898
1905
  var util = __require("util");
@@ -1961,10 +1968,10 @@ var require_yauzl = __commonJS({
1961
1968
  if (options2.validateEntrySizes == null) options2.validateEntrySizes = true;
1962
1969
  if (options2.strictFileNames == null) options2.strictFileNames = false;
1963
1970
  if (callback == null) callback = defaultCallback;
1964
- fs37.open(path30, "r", function(err, fd) {
1971
+ fs36.open(path30, "r", function(err, fd) {
1965
1972
  if (err) return callback(err);
1966
1973
  fromFd(fd, options2, function(err2, zipfile) {
1967
- if (err2) fs37.close(fd, defaultCallback);
1974
+ if (err2) fs36.close(fd, defaultCallback);
1968
1975
  callback(err2, zipfile);
1969
1976
  });
1970
1977
  });
@@ -1981,7 +1988,7 @@ var require_yauzl = __commonJS({
1981
1988
  if (options2.validateEntrySizes == null) options2.validateEntrySizes = true;
1982
1989
  if (options2.strictFileNames == null) options2.strictFileNames = false;
1983
1990
  if (callback == null) callback = defaultCallback;
1984
- fs37.fstat(fd, function(err, stats) {
1991
+ fs36.fstat(fd, function(err, stats) {
1985
1992
  if (err) return callback(err);
1986
1993
  var reader = new fd_slicer.FdSlicer(fd);
1987
1994
  fromRandomAccessReader(reader, stats.size, options2, callback);
@@ -2840,6 +2847,14 @@ function matchFilenameSignatures(filePath, patterns) {
2840
2847
  const filename = path2.basename(filePath);
2841
2848
  return patterns.some((pattern) => pattern.test(filename));
2842
2849
  }
2850
+ function matchFilenameFallbackPatterns(filePath, patterns) {
2851
+ try {
2852
+ const content = fs2.readFileSync(filePath, "utf-8");
2853
+ return patterns.every((pattern) => pattern.test(content));
2854
+ } catch {
2855
+ return false;
2856
+ }
2857
+ }
2843
2858
  function matchRequiredFields(headContent, fields) {
2844
2859
  return fields.every((field) => {
2845
2860
  const pattern = new RegExp(`"${field.replace(".", '"\\s*:\\s*.*"')}"\\s*:`);
@@ -2961,6 +2976,11 @@ var FormatSniffer = class {
2961
2976
  return false;
2962
2977
  }
2963
2978
  }
2979
+ if (!headMatch && filenameMatch && signatures.filenameFallbackPatterns) {
2980
+ if (!filePath || !matchFilenameFallbackPatterns(filePath, signatures.filenameFallbackPatterns)) {
2981
+ return false;
2982
+ }
2983
+ }
2964
2984
  if (signatures.requiredFields && signatures.requiredFields.length > 0) {
2965
2985
  if (!matchRequiredFields(headContent, signatures.requiredFields)) {
2966
2986
  return false;
@@ -4082,8 +4102,10 @@ var feature4 = {
4082
4102
  // 比单文件版本优先级更高
4083
4103
  extensions: [".json"],
4084
4104
  signatures: {
4085
- // 使用 head 签名 "format": "chunked-jsonl" 来区分。
4086
- head: [/"format"\s*:\s*"chunked-jsonl"/],
4105
+ // V5 使用 metadata.format,0.1.x 将格式标识移至 chunked.format
4106
+ head: [/"format"\s*:\s*"chunked-jsonl"/, /"chunked"\s*:\s*\{[^{}]*"format"\s*:\s*"jsonl"/],
4107
+ filename: [/^manifest\.json$/i],
4108
+ filenameFallbackPatterns: [/"chunked"\s*:\s*\{[\s\S]*?"format"\s*:\s*"jsonl"/],
4087
4109
  requiredFields: ["metadata", "chatInfo"]
4088
4110
  }
4089
4111
  };
@@ -4214,9 +4236,10 @@ async function* parseChunkedJsonl(options2) {
4214
4236
  yield { type: "error", data: new Error(`\u65E0\u6CD5\u8BFB\u53D6 manifest.json: ${errorMsg}`) };
4215
4237
  return;
4216
4238
  }
4217
- if (manifest.metadata.format !== "chunked-jsonl") {
4218
- onLog?.("error", `\u4E0D\u652F\u6301\u7684\u683C\u5F0F: ${manifest.metadata.format}`);
4219
- yield { type: "error", data: new Error(`\u4E0D\u652F\u6301\u7684\u683C\u5F0F: ${manifest.metadata.format}`) };
4239
+ if (manifest.metadata.format !== "chunked-jsonl" && manifest.chunked.format !== "jsonl") {
4240
+ const format = manifest.metadata.format ?? manifest.chunked.format ?? "unknown";
4241
+ onLog?.("error", `\u4E0D\u652F\u6301\u7684\u683C\u5F0F: ${format}`);
4242
+ yield { type: "error", data: new Error(`\u4E0D\u652F\u6301\u7684\u683C\u5F0F: ${format}`) };
4220
4243
  return;
4221
4244
  }
4222
4245
  const totalBytes = calculateTotalBytes(manifest, baseDir);
@@ -6736,6 +6759,8 @@ var MAX_UNIX_SECONDS = 1e11;
6736
6759
  var KNOWN_MESSAGE_TYPES = new Set(
6737
6760
  Object.values(MessageType).filter((value) => typeof value === "number")
6738
6761
  );
6762
+ var SYSTEM_SENDER_ID = "SYSTEM";
6763
+ var SYSTEM_SENDER_MESSAGE_TYPES = /* @__PURE__ */ new Set([80 /* SYSTEM */, 81 /* RECALL */]);
6739
6764
  function createState(format, fileSize) {
6740
6765
  return {
6741
6766
  format,
@@ -6910,8 +6935,9 @@ function validateMessage(state, value, path30, location) {
6910
6935
  addIssue(state, "error", "INVALID_MESSAGE", "Expected a message object.", childLocation(location, path30));
6911
6936
  return;
6912
6937
  }
6913
- if (validateRequiredString(state, value.sender, `${path30}.sender`, location)) {
6914
- state.senderIds.add(value.sender);
6938
+ const sender = validateRequiredString(state, value.sender, `${path30}.sender`, location) ? value.sender : void 0;
6939
+ if (sender !== void 0) {
6940
+ state.senderIds.add(sender);
6915
6941
  }
6916
6942
  validateRequiredString(state, value.accountName, `${path30}.accountName`, location);
6917
6943
  if (validateUnixSeconds(state, value.timestamp, `${path30}.timestamp`, location)) {
@@ -6926,11 +6952,20 @@ function validateMessage(state, value, path30, location) {
6926
6952
  }
6927
6953
  state.lastTimestamp = value.timestamp;
6928
6954
  }
6929
- if (typeof value.type !== "number" || !Number.isInteger(value.type) || !KNOWN_MESSAGE_TYPES.has(value.type)) {
6955
+ const messageType = typeof value.type === "number" && Number.isInteger(value.type) && KNOWN_MESSAGE_TYPES.has(value.type) ? value.type : void 0;
6956
+ if (messageType === void 0) {
6930
6957
  addIssue(state, "error", "INVALID_MESSAGE_TYPE", "Expected a supported numeric ChatLab message type.", {
6931
6958
  ...location,
6932
6959
  path: `${path30}.type`
6933
6960
  });
6961
+ } else if (sender === SYSTEM_SENDER_ID && !SYSTEM_SENDER_MESSAGE_TYPES.has(messageType)) {
6962
+ addIssue(
6963
+ state,
6964
+ "error",
6965
+ "INVALID_SYSTEM_SENDER_TYPE",
6966
+ "The reserved SYSTEM sender is only valid for system and recall messages.",
6967
+ childLocation(location, `${path30}.sender`)
6968
+ );
6934
6969
  }
6935
6970
  if (!hasOwn(value, "content") || typeof value.content !== "string" && value.content !== null) {
6936
6971
  addIssue(state, "error", "INVALID_MESSAGE_CONTENT", "Expected content to be a string or null.", {
@@ -6979,7 +7014,7 @@ function finalizeState(state, requireExplicitMembers, enforceRequiredSections =
6979
7014
  }
6980
7015
  if (state.memberIds.size > 0) {
6981
7016
  for (const senderId of state.senderIds) {
6982
- if (!state.memberIds.has(senderId)) {
7017
+ if (senderId !== SYSTEM_SENDER_ID && !state.memberIds.has(senderId)) {
6983
7018
  addIssue(
6984
7019
  state,
6985
7020
  "error",
@@ -7118,6 +7153,154 @@ async function validateChatLabFile(filePath) {
7118
7153
  return finalizeState(state, false, false);
7119
7154
  }
7120
7155
 
7156
+ // ../../packages/parser/src/chatlab-demo-timeline.ts
7157
+ var SECONDS_PER_MINUTE = 60;
7158
+ var DEFAULT_DEMO_TIME_ZONE_OFFSET_MINUTES = 8 * 60;
7159
+ var MAX_TIME_ZONE_OFFSET_MINUTES = 14 * 60;
7160
+ function rebaseChatLabDemoDocuments(jsonDocuments, now = /* @__PURE__ */ new Date(), targetTimeZone) {
7161
+ if (jsonDocuments.length === 0) throw new Error("Demo timeline requires at least one document");
7162
+ if (!Number.isFinite(now.getTime())) throw new Error("Demo timeline requires a valid import time");
7163
+ const documents = jsonDocuments.map((json, index) => parseDemoDocument(json, index));
7164
+ const timeZoneOffsetMinutes = resolveTimeZoneOffsetMinutes(documents);
7165
+ const sourceLatestTimestamp = Math.max(
7166
+ ...documents.flatMap((document) => document.messages.map((message) => message.timestamp))
7167
+ );
7168
+ const sourceLatestWallTime = new Date((sourceLatestTimestamp + timeZoneOffsetMinutes * SECONDS_PER_MINUTE) * 1e3);
7169
+ const latestTimestamp = resolveTargetLatestTimestamp(now, sourceLatestWallTime, targetTimeZone);
7170
+ const offsetSeconds = latestTimestamp - sourceLatestTimestamp;
7171
+ const exportedAt = Math.floor(now.getTime() / 1e3);
7172
+ for (const document of documents) {
7173
+ document.chatlab.exportedAt = exportedAt;
7174
+ for (const message of document.messages) {
7175
+ message.timestamp += offsetSeconds;
7176
+ }
7177
+ }
7178
+ return {
7179
+ documents: documents.map((document) => JSON.stringify(document)),
7180
+ offsetSeconds,
7181
+ latestTimestamp
7182
+ };
7183
+ }
7184
+ function resolveTargetLatestTimestamp(now, sourceWallTime, targetTimeZone) {
7185
+ if (!targetTimeZone) {
7186
+ const targetLatestTime = new Date(now);
7187
+ targetLatestTime.setDate(targetLatestTime.getDate() - 1);
7188
+ targetLatestTime.setHours(
7189
+ sourceWallTime.getUTCHours(),
7190
+ sourceWallTime.getUTCMinutes(),
7191
+ sourceWallTime.getUTCSeconds(),
7192
+ 0
7193
+ );
7194
+ return Math.floor(targetLatestTime.getTime() / 1e3);
7195
+ }
7196
+ let formatter;
7197
+ try {
7198
+ formatter = new Intl.DateTimeFormat("en-US-u-ca-gregory-nu-latn", {
7199
+ timeZone: targetTimeZone,
7200
+ year: "numeric",
7201
+ month: "2-digit",
7202
+ day: "2-digit",
7203
+ hour: "2-digit",
7204
+ minute: "2-digit",
7205
+ second: "2-digit",
7206
+ hourCycle: "h23"
7207
+ });
7208
+ } catch {
7209
+ throw new Error("Demo timeline has an invalid target time zone");
7210
+ }
7211
+ const currentDate = getZonedDateTimeParts(now, formatter);
7212
+ const yesterday = new Date(Date.UTC(currentDate.year, currentDate.month - 1, currentDate.day - 1));
7213
+ const targetParts = {
7214
+ year: yesterday.getUTCFullYear(),
7215
+ month: yesterday.getUTCMonth() + 1,
7216
+ day: yesterday.getUTCDate(),
7217
+ hour: sourceWallTime.getUTCHours(),
7218
+ minute: sourceWallTime.getUTCMinutes(),
7219
+ second: sourceWallTime.getUTCSeconds()
7220
+ };
7221
+ return Math.floor(zonedWallTimeToUnixMillis(targetParts, formatter) / 1e3);
7222
+ }
7223
+ function getZonedDateTimeParts(date, formatter) {
7224
+ const values = new Map(formatter.formatToParts(date).map((part) => [part.type, part.value]));
7225
+ const read = (type) => Number(values.get(type));
7226
+ const parts = {
7227
+ year: read("year"),
7228
+ month: read("month"),
7229
+ day: read("day"),
7230
+ hour: read("hour"),
7231
+ minute: read("minute"),
7232
+ second: read("second")
7233
+ };
7234
+ if (Object.values(parts).some((value) => !Number.isInteger(value))) {
7235
+ throw new Error("Demo timeline could not resolve the target time zone");
7236
+ }
7237
+ return parts;
7238
+ }
7239
+ function zonedWallTimeToUnixMillis(target, formatter) {
7240
+ const targetAsUtc = dateTimePartsToUtcMillis(target);
7241
+ let candidate = targetAsUtc;
7242
+ for (let attempt = 0; attempt < 3; attempt++) {
7243
+ const actual2 = getZonedDateTimeParts(new Date(candidate), formatter);
7244
+ const correction = targetAsUtc - dateTimePartsToUtcMillis(actual2);
7245
+ candidate += correction;
7246
+ if (correction === 0) return candidate;
7247
+ }
7248
+ const actual = getZonedDateTimeParts(new Date(candidate), formatter);
7249
+ if (dateTimePartsToUtcMillis(actual) !== targetAsUtc) {
7250
+ throw new Error("Demo timeline target wall time does not exist in the selected time zone");
7251
+ }
7252
+ return candidate;
7253
+ }
7254
+ function dateTimePartsToUtcMillis(parts) {
7255
+ return Date.UTC(parts.year, parts.month - 1, parts.day, parts.hour, parts.minute, parts.second);
7256
+ }
7257
+ function parseDemoDocument(json, index) {
7258
+ let value;
7259
+ try {
7260
+ value = JSON.parse(json);
7261
+ } catch {
7262
+ throw new Error(`Demo document ${index + 1} is not valid JSON`);
7263
+ }
7264
+ if (!isRecord2(value) || !isRecord2(value.chatlab) || !Array.isArray(value.messages)) {
7265
+ throw new Error(`Demo document ${index + 1} is not a ChatLab JSON document`);
7266
+ }
7267
+ if (value.messages.length === 0) {
7268
+ throw new Error(`Demo document ${index + 1} has no messages`);
7269
+ }
7270
+ const messages = value.messages.map((message, messageIndex) => {
7271
+ if (!isRecord2(message) || !isUnixSeconds(message.timestamp)) {
7272
+ throw new Error(`Demo document ${index + 1} has an invalid timestamp at message ${messageIndex + 1}`);
7273
+ }
7274
+ return message;
7275
+ });
7276
+ return {
7277
+ ...value,
7278
+ chatlab: value.chatlab,
7279
+ messages
7280
+ };
7281
+ }
7282
+ function resolveTimeZoneOffsetMinutes(documents) {
7283
+ const offsets = /* @__PURE__ */ new Set();
7284
+ for (const document of documents) {
7285
+ const configured = document.chatlab.demoTimeline?.timeZoneOffsetMinutes;
7286
+ const offset = configured ?? DEFAULT_DEMO_TIME_ZONE_OFFSET_MINUTES;
7287
+ if (typeof offset !== "number" || !Number.isInteger(offset) || Math.abs(offset) > MAX_TIME_ZONE_OFFSET_MINUTES) {
7288
+ throw new Error("Demo timeline has an invalid time zone offset");
7289
+ }
7290
+ offsets.add(offset);
7291
+ }
7292
+ if (offsets.size !== 1) {
7293
+ throw new Error("Demo documents must use the same time zone offset");
7294
+ }
7295
+ return offsets.values().next().value;
7296
+ }
7297
+ function isUnixSeconds(value) {
7298
+ return typeof value === "number" && Number.isInteger(value) && value >= 0;
7299
+ }
7300
+ function isRecord2(value) {
7301
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7302
+ }
7303
+
7121
7304
  // ../../packages/parser/src/index.ts
7122
7305
  var sniffer = createSniffer();
7123
7306
  sniffer.registerAll(formats);
@@ -7681,15 +7864,21 @@ function registerMessageAndCheckDuplicate(message, state) {
7681
7864
  // ../../packages/node-runtime/src/import/streaming-importer.ts
7682
7865
  var BATCH_COMMIT_SIZE = 5e4;
7683
7866
  var CHECKPOINT_INTERVAL = 2e5;
7867
+ var SYSTEM_SENDER_ID2 = "SYSTEM";
7868
+ var SYSTEM_MEMBER_NAME = "\u7CFB\u7EDF\u6D88\u606F";
7869
+ var RESERVED_SYSTEM_SENDER_FORMATS = /* @__PURE__ */ new Set(["chatlab", "chatlab-jsonl"]);
7684
7870
  var yieldToEventLoop = () => new Promise((resolve4) => setImmediate(resolve4));
7685
7871
  function defaultGenerateSessionId() {
7686
7872
  const ts = Date.now();
7687
7873
  const rand = Math.random().toString(36).substring(2, 8);
7688
7874
  return `chat_${ts}_${rand}`;
7689
7875
  }
7690
- function prepareMessageForCreate(message) {
7876
+ function normalizeSystemMemberName(formatId, platformId, name) {
7877
+ return RESERVED_SYSTEM_SENDER_FORMATS.has(formatId) && platformId === SYSTEM_SENDER_ID2 ? SYSTEM_MEMBER_NAME : name;
7878
+ }
7879
+ function prepareMessageForCreate(message, senderAccountName = message.senderAccountName) {
7691
7880
  if (!message.senderPlatformId) return { skipCounter: "skippedNoSenderId" };
7692
- if (!message.senderAccountName) return { skipCounter: "skippedNoAccountName" };
7881
+ if (!senderAccountName) return { skipCounter: "skippedNoAccountName" };
7693
7882
  if (message.timestamp === void 0 || message.timestamp === null || isNaN(message.timestamp)) {
7694
7883
  return { skipCounter: "skippedInvalidTimestamp" };
7695
7884
  }
@@ -7903,10 +8092,12 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
7903
8092
  callbackStats.totalMembersReceived += members.length;
7904
8093
  logger?.info(`Received member batch: ${members.length} members`);
7905
8094
  for (const member of members) {
8095
+ const accountName = normalizeSystemMemberName(formatFeature.id, member.platformId, member.accountName);
8096
+ const groupNickname = normalizeSystemMemberName(formatFeature.id, member.platformId, member.groupNickname);
7906
8097
  insertMember.run(
7907
8098
  member.platformId,
7908
- member.accountName || null,
7909
- member.groupNickname || null,
8099
+ accountName || null,
8100
+ groupNickname || null,
7910
8101
  member.aliases ? JSON.stringify(member.aliases) : "[]",
7911
8102
  member.avatar || null,
7912
8103
  member.roles ? JSON.stringify(member.roles) : "[]"
@@ -7929,7 +8120,17 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
7929
8120
  let memberInsertCount = 0;
7930
8121
  let nicknameChangeCount = 0;
7931
8122
  for (const msg of messages) {
7932
- const prepared = prepareMessageForCreate(msg);
8123
+ const senderAccountName = normalizeSystemMemberName(
8124
+ formatFeature.id,
8125
+ msg.senderPlatformId,
8126
+ msg.senderAccountName
8127
+ );
8128
+ const senderGroupNickname = normalizeSystemMemberName(
8129
+ formatFeature.id,
8130
+ msg.senderPlatformId,
8131
+ msg.senderGroupNickname
8132
+ );
8133
+ const prepared = prepareMessageForCreate(msg, senderAccountName);
7933
8134
  if ("skipCounter" in prepared) {
7934
8135
  callbackStats[prepared.skipCounter]++;
7935
8136
  continue;
@@ -7943,8 +8144,8 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
7943
8144
  if (!memberIdMap.has(msg.senderPlatformId)) {
7944
8145
  insertMember.run(
7945
8146
  msg.senderPlatformId,
7946
- msg.senderAccountName || null,
7947
- msg.senderGroupNickname || null,
8147
+ senderAccountName || null,
8148
+ senderGroupNickname || null,
7948
8149
  "[]",
7949
8150
  null,
7950
8151
  "[]"
@@ -7962,8 +8163,8 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
7962
8163
  t0 = Date.now();
7963
8164
  insertMessage.run(
7964
8165
  senderId,
7965
- msg.senderAccountName || null,
7966
- msg.senderGroupNickname || null,
8166
+ senderAccountName || null,
8167
+ senderGroupNickname || null,
7967
8168
  dedupMessage.timestamp,
7968
8169
  dedupMessage.type,
7969
8170
  dedupMessage.content,
@@ -7974,8 +8175,8 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
7974
8175
  messageCountInBatch++;
7975
8176
  totalMessageCount++;
7976
8177
  t0 = Date.now();
7977
- trackNickname(accountNameTracker, msg.senderPlatformId, msg.senderAccountName, msg.timestamp);
7978
- trackNickname(groupNicknameTracker, msg.senderPlatformId, msg.senderGroupNickname, msg.timestamp);
8178
+ trackNickname(accountNameTracker, msg.senderPlatformId, senderAccountName, msg.timestamp);
8179
+ trackNickname(groupNicknameTracker, msg.senderPlatformId, senderGroupNickname, msg.timestamp);
7979
8180
  nicknameTrackTime += Date.now() - t0;
7980
8181
  nicknameChangeCount += accountNameTracker.get(msg.senderPlatformId)?.history.length === 1 ? 0 : 0;
7981
8182
  if (messageCountInBatch >= BATCH_COMMIT_SIZE) {
@@ -8506,10 +8707,12 @@ async function incrementalImport(sessionId, filePath, deps, options2) {
8506
8707
  if (memberUpdateMode === "none") return;
8507
8708
  for (const m of members) {
8508
8709
  const existed = memberIdMap.has(m.platformId);
8710
+ const accountName = normalizeSystemMemberName(formatFeature.id, m.platformId, m.accountName);
8711
+ const groupNickname = normalizeSystemMemberName(formatFeature.id, m.platformId, m.groupNickname);
8509
8712
  upsertMember.run(
8510
8713
  m.platformId,
8511
- m.accountName || null,
8512
- m.groupNickname || null,
8714
+ accountName || null,
8715
+ groupNickname || null,
8513
8716
  m.aliases ? JSON.stringify(m.aliases) : "[]",
8514
8717
  m.avatar || null,
8515
8718
  m.roles ? JSON.stringify(m.roles) : "[]"
@@ -8546,12 +8749,22 @@ async function incrementalImport(sessionId, filePath, deps, options2) {
8546
8749
  duplicateCount++;
8547
8750
  continue;
8548
8751
  }
8752
+ const senderAccountName = normalizeSystemMemberName(
8753
+ formatFeature.id,
8754
+ msg.senderPlatformId,
8755
+ msg.senderAccountName
8756
+ );
8757
+ const senderGroupNickname = normalizeSystemMemberName(
8758
+ formatFeature.id,
8759
+ msg.senderPlatformId,
8760
+ msg.senderGroupNickname
8761
+ );
8549
8762
  let memberId = memberIdMap.get(msg.senderPlatformId);
8550
8763
  if (!memberId) {
8551
8764
  insertMemberMinimal.run(
8552
8765
  msg.senderPlatformId,
8553
- msg.senderAccountName || null,
8554
- msg.senderGroupNickname || null,
8766
+ senderAccountName || null,
8767
+ senderGroupNickname || null,
8555
8768
  null
8556
8769
  );
8557
8770
  const row = getMemberId.get(msg.senderPlatformId);
@@ -8564,8 +8777,8 @@ async function incrementalImport(sessionId, filePath, deps, options2) {
8564
8777
  if (!memberId) continue;
8565
8778
  const msgResult = insertMessage.run(
8566
8779
  memberId,
8567
- msg.senderAccountName || null,
8568
- msg.senderGroupNickname || null,
8780
+ senderAccountName || null,
8781
+ senderGroupNickname || null,
8569
8782
  timestamp,
8570
8783
  msg.type,
8571
8784
  msg.content || null,
@@ -8620,7 +8833,7 @@ async function incrementalImport(sessionId, filePath, deps, options2) {
8620
8833
  MAX(ts) as lastTimestamp
8621
8834
  FROM message`
8622
8835
  ).get();
8623
- const memberCountRow = db.prepare("SELECT COUNT(*) as count FROM member").get();
8836
+ const memberCountRow = db.prepare(`SELECT COUNT(*) as count FROM member WHERE COALESCE(account_name, '') != ?`).get(SYSTEM_MEMBER_NAME);
8624
8837
  try {
8625
8838
  await deps.postImportHook?.(db, sessionId);
8626
8839
  } catch {
@@ -9751,8 +9964,8 @@ var AssistantManager = class {
9751
9964
  }
9752
9965
  // ==================== Init ====================
9753
9966
  init() {
9754
- const { fs: fs37, assistantsDir } = this.deps;
9755
- fs37.ensureDir(assistantsDir);
9967
+ const { fs: fs36, assistantsDir } = this.deps;
9968
+ fs36.ensureDir(assistantsDir);
9756
9969
  const { generalCreated, generalUpdated } = this.syncGeneralAssistants();
9757
9970
  this.loadAll();
9758
9971
  this.initialized = true;
@@ -9764,25 +9977,25 @@ var AssistantManager = class {
9764
9977
  return { total: this.cache.size, generalCreated, generalUpdated };
9765
9978
  }
9766
9979
  syncGeneralAssistants() {
9767
- const { fs: fs37, assistantsDir } = this.deps;
9980
+ const { fs: fs36, assistantsDir } = this.deps;
9768
9981
  let generalCreated = false;
9769
9982
  let generalUpdated = false;
9770
9983
  for (const id of this.generalIds) {
9771
9984
  const config = this.getBuiltinConfig(id);
9772
9985
  if (!config) continue;
9773
- const filePath = fs37.joinPath(assistantsDir, `${id}.md`);
9774
- if (!fs37.fileExists(filePath)) {
9775
- fs37.writeFile(filePath, serializeAssistant(this.withBuiltinTracking(config)));
9986
+ const filePath = fs36.joinPath(assistantsDir, `${id}.md`);
9987
+ if (!fs36.fileExists(filePath)) {
9988
+ fs36.writeFile(filePath, serializeAssistant(this.withBuiltinTracking(config)));
9776
9989
  generalCreated = true;
9777
9990
  continue;
9778
9991
  }
9779
9992
  try {
9780
- const existing = parseAssistantFile(fs37.readFile(filePath), filePath);
9993
+ const existing = parseAssistantFile(fs36.readFile(filePath), filePath);
9781
9994
  if (!existing) continue;
9782
9995
  if (existing.builtinId !== id) {
9783
9996
  try {
9784
9997
  const backupId = this.backupAssistantOccupyingReservedId(existing);
9785
- fs37.writeFile(filePath, serializeAssistant(this.withBuiltinTracking(config)));
9998
+ fs36.writeFile(filePath, serializeAssistant(this.withBuiltinTracking(config)));
9786
9999
  generalCreated = true;
9787
10000
  this.deps.logger?.info("AssistantManager", "Backed up assistant occupying reserved default ID", {
9788
10001
  reservedId: id,
@@ -9798,7 +10011,7 @@ var AssistantManager = class {
9798
10011
  continue;
9799
10012
  }
9800
10013
  if (!this.shouldUpgradeBuiltin(existing, config)) continue;
9801
- fs37.writeFile(filePath, serializeAssistant(this.withBuiltinTracking(config, existing.id)));
10014
+ fs36.writeFile(filePath, serializeAssistant(this.withBuiltinTracking(config, existing.id)));
9802
10015
  generalUpdated = true;
9803
10016
  this.deps.logger?.info("AssistantManager", "Updated unmodified default assistant template", {
9804
10017
  id,
@@ -9814,14 +10027,14 @@ var AssistantManager = class {
9814
10027
  return { generalCreated, generalUpdated };
9815
10028
  }
9816
10029
  backupAssistantOccupyingReservedId(config) {
9817
- const { fs: fs37, assistantsDir } = this.deps;
10030
+ const { fs: fs36, assistantsDir } = this.deps;
9818
10031
  const baseId = this.deps.generateId?.() || `custom_${Date.now().toString(36)}`;
9819
10032
  let backupId = baseId;
9820
10033
  let suffix = 2;
9821
- while (this.generalIds.includes(backupId) || fs37.fileExists(fs37.joinPath(assistantsDir, `${backupId}.md`))) {
10034
+ while (this.generalIds.includes(backupId) || fs36.fileExists(fs36.joinPath(assistantsDir, `${backupId}.md`))) {
9822
10035
  backupId = `${baseId}_${suffix++}`;
9823
10036
  }
9824
- fs37.writeFile(fs37.joinPath(assistantsDir, `${backupId}.md`), serializeAssistant({ ...config, id: backupId }));
10037
+ fs36.writeFile(fs36.joinPath(assistantsDir, `${backupId}.md`), serializeAssistant({ ...config, id: backupId }));
9825
10038
  return backupId;
9826
10039
  }
9827
10040
  getConfigDigest(config) {
@@ -9858,13 +10071,13 @@ var AssistantManager = class {
9858
10071
  return { isUnmodified, isOutdated };
9859
10072
  }
9860
10073
  loadAll() {
9861
- const { fs: fs37, assistantsDir } = this.deps;
10074
+ const { fs: fs36, assistantsDir } = this.deps;
9862
10075
  this.cache.clear();
9863
- const files = fs37.listFiles(assistantsDir, ".md");
10076
+ const files = fs36.listFiles(assistantsDir, ".md");
9864
10077
  for (const file of files) {
9865
10078
  try {
9866
- const filePath = fs37.joinPath(assistantsDir, file);
9867
- const content = fs37.readFile(filePath);
10079
+ const filePath = fs36.joinPath(assistantsDir, file);
10080
+ const content = fs36.readFile(filePath);
9868
10081
  const config = parseAssistantFile(content, filePath);
9869
10082
  if (config) {
9870
10083
  this.cache.set(config.id, config);
@@ -10933,21 +11146,21 @@ var SkillManagerCore = class {
10933
11146
  }
10934
11147
  // ==================== Init ====================
10935
11148
  init() {
10936
- const { fs: fs37, skillsDir } = this.deps;
10937
- fs37.ensureDir(skillsDir);
11149
+ const { fs: fs36, skillsDir } = this.deps;
11150
+ fs36.ensureDir(skillsDir);
10938
11151
  this.loadAll();
10939
11152
  this.initialized = true;
10940
11153
  this.deps.logger?.info("SkillManager", "Initialized", { total: this.cache.size });
10941
11154
  return { total: this.cache.size };
10942
11155
  }
10943
11156
  loadAll() {
10944
- const { fs: fs37, skillsDir } = this.deps;
11157
+ const { fs: fs36, skillsDir } = this.deps;
10945
11158
  this.cache.clear();
10946
- const files = fs37.listFiles(skillsDir, ".md");
11159
+ const files = fs36.listFiles(skillsDir, ".md");
10947
11160
  for (const file of files) {
10948
11161
  try {
10949
- const filePath = fs37.joinPath(skillsDir, file);
10950
- const content = fs37.readFile(filePath);
11162
+ const filePath = fs36.joinPath(skillsDir, file);
11163
+ const content = fs36.readFile(filePath);
10951
11164
  const def = parseSkillFile(content, filePath);
10952
11165
  if (def) {
10953
11166
  this.cache.set(def.id, def);
@@ -13001,7 +13214,7 @@ var PLAN_INTENTS = [
13001
13214
  "mixed"
13002
13215
  ];
13003
13216
  var STREAM_MARKER_HOLDBACK_CHARS = Math.max("</draft>".length, "</plan>".length, "<json>".length) - 1;
13004
- function isRecord2(value) {
13217
+ function isRecord3(value) {
13005
13218
  return typeof value === "object" && value !== null && !Array.isArray(value);
13006
13219
  }
13007
13220
  function isIntent(value) {
@@ -13023,10 +13236,10 @@ function extractJsonObject4(text) {
13023
13236
  function parsePlanJson(rawText, availableTools) {
13024
13237
  try {
13025
13238
  const parsed = JSON.parse(extractJsonObject4(rawText));
13026
- if (!isRecord2(parsed)) return null;
13239
+ if (!isRecord3(parsed)) return null;
13027
13240
  const title = normalizeString(parsed.title);
13028
13241
  if (!title || !isIntent(parsed.intent) || !Array.isArray(parsed.steps)) return null;
13029
- const steps = parsed.steps.filter(isRecord2).map((step) => {
13242
+ const steps = parsed.steps.filter(isRecord3).map((step) => {
13030
13243
  const goal = normalizeString(step.goal);
13031
13244
  const evidenceNeeded = normalizeString(step.evidenceNeeded);
13032
13245
  if (!goal || !evidenceNeeded) return null;
@@ -15353,19 +15566,26 @@ var LLMConfigStore = class {
15353
15566
  this.resolveApiKey = deps.resolveApiKey;
15354
15567
  this.onStoreLoaded = deps.onStoreLoaded;
15355
15568
  }
15569
+ withStoreLock(action) {
15570
+ return this.storage.withLock ? this.storage.withLock("llm-config", action) : action();
15571
+ }
15356
15572
  loadStore() {
15357
15573
  const store = this.storage.readJson("llm-config");
15358
15574
  if (!store) {
15359
15575
  return { configs: [], defaultAssistant: null, fastModel: null };
15360
15576
  }
15361
15577
  this.onStoreLoaded?.(store.configs);
15362
- const resolvedConfigs = this.resolveApiKey ? store.configs.map((config) => {
15578
+ const sanitizedConfigs = store.configs.map((config) => ({
15579
+ ...config,
15580
+ apiKey: config.apiKey?.startsWith("enc:") ? "" : config.apiKey || ""
15581
+ }));
15582
+ const resolvedConfigs = this.resolveApiKey ? sanitizedConfigs.map((config) => {
15363
15583
  const profileKey = this.resolveApiKey(
15364
15584
  config.provider,
15365
15585
  config.authProfile
15366
15586
  );
15367
- return { ...config, apiKey: profileKey || config.apiKey || "" };
15368
- }) : store.configs;
15587
+ return { ...config, apiKey: profileKey || config.apiKey };
15588
+ }) : sanitizedConfigs;
15369
15589
  return {
15370
15590
  ...store,
15371
15591
  configs: resolvedConfigs,
@@ -15417,103 +15637,113 @@ var LLMConfigStore = class {
15417
15637
  return store.configs.find((c) => c.id === id) || null;
15418
15638
  }
15419
15639
  addConfig(config) {
15420
- const store = this.loadStore();
15421
- if (store.configs.length >= MAX_CONFIG_COUNT) {
15422
- return { success: false, error: this.t("llm.maxConfigs", { count: MAX_CONFIG_COUNT }) };
15423
- }
15424
- const now = Date.now();
15425
- const newConfig = {
15426
- ...config,
15427
- id: this.generateId(),
15428
- createdAt: now,
15429
- updatedAt: now
15430
- };
15431
- store.configs.push(newConfig);
15432
- if (store.configs.length === 1) {
15433
- store.defaultAssistant = { configId: newConfig.id, modelId: newConfig.model || "" };
15434
- }
15435
- if (newConfig.apiKey && this.onApiKeyCreated) {
15436
- const profileName = this.onApiKeyCreated(newConfig, newConfig.apiKey);
15437
- if (profileName) {
15438
- ;
15439
- newConfig.authProfile = profileName;
15640
+ return this.withStoreLock(() => {
15641
+ const store = this.loadStore();
15642
+ if (store.configs.length >= MAX_CONFIG_COUNT) {
15643
+ return { success: false, error: this.t("llm.maxConfigs", { count: MAX_CONFIG_COUNT }) };
15440
15644
  }
15441
- }
15442
- this.saveStore(store);
15443
- return { success: true, config: { ...newConfig, apiKey: "" } };
15645
+ const now = Date.now();
15646
+ const newConfig = {
15647
+ ...config,
15648
+ id: this.generateId(),
15649
+ createdAt: now,
15650
+ updatedAt: now
15651
+ };
15652
+ store.configs.push(newConfig);
15653
+ if (store.configs.length === 1) {
15654
+ store.defaultAssistant = { configId: newConfig.id, modelId: newConfig.model || "" };
15655
+ }
15656
+ if (newConfig.apiKey && this.onApiKeyCreated) {
15657
+ const profileName = this.onApiKeyCreated(newConfig, newConfig.apiKey);
15658
+ if (profileName) {
15659
+ ;
15660
+ newConfig.authProfile = profileName;
15661
+ }
15662
+ }
15663
+ this.saveStore(store);
15664
+ return { success: true, config: { ...newConfig, apiKey: "" } };
15665
+ });
15444
15666
  }
15445
15667
  updateConfig(id, updates) {
15446
- const store = this.loadStore();
15447
- const index = store.configs.findIndex((c) => c.id === id);
15448
- if (index === -1) {
15449
- return { success: false, error: this.t("llm.configNotFound") };
15450
- }
15451
- const oldConfig = store.configs[index];
15452
- const oldProfileName = oldConfig.authProfile;
15453
- const updated = {
15454
- ...oldConfig,
15455
- ...updates,
15456
- updatedAt: Date.now()
15457
- };
15458
- store.configs[index] = updated;
15459
- let oldProfileToDelete = null;
15460
- if (updates.apiKey && this.onApiKeyCreated) {
15461
- const profileName = this.onApiKeyCreated(updated, updates.apiKey);
15462
- if (profileName) {
15463
- ;
15464
- store.configs[index].authProfile = profileName;
15465
- if (oldProfileName && oldProfileName !== profileName && !isAuthProfileUsed(store.configs, oldProfileName, oldConfig.provider)) {
15466
- oldProfileToDelete = oldConfig;
15668
+ return this.withStoreLock(() => {
15669
+ const store = this.loadStore();
15670
+ const index = store.configs.findIndex((c) => c.id === id);
15671
+ if (index === -1) {
15672
+ return { success: false, error: this.t("llm.configNotFound") };
15673
+ }
15674
+ const oldConfig = store.configs[index];
15675
+ const oldProfileName = oldConfig.authProfile;
15676
+ const updated = {
15677
+ ...oldConfig,
15678
+ ...updates,
15679
+ updatedAt: Date.now()
15680
+ };
15681
+ store.configs[index] = updated;
15682
+ let oldProfileToDelete = null;
15683
+ if (updates.apiKey && this.onApiKeyCreated) {
15684
+ const profileName = this.onApiKeyCreated(updated, updates.apiKey);
15685
+ if (profileName) {
15686
+ ;
15687
+ store.configs[index].authProfile = profileName;
15688
+ if (oldProfileName && oldProfileName !== profileName && !isAuthProfileUsed(store.configs, oldProfileName, oldConfig.provider)) {
15689
+ oldProfileToDelete = oldConfig;
15690
+ }
15467
15691
  }
15468
15692
  }
15469
- }
15470
- this.saveStore(store);
15471
- if (oldProfileToDelete) this.onApiKeyDeleted?.(oldProfileToDelete);
15472
- return { success: true };
15693
+ this.saveStore(store);
15694
+ if (oldProfileToDelete) this.onApiKeyDeleted?.(oldProfileToDelete);
15695
+ return { success: true };
15696
+ });
15473
15697
  }
15474
15698
  deleteConfig(id) {
15475
- const store = this.loadStore();
15476
- const index = store.configs.findIndex((c) => c.id === id);
15477
- if (index === -1) {
15478
- return { success: false, error: this.t("llm.configNotFound") };
15479
- }
15480
- const deleted = store.configs[index];
15481
- store.configs.splice(index, 1);
15482
- const fallback = store.configs[0];
15483
- if (store.defaultAssistant?.configId === id) {
15484
- store.defaultAssistant = fallback ? { configId: fallback.id, modelId: fallback.model || "" } : null;
15485
- }
15486
- if (store.fastModel?.configId === id) {
15487
- store.fastModel = fallback ? { configId: fallback.id, modelId: fallback.model || "" } : null;
15488
- }
15489
- this.saveStore(store);
15490
- const deletedProfileName = getAuthProfile(deleted);
15491
- if (!deletedProfileName || !isAuthProfileUsed(store.configs, deletedProfileName, deleted.provider)) {
15492
- this.onApiKeyDeleted?.(deleted);
15493
- }
15494
- return { success: true };
15699
+ return this.withStoreLock(() => {
15700
+ const store = this.loadStore();
15701
+ const index = store.configs.findIndex((c) => c.id === id);
15702
+ if (index === -1) {
15703
+ return { success: false, error: this.t("llm.configNotFound") };
15704
+ }
15705
+ const deleted = store.configs[index];
15706
+ store.configs.splice(index, 1);
15707
+ const fallback = store.configs[0];
15708
+ if (store.defaultAssistant?.configId === id) {
15709
+ store.defaultAssistant = fallback ? { configId: fallback.id, modelId: fallback.model || "" } : null;
15710
+ }
15711
+ if (store.fastModel?.configId === id) {
15712
+ store.fastModel = fallback ? { configId: fallback.id, modelId: fallback.model || "" } : null;
15713
+ }
15714
+ this.saveStore(store);
15715
+ const deletedProfileName = getAuthProfile(deleted);
15716
+ if (!deletedProfileName || !isAuthProfileUsed(store.configs, deletedProfileName, deleted.provider)) {
15717
+ this.onApiKeyDeleted?.(deleted);
15718
+ }
15719
+ return { success: true };
15720
+ });
15495
15721
  }
15496
15722
  setDefaultAssistantModel(configId, modelId) {
15497
- const store = this.loadStore();
15498
- const config = store.configs.find((c) => c.id === configId);
15499
- if (!config) {
15500
- return { success: false, error: this.t("llm.configNotFound") };
15501
- }
15502
- store.defaultAssistant = { configId, modelId };
15503
- this.saveStore(store);
15504
- return { success: true };
15505
- }
15506
- setFastModel(slot) {
15507
- const store = this.loadStore();
15508
- if (slot !== null) {
15509
- const config = store.configs.find((c) => c.id === slot.configId);
15723
+ return this.withStoreLock(() => {
15724
+ const store = this.loadStore();
15725
+ const config = store.configs.find((c) => c.id === configId);
15510
15726
  if (!config) {
15511
15727
  return { success: false, error: this.t("llm.configNotFound") };
15512
15728
  }
15513
- }
15514
- store.fastModel = slot;
15515
- this.saveStore(store);
15516
- return { success: true };
15729
+ store.defaultAssistant = { configId, modelId };
15730
+ this.saveStore(store);
15731
+ return { success: true };
15732
+ });
15733
+ }
15734
+ setFastModel(slot) {
15735
+ return this.withStoreLock(() => {
15736
+ const store = this.loadStore();
15737
+ if (slot !== null) {
15738
+ const config = store.configs.find((c) => c.id === slot.configId);
15739
+ if (!config) {
15740
+ return { success: false, error: this.t("llm.configNotFound") };
15741
+ }
15742
+ }
15743
+ store.fastModel = slot;
15744
+ this.saveStore(store);
15745
+ return { success: true };
15746
+ });
15517
15747
  }
15518
15748
  hasActiveConfig() {
15519
15749
  return this.getDefaultAssistantConfig() !== null;
@@ -15521,20 +15751,30 @@ var LLMConfigStore = class {
15521
15751
  };
15522
15752
 
15523
15753
  // ../../packages/node-runtime/src/ai/file-config-storage.ts
15524
- import * as fs28 from "fs";
15525
15754
  import * as path22 from "path";
15526
15755
  function createFileConfigStorage(baseDir) {
15756
+ const heldLocks = /* @__PURE__ */ new Set();
15757
+ const getFilePath = (key) => path22.join(baseDir, `${key}.json`);
15527
15758
  return {
15528
15759
  readJson(key) {
15529
- try {
15530
- return JSON.parse(fs28.readFileSync(path22.join(baseDir, `${key}.json`), "utf-8"));
15531
- } catch {
15532
- return null;
15533
- }
15760
+ return readJsonFile(getFilePath(key));
15534
15761
  },
15535
15762
  writeJson(key, data) {
15536
- fs28.mkdirSync(baseDir, { recursive: true });
15537
- fs28.writeFileSync(path22.join(baseDir, `${key}.json`), JSON.stringify(data, null, 2), "utf-8");
15763
+ const filePath = getFilePath(key);
15764
+ const write = () => writeJsonFileAtomically(filePath, data);
15765
+ if (heldLocks.has(key)) write();
15766
+ else withFileLock(filePath, write);
15767
+ },
15768
+ withLock(key, action) {
15769
+ if (heldLocks.has(key)) return action();
15770
+ return withFileLock(getFilePath(key), () => {
15771
+ heldLocks.add(key);
15772
+ try {
15773
+ return action();
15774
+ } finally {
15775
+ heldLocks.delete(key);
15776
+ }
15777
+ });
15538
15778
  }
15539
15779
  };
15540
15780
  }
@@ -15542,23 +15782,57 @@ function createFileConfigStorage(baseDir) {
15542
15782
  // ../../packages/node-runtime/src/ai/auth-profile-llm-config-store.ts
15543
15783
  var defaultDeps = {
15544
15784
  resolveApiKey: (provider, authProfile) => resolveApiKey(provider, authProfile) || void 0,
15785
+ loadAuthProfiles,
15545
15786
  writeAuthProfile,
15546
15787
  deleteAuthProfile
15547
15788
  };
15548
15789
  function getAuthProfile2(config) {
15549
15790
  return config.authProfile;
15550
15791
  }
15551
- function createAuthProfileLlmConfigStore(storage, deps = defaultDeps) {
15792
+ function getNamedAuthProfile(config) {
15793
+ return config.name?.toLowerCase().replace(/\s+/g, "-") || config.provider;
15794
+ }
15795
+ function restoreLegacyAuthProfileReferences(configs, authProfiles) {
15796
+ const usedProfiles = new Set(configs.map(getAuthProfile2).filter((name) => Boolean(name)));
15797
+ for (const config of configs) {
15798
+ if (getAuthProfile2(config)) continue;
15799
+ const namedProfile = getNamedAuthProfile(config);
15800
+ const namedProfileValue = authProfiles.profiles[namedProfile];
15801
+ if (namedProfileValue?.provider === config.provider && !usedProfiles.has(namedProfile)) {
15802
+ ;
15803
+ config.authProfile = namedProfile;
15804
+ usedProfiles.add(namedProfile);
15805
+ continue;
15806
+ }
15807
+ const baseName = deriveAuthProfileName(config.provider, config);
15808
+ for (let index = 1; index <= Object.keys(authProfiles.profiles).length; index++) {
15809
+ const candidate = index === 1 ? baseName : `${baseName}-${index}`;
15810
+ const profile = authProfiles.profiles[candidate];
15811
+ if (!profile || profile.provider !== config.provider || usedProfiles.has(candidate)) continue;
15812
+ config.authProfile = candidate;
15813
+ usedProfiles.add(candidate);
15814
+ break;
15815
+ }
15816
+ }
15817
+ }
15818
+ function createAuthProfileLlmConfigStore(storage, deps = {}) {
15819
+ const resolvedDeps = { ...defaultDeps, ...deps };
15552
15820
  return new LLMConfigStore(storage, {
15553
- resolveApiKey: deps.resolveApiKey,
15821
+ t: deps.t,
15822
+ generateId: deps.generateId,
15823
+ onStoreLoaded: (configs) => {
15824
+ restoreLegacyAuthProfileReferences(configs, resolvedDeps.loadAuthProfiles());
15825
+ deps.onStoreLoaded?.(configs);
15826
+ },
15827
+ resolveApiKey: resolvedDeps.resolveApiKey,
15554
15828
  onApiKeyCreated: (config, apiKey) => {
15555
- const profileName = config.name?.toLowerCase().replace(/\s+/g, "-") || config.provider;
15556
- deps.writeAuthProfile(profileName, { type: "api_key", provider: config.provider, key: apiKey });
15829
+ const profileName = getNamedAuthProfile(config);
15830
+ resolvedDeps.writeAuthProfile(profileName, { type: "api_key", provider: config.provider, key: apiKey });
15557
15831
  return profileName;
15558
15832
  },
15559
15833
  onApiKeyDeleted: (config) => {
15560
15834
  const profileName = getAuthProfile2(config);
15561
- if (profileName) deps.deleteAuthProfile(profileName);
15835
+ if (profileName) resolvedDeps.deleteAuthProfile(profileName);
15562
15836
  }
15563
15837
  });
15564
15838
  }
@@ -15572,43 +15846,52 @@ var CustomProviderStore = class {
15572
15846
  this.storage = storage;
15573
15847
  }
15574
15848
  storage;
15849
+ withLock(action) {
15850
+ return this.storage.withLock ? this.storage.withLock("custom-providers", action) : action();
15851
+ }
15575
15852
  getAll() {
15576
15853
  return this.storage.readJson("custom-providers") ?? [];
15577
15854
  }
15578
15855
  add(input) {
15579
- const providers = this.getAll();
15580
- const newProvider = {
15581
- id: generateCustomId(),
15582
- name: input.name,
15583
- kind: input.kind || "openai-compatible",
15584
- defaultBaseUrl: input.defaultBaseUrl,
15585
- authMode: "api-key",
15586
- supportsCustomModels: input.supportsCustomModels ?? true,
15587
- modelIds: input.modelIds ?? [],
15588
- builtin: false,
15589
- enabledByDefault: false,
15590
- website: input.website,
15591
- consoleUrl: input.consoleUrl
15592
- };
15593
- providers.push(newProvider);
15594
- this.storage.writeJson("custom-providers", providers);
15595
- return newProvider;
15856
+ return this.withLock(() => {
15857
+ const providers = this.getAll();
15858
+ const newProvider = {
15859
+ id: generateCustomId(),
15860
+ name: input.name,
15861
+ kind: input.kind || "openai-compatible",
15862
+ defaultBaseUrl: input.defaultBaseUrl,
15863
+ authMode: "api-key",
15864
+ supportsCustomModels: input.supportsCustomModels ?? true,
15865
+ modelIds: input.modelIds ?? [],
15866
+ builtin: false,
15867
+ enabledByDefault: false,
15868
+ website: input.website,
15869
+ consoleUrl: input.consoleUrl
15870
+ };
15871
+ providers.push(newProvider);
15872
+ this.storage.writeJson("custom-providers", providers);
15873
+ return newProvider;
15874
+ });
15596
15875
  }
15597
15876
  update(id, updates) {
15598
- const providers = this.getAll();
15599
- const index = providers.findIndex((p) => p.id === id);
15600
- if (index === -1) return { success: false, error: "Custom provider not found" };
15601
- providers[index] = { ...providers[index], ...updates };
15602
- this.storage.writeJson("custom-providers", providers);
15603
- return { success: true };
15877
+ return this.withLock(() => {
15878
+ const providers = this.getAll();
15879
+ const index = providers.findIndex((p) => p.id === id);
15880
+ if (index === -1) return { success: false, error: "Custom provider not found" };
15881
+ providers[index] = { ...providers[index], ...updates };
15882
+ this.storage.writeJson("custom-providers", providers);
15883
+ return { success: true };
15884
+ });
15604
15885
  }
15605
15886
  delete(id) {
15606
- const providers = this.getAll();
15607
- const index = providers.findIndex((p) => p.id === id);
15608
- if (index === -1) return { success: false, error: "Custom provider not found" };
15609
- providers.splice(index, 1);
15610
- this.storage.writeJson("custom-providers", providers);
15611
- return { success: true };
15887
+ return this.withLock(() => {
15888
+ const providers = this.getAll();
15889
+ const index = providers.findIndex((p) => p.id === id);
15890
+ if (index === -1) return { success: false, error: "Custom provider not found" };
15891
+ providers.splice(index, 1);
15892
+ this.storage.writeJson("custom-providers", providers);
15893
+ return { success: true };
15894
+ });
15612
15895
  }
15613
15896
  };
15614
15897
  var CustomModelStore = class {
@@ -15616,51 +15899,96 @@ var CustomModelStore = class {
15616
15899
  this.storage = storage;
15617
15900
  }
15618
15901
  storage;
15902
+ withLock(action) {
15903
+ return this.storage.withLock ? this.storage.withLock("custom-models", action) : action();
15904
+ }
15619
15905
  getAll() {
15620
15906
  return this.storage.readJson("custom-models") ?? [];
15621
15907
  }
15622
15908
  add(input) {
15623
- const models = this.getAll();
15624
- if (models.find((m) => m.id === input.id && m.providerId === input.providerId)) {
15625
- return {
15626
- success: false,
15627
- error: `Model "${input.id}" already exists under provider "${input.providerId}"`
15909
+ return this.withLock(() => {
15910
+ const models = this.getAll();
15911
+ if (models.find((m) => m.id === input.id && m.providerId === input.providerId)) {
15912
+ return {
15913
+ success: false,
15914
+ error: `Model "${input.id}" already exists under provider "${input.providerId}"`
15915
+ };
15916
+ }
15917
+ const newModel = {
15918
+ id: input.id,
15919
+ providerId: input.providerId,
15920
+ name: input.name,
15921
+ description: input.description,
15922
+ contextWindow: input.contextWindow,
15923
+ capabilities: input.capabilities ?? ["chat"],
15924
+ recommendedFor: input.recommendedFor ?? ["chat"],
15925
+ status: input.status ?? "stable",
15926
+ builtin: false,
15927
+ editable: true
15628
15928
  };
15629
- }
15630
- const newModel = {
15631
- id: input.id,
15632
- providerId: input.providerId,
15633
- name: input.name,
15634
- description: input.description,
15635
- contextWindow: input.contextWindow,
15636
- capabilities: input.capabilities ?? ["chat"],
15637
- recommendedFor: input.recommendedFor ?? ["chat"],
15638
- status: input.status ?? "stable",
15639
- builtin: false,
15640
- editable: true
15641
- };
15642
- models.push(newModel);
15643
- this.storage.writeJson("custom-models", models);
15644
- return { success: true, model: newModel };
15929
+ models.push(newModel);
15930
+ this.storage.writeJson("custom-models", models);
15931
+ return { success: true, model: newModel };
15932
+ });
15645
15933
  }
15646
15934
  update(providerId, modelId, updates) {
15647
- const models = this.getAll();
15648
- const index = models.findIndex((m) => m.id === modelId && m.providerId === providerId);
15649
- if (index === -1) return { success: false, error: "Custom model not found" };
15650
- models[index] = { ...models[index], ...updates };
15651
- this.storage.writeJson("custom-models", models);
15652
- return { success: true };
15935
+ return this.withLock(() => {
15936
+ const models = this.getAll();
15937
+ const index = models.findIndex((m) => m.id === modelId && m.providerId === providerId);
15938
+ if (index === -1) return { success: false, error: "Custom model not found" };
15939
+ models[index] = { ...models[index], ...updates };
15940
+ this.storage.writeJson("custom-models", models);
15941
+ return { success: true };
15942
+ });
15653
15943
  }
15654
15944
  delete(providerId, modelId) {
15655
- const models = this.getAll();
15656
- const index = models.findIndex((m) => m.id === modelId && m.providerId === providerId);
15657
- if (index === -1) return { success: false, error: "Custom model not found" };
15658
- models.splice(index, 1);
15659
- this.storage.writeJson("custom-models", models);
15660
- return { success: true };
15945
+ return this.withLock(() => {
15946
+ const models = this.getAll();
15947
+ const index = models.findIndex((m) => m.id === modelId && m.providerId === providerId);
15948
+ if (index === -1) return { success: false, error: "Custom model not found" };
15949
+ models.splice(index, 1);
15950
+ this.storage.writeJson("custom-models", models);
15951
+ return { success: true };
15952
+ });
15661
15953
  }
15662
15954
  };
15663
15955
 
15956
+ // ../../packages/node-runtime/src/ai/llm-runtime-stores.ts
15957
+ function ensureLegacyCustomModels(configs, customModelStore) {
15958
+ for (const config of configs) {
15959
+ const providerId = config.provider;
15960
+ if (config.model && getBuiltinProviderById(providerId) && !getBuiltinModelById(providerId, config.model)) {
15961
+ customModelStore.add({
15962
+ id: config.model,
15963
+ providerId,
15964
+ name: config.model,
15965
+ capabilities: ["chat"],
15966
+ recommendedFor: ["chat"],
15967
+ status: "stable"
15968
+ });
15969
+ }
15970
+ }
15971
+ }
15972
+ function createLlmRuntimeStores(aiDataDir, options2 = {}) {
15973
+ const storage = createFileConfigStorage(aiDataDir);
15974
+ const customProviderStore = new CustomProviderStore(storage);
15975
+ const customModelStore = new CustomModelStore(storage);
15976
+ const llmConfigStore = createAuthProfileLlmConfigStore(storage, {
15977
+ ...options2.authProfileDeps,
15978
+ t: options2.t,
15979
+ generateId: options2.generateId,
15980
+ onStoreLoaded: (configs) => {
15981
+ ensureLegacyCustomModels(configs, customModelStore);
15982
+ options2.onStoreLoaded?.(configs);
15983
+ }
15984
+ });
15985
+ return {
15986
+ llmConfigStore,
15987
+ customProviderStore,
15988
+ customModelStore
15989
+ };
15990
+ }
15991
+
15664
15992
  // ../../packages/node-runtime/src/ai/llm-builder.ts
15665
15993
  function normalizeAnthropicBaseUrl(url) {
15666
15994
  return url.replace(/\/v1\/?$/, "");
@@ -16382,7 +16710,7 @@ function exportWithFormat(params, openDatabase) {
16382
16710
  }
16383
16711
 
16384
16712
  // ../../packages/node-runtime/src/merger/temp-db.ts
16385
- import * as fs29 from "fs";
16713
+ import * as fs28 from "fs";
16386
16714
  import * as path23 from "path";
16387
16715
  var TEMP_DB_SCHEMA = `
16388
16716
  CREATE TABLE IF NOT EXISTS meta (
@@ -16628,18 +16956,18 @@ function exportSessionToJson(db) {
16628
16956
  }
16629
16957
  function deleteTempDatabase(dbPath) {
16630
16958
  try {
16631
- if (fs29.existsSync(dbPath)) fs29.unlinkSync(dbPath);
16959
+ if (fs28.existsSync(dbPath)) fs28.unlinkSync(dbPath);
16632
16960
  const walPath = dbPath + "-wal";
16633
16961
  const shmPath = dbPath + "-shm";
16634
- if (fs29.existsSync(walPath)) fs29.unlinkSync(walPath);
16635
- if (fs29.existsSync(shmPath)) fs29.unlinkSync(shmPath);
16962
+ if (fs28.existsSync(walPath)) fs28.unlinkSync(walPath);
16963
+ if (fs28.existsSync(shmPath)) fs28.unlinkSync(shmPath);
16636
16964
  } catch {
16637
16965
  }
16638
16966
  }
16639
16967
  function cleanupTempDatabases(tempDir) {
16640
16968
  try {
16641
- if (!fs29.existsSync(tempDir)) return;
16642
- const files = fs29.readdirSync(tempDir);
16969
+ if (!fs28.existsSync(tempDir)) return;
16970
+ const files = fs28.readdirSync(tempDir);
16643
16971
  for (const file of files) {
16644
16972
  if (file.startsWith("merge_") && file.endsWith(".db")) {
16645
16973
  deleteTempDatabase(path23.join(tempDir, file));
@@ -17027,7 +17355,7 @@ function clearSessionOwner(adapter, sessionId) {
17027
17355
  }
17028
17356
 
17029
17357
  // ../../packages/node-runtime/src/services/contacts/overrides.ts
17030
- import fs30 from "fs";
17358
+ import fs29 from "fs";
17031
17359
  import path24 from "path";
17032
17360
  var CONTACT_OVERRIDES_FILE_NAME = "contact-overrides.json";
17033
17361
  var CONTACT_OVERRIDES_TMP_PREFIX = "contact-overrides.tmp-";
@@ -17043,26 +17371,26 @@ function getContactOverridesPath(snapshotDir) {
17043
17371
  }
17044
17372
  function readContactOverrides(snapshotDir) {
17045
17373
  const filePath = getContactOverridesPath(snapshotDir);
17046
- if (!fs30.existsSync(filePath)) return createEmptyContactOverridesFile();
17374
+ if (!fs29.existsSync(filePath)) return createEmptyContactOverridesFile();
17047
17375
  try {
17048
- return normalizeContactOverrides(JSON.parse(fs30.readFileSync(filePath, "utf-8")));
17376
+ return normalizeContactOverrides(JSON.parse(fs29.readFileSync(filePath, "utf-8")));
17049
17377
  } catch (error) {
17050
17378
  appLogger.warn("contacts", "contact overrides file is unreadable", error);
17051
17379
  return createEmptyContactOverridesFile();
17052
17380
  }
17053
17381
  }
17054
17382
  function writeContactOverrides(snapshotDir, overrides) {
17055
- if (!fs30.existsSync(snapshotDir)) fs30.mkdirSync(snapshotDir, { recursive: true });
17383
+ if (!fs29.existsSync(snapshotDir)) fs29.mkdirSync(snapshotDir, { recursive: true });
17056
17384
  const tmpPath = path24.join(snapshotDir, `${CONTACT_OVERRIDES_TMP_PREFIX}${process.pid}-${Date.now()}`);
17057
- fs30.writeFileSync(tmpPath, JSON.stringify(normalizeContactOverrides(overrides), null, 2), "utf-8");
17058
- fs30.renameSync(tmpPath, getContactOverridesPath(snapshotDir));
17385
+ fs29.writeFileSync(tmpPath, JSON.stringify(normalizeContactOverrides(overrides), null, 2), "utf-8");
17386
+ fs29.renameSync(tmpPath, getContactOverridesPath(snapshotDir));
17059
17387
  }
17060
17388
  function normalizeContactOverrides(value) {
17061
- const input = isRecord3(value) ? value : {};
17062
- const manualFriendsInput = isRecord3(input.manualFriends) ? input.manualFriends : {};
17389
+ const input = isRecord4(value) ? value : {};
17390
+ const manualFriendsInput = isRecord4(input.manualFriends) ? input.manualFriends : {};
17063
17391
  const manualFriends = {};
17064
17392
  for (const [key, entry] of Object.entries(manualFriendsInput)) {
17065
- if (!key || !isRecord3(entry)) continue;
17393
+ if (!key || !isRecord4(entry)) continue;
17066
17394
  const createdAt = Number.isFinite(entry.createdAt) ? Number(entry.createdAt) : Date.now();
17067
17395
  const updatedAt = Number.isFinite(entry.updatedAt) ? Number(entry.updatedAt) : createdAt;
17068
17396
  manualFriends[key] = { key, createdAt, updatedAt };
@@ -17072,7 +17400,7 @@ function normalizeContactOverrides(value) {
17072
17400
  manualFriends
17073
17401
  };
17074
17402
  }
17075
- function isRecord3(value) {
17403
+ function isRecord4(value) {
17076
17404
  return typeof value === "object" && value !== null && !Array.isArray(value);
17077
17405
  }
17078
17406
 
@@ -17090,7 +17418,7 @@ function buildContactsSignature(adapter, timeRangePreset) {
17090
17418
  }
17091
17419
 
17092
17420
  // ../../packages/node-runtime/src/services/contacts/snapshot.ts
17093
- import fs31 from "fs";
17421
+ import fs30 from "fs";
17094
17422
  import path25 from "path";
17095
17423
  var CONTACTS_SNAPSHOT_TMP_PREFIX = "contacts-snapshot.tmp-";
17096
17424
  function getContactsSnapshotPath(snapshotDir, timeRangePreset) {
@@ -17099,14 +17427,14 @@ function getContactsSnapshotPath(snapshotDir, timeRangePreset) {
17099
17427
  }
17100
17428
  function readContactsSnapshot(snapshotDir, timeRangePreset, options2 = {}) {
17101
17429
  const snapshotPath = getContactsSnapshotPath(snapshotDir, timeRangePreset);
17102
- if (!fs31.existsSync(snapshotPath)) return null;
17430
+ if (!fs30.existsSync(snapshotPath)) return null;
17103
17431
  try {
17104
- return JSON.parse(fs31.readFileSync(snapshotPath, "utf-8"));
17432
+ return JSON.parse(fs30.readFileSync(snapshotPath, "utf-8"));
17105
17433
  } catch (error) {
17106
17434
  const ts = options2.now?.() ?? Date.now();
17107
17435
  const backupPath = path25.join(snapshotDir, `contacts-snapshot.corrupt-${ts}.json`);
17108
17436
  try {
17109
- fs31.renameSync(snapshotPath, backupPath);
17437
+ fs30.renameSync(snapshotPath, backupPath);
17110
17438
  } catch (renameError) {
17111
17439
  appLogger.warn("contacts", "failed to backup corrupt contacts snapshot", renameError);
17112
17440
  }
@@ -17115,17 +17443,17 @@ function readContactsSnapshot(snapshotDir, timeRangePreset, options2 = {}) {
17115
17443
  }
17116
17444
  }
17117
17445
  function writeContactsSnapshot(snapshotDir, snapshot) {
17118
- if (!fs31.existsSync(snapshotDir)) fs31.mkdirSync(snapshotDir, { recursive: true });
17446
+ if (!fs30.existsSync(snapshotDir)) fs30.mkdirSync(snapshotDir, { recursive: true });
17119
17447
  const tmpPath = path25.join(snapshotDir, `${CONTACTS_SNAPSHOT_TMP_PREFIX}${process.pid}-${Date.now()}`);
17120
- fs31.writeFileSync(tmpPath, JSON.stringify(snapshot, null, 2), "utf-8");
17121
- fs31.renameSync(tmpPath, getContactsSnapshotPath(snapshotDir, snapshot.timeRange.preset));
17448
+ fs30.writeFileSync(tmpPath, JSON.stringify(snapshot, null, 2), "utf-8");
17449
+ fs30.renameSync(tmpPath, getContactsSnapshotPath(snapshotDir, snapshot.timeRange.preset));
17122
17450
  }
17123
17451
  function cleanupContactsSnapshotTempFiles(snapshotDir) {
17124
- if (!fs31.existsSync(snapshotDir)) return;
17125
- for (const name of fs31.readdirSync(snapshotDir)) {
17452
+ if (!fs30.existsSync(snapshotDir)) return;
17453
+ for (const name of fs30.readdirSync(snapshotDir)) {
17126
17454
  if (!name.startsWith(CONTACTS_SNAPSHOT_TMP_PREFIX)) continue;
17127
17455
  try {
17128
- fs31.rmSync(path25.join(snapshotDir, name), { force: true });
17456
+ fs30.rmSync(path25.join(snapshotDir, name), { force: true });
17129
17457
  } catch (error) {
17130
17458
  appLogger.warn("contacts", "failed to remove contacts snapshot temp file", error);
17131
17459
  }
@@ -17623,7 +17951,7 @@ function buildPeopleRelationshipsSignature(adapter, timeRangePreset) {
17623
17951
  }
17624
17952
 
17625
17953
  // ../../packages/node-runtime/src/services/people/relationships/snapshot.ts
17626
- import fs32 from "fs";
17954
+ import fs31 from "fs";
17627
17955
  import path26 from "path";
17628
17956
  var PEOPLE_RELATIONSHIPS_SNAPSHOT_TMP_PREFIX = "people-relationships-snapshot.tmp-";
17629
17957
  function getPeopleRelationshipsSnapshotPath(snapshotDir, timeRangePreset) {
@@ -17632,14 +17960,14 @@ function getPeopleRelationshipsSnapshotPath(snapshotDir, timeRangePreset) {
17632
17960
  }
17633
17961
  function readPeopleRelationshipsSnapshot(snapshotDir, timeRangePreset, options2 = {}) {
17634
17962
  const snapshotPath = getPeopleRelationshipsSnapshotPath(snapshotDir, timeRangePreset);
17635
- if (!fs32.existsSync(snapshotPath)) return null;
17963
+ if (!fs31.existsSync(snapshotPath)) return null;
17636
17964
  try {
17637
- return JSON.parse(fs32.readFileSync(snapshotPath, "utf-8"));
17965
+ return JSON.parse(fs31.readFileSync(snapshotPath, "utf-8"));
17638
17966
  } catch (error) {
17639
17967
  const ts = options2.now?.() ?? Date.now();
17640
17968
  const backupPath = path26.join(snapshotDir, `graph-snapshot.corrupt-${ts}.json`);
17641
17969
  try {
17642
- fs32.renameSync(snapshotPath, backupPath);
17970
+ fs31.renameSync(snapshotPath, backupPath);
17643
17971
  } catch (renameError) {
17644
17972
  appLogger.warn("people-relationships", "failed to backup corrupt people relationships snapshot", renameError);
17645
17973
  }
@@ -17648,17 +17976,17 @@ function readPeopleRelationshipsSnapshot(snapshotDir, timeRangePreset, options2
17648
17976
  }
17649
17977
  }
17650
17978
  function writePeopleRelationshipsSnapshot(snapshotDir, snapshot) {
17651
- if (!fs32.existsSync(snapshotDir)) fs32.mkdirSync(snapshotDir, { recursive: true });
17979
+ if (!fs31.existsSync(snapshotDir)) fs31.mkdirSync(snapshotDir, { recursive: true });
17652
17980
  const tmpPath = path26.join(snapshotDir, `${PEOPLE_RELATIONSHIPS_SNAPSHOT_TMP_PREFIX}${process.pid}-${Date.now()}`);
17653
- fs32.writeFileSync(tmpPath, JSON.stringify(snapshot, null, 2), "utf-8");
17654
- fs32.renameSync(tmpPath, getPeopleRelationshipsSnapshotPath(snapshotDir, snapshot.timeRange.preset));
17981
+ fs31.writeFileSync(tmpPath, JSON.stringify(snapshot, null, 2), "utf-8");
17982
+ fs31.renameSync(tmpPath, getPeopleRelationshipsSnapshotPath(snapshotDir, snapshot.timeRange.preset));
17655
17983
  }
17656
17984
  function cleanupPeopleRelationshipsSnapshotTempFiles(snapshotDir) {
17657
- if (!fs32.existsSync(snapshotDir)) return;
17658
- for (const name of fs32.readdirSync(snapshotDir)) {
17985
+ if (!fs31.existsSync(snapshotDir)) return;
17986
+ for (const name of fs31.readdirSync(snapshotDir)) {
17659
17987
  if (!name.startsWith(PEOPLE_RELATIONSHIPS_SNAPSHOT_TMP_PREFIX)) continue;
17660
17988
  try {
17661
- fs32.rmSync(path26.join(snapshotDir, name), { force: true });
17989
+ fs31.rmSync(path26.join(snapshotDir, name), { force: true });
17662
17990
  } catch (error) {
17663
17991
  appLogger.warn("people-relationships", "failed to remove people relationships snapshot temp file", error);
17664
17992
  }
@@ -17794,8 +18122,10 @@ var DefaultPeopleRelationshipsService = class {
17794
18122
  const snapshot = this.getSnapshotForResponse(timeRangePreset);
17795
18123
  const status = this.getCacheStatus(signature, timeRangePreset);
17796
18124
  const includeSnapshot = shouldIncludeSnapshot(status, options2.acceptStale);
17797
- const graph = includeSnapshot && snapshot ? buildPeopleRelationshipsNeighborhoodGraph(snapshot, key) : emptyGraph();
17798
- const contact = includeSnapshot ? snapshot?.nodes.find((node) => node.key === key) ?? null : null;
18125
+ const graphScope = normalizePeopleRelationshipsGraphScope(options2.graphScope);
18126
+ const scopedSnapshot = snapshot ? buildNeighborhoodSnapshotForScope(snapshot, graphScope) : null;
18127
+ const graph = includeSnapshot && scopedSnapshot ? buildPeopleRelationshipsNeighborhoodGraph(scopedSnapshot, key) : emptyGraph();
18128
+ const contact = includeSnapshot ? scopedSnapshot?.nodes.find((node) => node.key === key) ?? null : null;
17799
18129
  return {
17800
18130
  contact,
17801
18131
  graph,
@@ -17927,7 +18257,7 @@ var DefaultPeopleRelationshipsService = class {
17927
18257
  const graph = includeSnapshot && snapshot ? buildGraphForScope(snapshot, graphScope) : emptyGraph();
17928
18258
  return {
17929
18259
  graph,
17930
- searchResults: includeSnapshot && snapshot ? buildSearchResults(snapshot, options2.query, graph) : [],
18260
+ searchResults: includeSnapshot && snapshot ? buildSearchResults(snapshot, options2.query, graph, graphScope) : [],
17931
18261
  diagnostics: includeSnapshot ? sanitizePeopleRelationshipsDiagnostics(snapshot?.diagnostics ?? createEmptyDiagnostics()) : createEmptyDiagnostics(),
17932
18262
  algorithmVersion: includeSnapshot ? snapshot?.algorithmVersion ?? PEOPLE_RELATIONSHIPS_ALGORITHM_VERSION : PEOPLE_RELATIONSHIPS_ALGORITHM_VERSION,
17933
18263
  timeRange: snapshot?.timeRange ?? resolvePeopleRelationshipsTimeRange(timeRangePreset, null),
@@ -17985,6 +18315,16 @@ function buildFriendsRelationshipsGraph(snapshot) {
17985
18315
  communities: filterCommunitiesForNodes(snapshot.communities, nodes)
17986
18316
  };
17987
18317
  }
18318
+ function buildNeighborhoodSnapshotForScope(snapshot, scope) {
18319
+ if (scope !== "friends") return snapshot;
18320
+ const graph = buildFriendsRelationshipsGraph(snapshot);
18321
+ return {
18322
+ ...snapshot,
18323
+ nodes: graph.nodes,
18324
+ edges: graph.edges,
18325
+ communities: graph.communities
18326
+ };
18327
+ }
17988
18328
  function buildCloseRelationshipsGraph(snapshot) {
17989
18329
  const selectedKeys = /* @__PURE__ */ new Set();
17990
18330
  for (const node of snapshot.nodes) {
@@ -18025,11 +18365,12 @@ function filterCommunitiesForNodes(communities, nodes) {
18025
18365
  size: communitySizes.get(community.id) ?? community.size
18026
18366
  }));
18027
18367
  }
18028
- function buildSearchResults(snapshot, queryInput, graph) {
18368
+ function buildSearchResults(snapshot, queryInput, graph, graphScope) {
18029
18369
  const query = queryInput?.trim().toLowerCase() ?? "";
18030
18370
  if (!query) return [];
18031
18371
  const visibleKeys = new Set(graph.nodes.map((node) => node.key));
18032
- return snapshot.nodes.filter((node) => node.searchText.includes(query)).sort(compareNodes).slice(0, snapshot.limits.searchResultLimit).map((node) => ({
18372
+ const searchableNodes = graphScope === "friends" ? graph.nodes : snapshot.nodes;
18373
+ return searchableNodes.filter((node) => node.searchText.includes(query)).sort(compareNodes).slice(0, snapshot.limits.searchResultLimit).map((node) => ({
18033
18374
  key: node.key,
18034
18375
  kind: node.kind,
18035
18376
  displayName: node.displayName,
@@ -18180,7 +18521,7 @@ __export(relationships_exports, {
18180
18521
  });
18181
18522
 
18182
18523
  // ../../packages/node-runtime/src/services/global-insight/service.ts
18183
- import fs33 from "fs";
18524
+ import fs32 from "fs";
18184
18525
 
18185
18526
  // ../../packages/node-runtime/src/services/global-insight/signature.ts
18186
18527
  function buildAnnualSummarySignature(adapter, range) {
@@ -18413,6 +18754,7 @@ var DefaultGlobalInsightService = class {
18413
18754
  latestDataYear: includeSnapshot ? snapshot?.latestDataYear ?? null : null,
18414
18755
  metrics: includeSnapshot ? snapshot?.metrics ?? null : null,
18415
18756
  monthlyActivity: includeSnapshot ? snapshot?.monthlyActivity ?? [] : [],
18757
+ monthlyDirectContacts: includeSnapshot ? snapshot?.monthlyDirectContacts ?? [] : [],
18416
18758
  dailyActivity: includeSnapshot ? snapshot?.dailyActivity ?? [] : [],
18417
18759
  messageTypes: includeSnapshot ? snapshot?.messageTypes ?? [] : [],
18418
18760
  textLength: includeSnapshot ? snapshot?.textLength ?? null : null,
@@ -18433,7 +18775,7 @@ var DefaultGlobalInsightService = class {
18433
18775
  }
18434
18776
  getSnapshot(range) {
18435
18777
  const key = toAnnualSummaryRangeKey(range);
18436
- if (this.snapshots.has(key) && !fs33.existsSync(getAnnualSummarySnapshotPath(this.snapshotDir, range))) {
18778
+ if (this.snapshots.has(key) && !fs32.existsSync(getAnnualSummarySnapshotPath(this.snapshotDir, range))) {
18437
18779
  this.snapshots.delete(key);
18438
18780
  }
18439
18781
  if (!this.snapshots.has(key)) {
@@ -18481,7 +18823,7 @@ __export(global_insight_exports, {
18481
18823
  });
18482
18824
 
18483
18825
  // ../../packages/node-runtime/src/semantic-index/config.ts
18484
- import fs34 from "fs";
18826
+ import fs33 from "fs";
18485
18827
  import path27 from "path";
18486
18828
  var DEFAULT_SEMANTIC_INDEX_MODEL_DOWNLOAD_SOURCE = "huggingface";
18487
18829
  var SEMANTIC_INDEX_CONFIG_VERSION = 1;
@@ -18571,9 +18913,9 @@ var SemanticIndexConfigStore = class {
18571
18913
  return this.set({ ...this.get(), enabled });
18572
18914
  }
18573
18915
  get() {
18574
- if (!fs34.existsSync(this.filePath)) return defaultSemanticIndexConfig();
18916
+ if (!fs33.existsSync(this.filePath)) return defaultSemanticIndexConfig();
18575
18917
  try {
18576
- const raw = JSON.parse(fs34.readFileSync(this.filePath, "utf-8"));
18918
+ const raw = JSON.parse(fs33.readFileSync(this.filePath, "utf-8"));
18577
18919
  return normalizeConfig(raw);
18578
18920
  } catch {
18579
18921
  return defaultSemanticIndexConfig();
@@ -18582,8 +18924,8 @@ var SemanticIndexConfigStore = class {
18582
18924
  set(config) {
18583
18925
  const normalized = normalizeConfig(config);
18584
18926
  const dir = path27.dirname(this.filePath);
18585
- if (!fs34.existsSync(dir)) fs34.mkdirSync(dir, { recursive: true });
18586
- fs34.writeFileSync(this.filePath, JSON.stringify(normalized, null, 2), "utf-8");
18927
+ if (!fs33.existsSync(dir)) fs33.mkdirSync(dir, { recursive: true });
18928
+ fs33.writeFileSync(this.filePath, JSON.stringify(normalized, null, 2), "utf-8");
18587
18929
  return normalized;
18588
18930
  }
18589
18931
  resolveModelId() {
@@ -20682,7 +21024,7 @@ ${text}`;
20682
21024
  };
20683
21025
 
20684
21026
  // ../../packages/node-runtime/src/services/merge-cache.ts
20685
- import * as fs35 from "fs";
21027
+ import * as fs34 from "fs";
20686
21028
  import * as path29 from "path";
20687
21029
  import * as crypto from "crypto";
20688
21030
  var MergeSessionCache = class {
@@ -20692,8 +21034,8 @@ var MergeSessionCache = class {
20692
21034
  constructor(pathProvider, options2) {
20693
21035
  this.tempDir = pathProvider.getTempDir();
20694
21036
  this.nativeBinding = options2?.nativeBinding;
20695
- if (!fs35.existsSync(this.tempDir)) {
20696
- fs35.mkdirSync(this.tempDir, { recursive: true });
21037
+ if (!fs34.existsSync(this.tempDir)) {
21038
+ fs34.mkdirSync(this.tempDir, { recursive: true });
20697
21039
  }
20698
21040
  }
20699
21041
  generateTempDbPath(filename) {
@@ -20711,7 +21053,7 @@ var MergeSessionCache = class {
20711
21053
  /** Open a TempDbReader for a given handle. Caller must close the reader. */
20712
21054
  openReader(handle) {
20713
21055
  const entry = this.cache.get(handle);
20714
- if (!entry || !fs35.existsSync(entry.tempDbPath)) return null;
21056
+ if (!entry || !fs34.existsSync(entry.tempDbPath)) return null;
20715
21057
  const adapter = openBetterSqliteDatabase(entry.tempDbPath, {
20716
21058
  readonly: true,
20717
21059
  nativeBinding: this.nativeBinding
@@ -20756,21 +21098,21 @@ var MergeSessionCache = class {
20756
21098
  };
20757
21099
 
20758
21100
  // ../../packages/node-runtime/src/services/push-importer.ts
20759
- import * as fs36 from "fs";
20760
- var SYSTEM_SENDER_ID = "SYSTEM";
20761
- var SYSTEM_MEMBER_NAME = "\u7CFB\u7EDF\u6D88\u606F";
20762
- function isRecord4(value) {
21101
+ import * as fs35 from "fs";
21102
+ var SYSTEM_SENDER_ID3 = "SYSTEM";
21103
+ var SYSTEM_MEMBER_NAME2 = "\u7CFB\u7EDF\u6D88\u606F";
21104
+ function isRecord5(value) {
20763
21105
  return typeof value === "object" && value !== null && !Array.isArray(value);
20764
21106
  }
20765
21107
  function validateOptionalString2(value, field) {
20766
21108
  return value !== void 0 && typeof value !== "string" ? `${field} must be a string` : null;
20767
21109
  }
20768
21110
  function validatePayload(payload, isNew) {
20769
- if (!isRecord4(payload)) return "payload must be an object";
21111
+ if (!isRecord5(payload)) return "payload must be an object";
20770
21112
  const messages = payload.messages;
20771
21113
  if (!Array.isArray(messages) || messages.length === 0) return "messages is required and must be a non-empty array";
20772
21114
  if (payload.chatlab !== void 0) {
20773
- if (!isRecord4(payload.chatlab)) return "chatlab must be an object";
21115
+ if (!isRecord5(payload.chatlab)) return "chatlab must be an object";
20774
21116
  if (typeof payload.chatlab.version !== "string" || payload.chatlab.version.length === 0)
20775
21117
  return "chatlab.version must be a string";
20776
21118
  if (typeof payload.chatlab.exportedAt !== "number" || !Number.isFinite(payload.chatlab.exportedAt))
@@ -20783,7 +21125,7 @@ function validatePayload(payload, isNew) {
20783
21125
  if (!payload.meta) return "meta is required for new sessions";
20784
21126
  }
20785
21127
  if (payload.meta !== void 0) {
20786
- if (!isRecord4(payload.meta)) return "meta must be an object";
21128
+ if (!isRecord5(payload.meta)) return "meta must be an object";
20787
21129
  const metaFields = ["name", "platform", "type", "groupId", "groupAvatar", "ownerId"];
20788
21130
  for (const field of metaFields) {
20789
21131
  const error = validateOptionalString2(payload.meta[field], `meta.${field}`);
@@ -20793,7 +21135,7 @@ function validatePayload(payload, isNew) {
20793
21135
  if (isNew && !payload.meta.platform) return "meta.platform is required";
20794
21136
  if (isNew && !payload.meta.type) return "meta.type is required";
20795
21137
  }
20796
- if (payload.options !== void 0 && !isRecord4(payload.options)) return "options must be an object";
21138
+ if (payload.options !== void 0 && !isRecord5(payload.options)) return "options must be an object";
20797
21139
  const { metaUpdateMode, memberUpdateMode } = payload.options ?? {};
20798
21140
  if (metaUpdateMode !== void 0 && metaUpdateMode !== "patch" && metaUpdateMode !== "none") {
20799
21141
  return `options.metaUpdateMode must be 'patch' or 'none'`;
@@ -20805,7 +21147,7 @@ function validatePayload(payload, isNew) {
20805
21147
  if (payload.members) {
20806
21148
  for (let i = 0; i < payload.members.length; i++) {
20807
21149
  const member = payload.members[i];
20808
- if (!isRecord4(member)) return `members[${i}] must be an object`;
21150
+ if (!isRecord5(member)) return `members[${i}] must be an object`;
20809
21151
  if (typeof member.platformId !== "string" || member.platformId.length === 0)
20810
21152
  return `members[${i}].platformId must be a string`;
20811
21153
  for (const field of ["accountName", "groupNickname", "avatar"]) {
@@ -20816,7 +21158,7 @@ function validatePayload(payload, isNew) {
20816
21158
  if (!Array.isArray(member.roles)) return `members[${i}].roles must be an array`;
20817
21159
  for (let j = 0; j < member.roles.length; j++) {
20818
21160
  const role = member.roles[j];
20819
- if (!isRecord4(role) || typeof role.id !== "string" || role.id.length === 0)
21161
+ if (!isRecord5(role) || typeof role.id !== "string" || role.id.length === 0)
20820
21162
  return `members[${i}].roles[${j}].id must be a string`;
20821
21163
  }
20822
21164
  }
@@ -20824,7 +21166,7 @@ function validatePayload(payload, isNew) {
20824
21166
  }
20825
21167
  for (let i = 0; i < messages.length; i++) {
20826
21168
  const msg = messages[i];
20827
- if (!isRecord4(msg)) return `messages[${i}] must be an object`;
21169
+ if (!isRecord5(msg)) return `messages[${i}] must be an object`;
20828
21170
  if (typeof msg.sender !== "string" || msg.sender.length === 0) return `messages[${i}].sender must be a string`;
20829
21171
  if (typeof msg.timestamp !== "number" || !Number.isFinite(msg.timestamp) || msg.timestamp <= 0)
20830
21172
  return `messages[${i}].timestamp must be a positive number`;
@@ -20844,17 +21186,17 @@ function validatePayload(payload, isNew) {
20844
21186
  }
20845
21187
  function queryStats(db) {
20846
21188
  const row = db.prepare("SELECT COUNT(*) as total, MIN(ts) as first, MAX(ts) as last FROM message").get();
20847
- const memberRow = db.prepare(`SELECT COUNT(*) as cnt FROM member WHERE COALESCE(account_name, '') != ?`).get(SYSTEM_MEMBER_NAME);
21189
+ const memberRow = db.prepare(`SELECT COUNT(*) as cnt FROM member WHERE COALESCE(account_name, '') != ?`).get(SYSTEM_MEMBER_NAME2);
20848
21190
  return { totalCount: row.total, memberCount: memberRow.cnt, firstTimestamp: row.first, lastTimestamp: row.last };
20849
21191
  }
20850
21192
  function normalizeSenderAccountName(sender, accountName) {
20851
- return sender === SYSTEM_SENDER_ID ? SYSTEM_MEMBER_NAME : accountName;
21193
+ return sender === SYSTEM_SENDER_ID3 ? SYSTEM_MEMBER_NAME2 : accountName;
20852
21194
  }
20853
21195
  function normalizeSenderGroupNickname(sender, groupNickname) {
20854
- return sender === SYSTEM_SENDER_ID ? SYSTEM_MEMBER_NAME : groupNickname;
21196
+ return sender === SYSTEM_SENDER_ID3 ? SYSTEM_MEMBER_NAME2 : groupNickname;
20855
21197
  }
20856
21198
  function isCountedMember(platformId) {
20857
- return platformId !== SYSTEM_SENDER_ID;
21199
+ return platformId !== SYSTEM_SENDER_ID3;
20858
21200
  }
20859
21201
  function registerPushMessageAndCheckDuplicate(message, dedupState) {
20860
21202
  return registerMessageAndCheckDuplicate(
@@ -21123,7 +21465,7 @@ async function executePushImportUnlocked(deps, sessionId, payload) {
21123
21465
  return { ok: false, reason: "invalid_payload", message: "sessionId contains invalid characters" };
21124
21466
  }
21125
21467
  const dbPath = deps.getDbPath(sessionId);
21126
- const isNew = !fs36.existsSync(dbPath);
21468
+ const isNew = !fs35.existsSync(dbPath);
21127
21469
  const validationError = validatePayload(payload, isNew);
21128
21470
  if (validationError) {
21129
21471
  return { ok: false, reason: "invalid_payload", message: validationError };
@@ -21230,6 +21572,7 @@ export {
21230
21572
  createChatLabTempDir,
21231
21573
  removeChatLabTempDir,
21232
21574
  validateChatLabFile,
21575
+ rebaseChatLabDemoDocuments,
21233
21576
  detectFormat,
21234
21577
  detectAllFormats,
21235
21578
  getSupportedFormats,
@@ -21357,6 +21700,7 @@ export {
21357
21700
  createAuthProfileLlmConfigStore,
21358
21701
  CustomProviderStore,
21359
21702
  CustomModelStore,
21703
+ createLlmRuntimeStores,
21360
21704
  normalizeAnthropicBaseUrl,
21361
21705
  normalizeOpenAICompatibleBaseUrl,
21362
21706
  buildPiModel,
@@ -21449,4 +21793,4 @@ export {
21449
21793
  hashImportBody,
21450
21794
  ImportIdempotencyCache
21451
21795
  };
21452
- //# sourceMappingURL=chunk-KWJ5FZ74.mjs.map
21796
+ //# sourceMappingURL=chunk-RRC6U56Y.mjs.map