chatlab-cli 0.34.0 → 0.34.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/dist/{chat-command-XPY3WURC.mjs → chat-command-OWKJJ736.mjs} +8 -8
  2. package/dist/{chunk-OLE2USEN.mjs → chunk-3RWYALUP.mjs} +4 -2
  3. package/dist/{chunk-OLE2USEN.mjs.map → chunk-3RWYALUP.mjs.map} +1 -1
  4. package/dist/{chunk-IGEHMLHM.mjs → chunk-GHZFNAMF.mjs} +2 -2
  5. package/dist/{chunk-DGF3S3TZ.mjs → chunk-J7HAIT3T.mjs} +15 -9
  6. package/dist/chunk-J7HAIT3T.mjs.map +1 -0
  7. package/dist/{chunk-JCSPDTZL.mjs → chunk-MPHFZYB7.mjs} +4 -4
  8. package/dist/{chunk-ISRLGLUL.mjs → chunk-OHFVX2HH.mjs} +2 -2
  9. package/dist/{chunk-UO2XVFY6.mjs → chunk-RMW3524R.mjs} +25 -56
  10. package/dist/{chunk-UO2XVFY6.mjs.map → chunk-RMW3524R.mjs.map} +1 -1
  11. package/dist/{chunk-AQPDZAWB.mjs → chunk-RRC6U56Y.mjs} +259 -52
  12. package/dist/chunk-RRC6U56Y.mjs.map +1 -0
  13. package/dist/{chunk-IGK6UMN2.mjs → chunk-VTCZM2JS.mjs} +11 -11
  14. package/dist/{chunk-JTOHAMIW.mjs → chunk-XEGEOU2D.mjs} +2 -2
  15. package/dist/{chunk-BQ3QN4QT.mjs → chunk-YRCFDZ5Q.mjs} +3 -3
  16. package/dist/{chunk-S5NCEESV.mjs → chunk-ZM5DSHFF.mjs} +95 -5
  17. package/dist/chunk-ZM5DSHFF.mjs.map +1 -0
  18. package/dist/cli.mjs +8 -8
  19. package/dist/contacts-worker.mjs +2 -2
  20. package/dist/global-insight-worker.mjs +1 -1
  21. package/dist/{http-HV6XWU6X.mjs → http-X55S6MTO.mjs} +11 -11
  22. package/dist/{import-DP2XLZ2H.mjs → import-4AX6IX57.mjs} +7 -7
  23. package/dist/index.mjs +11 -11
  24. package/dist/{mcp-QDPFBPGW.mjs → mcp-GWC52AWE.mjs} +8 -8
  25. package/dist/people-relationships-worker.mjs +2 -2
  26. package/dist/semantic-index-worker.mjs +1 -1
  27. package/dist/{src-B3A2QHP5.mjs → src-DLLM4SEO.mjs} +8 -6
  28. package/dist/{stream-import-KEGNP3QK.mjs → stream-import-K24HWAAZ.mjs} +7 -7
  29. package/dist/{worker-runtime-MDYKX3BW.mjs → worker-runtime-6KKR55TD.mjs} +5 -5
  30. package/dist-cli-web/assets/{ActionToolsPanel.vue_vue_type_script_setup_true_lang-JxPR2O6b.js → ActionToolsPanel.vue_vue_type_script_setup_true_lang-D1BiZuQL.js} +5 -5
  31. package/dist-cli-web/assets/{BufferResource--dSbJb0k.js → BufferResource-IPkSmPao.js} +1 -1
  32. package/dist-cli-web/assets/{CanvasRenderer-Cm_dmJXZ.js → CanvasRenderer-OAQy65em.js} +1 -1
  33. package/dist-cli-web/assets/{DataDirCleanupNotice-B0s5txX3.js → DataDirCleanupNotice-jEI-YjFp.js} +1 -1
  34. package/dist-cli-web/assets/{EChartWordcloud-CwMVJLBO.js → EChartWordcloud-Pi48JdN2.js} +1 -1
  35. package/dist-cli-web/assets/{Filter-BjYScRpK.js → Filter-FQD30cRE.js} +1 -1
  36. package/dist-cli-web/assets/{LoadingState.vue_vue_type_script_setup_true_lang-BshQybD_.js → LoadingState.vue_vue_type_script_setup_true_lang-CCK5yTju.js} +1 -1
  37. package/dist-cli-web/assets/{MessageExportModal-DAJW2mFj.js → MessageExportModal-CZn3LbeY.js} +1 -1
  38. package/dist-cli-web/assets/{PageHeader-BKAjCuqs.js → PageHeader-B9B9K9by.js} +1 -1
  39. package/dist-cli-web/assets/{RelationshipGalaxyCanvas-mlZs7k4L.js → RelationshipGalaxyCanvas-CbTmpnZ6.js} +3 -3
  40. package/dist-cli-web/assets/{RelationshipGalaxyThreeCanvas-DgMG3jdU.js → RelationshipGalaxyThreeCanvas-Cu6NmKOq.js} +1 -1
  41. package/dist-cli-web/assets/{RenderTargetSystem-D00Ex44y.js → RenderTargetSystem-DnptJCQ0.js} +1 -1
  42. package/dist-cli-web/assets/{ThemeCard.vue_vue_type_script_setup_true_lang-Dsb6lzs-.js → ThemeCard.vue_vue_type_script_setup_true_lang-JXMFY6aD.js} +1 -1
  43. package/dist-cli-web/assets/{TimeSelect.vue_vue_type_script_setup_true_lang-BfR3tlkz.js → TimeSelect.vue_vue_type_script_setup_true_lang-QAZFwx5S.js} +1 -1
  44. package/dist-cli-web/assets/{WebGLRenderer-CTTusm2n.js → WebGLRenderer-BmjIF5se.js} +1 -1
  45. package/dist-cli-web/assets/{WebGPURenderer-pyv3EXor.js → WebGPURenderer-DkNcKkqj.js} +1 -1
  46. package/dist-cli-web/assets/{annual-summary-time-range-C_d1oZrj.js → annual-summary-time-range-DJ0HWI_t.js} +1 -1
  47. package/dist-cli-web/assets/{base-D91aVUwM.js → base-CnuE0ss0.js} +1 -1
  48. package/dist-cli-web/assets/{browserAll-C9fW936Y.js → browserAll-C_NnyNBz.js} +1 -1
  49. package/dist-cli-web/assets/{cli-web-C7uGKz_E.js → cli-web-t1gabACJ.js} +1 -1
  50. package/dist-cli-web/assets/{dateFormat-rY43adcv.js → dateFormat-p6nibkgt.js} +1 -1
  51. package/dist-cli-web/assets/{fetch-CNy9OQ2g.js → fetch-BBUvWvOM.js} +1 -1
  52. package/dist-cli-web/assets/{fetch-CS3T-v-1.js → fetch-BfYranz7.js} +1 -1
  53. package/dist-cli-web/assets/{fetch-DG3AeEjW.js → fetch-Bsm5YQ_7.js} +1 -1
  54. package/dist-cli-web/assets/{fetch-PLrI3V67.js → fetch-C4KJ7tGz.js} +1 -1
  55. package/dist-cli-web/assets/{fetch-CrSz5KJy.js → fetch-CMhV3TYQ.js} +1 -1
  56. package/dist-cli-web/assets/{fetch-CbnX5VoM.js → fetch-Ch4IMKin.js} +1 -1
  57. package/dist-cli-web/assets/{fetch-DYNgtIcU.js → fetch-DajjPQtq.js} +1 -1
  58. package/dist-cli-web/assets/{fetch-Kk2knkEo.js → fetch-WElo3Vix.js} +1 -1
  59. package/dist-cli-web/assets/{fetch-DZPC3D8R.js → fetch-WIOgRPd9.js} +1 -1
  60. package/dist-cli-web/assets/{fetch-C6po4XYB.js → fetch-_Hb-KRSr.js} +3 -3
  61. package/dist-cli-web/assets/{index-2S80bo1s.js → index-B8I5Pax_.js} +2 -2
  62. package/dist-cli-web/assets/{index-BKo68Iu5.js → index-BE4nd1aX.js} +1 -1
  63. package/dist-cli-web/assets/{index-DFHYr_-u.js → index-Bb6EtLMB.js} +1 -1
  64. package/dist-cli-web/assets/{index-DsdMsKYT.js → index-BcWaPFz7.js} +1 -1
  65. package/dist-cli-web/assets/{index-ZTgfCZvY.js → index-CKkIHbie.js} +3 -3
  66. package/dist-cli-web/assets/{index-3YO6RI5e.js → index-CbacXZN3.js} +2 -2
  67. package/dist-cli-web/assets/{index-JYfjMRb-.js → index-CjoTcSEc.js} +1 -1
  68. package/dist-cli-web/assets/index-CsX1Wt8l.js +173 -0
  69. package/dist-cli-web/assets/{index-2-OaYdzt.js → index-CsyURmWU.js} +1 -1
  70. package/dist-cli-web/assets/{index-CGI3Y8pq.js → index-DLnlRLCx.js} +1 -1
  71. package/dist-cli-web/assets/index-YzfjPohq.js +53 -0
  72. package/dist-cli-web/assets/{index-BrkDgcJ6.js → index-dObiAHg6.js} +1 -1
  73. package/dist-cli-web/assets/{index-DA3Q0TGT.js → index-x74lBtei.js} +1 -1
  74. package/dist-cli-web/assets/{people-page-header-D-LWaEqn.js → people-page-header-BW5cNPl7.js} +1 -1
  75. package/dist-cli-web/assets/{webworkerAll-CPOVECup.js → webworkerAll-8AFsQkH1.js} +1 -1
  76. package/dist-cli-web/index.html +1 -1
  77. package/package.json +1 -1
  78. package/dist/chunk-AQPDZAWB.mjs.map +0 -1
  79. package/dist/chunk-DGF3S3TZ.mjs.map +0 -1
  80. package/dist/chunk-S5NCEESV.mjs.map +0 -1
  81. package/dist-cli-web/assets/index-CW9H_fBd.js +0 -53
  82. package/dist-cli-web/assets/index-DmwA85vG.js +0 -173
  83. /package/dist/{chat-command-XPY3WURC.mjs.map → chat-command-OWKJJ736.mjs.map} +0 -0
  84. /package/dist/{chunk-IGEHMLHM.mjs.map → chunk-GHZFNAMF.mjs.map} +0 -0
  85. /package/dist/{chunk-JCSPDTZL.mjs.map → chunk-MPHFZYB7.mjs.map} +0 -0
  86. /package/dist/{chunk-ISRLGLUL.mjs.map → chunk-OHFVX2HH.mjs.map} +0 -0
  87. /package/dist/{chunk-IGK6UMN2.mjs.map → chunk-VTCZM2JS.mjs.map} +0 -0
  88. /package/dist/{chunk-JTOHAMIW.mjs.map → chunk-XEGEOU2D.mjs.map} +0 -0
  89. /package/dist/{chunk-BQ3QN4QT.mjs.map → chunk-YRCFDZ5Q.mjs.map} +0 -0
  90. /package/dist/{http-HV6XWU6X.mjs.map → http-X55S6MTO.mjs.map} +0 -0
  91. /package/dist/{import-DP2XLZ2H.mjs.map → import-4AX6IX57.mjs.map} +0 -0
  92. /package/dist/{mcp-QDPFBPGW.mjs.map → mcp-GWC52AWE.mjs.map} +0 -0
  93. /package/dist/{src-B3A2QHP5.mjs.map → src-DLLM4SEO.mjs.map} +0 -0
  94. /package/dist/{stream-import-KEGNP3QK.mjs.map → stream-import-K24HWAAZ.mjs.map} +0 -0
  95. /package/dist/{worker-runtime-MDYKX3BW.mjs.map → worker-runtime-6KKR55TD.mjs.map} +0 -0
