chatlab-cli 0.34.0 → 0.34.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 (125) hide show
  1. package/dist/{chat-command-XPY3WURC.mjs → chat-command-6IOH2QRF.mjs} +9 -9
  2. package/dist/{chunk-S5NCEESV.mjs → chunk-2XCNTG4O.mjs} +403 -76
  3. package/dist/chunk-2XCNTG4O.mjs.map +1 -0
  4. package/dist/{chunk-AQPDZAWB.mjs → chunk-4LW6443F.mjs} +1802 -712
  5. package/dist/chunk-4LW6443F.mjs.map +1 -0
  6. package/dist/{chunk-ISRLGLUL.mjs → chunk-4RLZFGO5.mjs} +2 -2
  7. package/dist/{chunk-IGEHMLHM.mjs → chunk-52P5ZRBD.mjs} +2 -2
  8. package/dist/{chunk-JTOHAMIW.mjs → chunk-652KEAX3.mjs} +2 -2
  9. package/dist/{chunk-DGF3S3TZ.mjs → chunk-72RWABYJ.mjs} +15 -9
  10. package/dist/chunk-72RWABYJ.mjs.map +1 -0
  11. package/dist/{chunk-JCSPDTZL.mjs → chunk-H6D4DZOC.mjs} +4 -4
  12. package/dist/{chunk-OLE2USEN.mjs → chunk-INBJ7SND.mjs} +53 -26
  13. package/dist/chunk-INBJ7SND.mjs.map +1 -0
  14. package/dist/{chunk-IGK6UMN2.mjs → chunk-JX6MFS6F.mjs} +43 -23
  15. package/dist/chunk-JX6MFS6F.mjs.map +1 -0
  16. package/dist/{chunk-UO2XVFY6.mjs → chunk-MENKFEPC.mjs} +147 -73
  17. package/dist/chunk-MENKFEPC.mjs.map +1 -0
  18. package/dist/{chunk-BQ3QN4QT.mjs → chunk-U6MVJSXX.mjs} +170 -66
  19. package/dist/chunk-U6MVJSXX.mjs.map +1 -0
  20. package/dist/chunk-UMBEHBIZ.mjs +41 -0
  21. package/dist/chunk-UMBEHBIZ.mjs.map +1 -0
  22. package/dist/{chunk-GFHSSCCR.mjs → chunk-VSOWNKPA.mjs} +1 -11
  23. package/dist/cli.mjs +10 -9
  24. package/dist/contacts-worker.mjs +3 -3
  25. package/dist/global-insight-worker.mjs +2 -2
  26. package/dist/{http-HV6XWU6X.mjs → http-HSK46XEU.mjs} +13 -12
  27. package/dist/{import-DP2XLZ2H.mjs → import-DF2WD2HE.mjs} +10 -8
  28. package/dist/index.mjs +13 -12
  29. package/dist/{mcp-QDPFBPGW.mjs → mcp-A2RND7KN.mjs} +12 -12
  30. package/dist/people-relationships-worker.mjs +3 -3
  31. package/dist/semantic-index-worker.mjs +1 -1
  32. package/dist/{service-KGL3RAIA.mjs → service-KZTHBDQ5.mjs} +2 -2
  33. package/dist/{src-B3A2QHP5.mjs → src-SHFHW2QB.mjs} +29 -7
  34. package/dist/{stream-import-KEGNP3QK.mjs → stream-import-GZ2QDE3Z.mjs} +10 -8
  35. package/dist/{undici-ZSXBT7EA.mjs → undici-MU5I3L6Q.mjs} +2 -2
  36. package/dist/{update-checker-LGMTEKMT.mjs → update-checker-3N7HQEP2.mjs} +2 -2
  37. package/dist/{worker-runtime-MDYKX3BW.mjs → worker-runtime-OWN56GG5.mjs} +14 -8
  38. package/dist/worker-runtime-OWN56GG5.mjs.map +1 -0
  39. package/dist-cli-web/assets/{ActionToolsPanel.vue_vue_type_script_setup_true_lang-JxPR2O6b.js → ActionToolsPanel.vue_vue_type_script_setup_true_lang-yr_T4ttU.js} +14 -14
  40. package/dist-cli-web/assets/{BufferResource--dSbJb0k.js → BufferResource-B-LHxriL.js} +1 -1
  41. package/dist-cli-web/assets/{CanvasRenderer-Cm_dmJXZ.js → CanvasRenderer-W3h_GGHM.js} +1 -1
  42. package/dist-cli-web/assets/{DataDirCleanupNotice-B0s5txX3.js → DataDirCleanupNotice-C6CMNhfs.js} +1 -1
  43. package/dist-cli-web/assets/{EChartWordcloud-CwMVJLBO.js → EChartWordcloud-Dt6rCzHf.js} +1 -1
  44. package/dist-cli-web/assets/{Filter-BjYScRpK.js → Filter-BpSopVKd.js} +1 -1
  45. package/dist-cli-web/assets/{LoadingState.vue_vue_type_script_setup_true_lang-BshQybD_.js → LoadingState.vue_vue_type_script_setup_true_lang-Bi_Uag3T.js} +1 -1
  46. package/dist-cli-web/assets/{MessageExportModal-DAJW2mFj.js → MessageExportModal-BoK-_h25.js} +1 -1
  47. package/dist-cli-web/assets/{PageHeader-BKAjCuqs.js → PageHeader-CD8B7Emf.js} +1 -1
  48. package/dist-cli-web/assets/{RelationshipGalaxyCanvas-mlZs7k4L.js → RelationshipGalaxyCanvas-BO3mo-Re.js} +7 -7
  49. package/dist-cli-web/assets/RelationshipGalaxyThreeCanvas-Brnpz6Ig.js +4108 -0
  50. package/dist-cli-web/assets/{RelationshipGalaxyThreeCanvas-CeYJABxI.css → RelationshipGalaxyThreeCanvas-CMuibfiA.css} +1 -1
  51. package/dist-cli-web/assets/{RenderTargetSystem-D00Ex44y.js → RenderTargetSystem-CNP4JLfK.js} +1 -1
  52. package/dist-cli-web/assets/{ThemeCard.vue_vue_type_script_setup_true_lang-Dsb6lzs-.js → ThemeCard.vue_vue_type_script_setup_true_lang-Na3LIoSJ.js} +1 -1
  53. package/dist-cli-web/assets/{TimeSelect.vue_vue_type_script_setup_true_lang-BfR3tlkz.js → TimeSelect.vue_vue_type_script_setup_true_lang-CKe1YZrV.js} +1 -1
  54. package/dist-cli-web/assets/{WebGLRenderer-CTTusm2n.js → WebGLRenderer-CIR5cTQN.js} +1 -1
  55. package/dist-cli-web/assets/{WebGPURenderer-pyv3EXor.js → WebGPURenderer-Dz3pCrzX.js} +1 -1
  56. package/dist-cli-web/assets/{annual-summary-time-range-C_d1oZrj.js → annual-summary-time-range-QhoA3uC6.js} +1 -1
  57. package/dist-cli-web/assets/{base-D91aVUwM.js → base-p9yfnTpk.js} +1 -1
  58. package/dist-cli-web/assets/{browserAll-C9fW936Y.js → browserAll-DMaXjf8N.js} +1 -1
  59. package/dist-cli-web/assets/cli-web-Dvy2aHxG.js +1 -0
  60. package/dist-cli-web/assets/{dateFormat-rY43adcv.js → dateFormat-5x3JKlIk.js} +1 -1
  61. package/dist-cli-web/assets/{fetch-CbnX5VoM.js → fetch-B0p6QRQ8.js} +1 -1
  62. package/dist-cli-web/assets/{fetch-DYNgtIcU.js → fetch-BI-Se2p7.js} +1 -1
  63. package/dist-cli-web/assets/{fetch-Kk2knkEo.js → fetch-BderOzzL.js} +1 -1
  64. package/dist-cli-web/assets/{fetch-DG3AeEjW.js → fetch-BtJWW2-O.js} +1 -1
  65. package/dist-cli-web/assets/fetch-CBaZNOpK.js +4 -0
  66. package/dist-cli-web/assets/{fetch-CNy9OQ2g.js → fetch-CH9Hm20R.js} +1 -1
  67. package/dist-cli-web/assets/{fetch-CrSz5KJy.js → fetch-CbpKKkdO.js} +1 -1
  68. package/dist-cli-web/assets/{fetch-PLrI3V67.js → fetch-Cne-uL1m.js} +1 -1
  69. package/dist-cli-web/assets/{fetch-DZPC3D8R.js → fetch-DRGykJYb.js} +1 -1
  70. package/dist-cli-web/assets/{fetch-CS3T-v-1.js → fetch-QLurhC_z.js} +1 -1
  71. package/dist-cli-web/assets/{index-JYfjMRb-.js → index-4NL2pYn0.js} +1 -1
  72. package/dist-cli-web/assets/{index-2-OaYdzt.js → index-B-KdENnr.js} +1 -1
  73. package/dist-cli-web/assets/{index-CGI3Y8pq.js → index-BDyixm5n.js} +1 -1
  74. package/dist-cli-web/assets/{index-BKo68Iu5.js → index-BaCd1avL.js} +1 -1
  75. package/dist-cli-web/assets/{index-ZTgfCZvY.js → index-CVBBDI3B.js} +3 -3
  76. package/dist-cli-web/assets/index-CXh01dqh.js +2 -0
  77. package/dist-cli-web/assets/index-CioAsn_2.js +137 -0
  78. package/dist-cli-web/assets/{index-DA3Q0TGT.js → index-Ct90lmPb.js} +1 -1
  79. package/dist-cli-web/assets/index-CumZ5uQ4.js +53 -0
  80. package/dist-cli-web/assets/index-CxGtGxLW.css +1 -0
  81. package/dist-cli-web/assets/{index-DsdMsKYT.js → index-DF2Dijfg.js} +1 -1
  82. package/dist-cli-web/assets/{index-3YO6RI5e.js → index-DYCPQMOl.js} +2 -2
  83. package/dist-cli-web/assets/{index-DFHYr_-u.js → index-Dp2uglLH.js} +1 -1
  84. package/dist-cli-web/assets/{index-BrkDgcJ6.js → index-IvxuxPNt.js} +1 -1
  85. package/dist-cli-web/assets/{people-page-header-D-LWaEqn.js → people-page-header-BRb9BrgP.js} +1 -1
  86. package/dist-cli-web/assets/telemetry-DPC69b73.js +1 -0
  87. package/dist-cli-web/assets/{webworkerAll-CPOVECup.js → webworkerAll-BoY19vZt.js} +1 -1
  88. package/dist-cli-web/index.html +1 -1
  89. package/package.json +3 -2
  90. package/dist/chunk-AQPDZAWB.mjs.map +0 -1
  91. package/dist/chunk-BQ3QN4QT.mjs.map +0 -1
  92. package/dist/chunk-DGF3S3TZ.mjs.map +0 -1
  93. package/dist/chunk-IGK6UMN2.mjs.map +0 -1
  94. package/dist/chunk-OLE2USEN.mjs.map +0 -1
  95. package/dist/chunk-S5NCEESV.mjs.map +0 -1
  96. package/dist/chunk-UO2XVFY6.mjs.map +0 -1
  97. package/dist/onnxruntime_binding-6Q6HXASN.node +0 -0
  98. package/dist/onnxruntime_binding-EKZT2NRK.node +0 -0
  99. package/dist/onnxruntime_binding-P6S7V3CI.node +0 -0
  100. package/dist/onnxruntime_binding-PJNNIIUO.node +0 -0
  101. package/dist/onnxruntime_binding-UN6SPTQK.node +0 -0
  102. package/dist/transformers.node-PUMHAODN.mjs +0 -42889
  103. package/dist/transformers.node-PUMHAODN.mjs.map +0 -1
  104. package/dist/worker-runtime-MDYKX3BW.mjs.map +0 -1
  105. package/dist-cli-web/assets/RelationshipGalaxyThreeCanvas-DgMG3jdU.js +0 -4108
  106. package/dist-cli-web/assets/cli-web-C7uGKz_E.js +0 -1
  107. package/dist-cli-web/assets/fetch-C6po4XYB.js +0 -3
  108. package/dist-cli-web/assets/index-2S80bo1s.js +0 -2
  109. package/dist-cli-web/assets/index-CW9H_fBd.js +0 -53
  110. package/dist-cli-web/assets/index-DmrrdYXH.css +0 -1
  111. package/dist-cli-web/assets/index-DmwA85vG.js +0 -173
  112. /package/dist/{chat-command-XPY3WURC.mjs.map → chat-command-6IOH2QRF.mjs.map} +0 -0
  113. /package/dist/{chunk-ISRLGLUL.mjs.map → chunk-4RLZFGO5.mjs.map} +0 -0
  114. /package/dist/{chunk-IGEHMLHM.mjs.map → chunk-52P5ZRBD.mjs.map} +0 -0
  115. /package/dist/{chunk-JTOHAMIW.mjs.map → chunk-652KEAX3.mjs.map} +0 -0
  116. /package/dist/{chunk-JCSPDTZL.mjs.map → chunk-H6D4DZOC.mjs.map} +0 -0
  117. /package/dist/{chunk-GFHSSCCR.mjs.map → chunk-VSOWNKPA.mjs.map} +0 -0
  118. /package/dist/{http-HV6XWU6X.mjs.map → http-HSK46XEU.mjs.map} +0 -0
  119. /package/dist/{import-DP2XLZ2H.mjs.map → import-DF2WD2HE.mjs.map} +0 -0
  120. /package/dist/{mcp-QDPFBPGW.mjs.map → mcp-A2RND7KN.mjs.map} +0 -0
  121. /package/dist/{service-KGL3RAIA.mjs.map → service-KZTHBDQ5.mjs.map} +0 -0
  122. /package/dist/{src-B3A2QHP5.mjs.map → src-SHFHW2QB.mjs.map} +0 -0
  123. /package/dist/{stream-import-KEGNP3QK.mjs.map → stream-import-GZ2QDE3Z.mjs.map} +0 -0
  124. /package/dist/{undici-ZSXBT7EA.mjs.map → undici-MU5I3L6Q.mjs.map} +0 -0
  125. /package/dist/{update-checker-LGMTEKMT.mjs.map → update-checker-3N7HQEP2.mjs.map} +0 -0
