chatlab-cli 0.31.0 → 0.31.2-beta.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 (135) hide show
  1. package/dist/{chat-command-CHV7RLBH.mjs → chat-command-V6NYTTPD.mjs} +8 -8
  2. package/dist/{chunk-DA5T64RY.mjs → chunk-54GVCXHZ.mjs} +2 -2
  3. package/dist/{chunk-T64GA5HP.mjs → chunk-5G2INROS.mjs} +867 -537
  4. package/dist/chunk-5G2INROS.mjs.map +1 -0
  5. package/dist/{chunk-JH5RAJT2.mjs → chunk-67HNEIKY.mjs} +2083 -1858
  6. package/dist/chunk-67HNEIKY.mjs.map +1 -0
  7. package/dist/{chunk-RD335EMA.mjs → chunk-7TDYBU5L.mjs} +29 -52
  8. package/dist/chunk-7TDYBU5L.mjs.map +1 -0
  9. package/dist/{chunk-RDCUGC24.mjs → chunk-HUKZ2PBC.mjs} +2 -2
  10. package/dist/{chunk-YPQ72HMX.mjs → chunk-LWC7JQ2W.mjs} +44 -5
  11. package/dist/chunk-LWC7JQ2W.mjs.map +1 -0
  12. package/dist/{chunk-EXD2SXWL.mjs → chunk-OIZ64ET3.mjs} +40 -7
  13. package/dist/chunk-OIZ64ET3.mjs.map +1 -0
  14. package/dist/{chunk-WQCY45U2.mjs → chunk-SJQVAKFA.mjs} +5 -4
  15. package/dist/chunk-SJQVAKFA.mjs.map +1 -0
  16. package/dist/{chunk-DBBL74RK.mjs → chunk-WL2ISRYH.mjs} +164 -82
  17. package/dist/chunk-WL2ISRYH.mjs.map +1 -0
  18. package/dist/{chunk-UWWFOEGF.mjs → chunk-XZ5FFDLX.mjs} +143 -137
  19. package/dist/chunk-XZ5FFDLX.mjs.map +1 -0
  20. package/dist/{chunk-SNCXU2QL.mjs → chunk-ZF67S6RY.mjs} +2 -2
  21. package/dist/cli.mjs +9 -7
  22. package/dist/contacts-worker.mjs +2 -2
  23. package/dist/global-insight-worker.mjs +1 -1
  24. package/dist/{http-3B5ARN7A.mjs → http-AMDWRKOH.mjs} +11 -11
  25. package/dist/{import-2DZGNSEX.mjs → import-WIJHB4LH.mjs} +9 -7
  26. package/dist/index.mjs +12 -12
  27. package/dist/{mcp-44I6FUUQ.mjs → mcp-NC5YNTM5.mjs} +8 -8
  28. package/dist/people-relationships-worker.mjs +2 -2
  29. package/dist/semantic-index-worker.mjs +1 -1
  30. package/dist/{src-R3QX6L3L.mjs → src-UY4GCVNF.mjs} +34 -6
  31. package/dist/{stream-import-VUEL2TTU.mjs → stream-import-JKQYRISL.mjs} +9 -7
  32. package/dist/{worker-runtime-GJAOIIZW.mjs → worker-runtime-KKUOJJTN.mjs} +5 -5
  33. package/dist-web/assets/{ActionToolsPanel-fAio70bI.css → ActionToolsPanel-BL0GQR6r.css} +1 -1
  34. package/dist-web/assets/ActionToolsPanel.vue_vue_type_script_setup_true_lang-DVdpZpfD.js +110 -0
  35. package/dist-web/assets/{BufferResource-BPGkshPa.js → BufferResource-i1amDJTV.js} +1 -1
  36. package/dist-web/assets/{CanvasRenderer-DTKkZhq4.js → CanvasRenderer-DGa7AjdC.js} +1 -1
  37. package/dist-web/assets/EChartWordcloud-BXC_4nUP.js +1 -0
  38. package/dist-web/assets/{Filter-CHXKzS2l.js → Filter-BTlq0yU-.js} +1 -1
  39. package/dist-web/assets/LoadingState.vue_vue_type_script_setup_true_lang-B2KAoiMG.js +1 -0
  40. package/dist-web/assets/MessageExportModal-D9C5t_zF.js +1 -0
  41. package/dist-web/assets/PageHeader-BEWr2vsg.js +1 -0
  42. package/dist-web/assets/{RelationshipGalaxyCanvas-Dwdy5flh.js → RelationshipGalaxyCanvas-CSgPNRif.js} +4 -4
  43. package/dist-web/assets/{RelationshipGalaxyThreeCanvas-CtY4TGen.js → RelationshipGalaxyThreeCanvas-CBAnU8vN.js} +1 -1
  44. package/dist-web/assets/{RenderTargetSystem-BE56mKRG.js → RenderTargetSystem-Ctlu222X.js} +1 -1
  45. package/dist-web/assets/ThemeCard.vue_vue_type_script_setup_true_lang-BWJ6kuSC.js +1 -0
  46. package/dist-web/assets/TimeSelect.vue_vue_type_script_setup_true_lang-D5vov0eO.js +1 -0
  47. package/dist-web/assets/{WebGLRenderer-Dm18dxOf.js → WebGLRenderer-D2Zvhmcw.js} +1 -1
  48. package/dist-web/assets/{WebGPURenderer-BF6TF-is.js → WebGPURenderer-BOtP6h9o.js} +1 -1
  49. package/dist-web/assets/annual-summary-time-range-CK0IIPsY.js +1 -0
  50. package/dist-web/assets/{base-CFPyD9Gy.js → base-BMjDSaj6.js} +1 -1
  51. package/dist-web/assets/{browserAll-Cn_CfkXl.js → browserAll-BhwLvWQY.js} +1 -1
  52. package/dist-web/assets/dateFormat-dteP1INW.js +1 -0
  53. package/dist-web/assets/{electron-B6xOabTq.js → electron-DCgfulPE.js} +1 -1
  54. package/dist-web/assets/{fetch-DMLq3xPG.js → fetch-6q7oz7ZO.js} +1 -1
  55. package/dist-web/assets/{fetch-C_EfVFJi.js → fetch-B_0HIxs5.js} +1 -1
  56. package/dist-web/assets/{fetch-DylpNKCR.js → fetch-BbU4MPPu.js} +1 -1
  57. package/dist-web/assets/fetch-BxHdB6X1.js +6 -0
  58. package/dist-web/assets/{fetch-CEhUu1Yu.js → fetch-CpvfCafG.js} +1 -1
  59. package/dist-web/assets/{fetch-etgwVKIw.js → fetch-CubnKpLG.js} +1 -1
  60. package/dist-web/assets/{fetch-BRXmDI_2.js → fetch-D5BrGna5.js} +1 -1
  61. package/dist-web/assets/fetch-DgXWr9nB.js +31 -0
  62. package/dist-web/assets/{fetch-BPkgnY0R.js → fetch-DvZuLuTE.js} +1 -1
  63. package/dist-web/assets/{fetch-DL_u25Ui.js → fetch-rJA9qLvd.js} +1 -1
  64. package/dist-web/assets/index-BfGKlkx3.js +2 -0
  65. package/dist-web/assets/index-BoalB6nB.js +1 -0
  66. package/dist-web/assets/index-Bp5VKUF9.js +1 -0
  67. package/dist-web/assets/index-Bs15Yc7I.js +1 -0
  68. package/dist-web/assets/index-CAjUCtGD.css +1 -0
  69. package/dist-web/assets/index-CLijvqy3.js +173 -0
  70. package/dist-web/assets/{index-0x1QPzKZ.js → index-CUzFFw5b.js} +1 -1
  71. package/dist-web/assets/index-Cj2GU1SR.js +1 -0
  72. package/dist-web/assets/{index-y7cxH1Et.css → index-CsqMIyA9.css} +1 -1
  73. package/dist-web/assets/index-CtmXho1w.css +1 -0
  74. package/dist-web/assets/index-D7aKwT6w.js +64 -0
  75. package/dist-web/assets/index-DXcFBsM1.js +24 -0
  76. package/dist-web/assets/index-DaZnh1zP.js +2 -0
  77. package/dist-web/assets/index-DeV8SAiM.js +25 -0
  78. package/dist-web/assets/index-WJCmqKnh.js +1 -0
  79. package/dist-web/assets/index-t6s0nOlb.js +1 -0
  80. package/dist-web/assets/people-page-header-D93GTPBO.js +1 -0
  81. package/dist-web/assets/vendor-nuxt-ui-DUpPmItD.js +15 -0
  82. package/dist-web/assets/vendor-reka-ui-BLnO2MqY.js +15 -0
  83. package/dist-web/assets/vendor-snapdom--nZvo8Sg.js +8 -0
  84. package/dist-web/assets/web-BoTDL3HM.js +1 -0
  85. package/dist-web/assets/{webworkerAll-BKGP--A4.js → webworkerAll-c0ZvpENM.js} +1 -1
  86. package/dist-web/index.html +5 -5
  87. package/package.json +1 -1
  88. package/dist/chunk-DBBL74RK.mjs.map +0 -1
  89. package/dist/chunk-EXD2SXWL.mjs.map +0 -1
  90. package/dist/chunk-JH5RAJT2.mjs.map +0 -1
  91. package/dist/chunk-RD335EMA.mjs.map +0 -1
  92. package/dist/chunk-T64GA5HP.mjs.map +0 -1
  93. package/dist/chunk-UWWFOEGF.mjs.map +0 -1
  94. package/dist/chunk-WQCY45U2.mjs.map +0 -1
  95. package/dist/chunk-YPQ72HMX.mjs.map +0 -1
  96. package/dist-web/assets/ActionToolsPanel.vue_vue_type_script_setup_true_lang-CdJT0t2f.js +0 -110
  97. package/dist-web/assets/EChartWordcloud-DU3ZYdgz.js +0 -1
  98. package/dist-web/assets/LoadingState.vue_vue_type_script_setup_true_lang-DACMroOe.js +0 -1
  99. package/dist-web/assets/MessageExportModal-h-zl0dx1.js +0 -1
  100. package/dist-web/assets/PageHeader-CK0hTsdx.js +0 -1
  101. package/dist-web/assets/ThemeCard.vue_vue_type_script_setup_true_lang-BoZyssJF.js +0 -1
  102. package/dist-web/assets/TimeSelect.vue_vue_type_script_setup_true_lang-27hMyAUE.js +0 -1
  103. package/dist-web/assets/annual-summary-time-range-DVLXK1r4.js +0 -1
  104. package/dist-web/assets/dateFormat-BcqNKTQ1.js +0 -1
  105. package/dist-web/assets/fetch-BUm1isWe.js +0 -5
  106. package/dist-web/assets/fetch-CBOJwwJp.js +0 -17
  107. package/dist-web/assets/index-B5S9FnfP.js +0 -1
  108. package/dist-web/assets/index-BS6loLHW.js +0 -1
  109. package/dist-web/assets/index-BrTlAl8b.js +0 -1
  110. package/dist-web/assets/index-C3TnydSt.js +0 -24
  111. package/dist-web/assets/index-CAWO10k1.js +0 -2
  112. package/dist-web/assets/index-C_0GHEcb.css +0 -1
  113. package/dist-web/assets/index-Chm17wNe.js +0 -2
  114. package/dist-web/assets/index-DAr_2DlV.js +0 -173
  115. package/dist-web/assets/index-Em6upenM.js +0 -64
  116. package/dist-web/assets/index-FoTy2Cce.js +0 -1
  117. package/dist-web/assets/index-YADL4XIp.js +0 -22
  118. package/dist-web/assets/index-_6lck7Bv.css +0 -1
  119. package/dist-web/assets/index-aMIgqj43.js +0 -1
  120. package/dist-web/assets/index-zZVsV5HB.js +0 -1
  121. package/dist-web/assets/people-page-header-BdKM1qhX.js +0 -1
  122. package/dist-web/assets/vendor-nuxt-ui-CS1uxE9C.js +0 -15
  123. package/dist-web/assets/vendor-reka-ui-Cta6JPvN.js +0 -11
  124. package/dist-web/assets/vendor-snapdom-XnBoh1gd.js +0 -8
  125. package/dist-web/assets/web-BUZ-dZy0.js +0 -1
  126. /package/dist/{chat-command-CHV7RLBH.mjs.map → chat-command-V6NYTTPD.mjs.map} +0 -0
  127. /package/dist/{chunk-DA5T64RY.mjs.map → chunk-54GVCXHZ.mjs.map} +0 -0
  128. /package/dist/{chunk-RDCUGC24.mjs.map → chunk-HUKZ2PBC.mjs.map} +0 -0
  129. /package/dist/{chunk-SNCXU2QL.mjs.map → chunk-ZF67S6RY.mjs.map} +0 -0
  130. /package/dist/{http-3B5ARN7A.mjs.map → http-AMDWRKOH.mjs.map} +0 -0
  131. /package/dist/{import-2DZGNSEX.mjs.map → import-WIJHB4LH.mjs.map} +0 -0
  132. /package/dist/{mcp-44I6FUUQ.mjs.map → mcp-NC5YNTM5.mjs.map} +0 -0
  133. /package/dist/{src-R3QX6L3L.mjs.map → src-UY4GCVNF.mjs.map} +0 -0
  134. /package/dist/{stream-import-VUEL2TTU.mjs.map → stream-import-JKQYRISL.mjs.map} +0 -0
  135. /package/dist/{worker-runtime-GJAOIIZW.mjs.map → worker-runtime-KKUOJJTN.mjs.map} +0 -0
@@ -9,7 +9,7 @@ import {
9
9
  createEmptyContactsDiagnostics,
10
10
  normalizeContactsTimeRangePreset,
11
11
  resolveContactsTimeRange
12
- } from "./chunk-SNCXU2QL.mjs";
12
+ } from "./chunk-ZF67S6RY.mjs";
13
13
  import {
14
14
  PEOPLE_RELATIONSHIPS_ALGORITHM_VERSION,
15
15
  buildPeopleRelationshipsNeighborhoodGraph,
@@ -18,7 +18,7 @@ import {
18
18
  computePeopleRelationshipsSnapshot,
19
19
  normalizePeopleRelationshipsTimeRangePreset,
20
20
  resolvePeopleRelationshipsTimeRange
21
- } from "./chunk-RDCUGC24.mjs";
21
+ } from "./chunk-HUKZ2PBC.mjs";
22
22
  import {
23
23
  ANNUAL_SUMMARY_ALGORITHM_VERSION
24
24
  } from "./chunk-YAQLYL52.mjs";