@@ -9,7 +9,7 @@ import {
9
9
  createEmptyContactsDiagnostics,
10
10
  normalizeContactsTimeRangePreset,
11
11
  resolveContactsTimeRange
12
- } from "./chunk-IGEHMLHM.mjs";
12
+ } from "./chunk-GHZFNAMF.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-JTOHAMIW.mjs";
21
+ } from "./chunk-XEGEOU2D.mjs";
22
22
  import {
23
23
  ANNUAL_SUMMARY_ALGORITHM_VERSION
24
24
  } from "./chunk-QZCNVAH6.mjs";
@@ -110,7 +110,7 @@ import {
110
110
  writeAuthProfile,
111
111
  writeJsonFileAtomically,
112
112
  writeParseResultToDb
113
- } from "./chunk-OLE2USEN.mjs";
113
+ } from "./chunk-3RWYALUP.mjs";
114
114
  import {
115
115
  __commonJS,
116
116
  __export,
@@ -2847,6 +2847,14 @@ function matchFilenameSignatures(filePath, patterns) {
2847
2847
  const filename = path2.basename(filePath);
2848
2848
  return patterns.some((pattern) => pattern.test(filename));
2849
2849
  }
2850
+ function matchFilenameFallbackPatterns(filePath, patterns) {
2851
+ try {
2852
+ const content = fs2.readFileSync(filePath, "utf-8");
2853
+ return patterns.every((pattern) => pattern.test(content));
2854
+ } catch {
2855
+ return false;
2856
+ }
2857
+ }
2850
2858
  function matchRequiredFields(headContent, fields) {
2851
2859
  return fields.every((field) => {
2852
2860
  const pattern = new RegExp(`"${field.replace(".", '"\\s*:\\s*.*"')}"\\s*:`);
@@ -2968,6 +2976,11 @@ var FormatSniffer = class {
2968
2976
  return false;
2969
2977
  }
2970
2978
  }
2979
+ if (!headMatch && filenameMatch && signatures.filenameFallbackPatterns) {
2980
+ if (!filePath || !matchFilenameFallbackPatterns(filePath, signatures.filenameFallbackPatterns)) {
2981
+ return false;
2982
+ }
2983
+ }
2971
2984
  if (signatures.requiredFields && signatures.requiredFields.length > 0) {
2972
2985
  if (!matchRequiredFields(headContent, signatures.requiredFields)) {
2973
2986
  return false;
@@ -4089,8 +4102,10 @@ var feature4 = {
4089
4102
  // 比单文件版本优先级更高
4090
4103
  extensions: [".json"],
4091
4104
  signatures: {
4092
- // 使用 head 签名 "format": "chunked-jsonl" 来区分。
4093
- head: [/"format"\s*:\s*"chunked-jsonl"/],
4105
+ // V5 使用 metadata.format,0.1.x 将格式标识移至 chunked.format
4106
+ head: [/"format"\s*:\s*"chunked-jsonl"/, /"chunked"\s*:\s*\{[^{}]*"format"\s*:\s*"jsonl"/],
4107
+ filename: [/^manifest\.json$/i],
4108
+ filenameFallbackPatterns: [/"chunked"\s*:\s*\{[\s\S]*?"format"\s*:\s*"jsonl"/],
4094
4109
  requiredFields: ["metadata", "chatInfo"]
4095
4110
  }
4096
4111
  };
@@ -4221,9 +4236,10 @@ async function* parseChunkedJsonl(options2) {
4221
4236
  yield { type: "error", data: new Error(`\u65E0\u6CD5\u8BFB\u53D6 manifest.json: ${errorMsg}`) };
4222
4237
  return;
4223
4238
  }
4224
- if (manifest.metadata.format !== "chunked-jsonl") {
4225
- onLog?.("error", `\u4E0D\u652F\u6301\u7684\u683C\u5F0F: ${manifest.metadata.format}`);
4226
- yield { type: "error", data: new Error(`\u4E0D\u652F\u6301\u7684\u683C\u5F0F: ${manifest.metadata.format}`) };
4239
+ if (manifest.metadata.format !== "chunked-jsonl" && manifest.chunked.format !== "jsonl") {
4240
+ const format = manifest.metadata.format ?? manifest.chunked.format ?? "unknown";
4241
+ onLog?.("error", `\u4E0D\u652F\u6301\u7684\u683C\u5F0F: ${format}`);
4242
+ yield { type: "error", data: new Error(`\u4E0D\u652F\u6301\u7684\u683C\u5F0F: ${format}`) };
4227
4243
  return;
4228
4244
  }
4229
4245
  const totalBytes = calculateTotalBytes(manifest, baseDir);
@@ -6743,6 +6759,8 @@ var MAX_UNIX_SECONDS = 1e11;
6743
6759
  var KNOWN_MESSAGE_TYPES = new Set(
6744
6760
  Object.values(MessageType).filter((value) => typeof value === "number")
6745
6761
  );
6762
+ var SYSTEM_SENDER_ID = "SYSTEM";
6763
+ var SYSTEM_SENDER_MESSAGE_TYPES = /* @__PURE__ */ new Set([80 /* SYSTEM */, 81 /* RECALL */]);
6746
6764
  function createState(format, fileSize) {
6747
6765
  return {
6748
6766
  format,
@@ -6917,8 +6935,9 @@ function validateMessage(state, value, path30, location) {
6917
6935
  addIssue(state, "error", "INVALID_MESSAGE", "Expected a message object.", childLocation(location, path30));
6918
6936
  return;
6919
6937
  }
6920
- if (validateRequiredString(state, value.sender, `${path30}.sender`, location)) {
6921
- state.senderIds.add(value.sender);
6938
+ const sender = validateRequiredString(state, value.sender, `${path30}.sender`, location) ? value.sender : void 0;
6939
+ if (sender !== void 0) {
6940
+ state.senderIds.add(sender);
6922
6941
  }
6923
6942
  validateRequiredString(state, value.accountName, `${path30}.accountName`, location);
6924
6943
  if (validateUnixSeconds(state, value.timestamp, `${path30}.timestamp`, location)) {
@@ -6933,11 +6952,20 @@ function validateMessage(state, value, path30, location) {
6933
6952
  }
6934
6953
  state.lastTimestamp = value.timestamp;
6935
6954
  }
6936
- if (typeof value.type !== "number" || !Number.isInteger(value.type) || !KNOWN_MESSAGE_TYPES.has(value.type)) {
6955
+ const messageType = typeof value.type === "number" && Number.isInteger(value.type) && KNOWN_MESSAGE_TYPES.has(value.type) ? value.type : void 0;
6956
+ if (messageType === void 0) {
6937
6957
  addIssue(state, "error", "INVALID_MESSAGE_TYPE", "Expected a supported numeric ChatLab message type.", {
6938
6958
  ...location,
6939
6959
  path: `${path30}.type`
6940
6960
  });
6961
+ } else if (sender === SYSTEM_SENDER_ID && !SYSTEM_SENDER_MESSAGE_TYPES.has(messageType)) {
6962
+ addIssue(
6963
+ state,
6964
+ "error",
6965
+ "INVALID_SYSTEM_SENDER_TYPE",
6966
+ "The reserved SYSTEM sender is only valid for system and recall messages.",
6967
+ childLocation(location, `${path30}.sender`)
6968
+ );
6941
6969
  }
6942
6970
  if (!hasOwn(value, "content") || typeof value.content !== "string" && value.content !== null) {
6943
6971
  addIssue(state, "error", "INVALID_MESSAGE_CONTENT", "Expected content to be a string or null.", {
@@ -6986,7 +7014,7 @@ function finalizeState(state, requireExplicitMembers, enforceRequiredSections =
6986
7014
  }
6987
7015
  if (state.memberIds.size > 0) {
6988
7016
  for (const senderId of state.senderIds) {
6989
- if (!state.memberIds.has(senderId)) {
7017
+ if (senderId !== SYSTEM_SENDER_ID && !state.memberIds.has(senderId)) {
6990
7018
  addIssue(
6991
7019
  state,
6992
7020
  "error",
@@ -7125,6 +7153,154 @@ async function validateChatLabFile(filePath) {
7125
7153
  return finalizeState(state, false, false);
7126
7154
  }
7127
7155
 
7156
+ // ../../packages/parser/src/chatlab-demo-timeline.ts
7157
+ var SECONDS_PER_MINUTE = 60;
7158
+ var DEFAULT_DEMO_TIME_ZONE_OFFSET_MINUTES = 8 * 60;
7159
+ var MAX_TIME_ZONE_OFFSET_MINUTES = 14 * 60;
7160
+ function rebaseChatLabDemoDocuments(jsonDocuments, now = /* @__PURE__ */ new Date(), targetTimeZone) {
7161
+ if (jsonDocuments.length === 0) throw new Error("Demo timeline requires at least one document");
7162
+ if (!Number.isFinite(now.getTime())) throw new Error("Demo timeline requires a valid import time");
7163
+ const documents = jsonDocuments.map((json, index) => parseDemoDocument(json, index));
7164
+ const timeZoneOffsetMinutes = resolveTimeZoneOffsetMinutes(documents);
7165
+ const sourceLatestTimestamp = Math.max(
7166
+ ...documents.flatMap((document) => document.messages.map((message) => message.timestamp))
7167
+ );
7168
+ const sourceLatestWallTime = new Date((sourceLatestTimestamp + timeZoneOffsetMinutes * SECONDS_PER_MINUTE) * 1e3);
7169
+ const latestTimestamp = resolveTargetLatestTimestamp(now, sourceLatestWallTime, targetTimeZone);
7170
+ const offsetSeconds = latestTimestamp - sourceLatestTimestamp;
7171
+ const exportedAt = Math.floor(now.getTime() / 1e3);
7172
+ for (const document of documents) {
7173
+ document.chatlab.exportedAt = exportedAt;
7174
+ for (const message of document.messages) {
7175
+ message.timestamp += offsetSeconds;
7176
+ }
7177
+ }
7178
+ return {
7179
+ documents: documents.map((document) => JSON.stringify(document)),
7180
+ offsetSeconds,
7181
+ latestTimestamp
7182
+ };
7183
+ }
7184
+ function resolveTargetLatestTimestamp(now, sourceWallTime, targetTimeZone) {
7185
+ if (!targetTimeZone) {
7186
+ const targetLatestTime = new Date(now);
7187
+ targetLatestTime.setDate(targetLatestTime.getDate() - 1);
7188
+ targetLatestTime.setHours(
7189
+ sourceWallTime.getUTCHours(),
7190
+ sourceWallTime.getUTCMinutes(),
7191
+ sourceWallTime.getUTCSeconds(),
7192
+ 0
7193
+ );
7194
+ return Math.floor(targetLatestTime.getTime() / 1e3);
7195
+ }
7196
+ let formatter;
7197
+ try {
7198
+ formatter = new Intl.DateTimeFormat("en-US-u-ca-gregory-nu-latn", {
7199
+ timeZone: targetTimeZone,
7200
+ year: "numeric",
7201
+ month: "2-digit",
7202
+ day: "2-digit",
7203
+ hour: "2-digit",
7204
+ minute: "2-digit",
7205
+ second: "2-digit",
7206
+ hourCycle: "h23"
7207
+ });
7208
+ } catch {
7209
+ throw new Error("Demo timeline has an invalid target time zone");
7210
+ }
7211
+ const currentDate = getZonedDateTimeParts(now, formatter);
7212
+ const yesterday = new Date(Date.UTC(currentDate.year, currentDate.month - 1, currentDate.day - 1));
7213
+ const targetParts = {
7214
+ year: yesterday.getUTCFullYear(),
7215
+ month: yesterday.getUTCMonth() + 1,
7216
+ day: yesterday.getUTCDate(),
7217
+ hour: sourceWallTime.getUTCHours(),
7218
+ minute: sourceWallTime.getUTCMinutes(),
7219
+ second: sourceWallTime.getUTCSeconds()
7220
+ };
7221
+ return Math.floor(zonedWallTimeToUnixMillis(targetParts, formatter) / 1e3);
7222
+ }
7223
+ function getZonedDateTimeParts(date, formatter) {
7224
+ const values = new Map(formatter.formatToParts(date).map((part) => [part.type, part.value]));
7225
+ const read = (type) => Number(values.get(type));
7226
+ const parts = {
7227
+ year: read("year"),
7228
+ month: read("month"),
7229
+ day: read("day"),
7230
+ hour: read("hour"),
7231
+ minute: read("minute"),
7232
+ second: read("second")
7233
+ };
7234
+ if (Object.values(parts).some((value) => !Number.isInteger(value))) {
7235
+ throw new Error("Demo timeline could not resolve the target time zone");
7236
+ }
7237
+ return parts;
7238
+ }
7239
+ function zonedWallTimeToUnixMillis(target, formatter) {
7240
+ const targetAsUtc = dateTimePartsToUtcMillis(target);
7241
+ let candidate = targetAsUtc;
7242
+ for (let attempt = 0; attempt < 3; attempt++) {
7243
+ const actual2 = getZonedDateTimeParts(new Date(candidate), formatter);
7244
+ const correction = targetAsUtc - dateTimePartsToUtcMillis(actual2);
7245
+ candidate += correction;
7246
+ if (correction === 0) return candidate;
7247
+ }
7248
+ const actual = getZonedDateTimeParts(new Date(candidate), formatter);
7249
+ if (dateTimePartsToUtcMillis(actual) !== targetAsUtc) {
7250
+ throw new Error("Demo timeline target wall time does not exist in the selected time zone");
7251
+ }
7252
+ return candidate;
7253
+ }
7254
+ function dateTimePartsToUtcMillis(parts) {
7255
+ return Date.UTC(parts.year, parts.month - 1, parts.day, parts.hour, parts.minute, parts.second);
7256
+ }
7257
+ function parseDemoDocument(json, index) {
7258
+ let value;
7259
+ try {
7260
+ value = JSON.parse(json);
7261
+ } catch {
7262
+ throw new Error(`Demo document ${index + 1} is not valid JSON`);
7263
+ }
7264
+ if (!isRecord2(value) || !isRecord2(value.chatlab) || !Array.isArray(value.messages)) {
7265
+ throw new Error(`Demo document ${index + 1} is not a ChatLab JSON document`);
7266
+ }
7267
+ if (value.messages.length === 0) {
7268
+ throw new Error(`Demo document ${index + 1} has no messages`);
7269
+ }
7270
+ const messages = value.messages.map((message, messageIndex) => {
7271
+ if (!isRecord2(message) || !isUnixSeconds(message.timestamp)) {
7272
+ throw new Error(`Demo document ${index + 1} has an invalid timestamp at message ${messageIndex + 1}`);
7273
+ }
7274
+ return message;
7275
+ });
7276
+ return {
7277
+ ...value,
7278
+ chatlab: value.chatlab,
7279
+ messages
7280
+ };
7281
+ }
7282
+ function resolveTimeZoneOffsetMinutes(documents) {
7283
+ const offsets = /* @__PURE__ */ new Set();
7284
+ for (const document of documents) {
7285
+ const configured = document.chatlab.demoTimeline?.timeZoneOffsetMinutes;
7286
+ const offset = configured ?? DEFAULT_DEMO_TIME_ZONE_OFFSET_MINUTES;
7287
+ if (typeof offset !== "number" || !Number.isInteger(offset) || Math.abs(offset) > MAX_TIME_ZONE_OFFSET_MINUTES) {
7288
+ throw new Error("Demo timeline has an invalid time zone offset");
7289
+ }
7290
+ offsets.add(offset);
7291
+ }
7292
+ if (offsets.size !== 1) {
7293
+ throw new Error("Demo documents must use the same time zone offset");
7294
+ }
7295
+ return offsets.values().next().value;
7296
+ }
7297
+ function isUnixSeconds(value) {
7298
+ return typeof value === "number" && Number.isInteger(value) && value >= 0;
7299
+ }
7300
+ function isRecord2(value) {
7301
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7302
+ }
7303
+
7128
7304
  // ../../packages/parser/src/index.ts
7129
7305
  var sniffer = createSniffer();
7130
7306
  sniffer.registerAll(formats);
@@ -7688,15 +7864,21 @@ function registerMessageAndCheckDuplicate(message, state) {
7688
7864
  // ../../packages/node-runtime/src/import/streaming-importer.ts
7689
7865
  var BATCH_COMMIT_SIZE = 5e4;
7690
7866
  var CHECKPOINT_INTERVAL = 2e5;
7867
+ var SYSTEM_SENDER_ID2 = "SYSTEM";
7868
+ var SYSTEM_MEMBER_NAME = "\u7CFB\u7EDF\u6D88\u606F";
7869
+ var RESERVED_SYSTEM_SENDER_FORMATS = /* @__PURE__ */ new Set(["chatlab", "chatlab-jsonl"]);
7691
7870
  var yieldToEventLoop = () => new Promise((resolve4) => setImmediate(resolve4));
7692
7871
  function defaultGenerateSessionId() {
7693
7872
  const ts = Date.now();
7694
7873
  const rand = Math.random().toString(36).substring(2, 8);
7695
7874
  return `chat_${ts}_${rand}`;
7696
7875
  }
7697
- function prepareMessageForCreate(message) {
7876
+ function normalizeSystemMemberName(formatId, platformId, name) {
7877
+ return RESERVED_SYSTEM_SENDER_FORMATS.has(formatId) && platformId === SYSTEM_SENDER_ID2 ? SYSTEM_MEMBER_NAME : name;
7878
+ }
7879
+ function prepareMessageForCreate(message, senderAccountName = message.senderAccountName) {
7698
7880
  if (!message.senderPlatformId) return { skipCounter: "skippedNoSenderId" };
7699
- if (!message.senderAccountName) return { skipCounter: "skippedNoAccountName" };
7881
+ if (!senderAccountName) return { skipCounter: "skippedNoAccountName" };
7700
7882
  if (message.timestamp === void 0 || message.timestamp === null || isNaN(message.timestamp)) {
7701
7883
  return { skipCounter: "skippedInvalidTimestamp" };
7702
7884
  }
@@ -7910,10 +8092,12 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
7910
8092
  callbackStats.totalMembersReceived += members.length;
7911
8093
  logger?.info(`Received member batch: ${members.length} members`);
7912
8094
  for (const member of members) {
8095
+ const accountName = normalizeSystemMemberName(formatFeature.id, member.platformId, member.accountName);
8096
+ const groupNickname = normalizeSystemMemberName(formatFeature.id, member.platformId, member.groupNickname);
7913
8097
  insertMember.run(
7914
8098
  member.platformId,
7915
- member.accountName || null,
7916
- member.groupNickname || null,
8099
+ accountName || null,
8100
+ groupNickname || null,
7917
8101
  member.aliases ? JSON.stringify(member.aliases) : "[]",
7918
8102
  member.avatar || null,
7919
8103
  member.roles ? JSON.stringify(member.roles) : "[]"
@@ -7936,7 +8120,17 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
7936
8120
  let memberInsertCount = 0;
7937
8121
  let nicknameChangeCount = 0;
7938
8122
  for (const msg of messages) {
7939
- const prepared = prepareMessageForCreate(msg);
8123
+ const senderAccountName = normalizeSystemMemberName(
8124
+ formatFeature.id,
8125
+ msg.senderPlatformId,
8126
+ msg.senderAccountName
8127
+ );
8128
+ const senderGroupNickname = normalizeSystemMemberName(
8129
+ formatFeature.id,
8130
+ msg.senderPlatformId,
8131
+ msg.senderGroupNickname
8132
+ );
8133
+ const prepared = prepareMessageForCreate(msg, senderAccountName);
7940
8134
  if ("skipCounter" in prepared) {
7941
8135
  callbackStats[prepared.skipCounter]++;
7942
8136
  continue;
@@ -7950,8 +8144,8 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
7950
8144
  if (!memberIdMap.has(msg.senderPlatformId)) {
7951
8145
  insertMember.run(
7952
8146
  msg.senderPlatformId,
7953
- msg.senderAccountName || null,
7954
- msg.senderGroupNickname || null,
8147
+ senderAccountName || null,
8148
+ senderGroupNickname || null,
7955
8149
  "[]",
7956
8150
  null,
7957
8151
  "[]"
@@ -7969,8 +8163,8 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
7969
8163
  t0 = Date.now();
7970
8164
  insertMessage.run(
7971
8165
  senderId,
7972
- msg.senderAccountName || null,
7973
- msg.senderGroupNickname || null,
8166
+ senderAccountName || null,
8167
+ senderGroupNickname || null,
7974
8168
  dedupMessage.timestamp,
7975
8169
  dedupMessage.type,
7976
8170
  dedupMessage.content,
@@ -7981,8 +8175,8 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
7981
8175
  messageCountInBatch++;
7982
8176
  totalMessageCount++;
7983
8177
  t0 = Date.now();
7984
- trackNickname(accountNameTracker, msg.senderPlatformId, msg.senderAccountName, msg.timestamp);
7985
- trackNickname(groupNicknameTracker, msg.senderPlatformId, msg.senderGroupNickname, msg.timestamp);
8178
+ trackNickname(accountNameTracker, msg.senderPlatformId, senderAccountName, msg.timestamp);
8179
+ trackNickname(groupNicknameTracker, msg.senderPlatformId, senderGroupNickname, msg.timestamp);
7986
8180
  nicknameTrackTime += Date.now() - t0;
7987
8181
  nicknameChangeCount += accountNameTracker.get(msg.senderPlatformId)?.history.length === 1 ? 0 : 0;
7988
8182
  if (messageCountInBatch >= BATCH_COMMIT_SIZE) {
@@ -8513,10 +8707,12 @@ async function incrementalImport(sessionId, filePath, deps, options2) {
8513
8707
  if (memberUpdateMode === "none") return;
8514
8708
  for (const m of members) {
8515
8709
  const existed = memberIdMap.has(m.platformId);
8710
+ const accountName = normalizeSystemMemberName(formatFeature.id, m.platformId, m.accountName);
8711
+ const groupNickname = normalizeSystemMemberName(formatFeature.id, m.platformId, m.groupNickname);
8516
8712
  upsertMember.run(
8517
8713
  m.platformId,
8518
- m.accountName || null,
8519
- m.groupNickname || null,
8714
+ accountName || null,
8715
+ groupNickname || null,
8520
8716
  m.aliases ? JSON.stringify(m.aliases) : "[]",
8521
8717
  m.avatar || null,
8522
8718
  m.roles ? JSON.stringify(m.roles) : "[]"
@@ -8553,12 +8749,22 @@ async function incrementalImport(sessionId, filePath, deps, options2) {
8553
8749
  duplicateCount++;
8554
8750
  continue;
8555
8751
  }
8752
+ const senderAccountName = normalizeSystemMemberName(
8753
+ formatFeature.id,
8754
+ msg.senderPlatformId,
8755
+ msg.senderAccountName
8756
+ );
8757
+ const senderGroupNickname = normalizeSystemMemberName(
8758
+ formatFeature.id,
8759
+ msg.senderPlatformId,
8760
+ msg.senderGroupNickname
8761
+ );
8556
8762
  let memberId = memberIdMap.get(msg.senderPlatformId);
8557
8763
  if (!memberId) {
8558
8764
  insertMemberMinimal.run(
8559
8765
  msg.senderPlatformId,
8560
- msg.senderAccountName || null,
8561
- msg.senderGroupNickname || null,
8766
+ senderAccountName || null,
8767
+ senderGroupNickname || null,
8562
8768
  null
8563
8769
  );
8564
8770
  const row = getMemberId.get(msg.senderPlatformId);
@@ -8571,8 +8777,8 @@ async function incrementalImport(sessionId, filePath, deps, options2) {
8571
8777
  if (!memberId) continue;
8572
8778
  const msgResult = insertMessage.run(
8573
8779
  memberId,
8574
- msg.senderAccountName || null,
8575
- msg.senderGroupNickname || null,
8780
+ senderAccountName || null,
8781
+ senderGroupNickname || null,
8576
8782
  timestamp,
8577
8783
  msg.type,
8578
8784
  msg.content || null,
@@ -8627,7 +8833,7 @@ async function incrementalImport(sessionId, filePath, deps, options2) {
8627
8833
  MAX(ts) as lastTimestamp
8628
8834
  FROM message`
8629
8835
  ).get();
8630
- const memberCountRow = db.prepare("SELECT COUNT(*) as count FROM member").get();
8836
+ const memberCountRow = db.prepare(`SELECT COUNT(*) as count FROM member WHERE COALESCE(account_name, '') != ?`).get(SYSTEM_MEMBER_NAME);
8631
8837
  try {
8632
8838
  await deps.postImportHook?.(db, sessionId);
8633
8839
  } catch {
@@ -13008,7 +13214,7 @@ var PLAN_INTENTS = [
13008
13214
  "mixed"
13009
13215
  ];
13010
13216
  var STREAM_MARKER_HOLDBACK_CHARS = Math.max("</draft>".length, "</plan>".length, "<json>".length) - 1;
13011
- function isRecord2(value) {
13217
+ function isRecord3(value) {
13012
13218
  return typeof value === "object" && value !== null && !Array.isArray(value);
13013
13219
  }
13014
13220
  function isIntent(value) {
@@ -13030,10 +13236,10 @@ function extractJsonObject4(text) {
13030
13236
  function parsePlanJson(rawText, availableTools) {
13031
13237
  try {
13032
13238
  const parsed = JSON.parse(extractJsonObject4(rawText));
13033
- if (!isRecord2(parsed)) return null;
13239
+ if (!isRecord3(parsed)) return null;
13034
13240
  const title = normalizeString(parsed.title);
13035
13241
  if (!title || !isIntent(parsed.intent) || !Array.isArray(parsed.steps)) return null;
13036
- const steps = parsed.steps.filter(isRecord2).map((step) => {
13242
+ const steps = parsed.steps.filter(isRecord3).map((step) => {
13037
13243
  const goal = normalizeString(step.goal);
13038
13244
  const evidenceNeeded = normalizeString(step.evidenceNeeded);
13039
13245
  if (!goal || !evidenceNeeded) return null;
@@ -17180,11 +17386,11 @@ function writeContactOverrides(snapshotDir, overrides) {
17180
17386
  fs29.renameSync(tmpPath, getContactOverridesPath(snapshotDir));
17181
17387
  }
17182
17388
  function normalizeContactOverrides(value) {
17183
- const input = isRecord3(value) ? value : {};
17184
- const manualFriendsInput = isRecord3(input.manualFriends) ? input.manualFriends : {};
17389
+ const input = isRecord4(value) ? value : {};
17390
+ const manualFriendsInput = isRecord4(input.manualFriends) ? input.manualFriends : {};
17185
17391
  const manualFriends = {};
17186
17392
  for (const [key, entry] of Object.entries(manualFriendsInput)) {
17187
- if (!key || !isRecord3(entry)) continue;
17393
+ if (!key || !isRecord4(entry)) continue;
17188
17394
  const createdAt = Number.isFinite(entry.createdAt) ? Number(entry.createdAt) : Date.now();
17189
17395
  const updatedAt = Number.isFinite(entry.updatedAt) ? Number(entry.updatedAt) : createdAt;
17190
17396
  manualFriends[key] = { key, createdAt, updatedAt };
@@ -17194,7 +17400,7 @@ function normalizeContactOverrides(value) {
17194
17400
  manualFriends
17195
17401
  };
17196
17402
  }
17197
- function isRecord3(value) {
17403
+ function isRecord4(value) {
17198
17404
  return typeof value === "object" && value !== null && !Array.isArray(value);
17199
17405
  }
17200
17406
 
@@ -20893,20 +21099,20 @@ var MergeSessionCache = class {
20893
21099
 
20894
21100
  // ../../packages/node-runtime/src/services/push-importer.ts
20895
21101
  import * as fs35 from "fs";
20896
- var SYSTEM_SENDER_ID = "SYSTEM";
20897
- var SYSTEM_MEMBER_NAME = "\u7CFB\u7EDF\u6D88\u606F";
20898
- function isRecord4(value) {
21102
+ var SYSTEM_SENDER_ID3 = "SYSTEM";
21103
+ var SYSTEM_MEMBER_NAME2 = "\u7CFB\u7EDF\u6D88\u606F";
21104
+ function isRecord5(value) {
20899
21105
  return typeof value === "object" && value !== null && !Array.isArray(value);
20900
21106
  }
20901
21107
  function validateOptionalString2(value, field) {
20902
21108
  return value !== void 0 && typeof value !== "string" ? `${field} must be a string` : null;
20903
21109
  }
20904
21110
  function validatePayload(payload, isNew) {
20905
- if (!isRecord4(payload)) return "payload must be an object";
21111
+ if (!isRecord5(payload)) return "payload must be an object";
20906
21112
  const messages = payload.messages;
20907
21113
  if (!Array.isArray(messages) || messages.length === 0) return "messages is required and must be a non-empty array";
20908
21114
  if (payload.chatlab !== void 0) {
20909
- if (!isRecord4(payload.chatlab)) return "chatlab must be an object";
21115
+ if (!isRecord5(payload.chatlab)) return "chatlab must be an object";
20910
21116
  if (typeof payload.chatlab.version !== "string" || payload.chatlab.version.length === 0)
20911
21117
  return "chatlab.version must be a string";
20912
21118
  if (typeof payload.chatlab.exportedAt !== "number" || !Number.isFinite(payload.chatlab.exportedAt))
@@ -20919,7 +21125,7 @@ function validatePayload(payload, isNew) {
20919
21125
  if (!payload.meta) return "meta is required for new sessions";
20920
21126
  }
20921
21127
  if (payload.meta !== void 0) {
20922
- if (!isRecord4(payload.meta)) return "meta must be an object";
21128
+ if (!isRecord5(payload.meta)) return "meta must be an object";
20923
21129
  const metaFields = ["name", "platform", "type", "groupId", "groupAvatar", "ownerId"];
20924
21130
  for (const field of metaFields) {
20925
21131
  const error = validateOptionalString2(payload.meta[field], `meta.${field}`);
@@ -20929,7 +21135,7 @@ function validatePayload(payload, isNew) {
20929
21135
  if (isNew && !payload.meta.platform) return "meta.platform is required";
20930
21136
  if (isNew && !payload.meta.type) return "meta.type is required";
20931
21137
  }
20932
- if (payload.options !== void 0 && !isRecord4(payload.options)) return "options must be an object";
21138
+ if (payload.options !== void 0 && !isRecord5(payload.options)) return "options must be an object";
20933
21139
  const { metaUpdateMode, memberUpdateMode } = payload.options ?? {};
20934
21140
  if (metaUpdateMode !== void 0 && metaUpdateMode !== "patch" && metaUpdateMode !== "none") {
20935
21141
  return `options.metaUpdateMode must be 'patch' or 'none'`;
@@ -20941,7 +21147,7 @@ function validatePayload(payload, isNew) {
20941
21147
  if (payload.members) {
20942
21148
  for (let i = 0; i < payload.members.length; i++) {
20943
21149
  const member = payload.members[i];
20944
- if (!isRecord4(member)) return `members[${i}] must be an object`;
21150
+ if (!isRecord5(member)) return `members[${i}] must be an object`;
20945
21151
  if (typeof member.platformId !== "string" || member.platformId.length === 0)
20946
21152
  return `members[${i}].platformId must be a string`;
20947
21153
  for (const field of ["accountName", "groupNickname", "avatar"]) {
@@ -20952,7 +21158,7 @@ function validatePayload(payload, isNew) {
20952
21158
  if (!Array.isArray(member.roles)) return `members[${i}].roles must be an array`;
20953
21159
  for (let j = 0; j < member.roles.length; j++) {
20954
21160
  const role = member.roles[j];
20955
- if (!isRecord4(role) || typeof role.id !== "string" || role.id.length === 0)
21161
+ if (!isRecord5(role) || typeof role.id !== "string" || role.id.length === 0)
20956
21162
  return `members[${i}].roles[${j}].id must be a string`;
20957
21163
  }
20958
21164
  }
@@ -20960,7 +21166,7 @@ function validatePayload(payload, isNew) {
20960
21166
  }
20961
21167
  for (let i = 0; i < messages.length; i++) {
20962
21168
  const msg = messages[i];
20963
- if (!isRecord4(msg)) return `messages[${i}] must be an object`;
21169
+ if (!isRecord5(msg)) return `messages[${i}] must be an object`;
20964
21170
  if (typeof msg.sender !== "string" || msg.sender.length === 0) return `messages[${i}].sender must be a string`;
20965
21171
  if (typeof msg.timestamp !== "number" || !Number.isFinite(msg.timestamp) || msg.timestamp <= 0)
20966
21172
  return `messages[${i}].timestamp must be a positive number`;
@@ -20980,17 +21186,17 @@ function validatePayload(payload, isNew) {
20980
21186
  }
20981
21187
  function queryStats(db) {
20982
21188
  const row = db.prepare("SELECT COUNT(*) as total, MIN(ts) as first, MAX(ts) as last FROM message").get();
20983
- const memberRow = db.prepare(`SELECT COUNT(*) as cnt FROM member WHERE COALESCE(account_name, '') != ?`).get(SYSTEM_MEMBER_NAME);
21189
+ const memberRow = db.prepare(`SELECT COUNT(*) as cnt FROM member WHERE COALESCE(account_name, '') != ?`).get(SYSTEM_MEMBER_NAME2);
20984
21190
  return { totalCount: row.total, memberCount: memberRow.cnt, firstTimestamp: row.first, lastTimestamp: row.last };
20985
21191
  }
20986
21192
  function normalizeSenderAccountName(sender, accountName) {
20987
- return sender === SYSTEM_SENDER_ID ? SYSTEM_MEMBER_NAME : accountName;
21193
+ return sender === SYSTEM_SENDER_ID3 ? SYSTEM_MEMBER_NAME2 : accountName;
20988
21194
  }
20989
21195
  function normalizeSenderGroupNickname(sender, groupNickname) {
20990
- return sender === SYSTEM_SENDER_ID ? SYSTEM_MEMBER_NAME : groupNickname;
21196
+ return sender === SYSTEM_SENDER_ID3 ? SYSTEM_MEMBER_NAME2 : groupNickname;
20991
21197
  }
20992
21198
  function isCountedMember(platformId) {
20993
- return platformId !== SYSTEM_SENDER_ID;
21199
+ return platformId !== SYSTEM_SENDER_ID3;
20994
21200
  }
20995
21201
  function registerPushMessageAndCheckDuplicate(message, dedupState) {
20996
21202
  return registerMessageAndCheckDuplicate(
@@ -21366,6 +21572,7 @@ export {
21366
21572
  createChatLabTempDir,
21367
21573
  removeChatLabTempDir,
21368
21574
  validateChatLabFile,
21575
+ rebaseChatLabDemoDocuments,
21369
21576
  detectFormat,
21370
21577
  detectAllFormats,
21371
21578
  getSupportedFormats,
@@ -21586,4 +21793,4 @@ export {
21586
21793
  hashImportBody,
21587
21794
  ImportIdempotencyCache
21588
21795
  };
21589
- //# sourceMappingURL=chunk-AQPDZAWB.mjs.map
21796
+ //# sourceMappingURL=chunk-RRC6U56Y.mjs.map