@@ -6,17 +6,17 @@ const __filename = __fileURLToPath(import.meta.url);
6
6
  const __dirname = __pathDirname(__filename);
7
7
  import {
8
8
  createCliRunAgentStream
9
- } from "./chunk-JCSPDTZL.mjs";
10
- import "./chunk-DGF3S3TZ.mjs";
11
- import "./chunk-S5NCEESV.mjs";
12
- import "./chunk-AQPDZAWB.mjs";
13
- import "./chunk-IGEHMLHM.mjs";
14
- import "./chunk-JTOHAMIW.mjs";
9
+ } from "./chunk-H6D4DZOC.mjs";
10
+ import "./chunk-72RWABYJ.mjs";
11
+ import "./chunk-2XCNTG4O.mjs";
12
+ import "./chunk-4LW6443F.mjs";
13
+ import "./chunk-52P5ZRBD.mjs";
14
+ import "./chunk-652KEAX3.mjs";
15
15
  import "./chunk-QZCNVAH6.mjs";
16
16
  import {
17
17
  getDefaultGeneralAssistantId
18
- } from "./chunk-OLE2USEN.mjs";
19
- import "./chunk-GFHSSCCR.mjs";
18
+ } from "./chunk-INBJ7SND.mjs";
19
+ import "./chunk-VSOWNKPA.mjs";
20
20
 