@@ -42,7 +42,9 @@ import {
42
42
  clearSessionIndex,
43
43
  collectPosTagStats,
44
44
  deleteAnnualSummarySnapshots,
45
+ deleteAuthProfile,
45
46
  deleteMember,
47
+ deleteMembers,
46
48
  generateIncrementalSessionIndex,
47
49
  generateMessageKey,
48
50
  generateSessionIndex,
@@ -93,7 +95,7 @@ import {
93
95
  updateSessionOwnerId,
94
96
  writeAnnualSummarySnapshot,
95
97
  writeAuthProfile
96
- } from "./chunk-UWWFOEGF.mjs";
98
+ } from "./chunk-XZ5FFDLX.mjs";
97
99
  import {
98
100
  __commonJS,
99
101
  __export,
@@ -709,8 +711,8 @@ var require_FilterBase = __commonJS({
709
711
  var FilterBase = class _FilterBase extends Transform {
710
712
  static stringFilter(string, separator) {
711
713
  return (stack) => {
712
- const path31 = stack.join(separator);
713
- return path31.length === string.length && path31 === string || path31.length > string.length && path31.substr(0, string.length) === string && path31.substr(string.length, separator.length) === separator;
714
+ const path33 = stack.join(separator);
715
+ return path33.length === string.length && path33 === string || path33.length > string.length && path33.substr(0, string.length) === string && path33.substr(string.length, separator.length) === separator;
714
716
  };
715
717
  }
716
718
  static regExpFilter(regExp, separator) {
@@ -1164,12 +1166,12 @@ var require_Assembler = __commonJS({
1164
1166
  return (this.stack.length >> 1) + (this.done ? 0 : 1);
1165
1167
  }
1166
1168
  get path() {
1167
- const path31 = [];
1169
+ const path33 = [];
1168
1170
  for (let i = 0; i < this.stack.length; i += 2) {
1169
1171
  const key = this.stack[i + 1];
1170
- path31.push(key === null ? this.stack[i].length : key);
1172
+ path33.push(key === null ? this.stack[i].length : key);
1171
1173
  }
1172
- return path31;
1174
+ return path33;
1173
1175
  }
1174
1176
  dropToLevel(level) {
1175
1177
  if (level < this.depth) {
@@ -1451,7 +1453,7 @@ var require_pend = __commonJS({
1451
1453
  var require_fd_slicer = __commonJS({
1452
1454
  "../../packages/node-runtime/node_modules/yauzl/fd-slicer.js"(exports) {
1453
1455
  "use strict";
1454
- var fs35 = __require("fs");
1456
+ var fs37 = __require("fs");
1455
1457
  var util = __require("util");
1456
1458
  var stream = __require("stream");
1457
1459
  var Readable = stream.Readable;
@@ -1471,7 +1473,7 @@ var require_fd_slicer = __commonJS({
1471
1473
  FdSlicer.prototype.read = function(buffer, offset, length, position, callback) {
1472
1474
  var self = this;
1473
1475
  self.pend.go(function(cb) {
1474
- fs35.read(self.fd, buffer, offset, length, position, function(err, bytesRead, buffer2) {
1476
+ fs37.read(self.fd, buffer, offset, length, position, function(err, bytesRead, buffer2) {
1475
1477
  cb();
1476
1478
  callback(err, bytesRead, buffer2);
1477
1479
  });
@@ -1488,7 +1490,7 @@ var require_fd_slicer = __commonJS({
1488
1490
  self.refCount -= 1;
1489
1491
  if (self.refCount < 0) throw new Error("invalid unref");
1490
1492
  if (self.refCount > 0) return;
1491
- fs35.close(self.fd, onCloseDone);
1493
+ fs37.close(self.fd, onCloseDone);
1492
1494
  function onCloseDone(err) {
1493
1495
  if (err) {
1494
1496
  self.emit("error", err);
@@ -1520,7 +1522,7 @@ var require_fd_slicer = __commonJS({
1520
1522
  }
1521
1523
  self.context.pend.go(function(cb) {
1522
1524
  var buffer = Buffer.allocUnsafe(toRead);
1523
- fs35.read(self.context.fd, buffer, 0, toRead, self.pos, function(err, bytesRead) {
1525
+ fs37.read(self.context.fd, buffer, 0, toRead, self.pos, function(err, bytesRead) {
1524
1526
  if (err) {
1525
1527
  self.destroy(err);
1526
1528
  } else if (bytesRead === 0) {
@@ -1882,7 +1884,7 @@ var require_crc32 = __commonJS({
1882
1884
  var require_yauzl = __commonJS({
1883
1885
  "../../packages/node-runtime/node_modules/yauzl/index.js"(exports) {
1884
1886
  "use strict";
1885
- var fs35 = __require("fs");
1887
+ var fs37 = __require("fs");
1886
1888
  var zlib = __require("zlib");
1887
1889
  var fd_slicer = require_fd_slicer();
1888
1890
  var util = __require("util");
@@ -1907,39 +1909,39 @@ var require_yauzl = __commonJS({
1907
1909
  exports.Entry = Entry;
1908
1910
  exports.LocalFileHeader = LocalFileHeader;
1909
1911
  exports.RandomAccessReader = RandomAccessReader;
1910
- function openPromise2(path31, options2) {
1911
- return new Promise((resolve2, reject) => {
1912
- open(path31, { ...options2, lazyEntries: true }, function(err, zipfile) {
1912
+ function openPromise2(path33, options2) {
1913
+ return new Promise((resolve4, reject) => {
1914
+ open(path33, { ...options2, lazyEntries: true }, function(err, zipfile) {
1913
1915
  if (err) return reject(err);
1914
- resolve2(zipfile);
1916
+ resolve4(zipfile);
1915
1917
  });
1916
1918
  });
1917
1919
  }
1918
1920
  function fromFdPromise(fd, options2) {
1919
- return new Promise((resolve2, reject) => {
1921
+ return new Promise((resolve4, reject) => {
1920
1922
  fromFd(fd, { ...options2, lazyEntries: true }, function(err, zipfile) {
1921
1923
  if (err) return reject(err);
1922
- resolve2(zipfile);
1924
+ resolve4(zipfile);
1923
1925
  });
1924
1926
  });
1925
1927
  }
1926
1928
  function fromBufferPromise(buffer, options2) {
1927
- return new Promise((resolve2, reject) => {
1929
+ return new Promise((resolve4, reject) => {
1928
1930
  fromBuffer(buffer, { ...options2, lazyEntries: true }, function(err, zipfile) {
1929
1931
  if (err) return reject(err);
1930
- resolve2(zipfile);
1932
+ resolve4(zipfile);
1931
1933
  });
1932
1934
  });
1933
1935
  }
1934
1936
  function fromRandomAccessReaderPromise(reader, totalSize, options2) {
1935
- return new Promise((resolve2, reject) => {
1937
+ return new Promise((resolve4, reject) => {
1936
1938
  fromRandomAccessReader(reader, totalSize, { ...options2, lazyEntries: true }, function(err, zipfile) {
1937
1939
  if (err) return reject(err);
1938
- resolve2(zipfile);
1940
+ resolve4(zipfile);
1939
1941
  });
1940
1942
  });
1941
1943
  }
1942
- function open(path31, options2, callback) {
1944
+ function open(path33, options2, callback) {
1943
1945
  if (typeof options2 === "function") {
1944
1946
  callback = options2;
1945
1947
  options2 = null;
@@ -1951,10 +1953,10 @@ var require_yauzl = __commonJS({
1951
1953
  if (options2.validateEntrySizes == null) options2.validateEntrySizes = true;
1952
1954
  if (options2.strictFileNames == null) options2.strictFileNames = false;
1953
1955
  if (callback == null) callback = defaultCallback;
1954
- fs35.open(path31, "r", function(err, fd) {
1956
+ fs37.open(path33, "r", function(err, fd) {
1955
1957
  if (err) return callback(err);
1956
1958
  fromFd(fd, options2, function(err2, zipfile) {
1957
- if (err2) fs35.close(fd, defaultCallback);
1959
+ if (err2) fs37.close(fd, defaultCallback);
1958
1960
  callback(err2, zipfile);
1959
1961
  });
1960
1962
  });
@@ -1971,7 +1973,7 @@ var require_yauzl = __commonJS({
1971
1973
  if (options2.validateEntrySizes == null) options2.validateEntrySizes = true;
1972
1974
  if (options2.strictFileNames == null) options2.strictFileNames = false;
1973
1975
  if (callback == null) callback = defaultCallback;
1974
- fs35.fstat(fd, function(err, stats) {
1976
+ fs37.fstat(fd, function(err, stats) {
1975
1977
  if (err) return callback(err);
1976
1978
  var reader = new fd_slicer.FdSlicer(fd);
1977
1979
  fromRandomAccessReader(reader, stats.size, options2, callback);
@@ -2219,15 +2221,15 @@ var require_yauzl = __commonJS({
2219
2221
  if (self.autoClose) self.close();
2220
2222
  }
2221
2223
  function onEntry(entry) {
2222
- let { resolve: resolve2 } = pendingResolveReject;
2224
+ let { resolve: resolve4 } = pendingResolveReject;
2223
2225
  pendingResolveReject = null;
2224
- resolve2({ value: entry });
2226
+ resolve4({ value: entry });
2225
2227
  }
2226
2228
  function onEnd() {
2227
- let { resolve: resolve2 } = pendingResolveReject;
2229
+ let { resolve: resolve4 } = pendingResolveReject;
2228
2230
  pendingResolveReject = null;
2229
2231
  cleanup();
2230
- resolve2({ done: true });
2232
+ resolve4({ done: true });
2231
2233
  }
2232
2234
  function onError(err) {
2233
2235
  let { reject } = pendingResolveReject;
@@ -2240,9 +2242,9 @@ var require_yauzl = __commonJS({
2240
2242
  return this;
2241
2243
  },
2242
2244
  next() {
2243
- const promise = new Promise((resolve2, reject) => {
2245
+ const promise = new Promise((resolve4, reject) => {
2244
2246
  if (pendingResolveReject != null) throw new Error("next() called before previous Promise was resolved.");
2245
- pendingResolveReject = { resolve: resolve2, reject };
2247
+ pendingResolveReject = { resolve: resolve4, reject };
2246
2248
  });
2247
2249
  self.readEntry();
2248
2250
  return promise;
@@ -2431,26 +2433,26 @@ var require_yauzl = __commonJS({
2431
2433
  });
2432
2434
  };
2433
2435
  ZipFile.prototype.openReadStreamPromise = function(entry, options2) {
2434
- return new Promise((resolve2, reject) => {
2436
+ return new Promise((resolve4, reject) => {
2435
2437
  this.openReadStream(entry, options2, function(err, readStream) {
2436
2438
  if (err) return reject(err);
2437
- resolve2(readStream);
2439
+ resolve4(readStream);
2438
2440
  });
2439
2441
  });
2440
2442
  };
2441
2443
  ZipFile.prototype.openReadStreamLowLevelPromise = function(fileDataStart, compressedSize, relativeStart, relativeEnd, decompress, uncompressedSize) {
2442
- return new Promise((resolve2, reject) => {
2444
+ return new Promise((resolve4, reject) => {
2443
2445
  this.openReadStream(fileDataStart, compressedSize, relativeStart, relativeEnd, decompress, uncompressedSize, function(err, readStream) {
2444
2446
  if (err) return reject(err);
2445
- resolve2(readStream);
2447
+ resolve4(readStream);
2446
2448
  });
2447
2449
  });
2448
2450
  };
2449
2451
  ZipFile.prototype.readLocalFileHeaderPromise = function(entry, options2) {
2450
- return new Promise((resolve2, reject) => {
2452
+ return new Promise((resolve4, reject) => {
2451
2453
  this.readLocalFileHeader(entry, options2, function(err, localFileHeader) {
2452
2454
  if (err) return reject(err);
2453
- resolve2(localFileHeader);
2455
+ resolve4(localFileHeader);
2454
2456
  });
2455
2457
  });
2456
2458
  };
@@ -2738,6 +2740,73 @@ var require_yauzl = __commonJS({
2738
2740
  }
2739
2741
  });
2740
2742
 
2743
+ // ../../packages/node-runtime/src/temp-workspace.ts
2744
+ import * as fs from "fs";
2745
+ import * as os from "os";
2746
+ import * as path from "path";
2747
+ var CHATLAB_TEMP_ROOT_ENV = "CHATLAB_TEMP_ROOT";
2748
+ var CHATLAB_TEMP_SCOPES = /* @__PURE__ */ new Set(["tests", "runtime", "imports", "merge", "sync", "parser", "build", "bench"]);
2749
+ function optionsEnv(options2) {
2750
+ return options2.env ?? process.env;
2751
+ }
2752
+ function resolveChatLabTempRoot(options2 = {}) {
2753
+ const envRoot = optionsEnv(options2)[CHATLAB_TEMP_ROOT_ENV]?.trim();
2754
+ if (envRoot) return path.resolve(envRoot);
2755
+ const platform2 = options2.platform ?? process.platform;
2756
+ const systemTempDir = options2.systemTempDir ?? os.tmpdir();
2757
+ return path.resolve(platform2 === "darwin" ? "/private/tmp/chatlab" : path.join(systemTempDir, "chatlab"));
2758
+ }
2759
+ function ensurePrivateOwnedDirectory(dirPath, label) {
2760
+ fs.mkdirSync(dirPath, { recursive: true, mode: 448 });
2761
+ const stats = fs.lstatSync(dirPath);
2762
+ if (stats.isSymbolicLink()) {
2763
+ throw new Error(`${label} must not be a symbolic link: ${dirPath}`);
2764
+ }
2765
+ if (!stats.isDirectory()) {
2766
+ throw new Error(`${label} must be a directory: ${dirPath}`);
2767
+ }
2768
+ if (typeof process.getuid === "function" && stats.uid !== process.getuid()) {
2769
+ throw new Error(`${label} is owned by another user: ${dirPath}`);
2770
+ }
2771
+ if (process.platform !== "win32") {
2772
+ fs.chmodSync(dirPath, 448);
2773
+ }
2774
+ }
2775
+ function ensureChatLabTempRoot(options2 = {}) {
2776
+ const root = resolveChatLabTempRoot(options2);
2777
+ ensurePrivateOwnedDirectory(root, "ChatLab temp root");
2778
+ optionsEnv(options2)[CHATLAB_TEMP_ROOT_ENV] = root;
2779
+ return root;
2780
+ }
2781
+ function assertValidScope(scope) {
2782
+ if (!CHATLAB_TEMP_SCOPES.has(scope)) {
2783
+ throw new Error(`Invalid ChatLab temp scope: ${scope}`);
2784
+ }
2785
+ }
2786
+ function assertValidPrefix(prefix) {
2787
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(prefix)) {
2788
+ throw new Error(`Invalid ChatLab temp prefix: ${prefix}`);
2789
+ }
2790
+ }
2791
+ function getChatLabTempScopeDir(scope, options2 = {}) {
2792
+ assertValidScope(scope);
2793
+ const scopeDir = path.join(ensureChatLabTempRoot(options2), scope);
2794
+ ensurePrivateOwnedDirectory(scopeDir, "ChatLab temp scope");
2795
+ return scopeDir;
2796
+ }
2797
+ function createChatLabTempDir(scope, prefix, options2 = {}) {
2798
+ assertValidPrefix(prefix);
2799
+ return fs.mkdtempSync(path.join(getChatLabTempScopeDir(scope, options2), prefix));
2800
+ }
2801
+ function removeChatLabTempDir(dirPath, scope, options2 = {}) {
2802
+ const scopeDir = path.resolve(getChatLabTempScopeDir(scope, options2));
2803
+ const resolvedDir = path.resolve(dirPath);
2804
+ if (path.dirname(resolvedDir) !== scopeDir) {
2805
+ throw new Error(`Refusing to remove non-owned ChatLab temp directory: ${resolvedDir}`);
2806
+ }
2807
+ fs.rmSync(resolvedDir, { recursive: true, force: true });
2808
+ }
2809
+
2741
2810
  // ../../packages/node-runtime/src/import/write-parse-result.ts
2742
2811
  function writeParseResultToDb(db, meta, members, messages) {
2743
2812
  let messageCount = 0;
@@ -2852,28 +2921,28 @@ function writeParseResultToDb(db, meta, members, messages) {
2852
2921
  }
2853
2922
 
2854
2923
  // ../../packages/parser/src/index.ts
2855
- import * as fs17 from "fs";
2856
- import * as path13 from "path";
2924
+ import * as fs18 from "fs";
2925
+ import * as path14 from "path";
2857
2926
 
2858
2927
  // ../../packages/parser/src/sniffer.ts
2859
- import * as fs from "fs";
2860
- import * as path from "path";
2928
+ import * as fs2 from "fs";
2929
+ import * as path2 from "path";
2861
2930
  var HEAD_SIZE = 64 * 1024;
2862
2931
  function readFileHead(filePath, size = HEAD_SIZE) {
2863
- const fd = fs.openSync(filePath, "r");
2932
+ const fd = fs2.openSync(filePath, "r");
2864
2933
  const buffer = Buffer.alloc(size);
2865
- const bytesRead = fs.readSync(fd, buffer, 0, size, 0);
2866
- fs.closeSync(fd);
2934
+ const bytesRead = fs2.readSync(fd, buffer, 0, size, 0);
2935
+ fs2.closeSync(fd);
2867
2936
  return buffer.slice(0, bytesRead).toString("utf-8");
2868
2937
  }
2869
2938
  function getExtension(filePath) {
2870
- return path.extname(filePath).toLowerCase();
2939
+ return path2.extname(filePath).toLowerCase();
2871
2940
  }
2872
2941
  function matchHeadSignatures(headContent, patterns) {
2873
2942
  return patterns.some((pattern) => pattern.test(headContent));
2874
2943
  }
2875
2944
  function matchFilenameSignatures(filePath, patterns) {
2876
- const filename = path.basename(filePath);
2945
+ const filename = path2.basename(filePath);
2877
2946
  return patterns.some((pattern) => pattern.test(filename));
2878
2947
  }
2879
2948
  function matchRequiredFields(headContent, fields) {
@@ -3021,18 +3090,18 @@ var import_stream_json = __toESM(require_stream_json(), 1);
3021
3090
  var import_Pick = __toESM(require_Pick(), 1);
3022
3091
  var import_StreamValues = __toESM(require_StreamValues(), 1);
3023
3092
  var import_stream_chain = __toESM(require_stream_chain(), 1);
3024
- import * as fs3 from "fs";
3093
+ import * as fs4 from "fs";
3025
3094
 
3026
3095
  // ../../packages/parser/src/utils.ts
3027
- import * as fs2 from "fs";
3096
+ import * as fs3 from "fs";
3028
3097
  function getFileSize(filePath) {
3029
- return fs2.statSync(filePath).size;
3098
+ return fs3.statSync(filePath).size;
3030
3099
  }
3031
3100
  function readFileHeadBytes(filePath, size) {
3032
- const fd = fs2.openSync(filePath, "r");
3101
+ const fd = fs3.openSync(filePath, "r");
3033
3102
  const buffer = Buffer.alloc(size);
3034
- const bytesRead = fs2.readSync(fd, buffer, 0, size, 0);
3035
- fs2.closeSync(fd);
3103
+ const bytesRead = fs3.readSync(fd, buffer, 0, size, 0);
3104
+ fs3.closeSync(fd);
3036
3105
  return buffer.slice(0, bytesRead).toString("utf-8");
3037
3106
  }
3038
3107
  var createProgress = (stage, bytesRead, totalBytes, messagesProcessed, message) => {
@@ -3062,7 +3131,7 @@ function isValidYear(timestampSeconds) {
3062
3131
  }
3063
3132
 
3064
3133
  // ../../packages/parser/src/formats/chatlab.ts
3065
- import * as path2 from "path";
3134
+ import * as path3 from "path";
3066
3135
 
3067
3136
  // ../../packages/parser/src/native/loader.ts
3068
3137
  import { createRequire } from "module";
@@ -3145,7 +3214,7 @@ async function* pumpNativeParser(adapter, options2, parser11, fallback) {
3145
3214
  if (!batch) break;
3146
3215
  messagesProcessed += batch.length;
3147
3216
  yield { type: "messages", data: batch.map((message) => adapter.mapMessage(message, metaJson)) };
3148
- await new Promise((resolve2) => setImmediate(resolve2));
3217
+ await new Promise((resolve4) => setImmediate(resolve4));
3149
3218
  }
3150
3219
  const doneProgress = createProgress("done", totalBytes, totalBytes, messagesProcessed, "");
3151
3220
  yield { type: "progress", data: doneProgress };
@@ -3243,7 +3312,7 @@ var { pick } = import_Pick.default;
3243
3312
  var { streamValues } = import_StreamValues.default;
3244
3313
  var { chain } = import_stream_chain.default;
3245
3314
  function extractNameFromFilePath(filePath) {
3246
- const basename13 = path2.basename(filePath);
3315
+ const basename13 = path3.basename(filePath);
3247
3316
  const name = basename13.replace(/\.json$/i, "");
3248
3317
  return name || "\u672A\u77E5\u7FA4\u804A";
3249
3318
  }
@@ -3317,8 +3386,8 @@ async function* parseChatLab(options2) {
3317
3386
  const members = [];
3318
3387
  const memberMapFromMessages = /* @__PURE__ */ new Map();
3319
3388
  const messageBatch = [];
3320
- await new Promise((resolve2, reject) => {
3321
- const readStream = fs3.createReadStream(filePath, { encoding: "utf-8" });
3389
+ await new Promise((resolve4, reject) => {
3390
+ const readStream = fs4.createReadStream(filePath, { encoding: "utf-8" });
3322
3391
  readStream.on("data", (chunk) => {
3323
3392
  bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
3324
3393
  });
@@ -3372,7 +3441,7 @@ async function* parseChatLab(options2) {
3372
3441
  if (batchCollector.length > 0) {
3373
3442
  messageBatch.push(...batchCollector);
3374
3443
  }
3375
- resolve2();
3444
+ resolve4();
3376
3445
  });
3377
3446
  pipeline2.on("error", reject);
3378
3447
  });
@@ -3410,11 +3479,11 @@ var module_ = {
3410
3479
  var chatlab_default = module_;
3411
3480
 
3412
3481
  // ../../packages/parser/src/formats/chatlab-jsonl.ts
3413
- import * as fs4 from "fs";
3482
+ import * as fs5 from "fs";
3414
3483
  import * as readline from "readline";
3415
- import * as path3 from "path";
3484
+ import * as path4 from "path";
3416
3485
  function extractNameFromFilePath2(filePath) {
3417
- const basename13 = path3.basename(filePath);
3486
+ const basename13 = path4.basename(filePath);
3418
3487
  const name = basename13.replace(/\.jsonl$/i, "");
3419
3488
  return name || "\u672A\u77E5\u7FA4\u804A";
3420
3489
  }
@@ -3455,7 +3524,7 @@ async function* parseChatLabJsonl(options2) {
3455
3524
  const messageBatch = [];
3456
3525
  let meta = null;
3457
3526
  let headerParsed = false;
3458
- const fileStream = fs4.createReadStream(filePath, { encoding: "utf-8" });
3527
+ const fileStream = fs5.createReadStream(filePath, { encoding: "utf-8" });
3459
3528
  const rl = readline.createInterface({
3460
3529
  input: fileStream,
3461
3530
  crlfDelay: Infinity
@@ -3580,28 +3649,30 @@ var import_stream_json3 = __toESM(require_stream_json(), 1);
3580
3649
  var import_Pick3 = __toESM(require_Pick(), 1);
3581
3650
  var import_StreamValues3 = __toESM(require_StreamValues(), 1);
3582
3651
  var import_stream_chain3 = __toESM(require_stream_chain(), 1);
3583
- import * as fs6 from "fs";
3584
- import * as path5 from "path";
3652
+ import * as fs7 from "fs";
3653
+ import * as path6 from "path";
3585
3654
 
3586
3655
  // ../../packages/parser/src/formats/shuakami-qq-preprocessor.ts
3587
3656
  var import_stream_json2 = __toESM(require_stream_json(), 1);
3588
3657
  var import_Pick2 = __toESM(require_Pick(), 1);
3589
3658
  var import_StreamValues2 = __toESM(require_StreamValues(), 1);
3590
3659
  var import_stream_chain2 = __toESM(require_stream_chain(), 1);
3591
- import * as fs5 from "fs";
3592
- import * as path4 from "path";
3593
- import * as os from "os";
3660
+ import * as fs6 from "fs";
3661
+ import * as path5 from "path";
3662
+ import * as os2 from "os";
3594
3663
  var { parser: parser3 } = import_stream_json2.default;
3595
3664
  var { pick: pick2 } = import_Pick2.default;
3596
3665
  var { streamValues: streamValues2 } = import_StreamValues2.default;
3597
3666
  var { chain: chain2 } = import_stream_chain2.default;
3598
3667
  var PREPROCESS_THRESHOLD = 50 * 1024 * 1024;
3599
3668
  function getTempDir() {
3600
- return path4.join(os.tmpdir(), "chatlab");
3669
+ const configuredRoot = process.env.CHATLAB_TEMP_ROOT?.trim();
3670
+ const root = configuredRoot ? path5.resolve(configuredRoot) : path5.resolve(process.platform === "darwin" ? "/private/tmp/chatlab" : path5.join(os2.tmpdir(), "chatlab"));
3671
+ return path5.join(root, "parser");
3601
3672
  }
3602
3673
  function ensureDir(dir) {
3603
- if (!fs5.existsSync(dir)) {
3604
- fs5.mkdirSync(dir, { recursive: true });
3674
+ if (!fs6.existsSync(dir)) {
3675
+ fs6.mkdirSync(dir, { recursive: true, mode: 448 });
3605
3676
  }
3606
3677
  }
3607
3678
  function extractJsonObject(content, key) {
@@ -3643,12 +3714,12 @@ function extractJsonObject(content, key) {
3643
3714
  }
3644
3715
  function readAvatarsFromFile(filePath) {
3645
3716
  try {
3646
- const stats = fs5.statSync(filePath);
3717
+ const stats = fs6.statSync(filePath);
3647
3718
  const tailSize = Math.min(stats.size, 5e6);
3648
- const fd = fs5.openSync(filePath, "r");
3719
+ const fd = fs6.openSync(filePath, "r");
3649
3720
  const buffer = Buffer.alloc(tailSize);
3650
- fs5.readSync(fd, buffer, 0, tailSize, stats.size - tailSize);
3651
- fs5.closeSync(fd);
3721
+ fs6.readSync(fd, buffer, 0, tailSize, stats.size - tailSize);
3722
+ fs6.closeSync(fd);
3652
3723
  const tailContent = buffer.toString("utf-8");
3653
3724
  return extractJsonObject(tailContent, "avatars");
3654
3725
  } catch {
@@ -3707,15 +3778,15 @@ async function preprocessQQJson(inputPath, onProgress) {
3707
3778
  let messagesProcessed = 0;
3708
3779
  const tempDir = getTempDir();
3709
3780
  ensureDir(tempDir);
3710
- const outputFilename = `slim_${Date.now()}_${path4.basename(inputPath)}`;
3711
- const outputPath = path4.join(tempDir, outputFilename);
3781
+ const outputFilename = `slim_${Date.now()}_${path5.basename(inputPath)}`;
3782
+ const outputPath = path5.join(tempDir, outputFilename);
3712
3783
  onProgress?.(createProgress("parsing", 0, totalBytes, 0, ""));
3713
3784
  const avatarsStr = readAvatarsFromFile(inputPath);
3714
- return new Promise((resolve2, reject) => {
3785
+ return new Promise((resolve4, reject) => {
3715
3786
  const headChunks = [];
3716
3787
  let headSize = 0;
3717
3788
  const maxHeadSize = 1e5;
3718
- const headStream = fs5.createReadStream(inputPath, { encoding: "utf-8" });
3789
+ const headStream = fs6.createReadStream(inputPath, { encoding: "utf-8" });
3719
3790
  let chatInfo = { name: "\u672A\u77E5\u7FA4\u804A", type: "group" };
3720
3791
  let metadata;
3721
3792
  let statistics;
@@ -3752,8 +3823,8 @@ async function preprocessQQJson(inputPath, onProgress) {
3752
3823
  } catch {
3753
3824
  }
3754
3825
  onProgress?.(createProgress("parsing", 0, totalBytes, 0, ""));
3755
- const readStream = fs5.createReadStream(inputPath, { encoding: "utf-8" });
3756
- const writeStream = fs5.createWriteStream(outputPath, { encoding: "utf-8" });
3826
+ const readStream = fs6.createReadStream(inputPath, { encoding: "utf-8" });
3827
+ const writeStream = fs6.createWriteStream(outputPath, { encoding: "utf-8" });
3757
3828
  readStream.on("data", (chunk) => {
3758
3829
  bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
3759
3830
  });
@@ -3793,13 +3864,13 @@ async function preprocessQQJson(inputPath, onProgress) {
3793
3864
  writeStream.end();
3794
3865
  writeStream.on("finish", () => {
3795
3866
  onProgress?.(createProgress("done", totalBytes, totalBytes, messagesProcessed, ""));
3796
- resolve2(outputPath);
3867
+ resolve4(outputPath);
3797
3868
  });
3798
3869
  });
3799
3870
  pipeline2.on("error", (err) => {
3800
3871
  writeStream.destroy();
3801
- if (fs5.existsSync(outputPath)) {
3802
- fs5.unlinkSync(outputPath);
3872
+ if (fs6.existsSync(outputPath)) {
3873
+ fs6.unlinkSync(outputPath);
3803
3874
  }
3804
3875
  onProgress?.(createProgress("error", bytesRead, totalBytes, messagesProcessed, err.message));
3805
3876
  reject(err);
@@ -3810,8 +3881,8 @@ async function preprocessQQJson(inputPath, onProgress) {
3810
3881
  }
3811
3882
  function cleanupTempFile(filePath) {
3812
3883
  try {
3813
- if (fs5.existsSync(filePath) && filePath.includes(getTempDir())) {
3814
- fs5.unlinkSync(filePath);
3884
+ if (fs6.existsSync(filePath) && path5.dirname(path5.resolve(filePath)) === path5.resolve(getTempDir())) {
3885
+ fs6.unlinkSync(filePath);
3815
3886
  }
3816
3887
  } catch {
3817
3888
  }
@@ -3878,9 +3949,12 @@ function extractJsonObject2(content, key) {
3878
3949
  return null;
3879
3950
  }
3880
3951
  function extractNameFromFilePath3(filePath) {
3881
- const basename13 = path5.basename(filePath);
3952
+ const basename13 = path6.basename(filePath);
3882
3953
  return basename13.replace(/\.json$/i, "") || "\u672A\u77E5\u7FA4\u804A";
3883
3954
  }
3955
+ function isPlaceholderSenderId(id) {
3956
+ return id === "0" || id === "\u672A\u77E5";
3957
+ }
3884
3958
  function countSenders(content) {
3885
3959
  const sendersStart = content.indexOf('"senders"');
3886
3960
  if (sendersStart === -1) return 0;
@@ -3895,8 +3969,19 @@ function countSenders(content) {
3895
3969
  }
3896
3970
  if (depth !== 0) return 0;
3897
3971
  const sendersContent = content.slice(arrayStart + 1, i - 1);
3898
- const uidMatches = sendersContent.match(/"uid"\s*:/g);
3899
- return uidMatches ? uidMatches.length : 0;
3972
+ const uidMatches = sendersContent.matchAll(/"uid"\s*:\s*"([^"]*)"/g);
3973
+ let count = 0;
3974
+ for (const match of uidMatches) {
3975
+ const uid = match[1];
3976
+ if (uid && !isPlaceholderSenderId(uid)) count++;
3977
+ }
3978
+ return count;
3979
+ }
3980
+ function resolveChatType(chatInfoType, headContent) {
3981
+ if (chatInfoType === "group") return "group" /* GROUP */;
3982
+ const sendersCount = countSenders(headContent);
3983
+ if (chatInfoType === "private") return sendersCount > 2 ? "group" /* GROUP */ : "private" /* PRIVATE */;
3984
+ return sendersCount > 2 ? "group" /* GROUP */ : sendersCount > 0 ? "private" /* PRIVATE */ : "group" /* GROUP */;
3900
3985
  }
3901
3986
  function convertMessageType(messageType, content, isRecalled) {
3902
3987
  if (isRecalled) return 81 /* RECALL */;
@@ -3950,8 +4035,7 @@ async function* parseV4(options2) {
3950
4035
  }
3951
4036
  } catch {
3952
4037
  }
3953
- const sendersCount = countSenders(headContent);
3954
- const chatType = sendersCount > 2 ? "group" /* GROUP */ : sendersCount > 0 ? "private" /* PRIVATE */ : "group" /* GROUP */;
4038
+ const chatType = resolveChatType(chatInfo.type, headContent);
3955
4039
  const meta = {
3956
4040
  name: chatInfo.name || extractNameFromFilePath3(filePath),
3957
4041
  platform: KNOWN_PLATFORMS.QQ,
@@ -3962,15 +4046,15 @@ async function* parseV4(options2) {
3962
4046
  yield { type: "meta", data: meta };
3963
4047
  const memberMap = /* @__PURE__ */ new Map();
3964
4048
  const messageBatch = [];
3965
- await new Promise((resolve2, reject) => {
3966
- const readStream = fs6.createReadStream(filePath, { encoding: "utf-8" });
4049
+ await new Promise((resolve4, reject) => {
4050
+ const readStream = fs7.createReadStream(filePath, { encoding: "utf-8" });
3967
4051
  readStream.on("data", (chunk) => {
3968
4052
  bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
3969
4053
  });
3970
4054
  const pipeline2 = chain3([readStream, parser4(), pick3({ filter: /^messages\.\d+$/ }), streamValues3()]);
3971
4055
  pipeline2.on("data", ({ value }) => {
3972
4056
  const platformId = value.sender.uin || value.sender.uid || value.rawMessage?.senderUin || value.rawMessage?.senderUid;
3973
- if (!platformId) {
4057
+ if (!platformId || isPlaceholderSenderId(platformId)) {
3974
4058
  skippedMessages++;
3975
4059
  return;
3976
4060
  }
@@ -3989,9 +4073,11 @@ async function* parseV4(options2) {
3989
4073
  skippedMessages++;
3990
4074
  return;
3991
4075
  }
3992
- const type = value.isSystemMessage ? 80 /* SYSTEM */ : convertMessageType(value.messageType, value.content, value.isRecalled);
4076
+ const isSystem = value.system ?? value.isSystemMessage;
4077
+ const isRecalled = value.recalled ?? value.isRecalled;
4078
+ const type = isSystem ? 80 /* SYSTEM */ : convertMessageType(value.messageType, value.content, isRecalled);
3993
4079
  let textContent = value.content?.text || "";
3994
- if (value.isRecalled) textContent = "[\u5DF2\u64A4\u56DE] " + textContent;
4080
+ if (isRecalled) textContent = "[\u5DF2\u64A4\u56DE] " + textContent;
3995
4081
  messageBatch.push({
3996
4082
  platformMessageId: value.messageId,
3997
4083
  // 消息的平台原始 ID
@@ -4016,17 +4102,17 @@ async function* parseV4(options2) {
4016
4102
  onProgress?.(progress);
4017
4103
  }
4018
4104
  });
4019
- pipeline2.on("end", resolve2);
4105
+ pipeline2.on("end", resolve4);
4020
4106
  pipeline2.on("error", reject);
4021
4107
  });
4022
4108
  const avatarsMap = /* @__PURE__ */ new Map();
4023
4109
  try {
4024
- const stats = fs6.statSync(filePath);
4110
+ const stats = fs7.statSync(filePath);
4025
4111
  const tailSize = Math.min(stats.size, 5e6);
4026
- const fd = fs6.openSync(filePath, "r");
4112
+ const fd = fs7.openSync(filePath, "r");
4027
4113
  const buffer = Buffer.alloc(tailSize);
4028
- fs6.readSync(fd, buffer, 0, tailSize, stats.size - tailSize);
4029
- fs6.closeSync(fd);
4114
+ fs7.readSync(fd, buffer, 0, tailSize, stats.size - tailSize);
4115
+ fs7.closeSync(fd);
4030
4116
  const tailContent = buffer.toString("utf-8");
4031
4117
  const avatarsStr = extractJsonObject2(tailContent, "avatars");
4032
4118
  if (avatarsStr) {
@@ -4078,8 +4164,8 @@ var module_3 = {
4078
4164
  var shuakami_qq_exporter_default = module_3;
4079
4165
 
4080
4166
  // ../../packages/parser/src/formats/shuakami-qq-exporter-chunked.ts
4081
- import * as fs7 from "fs";
4082
- import * as path6 from "path";
4167
+ import * as fs8 from "fs";
4168
+ import * as path7 from "path";
4083
4169
  import * as readline2 from "readline";
4084
4170
  var feature4 = {
4085
4171
  id: "shuakami-qq-exporter-chunked",
@@ -4128,7 +4214,7 @@ function convertMessageType2(msgType, content, isRecalled) {
4128
4214
  return 0 /* TEXT */;
4129
4215
  }
4130
4216
  function readManifest(manifestPath) {
4131
- const content = fs7.readFileSync(manifestPath, "utf-8");
4217
+ const content = fs8.readFileSync(manifestPath, "utf-8");
4132
4218
  return JSON.parse(content);
4133
4219
  }
4134
4220
  function getChunkRelativePath(chunk) {
@@ -4146,9 +4232,9 @@ function calculateTotalBytes(manifest, baseDir) {
4146
4232
  let total = 0;
4147
4233
  for (const chunk of manifest.chunked.chunks) {
4148
4234
  const relativePath = getChunkRelativePath(chunk);
4149
- const chunkPath = path6.join(baseDir, relativePath);
4150
- if (fs7.existsSync(chunkPath)) {
4151
- total += fs7.statSync(chunkPath).size;
4235
+ const chunkPath = path7.join(baseDir, relativePath);
4236
+ if (fs8.existsSync(chunkPath)) {
4237
+ total += fs8.statSync(chunkPath).size;
4152
4238
  }
4153
4239
  }
4154
4240
  return total;
@@ -4156,10 +4242,10 @@ function calculateTotalBytes(manifest, baseDir) {
4156
4242
  function readAvatars(baseDir, avatarsInfo) {
4157
4243
  const avatarsMap = /* @__PURE__ */ new Map();
4158
4244
  if (!avatarsInfo?.file) return avatarsMap;
4159
- const avatarsPath = path6.join(baseDir, avatarsInfo.file);
4160
- if (!fs7.existsSync(avatarsPath)) return avatarsMap;
4245
+ const avatarsPath = path7.join(baseDir, avatarsInfo.file);
4246
+ if (!fs8.existsSync(avatarsPath)) return avatarsMap;
4161
4247
  try {
4162
- const content = fs7.readFileSync(avatarsPath, "utf-8");
4248
+ const content = fs8.readFileSync(avatarsPath, "utf-8");
4163
4249
  const avatars = JSON.parse(content);
4164
4250
  for (const [uin, avatar] of Object.entries(avatars)) {
4165
4251
  if (avatar && typeof avatar === "string" && avatar.startsWith("data:image/")) {
@@ -4177,7 +4263,7 @@ async function* readJsonlFile(filePath, onParseError) {
4177
4263
  let parseErrorCount = 0;
4178
4264
  const MAX_PARSE_ERRORS_TO_LOG = 10;
4179
4265
  try {
4180
- fileStream = fs7.createReadStream(filePath, { encoding: "utf-8" });
4266
+ fileStream = fs8.createReadStream(filePath, { encoding: "utf-8" });
4181
4267
  rl = readline2.createInterface({
4182
4268
  input: fileStream,
4183
4269
  crlfDelay: Infinity
@@ -4208,7 +4294,7 @@ async function* readJsonlFile(filePath, onParseError) {
4208
4294
  async function* parseChunkedJsonl(options2) {
4209
4295
  const { filePath, batchSize = 5e3, onProgress, onLog } = options2;
4210
4296
  const manifestPath = filePath;
4211
- const baseDir = path6.dirname(manifestPath);
4297
+ const baseDir = path7.dirname(manifestPath);
4212
4298
  onLog?.("info", `\u5F00\u59CB\u89E3\u6790 manifest: ${manifestPath}`);
4213
4299
  onLog?.("info", `\u57FA\u7840\u76EE\u5F55: ${baseDir}`);
4214
4300
  let manifest;
@@ -4262,13 +4348,13 @@ async function* parseChunkedJsonl(options2) {
4262
4348
  for (let chunkIndex = 0; chunkIndex < manifest.chunked.chunks.length; chunkIndex++) {
4263
4349
  const chunkInfo = manifest.chunked.chunks[chunkIndex];
4264
4350
  const relativePath = getChunkRelativePath(chunkInfo);
4265
- const chunkPath = path6.join(baseDir, relativePath);
4351
+ const chunkPath = path7.join(baseDir, relativePath);
4266
4352
  const chunkMessageCount = getChunkMessageCount(chunkInfo);
4267
- if (!fs7.existsSync(chunkPath)) {
4353
+ if (!fs8.existsSync(chunkPath)) {
4268
4354
  onLog?.("error", `\u5206\u5757\u6587\u4EF6\u4E0D\u5B58\u5728: ${chunkPath}`);
4269
4355
  continue;
4270
4356
  }
4271
- const chunkSize = fs7.statSync(chunkPath).size;
4357
+ const chunkSize = fs8.statSync(chunkPath).size;
4272
4358
  let chunkMessagesRead = 0;
4273
4359
  let chunkParseErrors = 0;
4274
4360
  onLog?.(
@@ -4390,8 +4476,8 @@ var import_stream_json4 = __toESM(require_stream_json(), 1);
4390
4476
  var import_Pick4 = __toESM(require_Pick(), 1);
4391
4477
  var import_StreamValues4 = __toESM(require_StreamValues(), 1);
4392
4478
  var import_stream_chain4 = __toESM(require_stream_chain(), 1);
4393
- import * as fs8 from "fs";
4394
- import * as path7 from "path";
4479
+ import * as fs9 from "fs";
4480
+ import * as path8 from "path";
4395
4481
 
4396
4482
  // ../../packages/parser/src/native/weflow-native.ts
4397
4483
  var weflowAdapter = {
@@ -4464,7 +4550,7 @@ var { pick: pick4 } = import_Pick4.default;
4464
4550
  var { streamValues: streamValues4 } = import_StreamValues4.default;
4465
4551
  var { chain: chain4 } = import_stream_chain4.default;
4466
4552
  function extractNameFromFilePath4(filePath) {
4467
- const basename13 = path7.basename(filePath);
4553
+ const basename13 = path8.basename(filePath);
4468
4554
  const name = basename13.replace(/\.json$/i, "");
4469
4555
  return name || "\u672A\u77E5\u804A\u5929";
4470
4556
  }
@@ -4532,8 +4618,8 @@ async function* parseWeFlow(options2) {
4532
4618
  const headContent = readFileHeadBytes(filePath, 5e3);
4533
4619
  let session = null;
4534
4620
  try {
4535
- await new Promise((resolve2) => {
4536
- const sessionStream = fs8.createReadStream(filePath, { encoding: "utf-8" });
4621
+ await new Promise((resolve4) => {
4622
+ const sessionStream = fs9.createReadStream(filePath, { encoding: "utf-8" });
4537
4623
  let sessionContent = "";
4538
4624
  let inSession = false;
4539
4625
  let braceDepth = 0;
@@ -4584,9 +4670,9 @@ async function* parseWeFlow(options2) {
4584
4670
  } catch {
4585
4671
  }
4586
4672
  }
4587
- resolve2();
4673
+ resolve4();
4588
4674
  });
4589
- sessionStream.on("error", () => resolve2());
4675
+ sessionStream.on("error", () => resolve4());
4590
4676
  });
4591
4677
  } catch {
4592
4678
  }
@@ -4655,8 +4741,8 @@ async function* parseWeFlow(options2) {
4655
4741
  }
4656
4742
  if (avatarsMap.size === 0) {
4657
4743
  try {
4658
- await new Promise((resolve2) => {
4659
- const avatarStream = fs8.createReadStream(filePath, { encoding: "utf-8" });
4744
+ await new Promise((resolve4) => {
4745
+ const avatarStream = fs9.createReadStream(filePath, { encoding: "utf-8" });
4660
4746
  let avatarsContent = "";
4661
4747
  let inAvatars = false;
4662
4748
  let braceDepth = 0;
@@ -4712,9 +4798,9 @@ async function* parseWeFlow(options2) {
4712
4798
  } catch {
4713
4799
  }
4714
4800
  }
4715
- resolve2();
4801
+ resolve4();
4716
4802
  });
4717
- avatarStream.on("error", () => resolve2());
4803
+ avatarStream.on("error", () => resolve4());
4718
4804
  });
4719
4805
  } catch {
4720
4806
  }
@@ -4722,8 +4808,8 @@ async function* parseWeFlow(options2) {
4722
4808
  const groupAvatar = sessionData?.avatar || (groupId ? avatarsMap.get(groupId) : void 0);
4723
4809
  let ownerId;
4724
4810
  try {
4725
- await new Promise((resolve2) => {
4726
- const scanStream = fs8.createReadStream(filePath, { encoding: "utf-8" });
4811
+ await new Promise((resolve4) => {
4812
+ const scanStream = fs9.createReadStream(filePath, { encoding: "utf-8" });
4727
4813
  const scanPipeline = chain4([scanStream, parser5(), pick4({ filter: /^messages\.\d+$/ }), streamValues4()]);
4728
4814
  scanPipeline.on("data", ({ value }) => {
4729
4815
  if (value.isSend === 1 && value.senderUsername && !value.senderUsername.endsWith("@chatroom")) {
@@ -4731,9 +4817,9 @@ async function* parseWeFlow(options2) {
4731
4817
  scanStream.destroy();
4732
4818
  }
4733
4819
  });
4734
- scanStream.on("close", () => resolve2());
4735
- scanPipeline.on("end", () => resolve2());
4736
- scanPipeline.on("error", () => resolve2());
4820
+ scanStream.on("close", () => resolve4());
4821
+ scanPipeline.on("end", () => resolve4());
4822
+ scanPipeline.on("error", () => resolve4());
4737
4823
  });
4738
4824
  } catch {
4739
4825
  }
@@ -4748,8 +4834,8 @@ async function* parseWeFlow(options2) {
4748
4834
  yield { type: "meta", data: meta };
4749
4835
  const memberMap = /* @__PURE__ */ new Map();
4750
4836
  const messageBatch = [];
4751
- await new Promise((resolve2, reject) => {
4752
- const readStream = fs8.createReadStream(filePath, { encoding: "utf-8" });
4837
+ await new Promise((resolve4, reject) => {
4838
+ const readStream = fs9.createReadStream(filePath, { encoding: "utf-8" });
4753
4839
  readStream.on("data", (chunk) => {
4754
4840
  bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
4755
4841
  });
@@ -4821,7 +4907,7 @@ async function* parseWeFlow(options2) {
4821
4907
  if (batchCollector.length > 0) {
4822
4908
  messageBatch.push(...batchCollector);
4823
4909
  }
4824
- resolve2();
4910
+ resolve4();
4825
4911
  });
4826
4912
  pipeline2.on("error", reject);
4827
4913
  });
@@ -4886,7 +4972,7 @@ var import_stream_json5 = __toESM(require_stream_json(), 1);
4886
4972
  var import_Pick5 = __toESM(require_Pick(), 1);
4887
4973
  var import_StreamValues5 = __toESM(require_StreamValues(), 1);
4888
4974
  var import_stream_chain5 = __toESM(require_stream_chain(), 1);
4889
- import * as fs9 from "fs";
4975
+ import * as fs10 from "fs";
4890
4976
  var { parser: parser6 } = import_stream_json5.default;
4891
4977
  var { pick: pick5 } = import_Pick5.default;
4892
4978
  var { streamValues: streamValues5 } = import_StreamValues5.default;
@@ -5035,8 +5121,8 @@ async function* parseDiscordExporter(options2) {
5035
5121
  onLog?.("info", `\u7FA4\u804A\u540D\u79F0: ${chatName}`);
5036
5122
  const memberMap = /* @__PURE__ */ new Map();
5037
5123
  const messageBatch = [];
5038
- await new Promise((resolve2, reject) => {
5039
- const readStream = fs9.createReadStream(filePath, { encoding: "utf-8" });
5124
+ await new Promise((resolve4, reject) => {
5125
+ const readStream = fs10.createReadStream(filePath, { encoding: "utf-8" });
5040
5126
  readStream.on("data", (chunk) => {
5041
5127
  bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
5042
5128
  });
@@ -5114,7 +5200,7 @@ ${stickerTexts.join("\n")}` : stickerTexts.join("\n");
5114
5200
  if (batchCollector.length > 0) {
5115
5201
  messageBatch.push(...batchCollector);
5116
5202
  }
5117
- resolve2();
5203
+ resolve4();
5118
5204
  });
5119
5205
  pipeline2.on("error", reject);
5120
5206
  });
@@ -5152,7 +5238,7 @@ var import_stream_chain6 = __toESM(require_stream_chain(), 1);
5152
5238
  var import_stream_json6 = __toESM(require_stream_json(), 1);
5153
5239
  var import_Pick6 = __toESM(require_Pick(), 1);
5154
5240
  var import_StreamValues6 = __toESM(require_StreamValues(), 1);
5155
- import * as fs10 from "fs";
5241
+ import * as fs11 from "fs";
5156
5242
 
5157
5243
  // ../../packages/parser/src/formats/utils/telegram-utils.ts
5158
5244
  function mapChatType(telegramType) {
@@ -5237,8 +5323,8 @@ var feature8 = {
5237
5323
  };
5238
5324
  async function scanChats(filePath) {
5239
5325
  const chats = [];
5240
- return new Promise((resolve2, reject) => {
5241
- const readStream = fs10.createReadStream(filePath, { encoding: "utf-8" });
5326
+ return new Promise((resolve4, reject) => {
5327
+ const readStream = fs11.createReadStream(filePath, { encoding: "utf-8" });
5242
5328
  const pipeline2 = chain6([readStream, parser7(), pick6({ filter: /^chats\.list\.\d+$/ }), streamValues6()]);
5243
5329
  pipeline2.on("data", ({ value }) => {
5244
5330
  const chat = value;
@@ -5251,7 +5337,7 @@ async function scanChats(filePath) {
5251
5337
  });
5252
5338
  });
5253
5339
  pipeline2.on("end", () => {
5254
- resolve2(chats);
5340
+ resolve4(chats);
5255
5341
  });
5256
5342
  pipeline2.on("error", (err) => {
5257
5343
  reject(new Error(`\u626B\u63CF Telegram \u6587\u4EF6\u5931\u8D25: ${err.message}`));
@@ -5270,8 +5356,8 @@ async function* parseTelegram(options2) {
5270
5356
  onLog?.("info", `\u5F00\u59CB\u89E3\u6790 Telegram JSON \u6587\u4EF6\uFF0C\u5927\u5C0F: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`);
5271
5357
  onLog?.("info", `\u76EE\u6807\u804A\u5929\u7D22\u5F15: ${chatIndex}`);
5272
5358
  const chatPathFilter = `chats.list.${chatIndex}`;
5273
- const chatData = await new Promise((resolve2, reject) => {
5274
- const readStream = fs10.createReadStream(filePath, { encoding: "utf-8" });
5359
+ const chatData = await new Promise((resolve4, reject) => {
5360
+ const readStream = fs11.createReadStream(filePath, { encoding: "utf-8" });
5275
5361
  readStream.on("data", (chunk) => {
5276
5362
  bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
5277
5363
  });
@@ -5284,10 +5370,10 @@ async function* parseTelegram(options2) {
5284
5370
  let found = false;
5285
5371
  pipeline2.on("data", ({ value }) => {
5286
5372
  found = true;
5287
- resolve2(value);
5373
+ resolve4(value);
5288
5374
  });
5289
5375
  pipeline2.on("end", () => {
5290
- if (!found) resolve2(null);
5376
+ if (!found) resolve4(null);
5291
5377
  });
5292
5378
  pipeline2.on("error", reject);
5293
5379
  });
@@ -5379,7 +5465,7 @@ var telegram_native_default = module_8;
5379
5465
  var import_stream_chain7 = __toESM(require_stream_chain(), 1);
5380
5466
  var import_stream_json7 = __toESM(require_stream_json(), 1);
5381
5467
  var import_StreamValues7 = __toESM(require_StreamValues(), 1);
5382
- import * as fs11 from "fs";
5468
+ import * as fs12 from "fs";
5383
5469
  var { chain: chain7 } = import_stream_chain7.default;
5384
5470
  var { parser: parser8 } = import_stream_json7.default;
5385
5471
  var { streamValues: streamValues7 } = import_StreamValues7.default;
@@ -5408,18 +5494,18 @@ async function* parseTelegramSingle(options2) {
5408
5494
  yield { type: "progress", data: initialProgress };
5409
5495
  onProgress?.(initialProgress);
5410
5496
  onLog?.("info", `\u5F00\u59CB\u89E3\u6790 Telegram \u5355\u804A\u5929 JSON \u6587\u4EF6\uFF0C\u5927\u5C0F: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`);
5411
- const chatData = await new Promise((resolve2, reject) => {
5412
- const readStream = fs11.createReadStream(filePath, { encoding: "utf-8" });
5497
+ const chatData = await new Promise((resolve4, reject) => {
5498
+ const readStream = fs12.createReadStream(filePath, { encoding: "utf-8" });
5413
5499
  const pipeline2 = chain7([readStream, parser8(), streamValues7()]);
5414
5500
  let found = false;
5415
5501
  pipeline2.on("data", ({ value }) => {
5416
5502
  if (!found) {
5417
5503
  found = true;
5418
- resolve2(value);
5504
+ resolve4(value);
5419
5505
  }
5420
5506
  });
5421
5507
  pipeline2.on("end", () => {
5422
- if (!found) resolve2(null);
5508
+ if (!found) resolve4(null);
5423
5509
  });
5424
5510
  pipeline2.on("error", reject);
5425
5511
  });
@@ -5507,11 +5593,11 @@ var module_9 = {
5507
5593
  var telegram_native_single_default = module_9;
5508
5594
 
5509
5595
  // ../../packages/parser/src/formats/whatsapp-native-txt.ts
5510
- import * as fs12 from "fs";
5511
- import * as path8 from "path";
5596
+ import * as fs13 from "fs";
5597
+ import * as path9 from "path";
5512
5598
  import * as readline3 from "readline";
5513
5599
  function extractNameFromFilePath5(filePath) {
5514
- const basename13 = path8.basename(filePath);
5600
+ const basename13 = path9.basename(filePath);
5515
5601
  const matchZhCn = basename13.match(/^与(.+?)的\s*WhatsApp\s*聊天\.txt$/i);
5516
5602
  if (matchZhCn) return matchZhCn[1].trim();
5517
5603
  const matchZhTw = basename13.match(/^與(.+?)的\s*WhatsApp\s*對話\.txt$/i);
@@ -5519,7 +5605,7 @@ function extractNameFromFilePath5(filePath) {
5519
5605
  return basename13.replace(/\.txt$/i, "") || "\u672A\u77E5\u804A\u5929";
5520
5606
  }
5521
5607
  function shouldInferPrivateChatName(filePath, fallbackName) {
5522
- const basename13 = path8.basename(filePath);
5608
+ const basename13 = path9.basename(filePath);
5523
5609
  return /^_chat\.txt$/i.test(basename13) || /^whatsapp(?:[-_\s].*)?$/i.test(fallbackName);
5524
5610
  }
5525
5611
  function inferPrivateChatName(memberMap, fallbackName) {
@@ -5698,7 +5784,7 @@ async function* parseWhatsApp(options2) {
5698
5784
  messagesProcessed++;
5699
5785
  }
5700
5786
  };
5701
- const fileStream = fs12.createReadStream(filePath, { encoding: "utf-8" });
5787
+ const fileStream = fs13.createReadStream(filePath, { encoding: "utf-8" });
5702
5788
  const rl = readline3.createInterface({
5703
5789
  input: fileStream,
5704
5790
  crlfDelay: Infinity
@@ -5819,11 +5905,11 @@ var module_10 = {
5819
5905
  var whatsapp_native_txt_default = module_10;
5820
5906
 
5821
5907
  // ../../packages/parser/src/formats/qq-native-txt.ts
5822
- import * as fs13 from "fs";
5823
- import * as path9 from "path";
5908
+ import * as fs14 from "fs";
5909
+ import * as path10 from "path";
5824
5910
  import * as readline4 from "readline";
5825
5911
  function extractNameFromFilePath6(filePath) {
5826
- const basename13 = path9.basename(filePath);
5912
+ const basename13 = path10.basename(filePath);
5827
5913
  const name = basename13.replace(/\.txt$/i, "");
5828
5914
  return name || "\u672A\u77E5\u7FA4\u804A";
5829
5915
  }
@@ -5905,7 +5991,7 @@ async function* parseTxt(options2) {
5905
5991
  messagesProcessed++;
5906
5992
  }
5907
5993
  };
5908
- const fileStream = fs13.createReadStream(filePath, { encoding: "utf-8" });
5994
+ const fileStream = fs14.createReadStream(filePath, { encoding: "utf-8" });
5909
5995
  const rl = readline4.createInterface({
5910
5996
  input: fileStream,
5911
5997
  crlfDelay: Infinity
@@ -6005,8 +6091,8 @@ var module_11 = {
6005
6091
  var qq_native_txt_default = module_11;
6006
6092
 
6007
6093
  // ../../packages/parser/src/formats/instagram-native.ts
6008
- import * as fs14 from "fs";
6009
- import * as path10 from "path";
6094
+ import * as fs15 from "fs";
6095
+ import * as path11 from "path";
6010
6096
  var feature12 = {
6011
6097
  id: "instagram-native",
6012
6098
  name: "Instagram \u5B98\u65B9\u5BFC\u51FA",
@@ -6032,7 +6118,7 @@ function decodeInstagramText(text) {
6032
6118
  }
6033
6119
  }
6034
6120
  function extractNameFromFilePath7(filePath) {
6035
- const basename13 = path10.basename(filePath);
6121
+ const basename13 = path11.basename(filePath);
6036
6122
  return basename13.replace(/\.json$/i, "") || "\u672A\u77E5\u5BF9\u8BDD";
6037
6123
  }
6038
6124
  function isSystemMessage2(content) {
@@ -6101,7 +6187,7 @@ async function* parseInstagram(options2) {
6101
6187
  onLog?.("info", `\u5F00\u59CB\u89E3\u6790 Instagram \u804A\u5929\u8BB0\u5F55\uFF0C\u5927\u5C0F: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`);
6102
6188
  let data;
6103
6189
  try {
6104
- const content = fs14.readFileSync(filePath, "utf-8");
6190
+ const content = fs15.readFileSync(filePath, "utf-8");
6105
6191
  data = JSON.parse(content);
6106
6192
  } catch (error) {
6107
6193
  const err = new Error(`\u65E0\u6CD5\u89E3\u6790 Instagram JSON \u6587\u4EF6: ${error}`);
@@ -6196,8 +6282,8 @@ var import_stream_chain8 = __toESM(require_stream_chain(), 1);
6196
6282
  var import_stream_json8 = __toESM(require_stream_json(), 1);
6197
6283
  var import_Pick7 = __toESM(require_Pick(), 1);
6198
6284
  var import_StreamValues8 = __toESM(require_StreamValues(), 1);
6199
- import * as fs15 from "fs";
6200
- import * as path11 from "path";
6285
+ import * as fs16 from "fs";
6286
+ import * as path12 from "path";
6201
6287
  var { chain: chain8 } = import_stream_chain8.default;
6202
6288
  var { parser: parser9 } = import_stream_json8.default;
6203
6289
  var { pick: pick7 } = import_Pick7.default;
@@ -6280,12 +6366,12 @@ function normalizeIdentity(user) {
6280
6366
  };
6281
6367
  }
6282
6368
  function readJson(filePath) {
6283
- return JSON.parse(fs15.readFileSync(filePath, "utf8"));
6369
+ return JSON.parse(fs16.readFileSync(filePath, "utf8"));
6284
6370
  }
6285
6371
  function resolveManifestFile(manifestDir, relativePath) {
6286
- const resolved = path11.resolve(manifestDir, relativePath);
6287
- const relative2 = path11.relative(manifestDir, resolved);
6288
- if (relative2.startsWith("..") || path11.isAbsolute(relative2)) {
6372
+ const resolved = path12.resolve(manifestDir, relativePath);
6373
+ const relative2 = path12.relative(manifestDir, resolved);
6374
+ if (relative2.startsWith("..") || path12.isAbsolute(relative2)) {
6289
6375
  throw new Error(`Google Chat manifest path escapes its directory: ${relativePath}`);
6290
6376
  }
6291
6377
  return resolved;
@@ -6298,7 +6384,7 @@ function readManifest2(filePath) {
6298
6384
  if (manifest.chatType !== "private" && manifest.chatType !== "group") {
6299
6385
  throw new Error("Invalid Google Chat chat type");
6300
6386
  }
6301
- const manifestDir = path11.dirname(filePath);
6387
+ const manifestDir = path12.dirname(filePath);
6302
6388
  return {
6303
6389
  manifest,
6304
6390
  userInfoPath: resolveManifestFile(manifestDir, manifest.userInfoFile),
@@ -6376,7 +6462,7 @@ async function* parseGoogleChat(options2) {
6376
6462
  });
6377
6463
  }
6378
6464
  yield { type: "members", data: Array.from(memberMap.values()) };
6379
- const readStream = fs15.createReadStream(messagesPath, { encoding: "utf8" });
6465
+ const readStream = fs16.createReadStream(messagesPath, { encoding: "utf8" });
6380
6466
  let bytesRead = 0;
6381
6467
  let messagesProcessed = 0;
6382
6468
  readStream.on("data", (chunk) => {
@@ -6429,8 +6515,8 @@ var module_13 = {
6429
6515
  var google_chat_takeout_default = module_13;
6430
6516
 
6431
6517
  // ../../packages/parser/src/formats/line-native-txt.ts
6432
- import * as fs16 from "fs";
6433
- import * as path12 from "path";
6518
+ import * as fs17 from "fs";
6519
+ import * as path13 from "path";
6434
6520
  var feature14 = {
6435
6521
  id: "line-native-txt",
6436
6522
  name: "LINE \u5B98\u65B9\u5BFC\u51FA TXT",
@@ -6458,7 +6544,7 @@ var feature14 = {
6458
6544
  }
6459
6545
  };
6460
6546
  function extractNameFromFilePath8(filePath) {
6461
- const basename13 = path12.basename(filePath, ".txt");
6547
+ const basename13 = path13.basename(filePath, ".txt");
6462
6548
  const name = basename13.replace(/^\[LINE\]\s*/i, "").trim();
6463
6549
  return name || "\u672A\u77E5\u804A\u5929";
6464
6550
  }
@@ -6638,7 +6724,7 @@ async function* parseLINE(options2) {
6638
6724
  yield { type: "progress", data: initialProgress };
6639
6725
  onProgress?.(initialProgress);
6640
6726
  onLog?.("info", `\u5F00\u59CB\u89E3\u6790 LINE \u5BFC\u51FA\u6587\u4EF6\uFF0C\u5927\u5C0F: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`);
6641
- const content = fs16.readFileSync(filePath, "utf-8");
6727
+ const content = fs17.readFileSync(filePath, "utf-8");
6642
6728
  const lines = content.split("\n").map((line) => line.replace(/\r$/, ""));
6643
6729
  let currentDate = null;
6644
6730
  let chatName = extractNameFromFilePath8(filePath);
@@ -6946,12 +7032,12 @@ function findEntryFileInDirectory(dirPath, maxDepth = 1) {
6946
7032
  if (depth > maxDepth) return null;
6947
7033
  let entries;
6948
7034
  try {
6949
- entries = fs17.readdirSync(current, { withFileTypes: true });
7035
+ entries = fs18.readdirSync(current, { withFileTypes: true });
6950
7036
  } catch {
6951
7037
  return null;
6952
7038
  }
6953
7039
  for (const entry of entries) {
6954
- const full = path13.join(current, entry.name);
7040
+ const full = path14.join(current, entry.name);
6955
7041
  if (entry.isFile() && entry.name.endsWith(".json")) {
6956
7042
  const format = detectFormat(full);
6957
7043
  if (format) return full;
@@ -6959,7 +7045,7 @@ function findEntryFileInDirectory(dirPath, maxDepth = 1) {
6959
7045
  }
6960
7046
  for (const entry of entries) {
6961
7047
  if (entry.isDirectory()) {
6962
- const found = walk(path13.join(current, entry.name), depth + 1);
7048
+ const found = walk(path14.join(current, entry.name), depth + 1);
6963
7049
  if (found) return found;
6964
7050
  }
6965
7051
  }
@@ -7008,8 +7094,8 @@ function logNativeParserStatus() {
7008
7094
  }
7009
7095
 
7010
7096
  // ../../packages/node-runtime/src/import/perf-logger.ts
7011
- import * as fs18 from "fs";
7012
- import * as path14 from "path";
7097
+ import * as fs19 from "fs";
7098
+ import * as path15 from "path";
7013
7099
  var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
7014
7100
  LogLevel2["ERROR"] = "ERROR";
7015
7101
  LogLevel2["INFO"] = "INFO";
@@ -7021,11 +7107,11 @@ var currentLogFile = null;
7021
7107
  var errorCount = 0;
7022
7108
  function initPerfLog(sessionId, logDir) {
7023
7109
  try {
7024
- if (!fs18.existsSync(logDir)) {
7025
- fs18.mkdirSync(logDir, { recursive: true });
7110
+ if (!fs19.existsSync(logDir)) {
7111
+ fs19.mkdirSync(logDir, { recursive: true });
7026
7112
  }
7027
- currentLogFile = path14.join(logDir, `import_${sessionId}_${Date.now()}.log`);
7028
- fs18.writeFileSync(currentLogFile, `=== Import Log ===
7113
+ currentLogFile = path15.join(logDir, `import_${sessionId}_${Date.now()}.log`);
7114
+ fs19.writeFileSync(currentLogFile, `=== Import Log ===
7029
7115
  Start time: ${(/* @__PURE__ */ new Date()).toISOString()}
7030
7116
 
7031
7117
  `, "utf-8");
@@ -7046,7 +7132,7 @@ function logPerf(event, messagesProcessed, batchSize) {
7046
7132
  const logLine = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${event} | messages: ${messagesProcessed.toLocaleString()} | elapsed: ${duration}ms | speed: ${speed.toLocaleString()}/s | memory: ${memory}MB` + (batchSize ? ` | batch: ${batchSize}` : "") + "\n";
7047
7133
  if (currentLogFile) {
7048
7134
  try {
7049
- fs18.appendFileSync(currentLogFile, logLine, "utf-8");
7135
+ fs19.appendFileSync(currentLogFile, logLine, "utf-8");
7050
7136
  } catch {
7051
7137
  }
7052
7138
  }
@@ -7056,7 +7142,7 @@ function logPerf(event, messagesProcessed, batchSize) {
7056
7142
  function logPerfDetail(detail) {
7057
7143
  if (currentLogFile) {
7058
7144
  try {
7059
- fs18.appendFileSync(currentLogFile, ` ${detail}
7145
+ fs19.appendFileSync(currentLogFile, ` ${detail}
7060
7146
  `, "utf-8");
7061
7147
  } catch {
7062
7148
  }
@@ -7076,7 +7162,7 @@ function writeLogLine(level, message) {
7076
7162
  const logLine = `[${(/* @__PURE__ */ new Date()).toISOString()}] [${level}] ${message}
7077
7163
  `;
7078
7164
  try {
7079
- fs18.appendFileSync(currentLogFile, logLine, "utf-8");
7165
+ fs19.appendFileSync(currentLogFile, logLine, "utf-8");
7080
7166
  } catch {
7081
7167
  }
7082
7168
  }
@@ -7101,7 +7187,7 @@ Total members: ${totalMembers.toLocaleString()}
7101
7187
  Errors: ${errorCount}
7102
7188
  `;
7103
7189
  try {
7104
- fs18.appendFileSync(currentLogFile, summary, "utf-8");
7190
+ fs19.appendFileSync(currentLogFile, summary, "utf-8");
7105
7191
  } catch {
7106
7192
  }
7107
7193
  }
@@ -7200,8 +7286,8 @@ function segmentText(text, locale, minLength) {
7200
7286
  }
7201
7287
 
7202
7288
  // ../../packages/node-runtime/src/nlp/dict-manager.ts
7203
- import * as fs19 from "fs";
7204
- import * as path15 from "path";
7289
+ import * as fs20 from "fs";
7290
+ import * as path16 from "path";
7205
7291
  import { createHash } from "crypto";
7206
7292
  var DICT_DOWNLOAD_URL_BASE = "https://chatlab.fun/assets/nlp";
7207
7293
  var DICT_SHA256 = {
@@ -7213,19 +7299,19 @@ var AVAILABLE_DICTS = [
7213
7299
  { id: "zh-TW", label: "\u7E41\u9AD4\u4E2D\u6587", locale: "zh-TW" }
7214
7300
  ];
7215
7301
  function getDictFilePath(nlpDir, dictId) {
7216
- return path15.join(nlpDir, `${dictId}.dict`);
7302
+ return path16.join(nlpDir, `${dictId}.dict`);
7217
7303
  }
7218
7304
  function isDictDownloaded(nlpDir, dictId) {
7219
- return fs19.existsSync(getDictFilePath(nlpDir, dictId));
7305
+ return fs20.existsSync(getDictFilePath(nlpDir, dictId));
7220
7306
  }
7221
7307
  function getDictList(nlpDir) {
7222
7308
  return AVAILABLE_DICTS.map((d) => {
7223
7309
  const filePath = getDictFilePath(nlpDir, d.id);
7224
- const downloaded = fs19.existsSync(filePath);
7310
+ const downloaded = fs20.existsSync(filePath);
7225
7311
  let fileSize;
7226
7312
  if (downloaded) {
7227
7313
  try {
7228
- fileSize = fs19.statSync(filePath).size;
7314
+ fileSize = fs20.statSync(filePath).size;
7229
7315
  } catch {
7230
7316
  }
7231
7317
  }
@@ -7234,9 +7320,9 @@ function getDictList(nlpDir) {
7234
7320
  }
7235
7321
  function loadDictBuffer(nlpDir, dictId) {
7236
7322
  const filePath = getDictFilePath(nlpDir, dictId);
7237
- if (!fs19.existsSync(filePath)) return null;
7323
+ if (!fs20.existsSync(filePath)) return null;
7238
7324
  try {
7239
- return fs19.readFileSync(filePath);
7325
+ return fs20.readFileSync(filePath);
7240
7326
  } catch (error) {
7241
7327
  console.error(`[NLP DictManager] Failed to read dict file: ${filePath}`, error);
7242
7328
  return null;
@@ -7246,7 +7332,7 @@ async function downloadDict(nlpDir, dictId, onProgress) {
7246
7332
  if (!AVAILABLE_DICTS.find((d) => d.id === dictId)) {
7247
7333
  return { success: false, error: `Unknown dict: ${dictId}` };
7248
7334
  }
7249
- fs19.mkdirSync(nlpDir, { recursive: true });
7335
+ fs20.mkdirSync(nlpDir, { recursive: true });
7250
7336
  const url = `${DICT_DOWNLOAD_URL_BASE}/${dictId}.dict`;
7251
7337
  const filePath = getDictFilePath(nlpDir, dictId);
7252
7338
  const tmpPath = filePath + ".tmp";
@@ -7287,16 +7373,16 @@ async function downloadDict(nlpDir, dictId, onProgress) {
7287
7373
  if (actualSha256 !== expectedSha256) {
7288
7374
  return { success: false, error: "Dictionary integrity check failed (SHA256 mismatch)" };
7289
7375
  }
7290
- fs19.writeFileSync(tmpPath, buffer);
7291
- if (fs19.existsSync(filePath)) fs19.unlinkSync(filePath);
7292
- fs19.renameSync(tmpPath, filePath);
7376
+ fs20.writeFileSync(tmpPath, buffer);
7377
+ if (fs20.existsSync(filePath)) fs20.unlinkSync(filePath);
7378
+ fs20.renameSync(tmpPath, filePath);
7293
7379
  clearJiebaInstance(dictId);
7294
- console.log(`[NLP DictManager] Dict downloaded: ${dictId} (${fs19.statSync(filePath).size} bytes)`);
7380
+ console.log(`[NLP DictManager] Dict downloaded: ${dictId} (${fs20.statSync(filePath).size} bytes)`);
7295
7381
  return { success: true };
7296
7382
  } catch (error) {
7297
- if (fs19.existsSync(tmpPath)) {
7383
+ if (fs20.existsSync(tmpPath)) {
7298
7384
  try {
7299
- fs19.unlinkSync(tmpPath);
7385
+ fs20.unlinkSync(tmpPath);
7300
7386
  } catch {
7301
7387
  }
7302
7388
  }
@@ -7307,9 +7393,9 @@ async function downloadDict(nlpDir, dictId, onProgress) {
7307
7393
  }
7308
7394
  function deleteDict(nlpDir, dictId) {
7309
7395
  const filePath = getDictFilePath(nlpDir, dictId);
7310
- if (!fs19.existsSync(filePath)) return { success: true };
7396
+ if (!fs20.existsSync(filePath)) return { success: true };
7311
7397
  try {
7312
- fs19.unlinkSync(filePath);
7398
+ fs20.unlinkSync(filePath);
7313
7399
  clearJiebaInstance(dictId);
7314
7400
  console.log(`[NLP DictManager] Dict deleted: ${dictId}`);
7315
7401
  return { success: true };
@@ -7409,7 +7495,7 @@ function searchByFts(db, keywords, limit = 1e3, offset = 0) {
7409
7495
  }
7410
7496
 
7411
7497
  // ../../packages/node-runtime/src/import/streaming-importer.ts
7412
- import * as fs20 from "fs";
7498
+ import * as fs21 from "fs";
7413
7499
 
7414
7500
  // ../../packages/node-runtime/src/import/message-deduplicator.ts
7415
7501
  function generateFallbackMessageKey(message) {
@@ -7441,7 +7527,7 @@ function registerMessageAndCheckDuplicate(message, state) {
7441
7527
  // ../../packages/node-runtime/src/import/streaming-importer.ts
7442
7528
  var BATCH_COMMIT_SIZE = 5e4;
7443
7529
  var CHECKPOINT_INTERVAL = 2e5;
7444
- var yieldToEventLoop = () => new Promise((resolve2) => setImmediate(resolve2));
7530
+ var yieldToEventLoop = () => new Promise((resolve4) => setImmediate(resolve4));
7445
7531
  function defaultGenerateSessionId() {
7446
7532
  const ts = Date.now();
7447
7533
  const rand = Math.random().toString(36).substring(2, 8);
@@ -7890,8 +7976,8 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
7890
7976
  }
7891
7977
  return { success: true, sessionId, diagnostics };
7892
7978
  }
7893
- async function analyzeNewImport(filePath, onProgress) {
7894
- const formatFeature = detectFormat(filePath);
7979
+ async function analyzeNewImport(filePath, onProgress, options2) {
7980
+ const formatFeature = options2?.formatId ? getFormatFeatureById(options2.formatId) : detectFormat(filePath);
7895
7981
  if (!formatFeature) {
7896
7982
  return {
7897
7983
  totalMessages: 0,
@@ -7908,30 +7994,35 @@ async function analyzeNewImport(filePath, onProgress) {
7908
7994
  let totalMessages = 0;
7909
7995
  let newMessageCount = 0;
7910
7996
  let duplicateCount = 0;
7911
- await streamParseFile(filePath, {
7912
- onMeta: (parsedMeta) => {
7913
- meta = { name: parsedMeta.name, platform: parsedMeta.platform, type: parsedMeta.type };
7914
- },
7915
- onMembers: (members) => {
7916
- for (const m of members) memberSet.add(m.platformId);
7917
- },
7918
- onProgress: (progress) => {
7919
- onProgress(progress);
7920
- },
7921
- onMessageBatch: (batch) => {
7922
- for (const msg of batch) {
7923
- totalMessages++;
7924
- if (!memberSet.has(msg.senderPlatformId)) memberSet.add(msg.senderPlatformId);
7925
- const prepared = prepareMessageForCreate(msg);
7926
- if ("skipCounter" in prepared) continue;
7927
- if (registerMessageAndCheckDuplicate(prepared.message, dedupState)) {
7928
- duplicateCount++;
7929
- } else {
7930
- newMessageCount++;
7997
+ await streamParseFile(
7998
+ filePath,
7999
+ {
8000
+ formatOptions: options2?.chatIndex === void 0 ? void 0 : { chatIndex: options2.chatIndex },
8001
+ onMeta: (parsedMeta) => {
8002
+ meta = { name: parsedMeta.name, platform: parsedMeta.platform, type: parsedMeta.type };
8003
+ },
8004
+ onMembers: (members) => {
8005
+ for (const m of members) memberSet.add(m.platformId);
8006
+ },
8007
+ onProgress: (progress) => {
8008
+ onProgress(progress);
8009
+ },
8010
+ onMessageBatch: (batch) => {
8011
+ for (const msg of batch) {
8012
+ totalMessages++;
8013
+ if (!memberSet.has(msg.senderPlatformId)) memberSet.add(msg.senderPlatformId);
8014
+ const prepared = prepareMessageForCreate(msg);
8015
+ if ("skipCounter" in prepared) continue;
8016
+ if (registerMessageAndCheckDuplicate(prepared.message, dedupState)) {
8017
+ duplicateCount++;
8018
+ } else {
8019
+ newMessageCount++;
8020
+ }
7931
8021
  }
7932
8022
  }
7933
- }
7934
- });
8023
+ },
8024
+ options2?.formatId
8025
+ );
7935
8026
  return { totalMessages, newMessageCount, duplicateCount, totalMembers: memberSet.size, meta };
7936
8027
  }
7937
8028
  async function streamParseFileInfo(filePath, deps) {
@@ -7939,7 +8030,7 @@ async function streamParseFileInfo(filePath, deps) {
7939
8030
  if (!formatFeature) {
7940
8031
  throw new Error("Unrecognized file format");
7941
8032
  }
7942
- const fileSize = fs20.statSync(filePath).size;
8033
+ const fileSize = fs21.statSync(filePath).size;
7943
8034
  deps.onProgress({
7944
8035
  stage: "parsing",
7945
8036
  bytesRead: 0,
@@ -8028,7 +8119,7 @@ async function streamParseFileInfo(filePath, deps) {
8028
8119
  }
8029
8120
  db.close();
8030
8121
  try {
8031
- if (fs20.existsSync(tempDbPath)) fs20.unlinkSync(tempDbPath);
8122
+ if (fs21.existsSync(tempDbPath)) fs21.unlinkSync(tempDbPath);
8032
8123
  } catch {
8033
8124
  }
8034
8125
  throw error;
@@ -8128,8 +8219,8 @@ function normalizeImportTimestamp(timestamp) {
8128
8219
  const value = typeof timestamp === "string" && timestamp.trim() !== "" ? Number(timestamp) : timestamp;
8129
8220
  return typeof value === "number" && value > 0 && Number.isFinite(value) ? value : null;
8130
8221
  }
8131
- async function analyzeIncrementalImport(sessionId, filePath, deps) {
8132
- const formatFeature = detectFormat(filePath);
8222
+ async function analyzeIncrementalImport(sessionId, filePath, deps, options2) {
8223
+ const formatFeature = options2?.formatId ? getFormatFeatureById(options2.formatId) : detectFormat(filePath);
8133
8224
  if (!formatFeature) {
8134
8225
  return { error: "error.unrecognized_format", newMessageCount: 0, duplicateCount: 0, totalInFile: 0 };
8135
8226
  }
@@ -8144,27 +8235,32 @@ async function analyzeIncrementalImport(sessionId, filePath, deps) {
8144
8235
  let totalInFile = 0;
8145
8236
  let newMessageCount = 0;
8146
8237
  let duplicateCount = 0;
8147
- await streamParseFile(filePath, {
8148
- onMeta: () => {
8149
- },
8150
- onMembers: () => {
8151
- },
8152
- onProgress: (progress) => {
8153
- deps.onProgress(progress);
8154
- },
8155
- onMessageBatch: (batch) => {
8156
- for (const msg of batch) {
8157
- totalInFile++;
8158
- const timestamp = normalizeImportTimestamp(msg.timestamp);
8159
- if (timestamp === null) continue;
8160
- if (isDuplicate({ ...msg, timestamp }, existingPlatformMsgIds, existingKeys, existingFallbackOnlyKeys)) {
8161
- duplicateCount++;
8162
- } else {
8163
- newMessageCount++;
8238
+ await streamParseFile(
8239
+ filePath,
8240
+ {
8241
+ formatOptions: options2?.chatIndex === void 0 ? void 0 : { chatIndex: options2.chatIndex },
8242
+ onMeta: () => {
8243
+ },
8244
+ onMembers: () => {
8245
+ },
8246
+ onProgress: (progress) => {
8247
+ deps.onProgress(progress);
8248
+ },
8249
+ onMessageBatch: (batch) => {
8250
+ for (const msg of batch) {
8251
+ totalInFile++;
8252
+ const timestamp = normalizeImportTimestamp(msg.timestamp);
8253
+ if (timestamp === null) continue;
8254
+ if (isDuplicate({ ...msg, timestamp }, existingPlatformMsgIds, existingKeys, existingFallbackOnlyKeys)) {
8255
+ duplicateCount++;
8256
+ } else {
8257
+ newMessageCount++;
8258
+ }
8164
8259
  }
8165
8260
  }
8166
- }
8167
- });
8261
+ },
8262
+ options2?.formatId
8263
+ );
8168
8264
  return { newMessageCount, duplicateCount, totalInFile };
8169
8265
  }
8170
8266
  async function incrementalImport(sessionId, filePath, deps, options2) {
@@ -8418,6 +8514,12 @@ async function incrementalImport(sessionId, filePath, deps, options2) {
8418
8514
  }
8419
8515
  }
8420
8516
 
8517
+ // ../../packages/node-runtime/src/import/session-id.ts
8518
+ var SAFE_IMPORT_SESSION_ID_RE = /^[A-Za-z0-9_@-][A-Za-z0-9._@-]{0,127}$/;
8519
+ function isValidImportSessionId(sessionId) {
8520
+ return SAFE_IMPORT_SESSION_ID_RE.test(sessionId) && !sessionId.includes("..");
8521
+ }
8522
+
8421
8523
  // ../../packages/node-runtime/src/import/auto-import-matcher.ts
8422
8524
  var MATCH_WINDOW_SIZE = 5;
8423
8525
  function buildPrivateIdentity(ownerId, memberIds) {
@@ -8528,6 +8630,20 @@ async function resolveAutoImportTarget(filePath, deps, formatOptions) {
8528
8630
  }
8529
8631
 
8530
8632
  // ../../packages/node-runtime/src/import/auto-importer.ts
8633
+ async function planAutoImport(filePath, deps, options2) {
8634
+ if (options2.explicitSessionId) {
8635
+ if (!isValidImportSessionId(options2.explicitSessionId)) {
8636
+ throw new Error("sessionId contains invalid characters");
8637
+ }
8638
+ return deps.sessionExists(options2.explicitSessionId) ? { action: "incremental", sessionId: options2.explicitSessionId } : { action: "create", sessionId: options2.explicitSessionId };
8639
+ }
8640
+ const decision = await (deps.resolveTarget ?? resolveAutoImportTarget)(
8641
+ filePath,
8642
+ deps,
8643
+ options2.formatOptions
8644
+ );
8645
+ return decision.action === "incremental" ? { action: "incremental", sessionId: decision.sessionId, matchedBy: decision.matchedBy } : { action: "create", reason: decision.reason };
8646
+ }
8531
8647
  function mapCreateResult(result, createReason) {
8532
8648
  if (!result.success || !result.sessionId) {
8533
8649
  return { success: false, error: result.error, diagnostics: result.diagnostics };
@@ -8539,6 +8655,11 @@ function mapCreateResult(result, createReason) {
8539
8655
  ...createReason ? { createReason } : {},
8540
8656
  newMessageCount: result.diagnostics?.messagesWritten ?? 0,
8541
8657
  duplicateCount: result.diagnostics?.duplicateCount ?? 0,
8658
+ batch: result.diagnostics ? {
8659
+ receivedCount: result.diagnostics.messagesReceived,
8660
+ writtenCount: result.diagnostics.messagesWritten,
8661
+ duplicateCount: result.diagnostics.duplicateCount
8662
+ } : void 0,
8542
8663
  diagnostics: result.diagnostics
8543
8664
  };
8544
8665
  }
@@ -8550,61 +8671,41 @@ function mapIncrementalResult(sessionId, result, matchedBy) {
8550
8671
  importMode: "incremental",
8551
8672
  ...matchedBy ? { matchedBy } : {},
8552
8673
  newMessageCount: result.newMessageCount,
8553
- duplicateCount: result.batch?.duplicateCount ?? 0
8674
+ duplicateCount: result.batch?.duplicateCount ?? 0,
8675
+ batch: result.batch,
8676
+ session: result.session,
8677
+ updates: result.updates
8554
8678
  };
8555
8679
  }
8556
8680
  async function autoImportFile(filePath, deps, options2 = {}) {
8557
8681
  try {
8558
- if (options2.explicitSessionId) {
8559
- if (deps.sessionExists(options2.explicitSessionId)) {
8560
- const result3 = mapIncrementalResult(
8561
- options2.explicitSessionId,
8562
- await deps.appendSession(options2.explicitSessionId, filePath, options2.formatOptions)
8563
- );
8564
- appLogger.info("import", "Explicit incremental import completed", {
8565
- sessionId: options2.explicitSessionId,
8566
- success: result3.success,
8567
- newMessageCount: result3.newMessageCount,
8568
- duplicateCount: result3.duplicateCount
8569
- });
8570
- return result3;
8571
- }
8572
- const result2 = mapCreateResult(
8573
- await deps.createSession(filePath, options2.formatOptions, options2.explicitSessionId)
8574
- );
8575
- appLogger.info("import", "Explicit session import completed", {
8576
- sessionId: result2.sessionId,
8577
- success: result2.success,
8578
- importMode: result2.importMode
8682
+ if (!options2.explicitSessionId) {
8683
+ appLogger.info("import", "Automatic session matching started", {
8684
+ candidateCount: deps.listSessionIds().length
8579
8685
  });
8580
- return result2;
8581
8686
  }
8582
- appLogger.info("import", "Automatic session matching started", {
8583
- candidateCount: deps.listSessionIds().length
8584
- });
8585
- const decision = await (deps.resolveTarget ?? resolveAutoImportTarget)(
8586
- filePath,
8587
- deps,
8588
- options2.formatOptions
8589
- );
8590
- if (decision.action === "incremental") {
8687
+ const plan = await planAutoImport(filePath, deps, options2);
8688
+ if (plan.action === "incremental") {
8591
8689
  const result2 = mapIncrementalResult(
8592
- decision.sessionId,
8593
- await deps.appendSession(decision.sessionId, filePath, options2.formatOptions),
8594
- decision.matchedBy
8690
+ plan.sessionId,
8691
+ await deps.appendSession(plan.sessionId, filePath, options2.formatOptions),
8692
+ plan.matchedBy
8595
8693
  );
8596
- appLogger.info("import", "Automatic incremental import completed", {
8597
- sessionId: decision.sessionId,
8598
- matchedBy: decision.matchedBy,
8694
+ appLogger.info("import", "Incremental import completed", {
8695
+ sessionId: plan.sessionId,
8696
+ matchedBy: plan.matchedBy,
8599
8697
  success: result2.success,
8600
8698
  newMessageCount: result2.newMessageCount,
8601
8699
  duplicateCount: result2.duplicateCount
8602
8700
  });
8603
8701
  return result2;
8604
8702
  }
8605
- const result = mapCreateResult(await deps.createSession(filePath, options2.formatOptions), decision.reason);
8606
- appLogger.info("import", "Automatic import created a new session", {
8607
- reason: decision.reason,
8703
+ const result = mapCreateResult(
8704
+ await deps.createSession(filePath, options2.formatOptions, plan.sessionId),
8705
+ plan.reason
8706
+ );
8707
+ appLogger.info("import", "Import created a new session", {
8708
+ reason: plan.reason,
8608
8709
  sessionId: result.sessionId,
8609
8710
  success: result.success
8610
8711
  });
@@ -8614,10 +8715,57 @@ async function autoImportFile(filePath, deps, options2 = {}) {
8614
8715
  return { success: false, error: error instanceof Error ? error.message : String(error) };
8615
8716
  }
8616
8717
  }
8718
+ async function analyzeAutoImportFile(filePath, deps, options2 = {}) {
8719
+ try {
8720
+ const plan = await planAutoImport(filePath, deps, options2);
8721
+ if (plan.action === "incremental") {
8722
+ const analysis2 = await deps.analyzeAppendSession(plan.sessionId, filePath, options2.formatOptions);
8723
+ if (analysis2.error) return { success: false, error: analysis2.error };
8724
+ const result2 = {
8725
+ success: true,
8726
+ importMode: "incremental",
8727
+ sessionId: plan.sessionId,
8728
+ ...plan.matchedBy ? { matchedBy: plan.matchedBy } : {},
8729
+ totalMessageCount: analysis2.totalInFile,
8730
+ newMessageCount: analysis2.newMessageCount,
8731
+ duplicateCount: analysis2.duplicateCount
8732
+ };
8733
+ appLogger.info("import", "Incremental import analysis completed", {
8734
+ sessionId: plan.sessionId,
8735
+ matchedBy: plan.matchedBy,
8736
+ newMessageCount: analysis2.newMessageCount,
8737
+ duplicateCount: analysis2.duplicateCount
8738
+ });
8739
+ return result2;
8740
+ }
8741
+ const analysis = await deps.analyzeCreateSession(filePath, options2.formatOptions);
8742
+ if (analysis.error) return { success: false, error: analysis.error };
8743
+ const result = {
8744
+ success: true,
8745
+ importMode: "created",
8746
+ ...plan.sessionId ? { sessionId: plan.sessionId } : {},
8747
+ ...plan.reason ? { createReason: plan.reason } : {},
8748
+ totalMessageCount: analysis.totalMessages,
8749
+ newMessageCount: analysis.newMessageCount,
8750
+ duplicateCount: analysis.duplicateCount,
8751
+ totalMemberCount: analysis.totalMembers,
8752
+ meta: analysis.meta
8753
+ };
8754
+ appLogger.info("import", "New session import analysis completed", {
8755
+ reason: plan.reason,
8756
+ messageCount: analysis.totalMessages,
8757
+ memberCount: analysis.totalMembers
8758
+ });
8759
+ return result;
8760
+ } catch (error) {
8761
+ appLogger.error("import", "Automatic import analysis failed", error);
8762
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
8763
+ }
8764
+ }
8617
8765
 
8618
8766
  // ../../packages/node-runtime/src/import/import-lock.ts
8619
- import * as fs21 from "fs";
8620
- import * as path16 from "path";
8767
+ import * as fs22 from "fs";
8768
+ import * as path17 from "path";
8621
8769
  import { randomUUID } from "crypto";
8622
8770
  var IMPORT_LOCK_FILENAME = ".chatlab-import.lock";
8623
8771
  var IMPORT_IN_PROGRESS_ERROR_KEY = "error.import_in_progress";
@@ -8631,7 +8779,7 @@ var ImportInProgressError = class extends Error {
8631
8779
  };
8632
8780
  function parseOwner(lockPath) {
8633
8781
  try {
8634
- const parsed = JSON.parse(fs21.readFileSync(lockPath, "utf-8"));
8782
+ const parsed = JSON.parse(fs22.readFileSync(lockPath, "utf-8"));
8635
8783
  if (typeof parsed.pid !== "number" || !Number.isInteger(parsed.pid) || parsed.pid <= 0 || typeof parsed.token !== "string" || parsed.token.length === 0 || typeof parsed.startedAt !== "number") {
8636
8784
  return null;
8637
8785
  }
@@ -8654,13 +8802,13 @@ function removeStaleLock(lockPath) {
8654
8802
  if (isProcessRunning(owner.pid)) return false;
8655
8803
  } else {
8656
8804
  try {
8657
- if (Date.now() - fs21.statSync(lockPath).mtimeMs < 5e3) return false;
8805
+ if (Date.now() - fs22.statSync(lockPath).mtimeMs < 5e3) return false;
8658
8806
  } catch {
8659
8807
  return true;
8660
8808
  }
8661
8809
  }
8662
8810
  try {
8663
- fs21.unlinkSync(lockPath);
8811
+ fs22.unlinkSync(lockPath);
8664
8812
  appLogger.warn("import-lock", "Removed stale import lock", { ownerPid: owner?.pid });
8665
8813
  return true;
8666
8814
  } catch {
@@ -8669,7 +8817,7 @@ function removeStaleLock(lockPath) {
8669
8817
  }
8670
8818
  function releaseLock(lockPath, fd, owner) {
8671
8819
  try {
8672
- fs21.closeSync(fd);
8820
+ fs22.closeSync(fd);
8673
8821
  } catch (error) {
8674
8822
  appLogger.error("import-lock", "Failed to close import lock", error);
8675
8823
  }
@@ -8678,19 +8826,19 @@ function releaseLock(lockPath, fd, owner) {
8678
8826
  appLogger.warn("import-lock", "Import lock ownership changed before release");
8679
8827
  return;
8680
8828
  }
8681
- fs21.unlinkSync(lockPath);
8829
+ fs22.unlinkSync(lockPath);
8682
8830
  appLogger.info("import-lock", "Import lock released");
8683
8831
  } catch (error) {
8684
8832
  appLogger.error("import-lock", "Failed to release import lock", error);
8685
8833
  }
8686
8834
  }
8687
8835
  async function withDataDirImportLock(userDataDir, task) {
8688
- fs21.mkdirSync(userDataDir, { recursive: true });
8689
- const lockPath = path16.join(userDataDir, IMPORT_LOCK_FILENAME);
8836
+ fs22.mkdirSync(userDataDir, { recursive: true });
8837
+ const lockPath = path17.join(userDataDir, IMPORT_LOCK_FILENAME);
8690
8838
  let fd = null;
8691
8839
  for (let attempt = 0; attempt < 2; attempt++) {
8692
8840
  try {
8693
- fd = fs21.openSync(lockPath, "wx");
8841
+ fd = fs22.openSync(lockPath, "wx");
8694
8842
  break;
8695
8843
  } catch (error) {
8696
8844
  const code = error.code;
@@ -8709,8 +8857,8 @@ async function withDataDirImportLock(userDataDir, task) {
8709
8857
  startedAt: Date.now()
8710
8858
  };
8711
8859
  try {
8712
- fs21.writeFileSync(fd, JSON.stringify(owner), "utf-8");
8713
- fs21.fsyncSync(fd);
8860
+ fs22.writeFileSync(fd, JSON.stringify(owner), "utf-8");
8861
+ fs22.fsyncSync(fd);
8714
8862
  appLogger.info("import-lock", "Import lock acquired");
8715
8863
  return await task();
8716
8864
  } finally {
@@ -8730,8 +8878,8 @@ var ArchiveImportError = class extends Error {
8730
8878
 
8731
8879
  // ../../packages/node-runtime/src/import/archive/archive-reader.ts
8732
8880
  var import_yauzl = __toESM(require_yauzl(), 1);
8733
- import * as fs22 from "fs";
8734
- import * as path17 from "path";
8881
+ import * as fs23 from "fs";
8882
+ import * as path18 from "path";
8735
8883
  import { pipeline } from "stream/promises";
8736
8884
  var DEFAULT_MAX_ENTRIES = 1e5;
8737
8885
  var DEFAULT_MAX_ENTRY_BYTES = 20 * 1024 * 1024 * 1024;
@@ -8850,8 +8998,8 @@ var ZipArchiveReader = class {
8850
8998
  await this.visitEntries(async (entry, openStream) => {
8851
8999
  const destination = targets.get(entry.name);
8852
9000
  if (!destination || entry.isDirectory) return;
8853
- fs22.mkdirSync(path17.dirname(destination), { recursive: true });
8854
- await pipeline(await openStream(), fs22.createWriteStream(destination, { flags: "wx" }));
9001
+ fs23.mkdirSync(path18.dirname(destination), { recursive: true });
9002
+ await pipeline(await openStream(), fs23.createWriteStream(destination, { flags: "wx" }));
8855
9003
  remaining.delete(entry.name);
8856
9004
  });
8857
9005
  if (remaining.size > 0) {
@@ -8868,8 +9016,8 @@ var import_stream_chain9 = __toESM(require_stream_chain(), 1);
8868
9016
  var import_stream_json9 = __toESM(require_stream_json(), 1);
8869
9017
  var import_Pick8 = __toESM(require_Pick(), 1);
8870
9018
  var import_StreamValues9 = __toESM(require_StreamValues(), 1);
8871
- import * as fs23 from "fs";
8872
- import * as path18 from "path";
9019
+ import * as fs24 from "fs";
9020
+ import * as path19 from "path";
8873
9021
  var { chain: chain9 } = import_stream_chain9.default;
8874
9022
  var { parser: parser10 } = import_stream_json9.default;
8875
9023
  var { pick: pick8 } = import_Pick8.default;
@@ -8998,16 +9146,16 @@ var GoogleChatTakeoutResolver = class {
8998
9146
  `Google Chat conversation is missing required files: ${chat.chatId}`
8999
9147
  );
9000
9148
  }
9001
- fs23.mkdirSync(targetDir, { recursive: true });
9149
+ fs24.mkdirSync(targetDir, { recursive: true });
9002
9150
  await reader.pipeEntries(
9003
9151
  /* @__PURE__ */ new Map([
9004
- [userInfoEntry, path18.join(targetDir, "user_info.json")],
9005
- [groupInfoEntry, path18.join(targetDir, "group_info.json")],
9006
- [messagesEntry, path18.join(targetDir, "messages.json")]
9152
+ [userInfoEntry, path19.join(targetDir, "user_info.json")],
9153
+ [groupInfoEntry, path19.join(targetDir, "group_info.json")],
9154
+ [messagesEntry, path19.join(targetDir, "messages.json")]
9007
9155
  ])
9008
9156
  );
9009
- const manifestPath = path18.join(targetDir, "google-chat-import.json");
9010
- fs23.writeFileSync(
9157
+ const manifestPath = path19.join(targetDir, "google-chat-import.json");
9158
+ fs24.writeFileSync(
9011
9159
  manifestPath,
9012
9160
  JSON.stringify(
9013
9161
  {
@@ -9030,8 +9178,8 @@ var GoogleChatTakeoutResolver = class {
9030
9178
  };
9031
9179
 
9032
9180
  // ../../packages/node-runtime/src/import/archive/source-manager.ts
9033
- import * as fs24 from "fs";
9034
- import * as path19 from "path";
9181
+ import * as fs25 from "fs";
9182
+ import * as path20 from "path";
9035
9183
  import { randomUUID as randomUUID2 } from "crypto";
9036
9184
  var DEFAULT_TTL_MS = 30 * 60 * 1e3;
9037
9185
  var ArchiveImportSourceManager = class {
@@ -9042,11 +9190,11 @@ var ArchiveImportSourceManager = class {
9042
9190
  now;
9043
9191
  resolvers;
9044
9192
  constructor(options2 = {}) {
9045
- this.tempRoot = options2.tempRoot ?? path19.join(process.cwd(), ".chatlab-import-sources");
9193
+ this.tempRoot = options2.tempRoot ?? createChatLabTempDir("imports", "sources-");
9046
9194
  this.ttlMs = options2.ttlMs ?? DEFAULT_TTL_MS;
9047
9195
  this.now = options2.now ?? Date.now;
9048
9196
  this.resolvers = options2.resolvers ?? [new GoogleChatTakeoutResolver()];
9049
- fs24.mkdirSync(this.tempRoot, { recursive: true });
9197
+ fs25.mkdirSync(this.tempRoot, { recursive: true });
9050
9198
  }
9051
9199
  prepareLocalArchive(archivePath) {
9052
9200
  return this.prepareArchive(archivePath, false);
@@ -9103,7 +9251,7 @@ var ArchiveImportSourceManager = class {
9103
9251
  `Archive conversation was not found: ${chatId}`
9104
9252
  );
9105
9253
  }
9106
- const materializedDir = fs24.mkdtempSync(path19.join(this.tempRoot, `materialized-${sourceId}-`));
9254
+ const materializedDir = fs25.mkdtempSync(path20.join(this.tempRoot, `materialized-${sourceId}-`));
9107
9255
  try {
9108
9256
  const reader = new ZipArchiveReader(record.archivePath);
9109
9257
  const materialized = await record.resolver.materialize(reader, chat, materializedDir);
@@ -9154,7 +9302,7 @@ var ArchiveImportSourceManager = class {
9154
9302
  }
9155
9303
  removePath(targetPath) {
9156
9304
  try {
9157
- fs24.rmSync(targetPath, { recursive: true, force: true });
9305
+ fs25.rmSync(targetPath, { recursive: true, force: true });
9158
9306
  } catch {
9159
9307
  }
9160
9308
  }
@@ -9224,12 +9372,12 @@ ${rawErrorLabel}: ${details}`;
9224
9372
  }
9225
9373
 
9226
9374
  // ../../packages/node-runtime/src/ai/assistant-parser.ts
9227
- import * as path20 from "path";
9375
+ import * as path21 from "path";
9228
9376
  import matter from "gray-matter";
9229
9377
  function parseAssistantFile(content, filePath) {
9230
9378
  try {
9231
9379
  const { data: fm, content: body } = matter(content);
9232
- const id = fm.id ?? path20.basename(filePath, ".md");
9380
+ const id = fm.id ?? path21.basename(filePath, ".md");
9233
9381
  const name = fm.name;
9234
9382
  if (!name) return null;
9235
9383
  return {
@@ -9308,8 +9456,8 @@ var AssistantManager = class {
9308
9456
  }
9309
9457
  // ==================== Init ====================
9310
9458
  init() {
9311
- const { fs: fs35, assistantsDir } = this.deps;
9312
- fs35.ensureDir(assistantsDir);
9459
+ const { fs: fs37, assistantsDir } = this.deps;
9460
+ fs37.ensureDir(assistantsDir);
9313
9461
  const generalCreated = this.ensureGeneralAssistants();
9314
9462
  this.loadAll();
9315
9463
  this.initialized = true;
@@ -9320,26 +9468,26 @@ var AssistantManager = class {
9320
9468
  return { total: this.cache.size, generalCreated };
9321
9469
  }
9322
9470
  ensureGeneralAssistants() {
9323
- const { fs: fs35, assistantsDir } = this.deps;
9471
+ const { fs: fs37, assistantsDir } = this.deps;
9324
9472
  let anyCreated = false;
9325
9473
  for (const id of this.generalIds) {
9326
9474
  const config = this.getBuiltinConfig(id);
9327
9475
  if (!config) continue;
9328
- const filePath = fs35.joinPath(assistantsDir, `${id}.md`);
9329
- if (fs35.fileExists(filePath)) continue;
9330
- fs35.writeFile(filePath, serializeAssistant({ ...config, builtinId: config.id }));
9476
+ const filePath = fs37.joinPath(assistantsDir, `${id}.md`);
9477
+ if (fs37.fileExists(filePath)) continue;
9478
+ fs37.writeFile(filePath, serializeAssistant({ ...config, builtinId: config.id }));
9331
9479
  anyCreated = true;
9332
9480
  }
9333
9481
  return anyCreated;
9334
9482
  }
9335
9483
  loadAll() {
9336
- const { fs: fs35, assistantsDir } = this.deps;
9484
+ const { fs: fs37, assistantsDir } = this.deps;
9337
9485
  this.cache.clear();
9338
- const files = fs35.listFiles(assistantsDir, ".md");
9486
+ const files = fs37.listFiles(assistantsDir, ".md");
9339
9487
  for (const file of files) {
9340
9488
  try {
9341
- const filePath = fs35.joinPath(assistantsDir, file);
9342
- const content = fs35.readFile(filePath);
9489
+ const filePath = fs37.joinPath(assistantsDir, file);
9490
+ const content = fs37.readFile(filePath);
9343
9491
  const config = parseAssistantFile(content, filePath);
9344
9492
  if (config) {
9345
9493
  this.cache.set(config.id, config);
@@ -9451,12 +9599,12 @@ var AssistantManager = class {
9451
9599
  };
9452
9600
 
9453
9601
  // ../../packages/node-runtime/src/ai/skill-parser.ts
9454
- import * as path21 from "path";
9602
+ import * as path22 from "path";
9455
9603
  import matter2 from "gray-matter";
9456
9604
  function parseSkillFile(content, filePath) {
9457
9605
  try {
9458
9606
  const { data: fm, content: prompt } = matter2(content);
9459
- const id = fm.id ?? path21.basename(filePath, ".md");
9607
+ const id = fm.id ?? path22.basename(filePath, ".md");
9460
9608
  const name = fm.name;
9461
9609
  if (!name) return null;
9462
9610
  return {
@@ -9475,7 +9623,7 @@ function parseSkillFile(content, filePath) {
9475
9623
  function extractSkillId(content, filePath) {
9476
9624
  try {
9477
9625
  const { data: fm } = matter2(content);
9478
- return fm.id ?? path21.basename(filePath, ".md");
9626
+ return fm.id ?? path22.basename(filePath, ".md");
9479
9627
  } catch {
9480
9628
  return null;
9481
9629
  }
@@ -9494,8 +9642,8 @@ function validateChatScope(raw) {
9494
9642
 
9495
9643
  // ../../packages/node-runtime/src/ai/chats.ts
9496
9644
  import Database from "better-sqlite3";
9497
- import * as fs25 from "fs";
9498
- import * as path22 from "path";
9645
+ import * as fs26 from "fs";
9646
+ import * as path23 from "path";
9499
9647
  var DEFAULT_GENERAL_ID = "general_cn";
9500
9648
  var defaultLogger = {
9501
9649
  warn(_category, message, extra) {
@@ -9514,14 +9662,14 @@ var AIChatManager = class {
9514
9662
  this.nativeBinding = options2?.nativeBinding;
9515
9663
  }
9516
9664
  ensureDir(dir) {
9517
- if (!fs25.existsSync(dir)) {
9518
- fs25.mkdirSync(dir, { recursive: true });
9665
+ if (!fs26.existsSync(dir)) {
9666
+ fs26.mkdirSync(dir, { recursive: true });
9519
9667
  }
9520
9668
  }
9521
9669
  getDb() {
9522
9670
  if (this.db) return this.db;
9523
9671
  this.ensureDir(this.aiDataDir);
9524
- const dbPath = path22.join(this.aiDataDir, "conversations.db");
9672
+ const dbPath = path23.join(this.aiDataDir, "conversations.db");
9525
9673
  this.db = this.nativeBinding ? new Database(dbPath, { nativeBinding: this.nativeBinding }) : new Database(dbPath);
9526
9674
  this.db.pragma("journal_mode = WAL");
9527
9675
  this.db.exec(`
@@ -9764,16 +9912,16 @@ var AIChatManager = class {
9764
9912
  if (allRows.length === 0) return [];
9765
9913
  const rowMap = new Map(allRows.map((row) => [row.id, row]));
9766
9914
  let currentId = leafMessageId ?? this.getActiveMessageId(aiChatId);
9767
- const path31 = [];
9915
+ const path33 = [];
9768
9916
  const seen = /* @__PURE__ */ new Set();
9769
9917
  while (currentId && !seen.has(currentId)) {
9770
9918
  seen.add(currentId);
9771
9919
  const row = rowMap.get(currentId);
9772
9920
  if (!row) break;
9773
- path31.push(row);
9921
+ path33.push(row);
9774
9922
  currentId = row.parentId;
9775
9923
  }
9776
- return path31.length > 0 ? path31.reverse() : allRows;
9924
+ return path33.length > 0 ? path33.reverse() : allRows;
9777
9925
  }
9778
9926
  // ==================== 生命周期 ====================
9779
9927
  close() {
@@ -10343,21 +10491,21 @@ var SkillManagerCore = class {
10343
10491
  }
10344
10492
  // ==================== Init ====================
10345
10493
  init() {
10346
- const { fs: fs35, skillsDir } = this.deps;
10347
- fs35.ensureDir(skillsDir);
10494
+ const { fs: fs37, skillsDir } = this.deps;
10495
+ fs37.ensureDir(skillsDir);
10348
10496
  this.loadAll();
10349
10497
  this.initialized = true;
10350
10498
  this.deps.logger?.info("SkillManager", "Initialized", { total: this.cache.size });
10351
10499
  return { total: this.cache.size };
10352
10500
  }
10353
10501
  loadAll() {
10354
- const { fs: fs35, skillsDir } = this.deps;
10502
+ const { fs: fs37, skillsDir } = this.deps;
10355
10503
  this.cache.clear();
10356
- const files = fs35.listFiles(skillsDir, ".md");
10504
+ const files = fs37.listFiles(skillsDir, ".md");
10357
10505
  for (const file of files) {
10358
10506
  try {
10359
- const filePath = fs35.joinPath(skillsDir, file);
10360
- const content = fs35.readFile(filePath);
10507
+ const filePath = fs37.joinPath(skillsDir, file);
10508
+ const content = fs37.readFile(filePath);
10361
10509
  const def = parseSkillFile(content, filePath);
10362
10510
  if (def) {
10363
10511
  this.cache.set(def.id, def);
@@ -10509,8 +10657,8 @@ var SkillManagerCore = class {
10509
10657
  };
10510
10658
 
10511
10659
  // ../../packages/node-runtime/src/ai/skill-manager.ts
10512
- import * as fs26 from "fs";
10513
- import * as path23 from "path";
10660
+ import * as fs27 from "fs";
10661
+ import * as path24 from "path";
10514
10662
  var SKILLS_DIR_NAME = "skills";
10515
10663
  var defaultLogger2 = {
10516
10664
  info: () => {
@@ -10520,26 +10668,26 @@ var defaultLogger2 = {
10520
10668
  };
10521
10669
  var nodeFs = {
10522
10670
  ensureDir(dir) {
10523
- fs26.mkdirSync(dir, { recursive: true });
10671
+ fs27.mkdirSync(dir, { recursive: true });
10524
10672
  },
10525
10673
  listFiles(dir, ext) {
10526
- if (!fs26.existsSync(dir)) return [];
10527
- return fs26.readdirSync(dir).filter((file) => file.endsWith(ext));
10674
+ if (!fs27.existsSync(dir)) return [];
10675
+ return fs27.readdirSync(dir).filter((file) => file.endsWith(ext));
10528
10676
  },
10529
10677
  readFile(filePath) {
10530
- return fs26.readFileSync(filePath, "utf-8");
10678
+ return fs27.readFileSync(filePath, "utf-8");
10531
10679
  },
10532
10680
  writeFile(filePath, content) {
10533
- fs26.writeFileSync(filePath, content, "utf-8");
10681
+ fs27.writeFileSync(filePath, content, "utf-8");
10534
10682
  },
10535
10683
  deleteFile(filePath) {
10536
- fs26.unlinkSync(filePath);
10684
+ fs27.unlinkSync(filePath);
10537
10685
  },
10538
10686
  fileExists(filePath) {
10539
- return fs26.existsSync(filePath);
10687
+ return fs27.existsSync(filePath);
10540
10688
  },
10541
10689
  joinPath(...parts) {
10542
- return path23.join(...parts);
10690
+ return path24.join(...parts);
10543
10691
  }
10544
10692
  };
10545
10693
  var SkillManager = class {
@@ -10549,7 +10697,7 @@ var SkillManager = class {
10549
10697
  this.logger = logger ?? defaultLogger2;
10550
10698
  this.core = new SkillManagerCore({
10551
10699
  fs: nodeFs,
10552
- skillsDir: path23.join(aiDataDir, SKILLS_DIR_NAME),
10700
+ skillsDir: path24.join(aiDataDir, SKILLS_DIR_NAME),
10553
10701
  builtinRawSkills: [],
10554
10702
  logger: {
10555
10703
  info: () => {
@@ -14379,9 +14527,9 @@ var localeMap = {
14379
14527
  "ja-JP": ja_JP_default,
14380
14528
  "zh-TW": zh_TW_default
14381
14529
  };
14382
- function getNestedValue(obj, path31) {
14530
+ function getNestedValue(obj, path33) {
14383
14531
  let current = obj;
14384
- for (const segment2 of path31.split(".")) {
14532
+ for (const segment2 of path33.split(".")) {
14385
14533
  if (current == null || typeof current !== "object") return void 0;
14386
14534
  current = current[segment2];
14387
14535
  }
@@ -14894,6 +15042,49 @@ var LLMConfigStore = class {
14894
15042
  }
14895
15043
  };
14896
15044
 
15045
+ // ../../packages/node-runtime/src/ai/file-config-storage.ts
15046
+ import * as fs28 from "fs";
15047
+ import * as path25 from "path";
15048
+ function createFileConfigStorage(baseDir) {
15049
+ return {
15050
+ readJson(key) {
15051
+ try {
15052
+ return JSON.parse(fs28.readFileSync(path25.join(baseDir, `${key}.json`), "utf-8"));
15053
+ } catch {
15054
+ return null;
15055
+ }
15056
+ },
15057
+ writeJson(key, data) {
15058
+ fs28.mkdirSync(baseDir, { recursive: true });
15059
+ fs28.writeFileSync(path25.join(baseDir, `${key}.json`), JSON.stringify(data, null, 2), "utf-8");
15060
+ }
15061
+ };
15062
+ }
15063
+
15064
+ // ../../packages/node-runtime/src/ai/auth-profile-llm-config-store.ts
15065
+ var defaultDeps = {
15066
+ resolveApiKey: (provider, authProfile) => resolveApiKey(provider, authProfile) || void 0,
15067
+ writeAuthProfile,
15068
+ deleteAuthProfile
15069
+ };
15070
+ function getAuthProfile2(config) {
15071
+ return config.authProfile;
15072
+ }
15073
+ function createAuthProfileLlmConfigStore(storage, deps = defaultDeps) {
15074
+ return new LLMConfigStore(storage, {
15075
+ resolveApiKey: deps.resolveApiKey,
15076
+ onApiKeyCreated: (config, apiKey) => {
15077
+ const profileName = config.name?.toLowerCase().replace(/\s+/g, "-") || config.provider;
15078
+ deps.writeAuthProfile(profileName, { type: "api_key", provider: config.provider, key: apiKey });
15079
+ return profileName;
15080
+ },
15081
+ onApiKeyDeleted: (config) => {
15082
+ const profileName = getAuthProfile2(config);
15083
+ if (profileName) deps.deleteAuthProfile(profileName);
15084
+ }
15085
+ });
15086
+ }
15087
+
14897
15088
  // ../../packages/node-runtime/src/ai/custom-store.ts
14898
15089
  function generateCustomId() {
14899
15090
  return `custom:${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
@@ -15713,8 +15904,8 @@ function exportWithFormat(params, openDatabase) {
15713
15904
  }
15714
15905
 
15715
15906
  // ../../packages/node-runtime/src/merger/temp-db.ts
15716
- import * as fs27 from "fs";
15717
- import * as path24 from "path";
15907
+ import * as fs29 from "fs";
15908
+ import * as path26 from "path";
15718
15909
  var TEMP_DB_SCHEMA = `
15719
15910
  CREATE TABLE IF NOT EXISTS meta (
15720
15911
  name TEXT NOT NULL,
@@ -15959,21 +16150,21 @@ function exportSessionToJson(db) {
15959
16150
  }
15960
16151
  function deleteTempDatabase(dbPath) {
15961
16152
  try {
15962
- if (fs27.existsSync(dbPath)) fs27.unlinkSync(dbPath);
16153
+ if (fs29.existsSync(dbPath)) fs29.unlinkSync(dbPath);
15963
16154
  const walPath = dbPath + "-wal";
15964
16155
  const shmPath = dbPath + "-shm";
15965
- if (fs27.existsSync(walPath)) fs27.unlinkSync(walPath);
15966
- if (fs27.existsSync(shmPath)) fs27.unlinkSync(shmPath);
16156
+ if (fs29.existsSync(walPath)) fs29.unlinkSync(walPath);
16157
+ if (fs29.existsSync(shmPath)) fs29.unlinkSync(shmPath);
15967
16158
  } catch {
15968
16159
  }
15969
16160
  }
15970
16161
  function cleanupTempDatabases(tempDir) {
15971
16162
  try {
15972
- if (!fs27.existsSync(tempDir)) return;
15973
- const files = fs27.readdirSync(tempDir);
16163
+ if (!fs29.existsSync(tempDir)) return;
16164
+ const files = fs29.readdirSync(tempDir);
15974
16165
  for (const file of files) {
15975
16166
  if (file.startsWith("merge_") && file.endsWith(".db")) {
15976
- deleteTempDatabase(path24.join(tempDir, file));
16167
+ deleteTempDatabase(path26.join(tempDir, file));
15977
16168
  }
15978
16169
  }
15979
16170
  } catch {
@@ -16052,6 +16243,7 @@ function deleteSession(adapter, sessionId) {
16052
16243
  var member_service_exports = {};
16053
16244
  __export(member_service_exports, {
16054
16245
  deleteMember: () => deleteMember2,
16246
+ deleteMembers: () => deleteMembers2,
16055
16247
  getMemberNameHistory: () => getMemberNameHistory2,
16056
16248
  getMembers: () => getMembers,
16057
16249
  getMembersPaginated: () => getMembersPaginated2,
@@ -16085,6 +16277,10 @@ function deleteMember2(adapter, sessionId, memberId) {
16085
16277
  const db = adapter.ensureWritable(sessionId);
16086
16278
  return deleteMember(db, memberId);
16087
16279
  }
16280
+ function deleteMembers2(adapter, sessionId, memberIds) {
16281
+ const db = adapter.ensureWritable(sessionId);
16282
+ return deleteMembers(db, memberIds);
16283
+ }
16088
16284
  function getMemberNameHistory2(adapter, sessionId, memberId) {
16089
16285
  const db = adapter.ensureReadonly(sessionId);
16090
16286
  return getMemberNameHistory(db, memberId);
@@ -16353,8 +16549,8 @@ function clearSessionOwner(adapter, sessionId) {
16353
16549
  }
16354
16550
 
16355
16551
  // ../../packages/node-runtime/src/services/contacts/overrides.ts
16356
- import fs28 from "fs";
16357
- import path25 from "path";
16552
+ import fs30 from "fs";
16553
+ import path27 from "path";
16358
16554
  var CONTACT_OVERRIDES_FILE_NAME = "contact-overrides.json";
16359
16555
  var CONTACT_OVERRIDES_TMP_PREFIX = "contact-overrides.tmp-";
16360
16556
  var CONTACT_OVERRIDES_VERSION = 1;
@@ -16365,23 +16561,23 @@ function createEmptyContactOverridesFile() {
16365
16561
  };
16366
16562
  }
16367
16563
  function getContactOverridesPath(snapshotDir) {
16368
- return path25.join(snapshotDir, CONTACT_OVERRIDES_FILE_NAME);
16564
+ return path27.join(snapshotDir, CONTACT_OVERRIDES_FILE_NAME);
16369
16565
  }
16370
16566
  function readContactOverrides(snapshotDir) {
16371
16567
  const filePath = getContactOverridesPath(snapshotDir);
16372
- if (!fs28.existsSync(filePath)) return createEmptyContactOverridesFile();
16568
+ if (!fs30.existsSync(filePath)) return createEmptyContactOverridesFile();
16373
16569
  try {
16374
- return normalizeContactOverrides(JSON.parse(fs28.readFileSync(filePath, "utf-8")));
16570
+ return normalizeContactOverrides(JSON.parse(fs30.readFileSync(filePath, "utf-8")));
16375
16571
  } catch (error) {
16376
16572
  appLogger.warn("contacts", "contact overrides file is unreadable", error);
16377
16573
  return createEmptyContactOverridesFile();
16378
16574
  }
16379
16575
  }
16380
16576
  function writeContactOverrides(snapshotDir, overrides) {
16381
- if (!fs28.existsSync(snapshotDir)) fs28.mkdirSync(snapshotDir, { recursive: true });
16382
- const tmpPath = path25.join(snapshotDir, `${CONTACT_OVERRIDES_TMP_PREFIX}${process.pid}-${Date.now()}`);
16383
- fs28.writeFileSync(tmpPath, JSON.stringify(normalizeContactOverrides(overrides), null, 2), "utf-8");
16384
- fs28.renameSync(tmpPath, getContactOverridesPath(snapshotDir));
16577
+ if (!fs30.existsSync(snapshotDir)) fs30.mkdirSync(snapshotDir, { recursive: true });
16578
+ const tmpPath = path27.join(snapshotDir, `${CONTACT_OVERRIDES_TMP_PREFIX}${process.pid}-${Date.now()}`);
16579
+ fs30.writeFileSync(tmpPath, JSON.stringify(normalizeContactOverrides(overrides), null, 2), "utf-8");
16580
+ fs30.renameSync(tmpPath, getContactOverridesPath(snapshotDir));
16385
16581
  }
16386
16582
  function normalizeContactOverrides(value) {
16387
16583
  const input = isRecord2(value) ? value : {};
@@ -16416,23 +16612,23 @@ function buildContactsSignature(adapter, timeRangePreset) {
16416
16612
  }
16417
16613
 
16418
16614
  // ../../packages/node-runtime/src/services/contacts/snapshot.ts
16419
- import fs29 from "fs";
16420
- import path26 from "path";
16615
+ import fs31 from "fs";
16616
+ import path28 from "path";
16421
16617
  var CONTACTS_SNAPSHOT_TMP_PREFIX = "contacts-snapshot.tmp-";
16422
16618
  function getContactsSnapshotPath(snapshotDir, timeRangePreset) {
16423
16619
  const preset = normalizeContactsTimeRangePreset(timeRangePreset);
16424
- return path26.join(snapshotDir, `contacts-snapshot-${preset}.json`);
16620
+ return path28.join(snapshotDir, `contacts-snapshot-${preset}.json`);
16425
16621
  }
16426
16622
  function readContactsSnapshot(snapshotDir, timeRangePreset, options2 = {}) {
16427
16623
  const snapshotPath = getContactsSnapshotPath(snapshotDir, timeRangePreset);
16428
- if (!fs29.existsSync(snapshotPath)) return null;
16624
+ if (!fs31.existsSync(snapshotPath)) return null;
16429
16625
  try {
16430
- return JSON.parse(fs29.readFileSync(snapshotPath, "utf-8"));
16626
+ return JSON.parse(fs31.readFileSync(snapshotPath, "utf-8"));
16431
16627
  } catch (error) {
16432
16628
  const ts = options2.now?.() ?? Date.now();
16433
- const backupPath = path26.join(snapshotDir, `contacts-snapshot.corrupt-${ts}.json`);
16629
+ const backupPath = path28.join(snapshotDir, `contacts-snapshot.corrupt-${ts}.json`);
16434
16630
  try {
16435
- fs29.renameSync(snapshotPath, backupPath);
16631
+ fs31.renameSync(snapshotPath, backupPath);
16436
16632
  } catch (renameError) {
16437
16633
  appLogger.warn("contacts", "failed to backup corrupt contacts snapshot", renameError);
16438
16634
  }
@@ -16441,17 +16637,17 @@ function readContactsSnapshot(snapshotDir, timeRangePreset, options2 = {}) {
16441
16637
  }
16442
16638
  }
16443
16639
  function writeContactsSnapshot(snapshotDir, snapshot) {
16444
- if (!fs29.existsSync(snapshotDir)) fs29.mkdirSync(snapshotDir, { recursive: true });
16445
- const tmpPath = path26.join(snapshotDir, `${CONTACTS_SNAPSHOT_TMP_PREFIX}${process.pid}-${Date.now()}`);
16446
- fs29.writeFileSync(tmpPath, JSON.stringify(snapshot, null, 2), "utf-8");
16447
- fs29.renameSync(tmpPath, getContactsSnapshotPath(snapshotDir, snapshot.timeRange.preset));
16640
+ if (!fs31.existsSync(snapshotDir)) fs31.mkdirSync(snapshotDir, { recursive: true });
16641
+ const tmpPath = path28.join(snapshotDir, `${CONTACTS_SNAPSHOT_TMP_PREFIX}${process.pid}-${Date.now()}`);
16642
+ fs31.writeFileSync(tmpPath, JSON.stringify(snapshot, null, 2), "utf-8");
16643
+ fs31.renameSync(tmpPath, getContactsSnapshotPath(snapshotDir, snapshot.timeRange.preset));
16448
16644
  }
16449
16645
  function cleanupContactsSnapshotTempFiles(snapshotDir) {
16450
- if (!fs29.existsSync(snapshotDir)) return;
16451
- for (const name of fs29.readdirSync(snapshotDir)) {
16646
+ if (!fs31.existsSync(snapshotDir)) return;
16647
+ for (const name of fs31.readdirSync(snapshotDir)) {
16452
16648
  if (!name.startsWith(CONTACTS_SNAPSHOT_TMP_PREFIX)) continue;
16453
16649
  try {
16454
- fs29.rmSync(path26.join(snapshotDir, name), { force: true });
16650
+ fs31.rmSync(path28.join(snapshotDir, name), { force: true });
16455
16651
  } catch (error) {
16456
16652
  appLogger.warn("contacts", "failed to remove contacts snapshot temp file", error);
16457
16653
  }
@@ -16489,7 +16685,7 @@ function createWorker(workerData, entryUrlInput) {
16489
16685
  return new Worker(bootstrap, options2);
16490
16686
  }
16491
16687
  function createContactsWorkerRunner(options2) {
16492
- return ({ signature, timeRangePreset, signal, onProgress }) => new Promise((resolve2, reject) => {
16688
+ return ({ signature, timeRangePreset, signal, onProgress }) => new Promise((resolve4, reject) => {
16493
16689
  if (signal.aborted) {
16494
16690
  reject(createAbortError());
16495
16691
  return;
@@ -16520,7 +16716,7 @@ function createContactsWorkerRunner(options2) {
16520
16716
  if (message.type === "success" && message.snapshot) {
16521
16717
  settled = true;
16522
16718
  signal.removeEventListener("abort", abort);
16523
- resolve2(message.snapshot);
16719
+ resolve4(message.snapshot);
16524
16720
  void worker.terminate();
16525
16721
  return;
16526
16722
  }
@@ -16949,23 +17145,23 @@ function buildPeopleRelationshipsSignature(adapter, timeRangePreset) {
16949
17145
  }
16950
17146
 
16951
17147
  // ../../packages/node-runtime/src/services/people/relationships/snapshot.ts
16952
- import fs30 from "fs";
16953
- import path27 from "path";
17148
+ import fs32 from "fs";
17149
+ import path29 from "path";
16954
17150
  var PEOPLE_RELATIONSHIPS_SNAPSHOT_TMP_PREFIX = "people-relationships-snapshot.tmp-";
16955
17151
  function getPeopleRelationshipsSnapshotPath(snapshotDir, timeRangePreset) {
16956
17152
  const preset = normalizePeopleRelationshipsTimeRangePreset(timeRangePreset);
16957
- return path27.join(snapshotDir, `graph-snapshot-${preset}.json`);
17153
+ return path29.join(snapshotDir, `graph-snapshot-${preset}.json`);
16958
17154
  }
16959
17155
  function readPeopleRelationshipsSnapshot(snapshotDir, timeRangePreset, options2 = {}) {
16960
17156
  const snapshotPath = getPeopleRelationshipsSnapshotPath(snapshotDir, timeRangePreset);
16961
- if (!fs30.existsSync(snapshotPath)) return null;
17157
+ if (!fs32.existsSync(snapshotPath)) return null;
16962
17158
  try {
16963
- return JSON.parse(fs30.readFileSync(snapshotPath, "utf-8"));
17159
+ return JSON.parse(fs32.readFileSync(snapshotPath, "utf-8"));
16964
17160
  } catch (error) {
16965
17161
  const ts = options2.now?.() ?? Date.now();
16966
- const backupPath = path27.join(snapshotDir, `graph-snapshot.corrupt-${ts}.json`);
17162
+ const backupPath = path29.join(snapshotDir, `graph-snapshot.corrupt-${ts}.json`);
16967
17163
  try {
16968
- fs30.renameSync(snapshotPath, backupPath);
17164
+ fs32.renameSync(snapshotPath, backupPath);
16969
17165
  } catch (renameError) {
16970
17166
  appLogger.warn("people-relationships", "failed to backup corrupt people relationships snapshot", renameError);
16971
17167
  }
@@ -16974,17 +17170,17 @@ function readPeopleRelationshipsSnapshot(snapshotDir, timeRangePreset, options2
16974
17170
  }
16975
17171
  }
16976
17172
  function writePeopleRelationshipsSnapshot(snapshotDir, snapshot) {
16977
- if (!fs30.existsSync(snapshotDir)) fs30.mkdirSync(snapshotDir, { recursive: true });
16978
- const tmpPath = path27.join(snapshotDir, `${PEOPLE_RELATIONSHIPS_SNAPSHOT_TMP_PREFIX}${process.pid}-${Date.now()}`);
16979
- fs30.writeFileSync(tmpPath, JSON.stringify(snapshot, null, 2), "utf-8");
16980
- fs30.renameSync(tmpPath, getPeopleRelationshipsSnapshotPath(snapshotDir, snapshot.timeRange.preset));
17173
+ if (!fs32.existsSync(snapshotDir)) fs32.mkdirSync(snapshotDir, { recursive: true });
17174
+ const tmpPath = path29.join(snapshotDir, `${PEOPLE_RELATIONSHIPS_SNAPSHOT_TMP_PREFIX}${process.pid}-${Date.now()}`);
17175
+ fs32.writeFileSync(tmpPath, JSON.stringify(snapshot, null, 2), "utf-8");
17176
+ fs32.renameSync(tmpPath, getPeopleRelationshipsSnapshotPath(snapshotDir, snapshot.timeRange.preset));
16981
17177
  }
16982
17178
  function cleanupPeopleRelationshipsSnapshotTempFiles(snapshotDir) {
16983
- if (!fs30.existsSync(snapshotDir)) return;
16984
- for (const name of fs30.readdirSync(snapshotDir)) {
17179
+ if (!fs32.existsSync(snapshotDir)) return;
17180
+ for (const name of fs32.readdirSync(snapshotDir)) {
16985
17181
  if (!name.startsWith(PEOPLE_RELATIONSHIPS_SNAPSHOT_TMP_PREFIX)) continue;
16986
17182
  try {
16987
- fs30.rmSync(path27.join(snapshotDir, name), { force: true });
17183
+ fs32.rmSync(path29.join(snapshotDir, name), { force: true });
16988
17184
  } catch (error) {
16989
17185
  appLogger.warn("people-relationships", "failed to remove people relationships snapshot temp file", error);
16990
17186
  }
@@ -17022,7 +17218,7 @@ function createWorker2(workerData, entryUrlInput) {
17022
17218
  return new Worker2(bootstrap, options2);
17023
17219
  }
17024
17220
  function createPeopleRelationshipsWorkerRunner(options2) {
17025
- return ({ signature, timeRangePreset, signal, onProgress }) => new Promise((resolve2, reject) => {
17221
+ return ({ signature, timeRangePreset, signal, onProgress }) => new Promise((resolve4, reject) => {
17026
17222
  if (signal.aborted) {
17027
17223
  reject(createAbortError2());
17028
17224
  return;
@@ -17053,7 +17249,7 @@ function createPeopleRelationshipsWorkerRunner(options2) {
17053
17249
  if (message.type === "success" && message.snapshot) {
17054
17250
  settled = true;
17055
17251
  signal.removeEventListener("abort", abort);
17056
- resolve2(message.snapshot);
17252
+ resolve4(message.snapshot);
17057
17253
  void worker.terminate();
17058
17254
  return;
17059
17255
  }
@@ -17506,7 +17702,7 @@ __export(relationships_exports, {
17506
17702
  });
17507
17703
 
17508
17704
  // ../../packages/node-runtime/src/services/global-insight/service.ts
17509
- import fs31 from "fs";
17705
+ import fs33 from "fs";
17510
17706
 
17511
17707
  // ../../packages/node-runtime/src/services/global-insight/signature.ts
17512
17708
  function buildAnnualSummarySignature(adapter, range) {
@@ -17533,7 +17729,7 @@ function resolveDefaultAnnualSummaryWorkerEntryUrl(currentModuleUrl = import.met
17533
17729
  return entryExists(sibling) ? sibling : new URL("./global-insight-worker.js", moduleUrl);
17534
17730
  }
17535
17731
  function createAnnualSummaryWorkerRunner(options2) {
17536
- return ({ signature, range, signal, onProgress }) => new Promise((resolve2, reject) => {
17732
+ return ({ signature, range, signal, onProgress }) => new Promise((resolve4, reject) => {
17537
17733
  if (signal.aborted) {
17538
17734
  reject(new Error("annual summary worker aborted"));
17539
17735
  return;
@@ -17564,7 +17760,7 @@ function createAnnualSummaryWorkerRunner(options2) {
17564
17760
  if (message.type === "success" && message.snapshot) {
17565
17761
  settled = true;
17566
17762
  signal.removeEventListener("abort", abort);
17567
- resolve2(message.snapshot);
17763
+ resolve4(message.snapshot);
17568
17764
  void worker.terminate();
17569
17765
  return;
17570
17766
  }
@@ -17759,7 +17955,7 @@ var DefaultGlobalInsightService = class {
17759
17955
  }
17760
17956
  getSnapshot(range) {
17761
17957
  const key = toAnnualSummaryRangeKey(range);
17762
- if (this.snapshots.has(key) && !fs31.existsSync(getAnnualSummarySnapshotPath(this.snapshotDir, range))) {
17958
+ if (this.snapshots.has(key) && !fs33.existsSync(getAnnualSummarySnapshotPath(this.snapshotDir, range))) {
17763
17959
  this.snapshots.delete(key);
17764
17960
  }
17765
17961
  if (!this.snapshots.has(key)) {
@@ -17807,8 +18003,8 @@ __export(global_insight_exports, {
17807
18003
  });
17808
18004
 
17809
18005
  // ../../packages/node-runtime/src/semantic-index/config.ts
17810
- import fs32 from "fs";
17811
- import path28 from "path";
18006
+ import fs34 from "fs";
18007
+ import path30 from "path";
17812
18008
  var DEFAULT_SEMANTIC_INDEX_MODEL_DOWNLOAD_SOURCE = "huggingface";
17813
18009
  var SEMANTIC_INDEX_CONFIG_VERSION = 1;
17814
18010
  var SEARCH_MAX_RESULTS_DEFAULT = 10;
@@ -17897,9 +18093,9 @@ var SemanticIndexConfigStore = class {
17897
18093
  return this.set({ ...this.get(), enabled });
17898
18094
  }
17899
18095
  get() {
17900
- if (!fs32.existsSync(this.filePath)) return defaultSemanticIndexConfig();
18096
+ if (!fs34.existsSync(this.filePath)) return defaultSemanticIndexConfig();
17901
18097
  try {
17902
- const raw = JSON.parse(fs32.readFileSync(this.filePath, "utf-8"));
18098
+ const raw = JSON.parse(fs34.readFileSync(this.filePath, "utf-8"));
17903
18099
  return normalizeConfig(raw);
17904
18100
  } catch {
17905
18101
  return defaultSemanticIndexConfig();
@@ -17907,9 +18103,9 @@ var SemanticIndexConfigStore = class {
17907
18103
  }
17908
18104
  set(config) {
17909
18105
  const normalized = normalizeConfig(config);
17910
- const dir = path28.dirname(this.filePath);
17911
- if (!fs32.existsSync(dir)) fs32.mkdirSync(dir, { recursive: true });
17912
- fs32.writeFileSync(this.filePath, JSON.stringify(normalized, null, 2), "utf-8");
18106
+ const dir = path30.dirname(this.filePath);
18107
+ if (!fs34.existsSync(dir)) fs34.mkdirSync(dir, { recursive: true });
18108
+ fs34.writeFileSync(this.filePath, JSON.stringify(normalized, null, 2), "utf-8");
17913
18109
  return normalized;
17914
18110
  }
17915
18111
  resolveModelId() {
@@ -17918,7 +18114,7 @@ var SemanticIndexConfigStore = class {
17918
18114
  };
17919
18115
 
17920
18116
  // ../../packages/node-runtime/src/semantic-index/service.ts
17921
- import path29 from "path";
18117
+ import path31 from "path";
17922
18118
 
17923
18119
  // ../../packages/node-runtime/src/semantic-index/chunker-config.ts
17924
18120
  import { createHash as createHash2 } from "crypto";
@@ -18239,8 +18435,8 @@ function createEmbedder(config, deps = {}) {
18239
18435
  if (!config.api || !config.api.baseUrl || !config.api.model) {
18240
18436
  throw new Error("semantic index API config incomplete: baseUrl and model are required");
18241
18437
  }
18242
- const resolve2 = deps.resolveApiKey ?? resolveApiKey;
18243
- const apiKey = resolve2("", config.api.authProfile);
18438
+ const resolve4 = deps.resolveApiKey ?? resolveApiKey;
18439
+ const apiKey = resolve4("", config.api.authProfile);
18244
18440
  return new OpenAICompatibleEmbeddingProvider(
18245
18441
  { baseUrl: config.api.baseUrl, apiKey, model: config.api.model },
18246
18442
  { fetchFn: deps.fetchFn }
@@ -18277,8 +18473,8 @@ function extensionSuffix(platform2) {
18277
18473
  return "so";
18278
18474
  }
18279
18475
  function platformPackageName(platform2, arch2) {
18280
- const os2 = platform2 === "win32" ? "windows" : platform2;
18281
- return `${BASE_PACKAGE_NAME}-${os2}-${arch2}`;
18476
+ const os3 = platform2 === "win32" ? "windows" : platform2;
18477
+ return `${BASE_PACKAGE_NAME}-${os3}-${arch2}`;
18282
18478
  }
18283
18479
  function getLoadablePath() {
18284
18480
  if (!validPlatform(platform, arch)) {
@@ -18777,7 +18973,7 @@ var SemanticIndexJobQueue = class {
18777
18973
  /** 等待队列清空(含当前任务) */
18778
18974
  whenIdle() {
18779
18975
  if (!this.processing && this.pending.length === 0) return Promise.resolve();
18780
- return new Promise((resolve2) => this.idleResolvers.push(resolve2));
18976
+ return new Promise((resolve4) => this.idleResolvers.push(resolve4));
18781
18977
  }
18782
18978
  removePending(dbPathHash) {
18783
18979
  this.pending = this.pending.filter((j) => j.dbPathHash !== dbPathHash);
@@ -18799,7 +18995,7 @@ var SemanticIndexJobQueue = class {
18799
18995
  this.processing = false;
18800
18996
  const resolvers = this.idleResolvers;
18801
18997
  this.idleResolvers = [];
18802
- for (const resolve2 of resolvers) resolve2();
18998
+ for (const resolve4 of resolvers) resolve4();
18803
18999
  }
18804
19000
  };
18805
19001
 
@@ -19449,16 +19645,16 @@ function resolveSearchToolEvidenceTokens(maxResultTokens) {
19449
19645
  return maxResultTokens && maxResultTokens > 0 ? Math.min(SEARCH_TOOL_EVIDENCE_TOKENS, maxResultTokens) : SEARCH_TOOL_EVIDENCE_TOKENS;
19450
19646
  }
19451
19647
  function sessionIdFromDbPath(dbPath) {
19452
- return path29.basename(dbPath, ".db");
19648
+ return path31.basename(dbPath, ".db");
19453
19649
  }
19454
19650
  var SEMANTIC_INDEX_DB_FILE = "embedding_index.db";
19455
19651
  var SEMANTIC_INDEX_CONFIG_FILE = "semantic-index-config.json";
19456
19652
  function createSemanticIndexService(params) {
19457
19653
  const { pathProvider } = params;
19458
19654
  return new SemanticIndexService({
19459
- vectorDbPath: path29.join(pathProvider.getVectorDir(), SEMANTIC_INDEX_DB_FILE),
19460
- configPath: path29.join(pathProvider.getAiDataDir(), SEMANTIC_INDEX_CONFIG_FILE),
19461
- modelsCacheDir: path29.join(pathProvider.getAiDataDir(), "models", "semantic-index"),
19655
+ vectorDbPath: path31.join(pathProvider.getVectorDir(), SEMANTIC_INDEX_DB_FILE),
19656
+ configPath: path31.join(pathProvider.getAiDataDir(), SEMANTIC_INDEX_CONFIG_FILE),
19657
+ modelsCacheDir: path31.join(pathProvider.getAiDataDir(), "models", "semantic-index"),
19462
19658
  modelDownloadProxyUrl: params.modelDownloadProxyUrl,
19463
19659
  sessionAdapter: params.sessionAdapter,
19464
19660
  nativeBinding: params.nativeBinding,
@@ -20008,8 +20204,8 @@ ${text}`;
20008
20204
  };
20009
20205
 
20010
20206
  // ../../packages/node-runtime/src/services/merge-cache.ts
20011
- import * as fs33 from "fs";
20012
- import * as path30 from "path";
20207
+ import * as fs35 from "fs";
20208
+ import * as path32 from "path";
20013
20209
  import * as crypto from "crypto";
20014
20210
  var MergeSessionCache = class {
20015
20211
  cache = /* @__PURE__ */ new Map();
@@ -20018,15 +20214,15 @@ var MergeSessionCache = class {
20018
20214
  constructor(pathProvider, options2) {
20019
20215
  this.tempDir = pathProvider.getTempDir();
20020
20216
  this.nativeBinding = options2?.nativeBinding;
20021
- if (!fs33.existsSync(this.tempDir)) {
20022
- fs33.mkdirSync(this.tempDir, { recursive: true });
20217
+ if (!fs35.existsSync(this.tempDir)) {
20218
+ fs35.mkdirSync(this.tempDir, { recursive: true });
20023
20219
  }
20024
20220
  }
20025
20221
  generateTempDbPath(filename) {
20026
20222
  const ts = Date.now();
20027
20223
  const rand = Math.random().toString(36).slice(2, 8);
20028
20224
  const safeName = filename.replace(/[/\\?%*:|"<>]/g, "_").slice(0, 40);
20029
- return path30.join(this.tempDir, `merge_${safeName}_${ts}_${rand}.db`);
20225
+ return path32.join(this.tempDir, `merge_${safeName}_${ts}_${rand}.db`);
20030
20226
  }
20031
20227
  /** Store a parsed file's temp DB and return a handle for subsequent requests. */
20032
20228
  store(filename, tempDbPath) {
@@ -20037,7 +20233,7 @@ var MergeSessionCache = class {
20037
20233
  /** Open a TempDbReader for a given handle. Caller must close the reader. */
20038
20234
  openReader(handle) {
20039
20235
  const entry = this.cache.get(handle);
20040
- if (!entry || !fs33.existsSync(entry.tempDbPath)) return null;
20236
+ if (!entry || !fs35.existsSync(entry.tempDbPath)) return null;
20041
20237
  const adapter = openBetterSqliteDatabase(entry.tempDbPath, {
20042
20238
  readonly: true,
20043
20239
  nativeBinding: this.nativeBinding
@@ -20082,20 +20278,44 @@ var MergeSessionCache = class {
20082
20278
  };
20083
20279
 
20084
20280
  // ../../packages/node-runtime/src/services/push-importer.ts
20085
- import * as fs34 from "fs";
20281
+ import * as fs36 from "fs";
20086
20282
  var SYSTEM_SENDER_ID = "SYSTEM";
20087
20283
  var SYSTEM_MEMBER_NAME = "\u7CFB\u7EDF\u6D88\u606F";
20284
+ function isRecord3(value) {
20285
+ return typeof value === "object" && value !== null && !Array.isArray(value);
20286
+ }
20287
+ function validateOptionalString(value, field) {
20288
+ return value !== void 0 && typeof value !== "string" ? `${field} must be a string` : null;
20289
+ }
20088
20290
  function validatePayload(payload, isNew) {
20291
+ if (!isRecord3(payload)) return "payload must be an object";
20089
20292
  const messages = payload.messages;
20090
20293
  if (!Array.isArray(messages) || messages.length === 0) return "messages is required and must be a non-empty array";
20294
+ if (payload.chatlab !== void 0) {
20295
+ if (!isRecord3(payload.chatlab)) return "chatlab must be an object";
20296
+ if (typeof payload.chatlab.version !== "string" || payload.chatlab.version.length === 0)
20297
+ return "chatlab.version must be a string";
20298
+ if (typeof payload.chatlab.exportedAt !== "number" || !Number.isFinite(payload.chatlab.exportedAt))
20299
+ return "chatlab.exportedAt must be a number";
20300
+ const generatorError = validateOptionalString(payload.chatlab.generator, "chatlab.generator");
20301
+ if (generatorError) return generatorError;
20302
+ }
20091
20303
  if (isNew) {
20092
20304
  if (!payload.chatlab) return "chatlab is required for new sessions";
20093
20305
  if (!payload.meta) return "meta is required for new sessions";
20094
- const m = payload.meta;
20095
- if (!m.name) return "meta.name is required";
20096
- if (!m.platform) return "meta.platform is required";
20097
- if (!m.type) return "meta.type is required";
20098
20306
  }
20307
+ if (payload.meta !== void 0) {
20308
+ if (!isRecord3(payload.meta)) return "meta must be an object";
20309
+ const metaFields = ["name", "platform", "type", "groupId", "groupAvatar", "ownerId"];
20310
+ for (const field of metaFields) {
20311
+ const error = validateOptionalString(payload.meta[field], `meta.${field}`);
20312
+ if (error) return error;
20313
+ }
20314
+ if (isNew && !payload.meta.name) return "meta.name is required";
20315
+ if (isNew && !payload.meta.platform) return "meta.platform is required";
20316
+ if (isNew && !payload.meta.type) return "meta.type is required";
20317
+ }
20318
+ if (payload.options !== void 0 && !isRecord3(payload.options)) return "options must be an object";
20099
20319
  const { metaUpdateMode, memberUpdateMode } = payload.options ?? {};
20100
20320
  if (metaUpdateMode !== void 0 && metaUpdateMode !== "patch" && metaUpdateMode !== "none") {
20101
20321
  return `options.metaUpdateMode must be 'patch' or 'none'`;
@@ -20106,16 +20326,35 @@ function validatePayload(payload, isNew) {
20106
20326
  if (payload.members !== void 0 && !Array.isArray(payload.members)) return "members must be an array";
20107
20327
  if (payload.members) {
20108
20328
  for (let i = 0; i < payload.members.length; i++) {
20109
- if (typeof payload.members[i].platformId !== "string" || payload.members[i].platformId.length === 0)
20329
+ const member = payload.members[i];
20330
+ if (!isRecord3(member)) return `members[${i}] must be an object`;
20331
+ if (typeof member.platformId !== "string" || member.platformId.length === 0)
20110
20332
  return `members[${i}].platformId must be a string`;
20333
+ for (const field of ["accountName", "groupNickname", "avatar"]) {
20334
+ const error = validateOptionalString(member[field], `members[${i}].${field}`);
20335
+ if (error) return error;
20336
+ }
20337
+ if (member.roles !== void 0) {
20338
+ if (!Array.isArray(member.roles)) return `members[${i}].roles must be an array`;
20339
+ for (let j = 0; j < member.roles.length; j++) {
20340
+ const role = member.roles[j];
20341
+ if (!isRecord3(role) || typeof role.id !== "string" || role.id.length === 0)
20342
+ return `members[${i}].roles[${j}].id must be a string`;
20343
+ }
20344
+ }
20111
20345
  }
20112
20346
  }
20113
20347
  for (let i = 0; i < messages.length; i++) {
20114
20348
  const msg = messages[i];
20349
+ if (!isRecord3(msg)) return `messages[${i}] must be an object`;
20115
20350
  if (typeof msg.sender !== "string" || msg.sender.length === 0) return `messages[${i}].sender must be a string`;
20116
- if (typeof msg.timestamp !== "number" || msg.timestamp <= 0)
20351
+ if (typeof msg.timestamp !== "number" || !Number.isFinite(msg.timestamp) || msg.timestamp <= 0)
20117
20352
  return `messages[${i}].timestamp must be a positive number`;
20118
- if (typeof msg.type !== "number") return `messages[${i}].type must be a number`;
20353
+ if (typeof msg.type !== "number" || !Number.isFinite(msg.type)) return `messages[${i}].type must be a number`;
20354
+ for (const field of ["accountName", "groupNickname"]) {
20355
+ const error = validateOptionalString(msg[field], `messages[${i}].${field}`);
20356
+ if (error) return error;
20357
+ }
20119
20358
  if (msg.content !== void 0 && msg.content !== null && typeof msg.content !== "string")
20120
20359
  return `messages[${i}].content must be a string or null`;
20121
20360
  if (msg.platformMessageId !== void 0 && typeof msg.platformMessageId !== "string")
@@ -20136,47 +20375,79 @@ function normalizeSenderAccountName(sender, accountName) {
20136
20375
  function normalizeSenderGroupNickname(sender, groupNickname) {
20137
20376
  return sender === SYSTEM_SENDER_ID ? SYSTEM_MEMBER_NAME : groupNickname;
20138
20377
  }
20139
- function writeMessages(db, messages, existingPmids, existingKeys) {
20378
+ function isCountedMember(platformId) {
20379
+ return platformId !== SYSTEM_SENDER_ID;
20380
+ }
20381
+ function registerPushMessageAndCheckDuplicate(message, dedupState) {
20382
+ return registerMessageAndCheckDuplicate(
20383
+ {
20384
+ platformMessageId: message.platformMessageId,
20385
+ timestamp: message.timestamp,
20386
+ senderPlatformId: message.sender,
20387
+ type: message.type,
20388
+ content: message.content ?? null,
20389
+ replyToMessageId: message.replyToMessageId
20390
+ },
20391
+ dedupState
20392
+ );
20393
+ }
20394
+ function createExistingMessageDedupState(db) {
20395
+ const existingPmids = /* @__PURE__ */ new Set();
20396
+ const existingKeys = /* @__PURE__ */ new Set();
20397
+ const existingFallbackOnlyKeys = /* @__PURE__ */ new Set();
20398
+ const existingMessages = db.prepare(
20399
+ `SELECT msg.ts, m.platform_id, msg.type, msg.content, msg.reply_to_message_id, msg.platform_message_id
20400
+ FROM message msg
20401
+ JOIN member m ON msg.sender_id = m.id`
20402
+ ).all();
20403
+ for (const message of existingMessages) {
20404
+ if (message.platform_message_id) existingPmids.add(message.platform_message_id);
20405
+ const key = generateFallbackMessageKey({
20406
+ timestamp: message.ts,
20407
+ senderPlatformId: message.platform_id,
20408
+ type: message.type,
20409
+ content: message.content,
20410
+ replyToMessageId: message.reply_to_message_id ?? void 0
20411
+ });
20412
+ existingKeys.add(key);
20413
+ if (!message.platform_message_id) existingFallbackOnlyKeys.add(key);
20414
+ }
20415
+ return createMessageDedupState(existingPmids, existingKeys, existingFallbackOnlyKeys);
20416
+ }
20417
+ function writeMessages(db, messages, dedupState) {
20140
20418
  const insertMsg = db.prepare(
20141
20419
  `INSERT INTO message (sender_id, sender_account_name, sender_group_nickname, ts, type, content, reply_to_message_id, platform_message_id)
20142
20420
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
20143
20421
  );
20144
20422
  const getMemberId = db.prepare("SELECT id FROM member WHERE platform_id = ?");
20145
- const insertMinimalMember = db.prepare("INSERT OR IGNORE INTO member (platform_id, account_name) VALUES (?, ?)");
20423
+ const insertMinimalMember = db.prepare(
20424
+ "INSERT OR IGNORE INTO member (platform_id, account_name, group_nickname) VALUES (?, ?, ?)"
20425
+ );
20146
20426
  const memberIdCache = /* @__PURE__ */ new Map();
20147
20427
  let writtenCount = 0;
20148
20428
  let duplicateCount = 0;
20429
+ let membersAdded = 0;
20149
20430
  let minWrittenTs = Infinity;
20150
20431
  const ftsEntries = [];
20151
20432
  const sorted = [...messages].sort((a, b) => a.timestamp - b.timestamp);
20152
20433
  db.transaction(() => {
20153
20434
  for (const msg of sorted) {
20154
- const key = generateMessageKey(msg.timestamp, msg.sender, msg.content ?? null);
20155
- if (msg.platformMessageId) {
20156
- if (existingPmids.has(msg.platformMessageId)) {
20157
- duplicateCount++;
20158
- continue;
20159
- }
20160
- if (existingKeys.has(key)) {
20161
- duplicateCount++;
20162
- continue;
20163
- }
20164
- existingPmids.add(msg.platformMessageId);
20165
- existingKeys.add(key);
20166
- } else {
20167
- if (existingKeys.has(key)) {
20168
- duplicateCount++;
20169
- continue;
20170
- }
20171
- existingKeys.add(key);
20435
+ if (registerPushMessageAndCheckDuplicate(msg, dedupState)) {
20436
+ duplicateCount++;
20437
+ continue;
20172
20438
  }
20173
20439
  let memberId = memberIdCache.get(msg.sender);
20174
20440
  if (!memberId) {
20175
- insertMinimalMember.run(msg.sender, normalizeSenderAccountName(msg.sender, msg.accountName) || null);
20441
+ const insertResult = insertMinimalMember.run(
20442
+ msg.sender,
20443
+ normalizeSenderAccountName(msg.sender, msg.accountName) || null,
20444
+ normalizeSenderGroupNickname(msg.sender, msg.groupNickname) || null
20445
+ );
20176
20446
  const row = getMemberId.get(msg.sender);
20177
20447
  if (row) {
20178
20448
  memberId = row.id;
20179
20449
  memberIdCache.set(msg.sender, memberId);
20450
+ if (isCountedMember(msg.sender)) membersAdded += insertResult.changes;
20180
20451
  }
20181
20452
  }
20182
20453
  if (!memberId) continue;
@@ -20195,7 +20466,7 @@ function writeMessages(db, messages, existingPmids, existingKeys) {
20195
20466
  writtenCount++;
20196
20467
  }
20197
20468
  });
20198
- return { writtenCount, duplicateCount, minWrittenTs, ftsEntries };
20469
+ return { writtenCount, duplicateCount, membersAdded, minWrittenTs, ftsEntries };
20199
20470
  }
20200
20471
  function fullImport(db, meta, members, messages) {
20201
20472
  db.exec(CHAT_DB_SCHEMA);
@@ -20212,29 +20483,13 @@ function fullImport(db, meta, members, messages) {
20212
20483
  }
20213
20484
  }
20214
20485
  const allMembers = extraMembers.length > 0 ? [...members, ...extraMembers] : members;
20215
- const pmids = /* @__PURE__ */ new Set();
20216
- const hashKeys = /* @__PURE__ */ new Set();
20486
+ const dedupState = createMessageDedupState();
20217
20487
  let duplicateCount = 0;
20218
20488
  const dedupedMessages = [];
20219
20489
  for (const msg of messages) {
20220
- const key = generateMessageKey(msg.timestamp, msg.sender, msg.content ?? null);
20221
- if (msg.platformMessageId) {
20222
- if (pmids.has(msg.platformMessageId)) {
20223
- duplicateCount++;
20224
- continue;
20225
- }
20226
- if (hashKeys.has(key)) {
20227
- duplicateCount++;
20228
- continue;
20229
- }
20230
- pmids.add(msg.platformMessageId);
20231
- hashKeys.add(key);
20232
- } else {
20233
- if (hashKeys.has(key)) {
20234
- duplicateCount++;
20235
- continue;
20236
- }
20237
- hashKeys.add(key);
20490
+ if (registerPushMessageAndCheckDuplicate(msg, dedupState)) {
20491
+ duplicateCount++;
20492
+ continue;
20238
20493
  }
20239
20494
  dedupedMessages.push(msg);
20240
20495
  }
@@ -20262,15 +20517,12 @@ function fullImport(db, meta, members, messages) {
20262
20517
  generateSessionIndex(db);
20263
20518
  } catch {
20264
20519
  }
20265
- return { writtenCount: stats.messageCount, duplicateCount, membersAdded: members.length };
20520
+ return { writtenCount: stats.messageCount, duplicateCount };
20266
20521
  }
20267
- function incrementalImport2(db, payload) {
20522
+ function writeIncrementalImport(db, payload) {
20268
20523
  const metaUpdateMode = payload.options?.metaUpdateMode ?? "patch";
20269
20524
  const memberUpdateMode = payload.options?.memberUpdateMode ?? "upsert";
20270
- const existingPmids = /* @__PURE__ */ new Set();
20271
- const existingKeys = /* @__PURE__ */ new Set();
20272
- db.prepare("SELECT platform_message_id FROM message WHERE platform_message_id IS NOT NULL").all().forEach((r) => existingPmids.add(r.platform_message_id));
20273
- db.prepare(`SELECT msg.ts, m.platform_id, msg.content FROM message msg JOIN member m ON msg.sender_id = m.id`).all().forEach((r) => existingKeys.add(generateMessageKey(r.ts, r.platform_id, r.content)));
20525
+ const dedupState = createExistingMessageDedupState(db);
20274
20526
  let metaUpdated = false;
20275
20527
  let membersAdded = 0;
20276
20528
  let membersUpdated = 0;
@@ -20307,22 +20559,23 @@ function incrementalImport2(db, payload) {
20307
20559
  m.roles ? JSON.stringify(m.roles) : "[]"
20308
20560
  );
20309
20561
  if (!existed) {
20310
- membersAdded++;
20562
+ if (isCountedMember(m.platformId)) membersAdded++;
20311
20563
  const row = getMemberId.get(m.platformId);
20312
20564
  if (row) existingMemberIds.add(m.platformId);
20313
- } else {
20565
+ } else if (isCountedMember(m.platformId)) {
20314
20566
  membersUpdated++;
20315
20567
  }
20316
20568
  }
20317
20569
  });
20318
20570
  }
20319
20571
  const preWriteMaxTs = db.prepare("SELECT MAX(ts) as max_ts FROM message").get()?.max_ts ?? 0;
20320
- const { writtenCount, duplicateCount, minWrittenTs, ftsEntries } = writeMessages(
20321
- db,
20322
- payload.messages,
20323
- existingPmids,
20324
- existingKeys
20325
- );
20572
+ const {
20573
+ writtenCount,
20574
+ duplicateCount,
20575
+ membersAdded: autoCreatedMembersAdded,
20576
+ minWrittenTs,
20577
+ ftsEntries
20578
+ } = writeMessages(db, payload.messages, dedupState);
20326
20579
  if (ftsEntries.length > 0) {
20327
20580
  try {
20328
20581
  insertFtsEntries(db, ftsEntries);
@@ -20342,18 +20595,40 @@ function incrementalImport2(db, payload) {
20342
20595
  if (!metaUpdated) {
20343
20596
  db.prepare("UPDATE meta SET imported_at = ?").run(Math.floor(Date.now() / 1e3));
20344
20597
  }
20345
- return { writtenCount, duplicateCount, metaUpdated, membersAdded, membersUpdated };
20598
+ return {
20599
+ writtenCount,
20600
+ duplicateCount,
20601
+ metaUpdated,
20602
+ membersAdded: membersAdded + autoCreatedMembersAdded,
20603
+ membersUpdated
20604
+ };
20605
+ }
20606
+ function incrementalImport2(db, payload) {
20607
+ return db.transaction(() => writeIncrementalImport(db, payload));
20346
20608
  }
20347
- var SAFE_SESSION_ID_RE = /^[a-zA-Z0-9_@-][a-zA-Z0-9_@.-]*$/;
20348
20609
  async function pushImport(dbManager, sessionId, payload) {
20349
- if (!SAFE_SESSION_ID_RE.test(sessionId) || sessionId.includes("..")) {
20350
- return { ok: false, reason: "invalid_payload", message: "sessionId contains invalid characters" };
20351
- }
20352
20610
  try {
20353
- return await withDataDirImportLock(
20354
- dbManager.getUserDataDir(),
20355
- () => pushImportUnlocked(dbManager, sessionId, payload)
20356
- );
20611
+ return await withDataDirImportLock(dbManager.getUserDataDir(), async () => {
20612
+ const outcome = await executePushImportUnlocked(
20613
+ {
20614
+ getDbPath: (id) => dbManager.getDbPath(id),
20615
+ openDatabase: (id, options2) => dbManager.openRawSessionDatabase(id, options2),
20616
+ deleteDatabase: (id) => {
20617
+ dbManager.deleteSessionDatabaseFiles(id);
20618
+ }
20619
+ },
20620
+ sessionId,
20621
+ payload
20622
+ );
20623
+ if (!outcome.ok) return outcome;
20624
+ try {
20625
+ dbManager.raiseCurrentChatDbCompatibilityGate();
20626
+ } catch (error) {
20627
+ if (outcome.result.created) dbManager.deleteSessionDatabaseFiles(sessionId);
20628
+ throw error;
20629
+ }
20630
+ return outcome;
20631
+ });
20357
20632
  } catch (error) {
20358
20633
  if (error instanceof ImportInProgressError) {
20359
20634
  return {
@@ -20365,26 +20640,24 @@ async function pushImport(dbManager, sessionId, payload) {
20365
20640
  throw error;
20366
20641
  }
20367
20642
  }
20368
- async function pushImportUnlocked(dbManager, sessionId, payload) {
20369
- const dbPath = dbManager.getDbPath(sessionId);
20370
- const isNew = !fs34.existsSync(dbPath);
20643
+ async function executePushImportUnlocked(deps, sessionId, payload) {
20644
+ if (!isValidImportSessionId(sessionId)) {
20645
+ return { ok: false, reason: "invalid_payload", message: "sessionId contains invalid characters" };
20646
+ }
20647
+ const dbPath = deps.getDbPath(sessionId);
20648
+ const isNew = !fs36.existsSync(dbPath);
20371
20649
  const validationError = validatePayload(payload, isNew);
20372
20650
  if (validationError) {
20373
20651
  return { ok: false, reason: "invalid_payload", message: validationError };
20374
20652
  }
20375
20653
  try {
20376
20654
  if (isNew) {
20377
- const db2 = dbManager.openRawSessionDatabase(sessionId, { create: true });
20655
+ const db2 = deps.openDatabase(sessionId, { create: true });
20378
20656
  try {
20379
- const { writtenCount, duplicateCount, membersAdded } = fullImport(
20380
- db2,
20381
- payload.meta,
20382
- payload.members ?? [],
20383
- payload.messages
20384
- );
20657
+ const { writtenCount, duplicateCount } = fullImport(db2, payload.meta, payload.members ?? [], payload.messages);
20385
20658
  const session = queryStats(db2);
20386
- dbManager.raiseCurrentChatDbCompatibilityGate();
20387
- return {
20659
+ const membersAdded = session.memberCount;
20660
+ const outcome = {
20388
20661
  ok: true,
20389
20662
  result: {
20390
20663
  sessionId,
@@ -20394,16 +20667,17 @@ async function pushImportUnlocked(dbManager, sessionId, payload) {
20394
20667
  updates: { metaUpdated: true, membersAdded, membersUpdated: 0 }
20395
20668
  }
20396
20669
  };
20670
+ appLogger.info("push-import", "Push import completed", outcome.result);
20671
+ return outcome;
20397
20672
  } finally {
20398
20673
  db2.close();
20399
20674
  }
20400
20675
  }
20401
- const db = dbManager.openRawSessionDatabase(sessionId, { readonly: false });
20676
+ const db = deps.openDatabase(sessionId, { readonly: false });
20402
20677
  try {
20403
20678
  const { writtenCount, duplicateCount, metaUpdated, membersAdded, membersUpdated } = incrementalImport2(db, payload);
20404
20679
  const session = queryStats(db);
20405
- dbManager.raiseCurrentChatDbCompatibilityGate();
20406
- return {
20680
+ const outcome = {
20407
20681
  ok: true,
20408
20682
  result: {
20409
20683
  sessionId,
@@ -20413,6 +20687,8 @@ async function pushImportUnlocked(dbManager, sessionId, payload) {
20413
20687
  updates: { metaUpdated, membersAdded, membersUpdated }
20414
20688
  }
20415
20689
  };
20690
+ appLogger.info("push-import", "Push import completed", outcome.result);
20691
+ return outcome;
20416
20692
  } finally {
20417
20693
  db.close();
20418
20694
  }
@@ -20420,15 +20696,61 @@ async function pushImportUnlocked(dbManager, sessionId, payload) {
20420
20696
  if (err instanceof DataDirCompatibilityError) throw err;
20421
20697
  if (isNew) {
20422
20698
  try {
20423
- dbManager.deleteSessionDatabaseFiles(sessionId);
20699
+ deps.deleteDatabase(sessionId);
20424
20700
  } catch {
20425
20701
  }
20426
20702
  }
20703
+ appLogger.error("push-import", "Push import failed", err);
20427
20704
  return { ok: false, reason: "import_failed", message: err instanceof Error ? err.message : String(err) };
20428
20705
  }
20429
20706
  }
20430
20707
 
20708
+ // ../../packages/node-runtime/src/services/import-idempotency.ts
20709
+ import { createHash as createHash4 } from "crypto";
20710
+ var DEFAULT_IMPORT_IDEMPOTENCY_TTL_MS = 60 * 60 * 1e3;
20711
+ function hashImportBody(body) {
20712
+ return createHash4("sha256").update(JSON.stringify(body ?? "")).digest("hex");
20713
+ }
20714
+ var ImportIdempotencyCache = class {
20715
+ constructor(ttlMs = DEFAULT_IMPORT_IDEMPOTENCY_TTL_MS) {
20716
+ this.ttlMs = ttlMs;
20717
+ }
20718
+ ttlMs;
20719
+ entries = /* @__PURE__ */ new Map();
20720
+ start(key, bodyHash, now = Date.now()) {
20721
+ this.prune(now);
20722
+ const entry = this.entries.get(key);
20723
+ if (!entry) {
20724
+ this.entries.set(key, { bodyHash, status: "pending", timestamp: now });
20725
+ return { status: "started" };
20726
+ }
20727
+ if (entry.bodyHash !== bodyHash) return { status: "conflict" };
20728
+ if (entry.status === "pending") return { status: "pending" };
20729
+ return { status: "success", response: entry.response };
20730
+ }
20731
+ success(key, response) {
20732
+ const entry = this.entries.get(key);
20733
+ if (!entry) return;
20734
+ entry.status = "success";
20735
+ entry.response = response;
20736
+ }
20737
+ fail(key) {
20738
+ this.entries.delete(key);
20739
+ }
20740
+ prune(now) {
20741
+ for (const [key, entry] of this.entries) {
20742
+ if (now - entry.timestamp > this.ttlMs) this.entries.delete(key);
20743
+ }
20744
+ }
20745
+ };
20746
+
20431
20747
  export {
20748
+ CHATLAB_TEMP_ROOT_ENV,
20749
+ resolveChatLabTempRoot,
20750
+ ensureChatLabTempRoot,
20751
+ getChatLabTempScopeDir,
20752
+ createChatLabTempDir,
20753
+ removeChatLabTempDir,
20432
20754
  writeParseResultToDb,
20433
20755
  detectFormat,
20434
20756
  detectAllFormats,
@@ -20466,8 +20788,10 @@ export {
20466
20788
  streamParseFileInfo,
20467
20789
  analyzeIncrementalImport,
20468
20790
  incrementalImport,
20791
+ isValidImportSessionId,
20469
20792
  resolveAutoImportTarget,
20470
20793
  autoImportFile,
20794
+ analyzeAutoImportFile,
20471
20795
  IMPORT_LOCK_FILENAME,
20472
20796
  IMPORT_IN_PROGRESS_ERROR_KEY,
20473
20797
  ImportInProgressError,
@@ -20548,6 +20872,8 @@ export {
20548
20872
  checkSessionsCanGenerateSummary,
20549
20873
  MAX_CONFIG_COUNT,
20550
20874
  LLMConfigStore,
20875
+ createFileConfigStorage,
20876
+ createAuthProfileLlmConfigStore,
20551
20877
  CustomProviderStore,
20552
20878
  CustomModelStore,
20553
20879
  normalizeAnthropicBaseUrl,
@@ -20636,6 +20962,10 @@ export {
20636
20962
  createSemanticIndexService,
20637
20963
  SemanticIndexService,
20638
20964
  MergeSessionCache,
20639
- pushImport
20965
+ pushImport,
20966
+ executePushImportUnlocked,
20967
+ DEFAULT_IMPORT_IDEMPOTENCY_TTL_MS,
20968
+ hashImportBody,
20969
+ ImportIdempotencyCache
20640
20970
  };
20641
- //# sourceMappingURL=chunk-T64GA5HP.mjs.map
20971
+ //# sourceMappingURL=chunk-5G2INROS.mjs.map