21
21
  // src/ai/chat-command.ts
22
22
  import { createInterface } from "readline/promises";
@@ -312,4 +312,4 @@ export {
312
312
  runChatCommand,
313
313
  runChatTurn
314
314
  };
315
- //# sourceMappingURL=chat-command-XPY3WURC.mjs.map
315
+ //# sourceMappingURL=chat-command-6IOH2QRF.mjs.map
@@ -14,6 +14,8 @@ import {
14
14
  DESENSITIZE_RULES_SCHEMA_VERSION,
15
15
  EMBEDDING_INDEX_SCHEMA,
16
16
  EmbeddingIndexStore,
17
+ LOCAL_EMBEDDING_RUNTIME_PACKAGE,
18
+ LOCAL_EMBEDDING_RUNTIME_VERSION,
17
19
  LocalEmbeddingProvider,
18
20
  OpenAICompatibleEmbeddingProvider,
19
21
  QWEN3_PROFILE,
@@ -41,7 +43,9 @@ import {
41
43
  createChatDbFtsSearcher,
42
44
  createChatDbMessageRangeReader,
43
45
  createChatDbMessageSource,
46
+ createChatLabTempDir,
44
47
  createEmbedder,
48
+ createLocalEmbeddingRuntimeManager,
45
49
  createSemanticIndexService,
46
50
  defaultSemanticIndexConfig,
47
51
  deriveParentId,
@@ -57,13 +61,15 @@ import {
57
61
  isSemanticVoid,
58
62
  parseParentBounds,
59
63
  persistSemanticIndexConfig,
64
+ rebaseChatLabDemoDocuments,
60
65
  reciprocalRankFusion,
66
+ removeChatLabTempDir,
61
67
  resolveModelId,
62
68
  resolveSemanticIndexApiKeySet,
63
69
  runWarmup,
64
70
  vecTableName,
65
71
  vecTableSchema
66
- } from "./chunk-AQPDZAWB.mjs";
72
+ } from "./chunk-4LW6443F.mjs";
67
73
  import {
68
74
  CHATLAB_FORMAT_VERSION,
69
75
  MEANINGFUL_POS_TAGS,
@@ -78,13 +84,16 @@ import {
78
84
  mergeMembers2 as mergeMembers,
79
85
  migrateFromElectronIfNeeded,
80
86
  normalizePlatformId,
87
+ readJsonFile,
81
88
  resolveApiKey,
82
89
  snapshotPathProvider,
83
- writeConfigField
84
- } from "./chunk-OLE2USEN.mjs";
90
+ withFileLock,
91
+ writeConfigField,
92
+ writeJsonFileAtomically
93
+ } from "./chunk-INBJ7SND.mjs";
85
94
  import {
86
95
  __export
87
- } from "./chunk-GFHSSCCR.mjs";
96
+ } from "./chunk-VSOWNKPA.mjs";
88
97
 
89
98
  // ../../packages/node-runtime/src/node-path-provider.ts
90
99
  import * as fs2 from "fs";
@@ -337,7 +346,7 @@ function deletePendingDataDirCleanup(systemDir, currentDir, cleanupId, deps = {}
337
346
  if (!cleanup) return { success: false, error: "Pending data directory cleanup not found" };
338
347
  const sourceDir = cleanup.sourceDir;
339
348
  const overlapsCurrentDir = normalizePathForCompare(sourceDir) === normalizePathForCompare(currentDir) || isSubPath(sourceDir, currentDir) || isSubPath(currentDir, sourceDir);
340
- const overlapsSystemDir = normalizePathForCompare(sourceDir) === normalizePathForCompare(systemDir) || isSubPath(sourceDir, systemDir);
349
+ const overlapsSystemDir = normalizePathForCompare(sourceDir) === normalizePathForCompare(systemDir) || isSubPath(sourceDir, systemDir) || isSubPath(systemDir, sourceDir);
341
350
  if (overlapsCurrentDir || overlapsSystemDir) {
342
351
  appLogger.warn("data-dir", "Old data directory cleanup rejected because the path is still in use", { cleanupId });
343
352
  return { success: false, error: "Old data directory overlaps a directory still in use" };
@@ -873,100 +882,365 @@ function* serializeChatLabToJsonl(data) {
873
882
  }
874
883
 
875
884
  // ../../packages/node-runtime/src/services/analytics.ts
876
- import * as fs4 from "fs";
877
885
  import * as path4 from "path";
878
- var REGIONS = {
879
- US: "https://us.aptabase.com",
880
- EU: "https://eu.aptabase.com"
886
+ import { randomUUID as randomUUID2 } from "crypto";
887
+ var DEFAULT_DATA = {
888
+ lastReportDate: null,
889
+ firstReportDate: null,
890
+ anonymousId: null,
891
+ enabled: true
881
892
  };
882
- var DEFAULT_DATA = { lastReportDate: null, firstReportDate: null, enabled: true };
893
+ var EVENT_NAMES = /* @__PURE__ */ new Set([
894
+ "app_started",
895
+ "app_active_new",
896
+ "app_active",
897
+ "chat_import_started",
898
+ "chat_import_completed",
899
+ "chat_import_failed",
900
+ "incremental_import_used",
901
+ "feature_used",
902
+ "ai_setup_completed",
903
+ "ai_request_started",
904
+ "ai_request_completed"
905
+ ]);
906
+ var FEATURE_IDS = /* @__PURE__ */ new Set([
907
+ "insights",
908
+ "ranking",
909
+ "ai_chat",
910
+ "sql_lab",
911
+ "message_search",
912
+ "member_management",
913
+ "session_merge",
914
+ "export"
915
+ ]);
916
+ var FAILURE_REASONS = /* @__PURE__ */ new Set([
917
+ "auth",
918
+ "network",
919
+ "rate_limit",
920
+ "model_not_found",
921
+ "aborted",
922
+ "parse",
923
+ "write",
924
+ "unknown"
925
+ ]);
926
+ var APP_LOCALES = /* @__PURE__ */ new Set(["zh-CN", "zh-TW", "en-US", "ja-JP"]);
927
+ function getUmamiConfigFromEnv() {
928
+ const endpoint = "https://t.feapp.cn/api/send"?.trim();
929
+ const websiteId = "3fbbc313-d122-4649-9c50-eef4bfad2650"?.trim();
930
+ return endpoint && websiteId ? { endpoint, websiteId } : void 0;
931
+ }
932
+ function normalizeOs() {
933
+ if (process.platform === "darwin") return "macos";
934
+ if (process.platform === "win32") return "windows";
935
+ if (process.platform === "linux") return "linux";
936
+ return "other";
937
+ }
938
+ function normalizeLocale(value) {
939
+ if (typeof value !== "string") return "unknown";
940
+ const trimmed = value.trim();
941
+ return APP_LOCALES.has(trimmed) ? trimmed : "unknown";
942
+ }
943
+ function normalizeAnalyticsImportPlatform(value) {
944
+ if (typeof value !== "string") return "unknown";
945
+ const platform = value.trim();
946
+ const hasPathOrControlCharacter = [...platform].some(
947
+ (char) => char === "/" || char === "\\" || char.charCodeAt(0) < 32 || char.charCodeAt(0) === 127
948
+ );
949
+ return platform.length > 0 && platform.length <= 64 && !hasPathOrControlCharacter ? platform : "unknown";
950
+ }
951
+ function normalizeDuration(value) {
952
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return null;
953
+ return Math.min(Math.round(value), 24 * 60 * 60 * 1e3);
954
+ }
955
+ function normalizeEvent(eventName, props = {}) {
956
+ if (!EVENT_NAMES.has(eventName)) return null;
957
+ const name = eventName;
958
+ const properties = {};
959
+ if (name.startsWith("chat_import_")) {
960
+ properties.chat_platform = normalizeAnalyticsImportPlatform(props.chat_platform);
961
+ }
962
+ if (name === "chat_import_completed" || name === "ai_request_completed") {
963
+ const duration = normalizeDuration(props.duration_ms);
964
+ if (duration !== null) properties.duration_ms = duration;
965
+ }
966
+ if (name === "feature_used") {
967
+ if (typeof props.feature_id !== "string" || !FEATURE_IDS.has(props.feature_id)) return null;
968
+ properties.feature_id = props.feature_id;
969
+ }
970
+ if (name === "ai_request_completed") {
971
+ if (typeof props.success !== "boolean") return null;
972
+ properties.success = props.success;
973
+ }
974
+ if (name === "chat_import_failed" || name === "ai_request_completed" && props.success === false) {
975
+ const reason = typeof props.failure_reason === "string" ? props.failure_reason : "unknown";
976
+ properties.failure_reason = FAILURE_REASONS.has(reason) ? reason : "unknown";
977
+ }
978
+ return { name, properties };
979
+ }
980
+ function eventPath(event) {
981
+ if (event.name === "incremental_import_used") return "/import/incremental";
982
+ if (event.name.startsWith("chat_import_")) return "/import";
983
+ if (event.name.startsWith("ai_")) return "/ai";
984
+ if (event.name === "feature_used") return `/features/${event.properties.feature_id}`;
985
+ return "/app";
986
+ }
883
987
  var AnalyticsService = class {
884
988
  dataPath;
885
- endpoint;
886
- appKey;
887
- appVersion;
888
- sessionId;
889
- constructor(systemDir, appKey, appVersion) {
989
+ options;
990
+ sessionId = randomUUID2();
991
+ appLocale = "unknown";
992
+ startupAttempted = false;
993
+ // Product constraint: only one ChatLab runtime is expected to use a system directory at a time.
994
+ // Daily-active deduplication is intentionally process-local unless concurrent runtimes become supported.
995
+ dailyActivePromise = null;
996
+ constructor(systemDir, options) {
890
997
  this.dataPath = path4.join(systemDir, "analytics.json");
891
- this.appKey = appKey;
892
- this.appVersion = appVersion;
893
- this.sessionId = `${Math.floor(Date.now() / 1e3)}${Math.floor(Math.random() * 1e8).toString().padStart(8, "0")}`;
894
- const parts = appKey.split("-");
895
- const base = parts.length === 3 ? REGIONS[parts[1]] : void 0;
896
- this.endpoint = base ? `${base}/api/v0/event` : null;
998
+ this.options = {
999
+ ...options,
1000
+ umami: options.umami ?? getUmamiConfigFromEnv()
1001
+ };
897
1002
  }
898
1003
  load() {
899
1004
  try {
900
- if (fs4.existsSync(this.dataPath)) {
901
- return { ...DEFAULT_DATA, ...JSON.parse(fs4.readFileSync(this.dataPath, "utf-8")) };
902
- }
903
- } catch (_e) {
1005
+ const stored = readJsonFile(this.dataPath);
1006
+ if (stored) return { ...DEFAULT_DATA, ...stored };
1007
+ } catch (error) {
1008
+ appLogger.error("analytics", "Failed to read analytics settings; using defaults", error);
904
1009
  }
905
1010
  return { ...DEFAULT_DATA };
906
1011
  }
907
- save(data) {
1012
+ updateData(update, fallback) {
908
1013
  try {
909
- fs4.writeFileSync(this.dataPath, JSON.stringify(data, null, 2), "utf-8");
910
- } catch (e) {
911
- console.error("[Analytics] Failed to save:", e);
1014
+ return withFileLock(this.dataPath, () => {
1015
+ const data = this.load();
1016
+ const result = update(data);
1017
+ writeJsonFileAtomically(this.dataPath, data, 384);
1018
+ return result;
1019
+ });
1020
+ } catch (error) {
1021
+ appLogger.error("analytics", "Failed to update analytics settings", error);
1022
+ return fallback;
912
1023
  }
913
1024
  }
914
- getEnabled() {
915
- return this.load().enabled;
1025
+ getOrCreateAnonymousId() {
1026
+ const fallback = randomUUID2();
1027
+ return this.updateData((data) => {
1028
+ data.anonymousId ??= randomUUID2();
1029
+ return data.anonymousId;
1030
+ }, fallback);
916
1031
  }
917
- setEnabled(enabled) {
918
- const data = this.load();
919
- data.enabled = enabled;
920
- this.save(data);
1032
+ isAiModelConfigured() {
1033
+ try {
1034
+ return this.options.getAiModelConfigured?.() === true;
1035
+ } catch (error) {
1036
+ appLogger.error("analytics", "Failed to resolve AI configuration state", error);
1037
+ return false;
1038
+ }
921
1039
  }
922
- async track(eventName, props) {
923
- if (!this.endpoint) return false;
924
- if (!this.getEnabled()) return false;
1040
+ buildEnvelope(event) {
1041
+ return {
1042
+ ...event,
1043
+ anonymousId: this.getOrCreateAnonymousId(),
1044
+ sessionId: this.sessionId,
1045
+ appVersion: this.options.appVersion,
1046
+ appType: this.options.appType,
1047
+ os: normalizeOs(),
1048
+ appLocale: this.appLocale,
1049
+ aiModelConfigured: this.isAiModelConfigured()
1050
+ };
1051
+ }
1052
+ commonProperties(envelope) {
1053
+ return {
1054
+ session_id: envelope.sessionId,
1055
+ app_version: envelope.appVersion,
1056
+ app_type: envelope.appType,
1057
+ os: envelope.os,
1058
+ app_locale: envelope.appLocale,
1059
+ ai_model_configured: envelope.aiModelConfigured,
1060
+ schema_version: 1
1061
+ };
1062
+ }
1063
+ async sendToUmami(envelope) {
1064
+ const umami = this.options.umami;
1065
+ if (!umami) return false;
925
1066
  try {
926
- const resp = await fetch(this.endpoint, {
1067
+ const response = await fetch(umami.endpoint, {
927
1068
  method: "POST",
928
- headers: { "Content-Type": "application/json", "App-Key": this.appKey },
1069
+ headers: {
1070
+ "Content-Type": "application/json",
1071
+ "User-Agent": `ChatLab/${envelope.appVersion} (${envelope.os}; ${envelope.appType})`
1072
+ },
929
1073
  body: JSON.stringify({
930
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
931
- sessionId: this.sessionId,
932
- eventName,
933
- systemProps: {
934
- isDebug: false,
935
- locale: "",
936
- osName: process.platform,
937
- osVersion: "",
938
- engineName: "Node.js",
939
- engineVersion: process.versions.node,
940
- appVersion: this.appVersion,
941
- sdkVersion: "chatlab@1"
942
- },
943
- props
944
- })
1074
+ type: "event",
1075
+ payload: {
1076
+ website: umami.websiteId,
1077
+ hostname: "chatlab",
1078
+ url: eventPath(envelope),
1079
+ language: envelope.appLocale,
1080
+ name: envelope.name,
1081
+ id: envelope.anonymousId,
1082
+ data: {
1083
+ ...this.commonProperties(envelope),
1084
+ ...envelope.properties
1085
+ }
1086
+ }
1087
+ }),
1088
+ signal: AbortSignal.timeout(5e3)
945
1089
  });
946
- return resp.ok;
947
- } catch (e) {
948
- console.error(`[Analytics] Failed to track ${eventName}:`, e);
1090
+ if (!response.ok) {
1091
+ appLogger.warn("analytics", "Umami rejected analytics event", {
1092
+ eventName: envelope.name,
1093
+ status: response.status
1094
+ });
1095
+ }
1096
+ return response.ok;
1097
+ } catch (error) {
1098
+ appLogger.error("analytics", "Failed to send analytics event to Umami", error);
949
1099
  return false;
950
1100
  }
951
1101
  }
952
- async trackDailyActive(props) {
953
- if (!this.endpoint) return;
1102
+ getEnabled() {
1103
+ return this.load().enabled;
1104
+ }
1105
+ setEnabled(enabled) {
1106
+ this.updateData((data) => {
1107
+ data.enabled = enabled;
1108
+ }, void 0);
1109
+ }
1110
+ setAppLocale(locale) {
1111
+ this.appLocale = normalizeLocale(locale);
1112
+ }
1113
+ async track(eventName, props) {
1114
+ if (!this.getEnabled()) return false;
1115
+ if (props?.app_locale !== void 0) this.setAppLocale(String(props.app_locale));
1116
+ const event = normalizeEvent(eventName, props);
1117
+ if (!event) return false;
1118
+ if (!this.options.umami) return false;
1119
+ const envelope = this.buildEnvelope(event);
1120
+ const delivered = await this.sendToUmami(envelope);
1121
+ appLogger.debug("analytics", delivered ? "Analytics event delivered" : "Analytics event was not delivered", {
1122
+ eventName: envelope.name
1123
+ });
1124
+ return delivered;
1125
+ }
1126
+ trackDailyActive(props) {
1127
+ if (this.dailyActivePromise) {
1128
+ const locale = props?.app_locale ?? props?.locale;
1129
+ if (locale !== void 0) this.setAppLocale(String(locale));
1130
+ return this.dailyActivePromise;
1131
+ }
1132
+ this.dailyActivePromise = this.trackDailyActiveInternal(props).finally(() => {
1133
+ this.dailyActivePromise = null;
1134
+ });
1135
+ return this.dailyActivePromise;
1136
+ }
1137
+ async trackDailyActiveInternal(props) {
1138
+ const locale = props?.app_locale ?? props?.locale;
1139
+ if (locale !== void 0) this.setAppLocale(String(locale));
954
1140
  const data = this.load();
955
1141
  if (!data.enabled) return;
1142
+ if (!this.startupAttempted) {
1143
+ this.startupAttempted = true;
1144
+ await this.track("app_started");
1145
+ }
956
1146
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
957
1147
  const isNew = data.firstReportDate === null;
958
- if (isNew) data.firstReportDate = today;
959
- if (data.lastReportDate === today) {
960
- if (isNew) this.save(data);
961
- return;
962
- }
963
- const tracked = await this.track(isNew ? "app_active_new" : "app_active", props);
1148
+ if (data.lastReportDate === today) return;
1149
+ const tracked = await this.track(isNew ? "app_active_new" : "app_active");
964
1150
  if (!tracked) return;
965
- data.lastReportDate = today;
966
- this.save(data);
1151
+ this.updateData((persisted) => {
1152
+ persisted.firstReportDate ??= today;
1153
+ persisted.lastReportDate = today;
1154
+ }, void 0);
967
1155
  }
968
1156
  };
969
1157
 
1158
+ // ../../packages/node-runtime/src/services/demo-import.ts
1159
+ import * as fs4 from "fs";
1160
+ import * as path5 from "path";
1161
+ var DEMO_BASE_URL = "https://chatlab.fun/assets/demo";
1162
+ var DEMO_FILES = ["demo-group.json", "demo-private-B-wukong.json"];
1163
+ async function importDemoSessions(options) {
1164
+ const total = DEMO_FILES.length;
1165
+ const fetchImpl = options.fetchImpl ?? fetch;
1166
+ const sessionIds = [];
1167
+ let tempDir;
1168
+ try {
1169
+ const createdTempDir = createChatLabTempDir("imports", options.tempPrefix);
1170
+ tempDir = createdTempDir;
1171
+ appLogger.info("demo-import", "Demo import started", {
1172
+ locale: options.locale,
1173
+ sessionCount: total,
1174
+ targetTimeZone: options.targetTimeZone ?? "runtime-local"
1175
+ });
1176
+ const downloaded = [];
1177
+ for (let index = 0; index < total; index++) {
1178
+ const filename = DEMO_FILES[index];
1179
+ options.onProgress?.({ stage: "downloading", current: index + 1, total });
1180
+ const response = await fetchImpl.call(globalThis, `${DEMO_BASE_URL}/${options.locale}/${filename}`, {
1181
+ signal: AbortSignal.timeout(6e4)
1182
+ });
1183
+ if (!response.ok) throw new Error(`Download demo failed (${filename}): HTTP ${response.status}`);
1184
+ const content = Buffer.from(await response.arrayBuffer());
1185
+ if (content.byteLength < 100) {
1186
+ throw new Error(`Downloaded demo file is too small (${filename})`);
1187
+ }
1188
+ downloaded.push(content.toString("utf8"));
1189
+ }
1190
+ const rebased = rebaseChatLabDemoDocuments(downloaded, options.now?.() ?? /* @__PURE__ */ new Date(), options.targetTimeZone);
1191
+ const localPaths = rebased.documents.map((document, index) => {
1192
+ const localPath = path5.join(createdTempDir, DEMO_FILES[index]);
1193
+ fs4.writeFileSync(localPath, document, "utf8");
1194
+ return localPath;
1195
+ });
1196
+ appLogger.info("demo-import", "Demo timeline prepared", {
1197
+ sessionCount: total,
1198
+ offsetSeconds: rebased.offsetSeconds,
1199
+ latestTimestamp: rebased.latestTimestamp
1200
+ });
1201
+ for (let index = 0; index < localPaths.length; index++) {
1202
+ options.onProgress?.({ stage: "importing", current: index + 1, total });
1203
+ const result = await options.importFile(localPaths[index]);
1204
+ if (!result.success || !result.sessionId) {
1205
+ throw new Error(result.error || `Failed to import demo: ${DEMO_FILES[index]}`);
1206
+ }
1207
+ sessionIds.push(result.sessionId);
1208
+ }
1209
+ const [groupSessionId, ...privateSessionIds] = sessionIds;
1210
+ options.onProgress?.({ stage: "done", current: total, total });
1211
+ appLogger.info("demo-import", "Demo import completed", { sessionCount: sessionIds.length });
1212
+ return { success: true, groupSessionId, privateSessionIds };
1213
+ } catch (error) {
1214
+ const rollbackFailures = [];
1215
+ for (const sessionId of sessionIds.toReversed()) {
1216
+ try {
1217
+ await options.deleteSession(sessionId);
1218
+ } catch (rollbackError) {
1219
+ rollbackFailures.push(rollbackError);
1220
+ appLogger.error("demo-import", `Failed to roll back Demo session ${sessionId}`, rollbackError);
1221
+ }
1222
+ }
1223
+ if (sessionIds.length > 0 && rollbackFailures.length === 0) {
1224
+ appLogger.info("demo-import", "Rolled back partially imported Demo sessions", {
1225
+ sessionCount: sessionIds.length
1226
+ });
1227
+ }
1228
+ const originalMessage = error instanceof Error ? error.message : String(error);
1229
+ const message = rollbackFailures.length === 0 ? originalMessage : `${originalMessage} (${rollbackFailures.length} Demo session(s) could not be rolled back.)`;
1230
+ options.onProgress?.({ stage: "error", current: 0, total, message });
1231
+ appLogger.error("demo-import", "Demo import failed", error);
1232
+ return { success: false, error: message };
1233
+ } finally {
1234
+ if (tempDir) {
1235
+ try {
1236
+ removeChatLabTempDir(tempDir, "imports");
1237
+ } catch (error) {
1238
+ appLogger.warn("demo-import", "Failed to clean up Demo temporary directory", error);
1239
+ }
1240
+ }
1241
+ }
1242
+ }
1243
+
970
1244
  // ../../packages/node-runtime/src/semantic-index/index.ts
971
1245
  var semantic_index_exports = {};
972
1246
  __export(semantic_index_exports, {
@@ -977,6 +1251,8 @@ __export(semantic_index_exports, {
977
1251
  DEFAULT_SEMANTIC_INDEX_MODEL_DOWNLOAD_SOURCE: () => DEFAULT_SEMANTIC_INDEX_MODEL_DOWNLOAD_SOURCE,
978
1252
  EMBEDDING_INDEX_SCHEMA: () => EMBEDDING_INDEX_SCHEMA,
979
1253
  EmbeddingIndexStore: () => EmbeddingIndexStore,
1254
+ LOCAL_EMBEDDING_RUNTIME_PACKAGE: () => LOCAL_EMBEDDING_RUNTIME_PACKAGE,
1255
+ LOCAL_EMBEDDING_RUNTIME_VERSION: () => LOCAL_EMBEDDING_RUNTIME_VERSION,
980
1256
  SEARCH_MAX_RESULTS_DEFAULT: () => SEARCH_MAX_RESULTS_DEFAULT,
981
1257
  SEARCH_MAX_RESULTS_MAX: () => SEARCH_MAX_RESULTS_MAX,
982
1258
  SEARCH_MAX_RESULTS_MIN: () => SEARCH_MAX_RESULTS_MIN,
@@ -1002,6 +1278,7 @@ __export(semantic_index_exports, {
1002
1278
  createChatDbMessageRangeReader: () => createChatDbMessageRangeReader,
1003
1279
  createChatDbMessageSource: () => createChatDbMessageSource,
1004
1280
  createEmbedder: () => createEmbedder,
1281
+ createLocalEmbeddingRuntimeManager: () => createLocalEmbeddingRuntimeManager,
1005
1282
  createSemanticIndexService: () => createSemanticIndexService,
1006
1283
  createSemanticIndexWorkerClient: () => createSemanticIndexWorkerClient,
1007
1284
  createSemanticIndexWorkerRuntimeClient: () => createSemanticIndexWorkerRuntimeClient,
@@ -1027,7 +1304,7 @@ __export(semantic_index_exports, {
1027
1304
  });
1028
1305
 
1029
1306
  // ../../packages/node-runtime/src/semantic-index/worker-client.ts
1030
- import path5 from "path";
1307
+ import path6 from "path";
1031
1308
 
1032
1309
  // ../../packages/node-runtime/src/semantic-index/worker-thread-transport.ts
1033
1310
  import { Worker } from "worker_threads";
@@ -1117,6 +1394,7 @@ function createSemanticIndexWorkerThreadTransport(options) {
1117
1394
 
1118
1395
  // ../../packages/node-runtime/src/semantic-index/worker-client.ts
1119
1396
  var DEFAULT_IDLE_TIMEOUT_MS = 10 * 60 * 1e3;
1397
+ var MODEL_PRELOAD_STATUS_POLL_MS = 2e3;
1120
1398
  var defaultTimers = {
1121
1399
  setTimeout: (callback, ms) => setTimeout(callback, ms),
1122
1400
  clearTimeout: (timer) => clearTimeout(timer)
@@ -1125,8 +1403,10 @@ var SemanticIndexWorkerClient = class {
1125
1403
  transport = null;
1126
1404
  pendingRequests = 0;
1127
1405
  idleTimer = null;
1406
+ modelPreloadPollTimer = null;
1128
1407
  activeBuildSessionIds = /* @__PURE__ */ new Set();
1129
1408
  hasUnknownActiveBuild = false;
1409
+ hasActiveModelPreload = false;
1130
1410
  activeModelDownloadProxyUrl;
1131
1411
  configStore;
1132
1412
  transportFactory;
@@ -1152,7 +1432,10 @@ var SemanticIndexWorkerClient = class {
1152
1432
  apiKey: options?.apiKey,
1153
1433
  writeAuthProfile: this.writeAuthProfile
1154
1434
  });
1155
- if (!saved.enabled) this.clearActiveBuildTracking();
1435
+ if (!saved.enabled) {
1436
+ this.clearActiveBuildTracking();
1437
+ }
1438
+ if (!saved.enabled || saved.mode !== "local") this.clearModelPreloadTracking();
1156
1439
  const needsWorker = saved.enabled && saved.mode === "local" && this.configStore.isConfigured();
1157
1440
  if (!this.transport && !needsWorker) return saved;
1158
1441
  if (needsWorker) await this.closeTransportForLocalModelProxyChangeIfNeeded();
@@ -1165,8 +1448,10 @@ var SemanticIndexWorkerClient = class {
1165
1448
  return resolveSemanticIndexApiKeySet(this.configStore.get(), this.resolveApiKey);
1166
1449
  }
1167
1450
  async getModelStatus() {
1168
- if (!this.transport) return "idle";
1169
- return this.call("getModelStatus", []);
1451
+ if (!this.transport && !this.shouldStartLocalModelWorker()) return "idle";
1452
+ const status = await this.call("getModelStatus", [], { scheduleIdle: false });
1453
+ this.updateModelPreloadStatus(status);
1454
+ return status;
1170
1455
  }
1171
1456
  enable(sessionId) {
1172
1457
  return this.call("enable", [sessionId]);
@@ -1304,6 +1589,10 @@ var SemanticIndexWorkerClient = class {
1304
1589
  if (isKeylessSemanticIndexApiBaseUrl(config.api?.baseUrl)) return true;
1305
1590
  return resolveSemanticIndexApiKeySet(config, this.resolveApiKey);
1306
1591
  }
1592
+ shouldStartLocalModelWorker() {
1593
+ const config = this.configStore.get();
1594
+ return config.enabled && config.mode === "local" && this.configStore.isConfigured();
1595
+ }
1307
1596
  updateActiveBuildFromCompleteSnapshot(statuses) {
1308
1597
  this.hasUnknownActiveBuild = false;
1309
1598
  this.activeBuildSessionIds = new Set(
@@ -1325,8 +1614,43 @@ var SemanticIndexWorkerClient = class {
1325
1614
  this.hasUnknownActiveBuild = false;
1326
1615
  this.activeBuildSessionIds.clear();
1327
1616
  }
1617
+ updateModelPreloadStatus(status) {
1618
+ this.hasActiveModelPreload = status === "installing-runtime" || status === "downloading-model";
1619
+ if (this.hasActiveModelPreload) this.scheduleModelPreloadPoll();
1620
+ else {
1621
+ this.clearModelPreloadPoll();
1622
+ this.scheduleIdleCloseIfNeeded();
1623
+ }
1624
+ }
1625
+ scheduleModelPreloadPoll() {
1626
+ this.clearModelPreloadPoll();
1627
+ if (!this.transport || !this.hasActiveModelPreload) return;
1628
+ this.modelPreloadPollTimer = this.timers.setTimeout(() => {
1629
+ this.modelPreloadPollTimer = null;
1630
+ void this.pollModelPreloadStatus();
1631
+ }, MODEL_PRELOAD_STATUS_POLL_MS);
1632
+ }
1633
+ async pollModelPreloadStatus() {
1634
+ if (!this.transport || !this.hasActiveModelPreload) return;
1635
+ try {
1636
+ await this.getModelStatus();
1637
+ } catch (error) {
1638
+ appLogger.error("semantic-index", "Background model preload status poll failed; closing worker", error);
1639
+ await this.closeFailedProbeTransport();
1640
+ }
1641
+ }
1642
+ clearModelPreloadPoll() {
1643
+ if (this.modelPreloadPollTimer) {
1644
+ this.timers.clearTimeout(this.modelPreloadPollTimer);
1645
+ this.modelPreloadPollTimer = null;
1646
+ }
1647
+ }
1648
+ clearModelPreloadTracking() {
1649
+ this.hasActiveModelPreload = false;
1650
+ this.clearModelPreloadPoll();
1651
+ }
1328
1652
  scheduleIdleCloseIfNeeded() {
1329
- if (!this.transport || this.pendingRequests > 0 || this.hasUnknownActiveBuild || this.activeBuildSessionIds.size > 0)
1653
+ if (!this.transport || this.pendingRequests > 0 || this.hasUnknownActiveBuild || this.hasActiveModelPreload || this.activeBuildSessionIds.size > 0)
1330
1654
  return;
1331
1655
  this.clearIdleTimer();
1332
1656
  this.idleTimer = this.timers.setTimeout(() => {
@@ -1345,6 +1669,7 @@ var SemanticIndexWorkerClient = class {
1345
1669
  const transport = this.transport;
1346
1670
  this.transport = null;
1347
1671
  this.activeModelDownloadProxyUrl = void 0;
1672
+ this.clearModelPreloadTracking();
1348
1673
  this.clearActiveBuildTracking();
1349
1674
  if (transport) await transport.close();
1350
1675
  }
@@ -1361,7 +1686,7 @@ function createSemanticIndexWorkerClient(options) {
1361
1686
  }
1362
1687
  function createSemanticIndexWorkerRuntimeClient(options) {
1363
1688
  const configStore = new SemanticIndexConfigStore(
1364
- path5.join(options.pathProvider.getAiDataDir(), SEMANTIC_INDEX_CONFIG_FILE)
1689
+ path6.join(options.pathProvider.getAiDataDir(), SEMANTIC_INDEX_CONFIG_FILE)
1365
1690
  );
1366
1691
  return createSemanticIndexWorkerClient({
1367
1692
  configStore,
@@ -1376,7 +1701,8 @@ function createSemanticIndexWorkerRuntimeClient(options) {
1376
1701
  runtime: options.runtime,
1377
1702
  nativeBinding: options.nativeBinding,
1378
1703
  sqliteVecLoadablePath: options.sqliteVecLoadablePath,
1379
- modelDownloadProxyUrl
1704
+ modelDownloadProxyUrl,
1705
+ localEmbeddingRuntime: options.localEmbeddingRuntime
1380
1706
  }
1381
1707
  })
1382
1708
  });
@@ -1421,7 +1747,8 @@ export {
1421
1747
  buildMergedOutput,
1422
1748
  serializeChatLabToJsonl,
1423
1749
  AnalyticsService,
1750
+ importDemoSessions,
1424
1751
  createSemanticIndexWorkerRuntimeClient,
1425
1752
  semantic_index_exports
1426
1753
  };
1427
- //# sourceMappingURL=chunk-S5NCEESV.mjs.map
1754
+ //# sourceMappingURL=chunk-2XCNTG4O.mjs.map