@remnic/core 9.3.629 → 9.3.631

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 (221) hide show
  1. package/dist/access-cli.js +15 -13
  2. package/dist/access-cli.js.map +1 -1
  3. package/dist/access-http.d.ts +5 -4
  4. package/dist/access-http.js +7 -6
  5. package/dist/access-mcp.d.ts +5 -4
  6. package/dist/access-mcp.js +6 -5
  7. package/dist/{access-service-BdThkfIE.d.ts → access-service-C9_EpVHd.d.ts} +2 -2
  8. package/dist/access-service.d.ts +5 -4
  9. package/dist/access-service.js +5 -4
  10. package/dist/action-confidence.d.ts +1 -1
  11. package/dist/active-memory-bridge.d.ts +1 -1
  12. package/dist/active-recall.d.ts +1 -1
  13. package/dist/active-recall.js +1 -1
  14. package/dist/auto-sync-RFADEHIQ.js +75 -0
  15. package/dist/auto-sync-RFADEHIQ.js.map +1 -0
  16. package/dist/behavior-learner.d.ts +1 -1
  17. package/dist/behavior-signals.d.ts +1 -1
  18. package/dist/bootstrap.d.ts +4 -3
  19. package/dist/briefing.d.ts +1 -1
  20. package/dist/briefing.js +3 -2
  21. package/dist/buffer-surprise-report.d.ts +1 -1
  22. package/dist/buffer.d.ts +1 -1
  23. package/dist/calibration.d.ts +1 -1
  24. package/dist/causal-behavior.d.ts +1 -1
  25. package/dist/causal-consolidation.d.ts +1 -1
  26. package/dist/causal-consolidation.js +4 -3
  27. package/dist/causal-consolidation.js.map +1 -1
  28. package/dist/{chunk-532VCWYW.js → chunk-242XFZ36.js} +2 -2
  29. package/dist/{chunk-XXO5TI3B.js → chunk-32U3N7H5.js} +3 -3
  30. package/dist/{chunk-KB4MFBF5.js → chunk-3RDYU3JS.js} +3 -3
  31. package/dist/{chunk-57QXN2CS.js → chunk-4S3N6HFG.js} +2 -2
  32. package/dist/{chunk-OLNNOHBC.js → chunk-5PT5I6JQ.js} +20 -14
  33. package/dist/{chunk-OLNNOHBC.js.map → chunk-5PT5I6JQ.js.map} +1 -1
  34. package/dist/{chunk-GE7Q7KXP.js → chunk-7A2QKUUA.js} +2 -2
  35. package/dist/{chunk-KKTXCFD7.js → chunk-7H5WCPBS.js} +95 -11
  36. package/dist/{chunk-KKTXCFD7.js.map → chunk-7H5WCPBS.js.map} +1 -1
  37. package/dist/{chunk-3MNBW7R7.js → chunk-C4KKM62E.js} +2 -2
  38. package/dist/{chunk-NKCW223V.js → chunk-CMN5AWAZ.js} +2 -2
  39. package/dist/{chunk-JXHMAQYT.js → chunk-DOBJH4I6.js} +4 -4
  40. package/dist/{chunk-TZDSNIRO.js → chunk-IFVFQRZ2.js} +5 -5
  41. package/dist/{chunk-LQYTQCXM.js → chunk-JCLECECB.js} +2 -2
  42. package/dist/chunk-KVDUDYEN.js +1164 -0
  43. package/dist/chunk-KVDUDYEN.js.map +1 -0
  44. package/dist/{chunk-QDV6VAD4.js → chunk-LEG7XWS2.js} +2 -2
  45. package/dist/chunk-M7XQSUBB.js +280 -0
  46. package/dist/chunk-M7XQSUBB.js.map +1 -0
  47. package/dist/{chunk-N5RGXWLQ.js → chunk-PUEAEQSN.js} +2 -2
  48. package/dist/{chunk-UGHUNQ74.js → chunk-QYGIQ5NM.js} +212 -417
  49. package/dist/chunk-QYGIQ5NM.js.map +1 -0
  50. package/dist/{chunk-JKCDQBDW.js → chunk-UXFOGILU.js} +2 -2
  51. package/dist/{chunk-MVQN73GT.js → chunk-VTR3MNYF.js} +2 -2
  52. package/dist/{chunk-KVFYTRMV.js → chunk-W25I7G6U.js} +2 -2
  53. package/dist/{chunk-3GLCUPXP.js → chunk-WLZBVYC6.js} +192 -889
  54. package/dist/chunk-WLZBVYC6.js.map +1 -0
  55. package/dist/{chunk-3R2UZV3U.js → chunk-X7EJF46S.js} +2 -2
  56. package/dist/{chunk-54KDA6UK.js → chunk-XG4NAWAV.js} +3 -3
  57. package/dist/{chunk-P2D2MM47.js → chunk-YROCXMCK.js} +2 -2
  58. package/dist/{cli-DAsHklrf.d.ts → cli-CuVEQWKr.d.ts} +3 -3
  59. package/dist/cli.d.ts +6 -5
  60. package/dist/cli.js +18 -17
  61. package/dist/compounding/engine.d.ts +1 -1
  62. package/dist/compounding/engine.js +3 -2
  63. package/dist/compounding/preference-consolidator.d.ts +1 -1
  64. package/dist/compression-optimizer.d.ts +1 -1
  65. package/dist/config.d.ts +1 -1
  66. package/dist/config.js +1 -1
  67. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  68. package/dist/connectors/codex-materialize-runner.js +3 -2
  69. package/dist/connectors/codex-materialize.d.ts +1 -1
  70. package/dist/connectors/index.d.ts +1 -1
  71. package/dist/connectors/index.js +3 -2
  72. package/dist/consolidation-provenance-check.d.ts +1 -1
  73. package/dist/consolidation-undo.d.ts +1 -1
  74. package/dist/contradiction/index.d.ts +1 -1
  75. package/dist/contradiction/index.js +4 -4
  76. package/dist/conversation-index/backend.d.ts +1 -1
  77. package/dist/conversation-index/chunker.d.ts +1 -1
  78. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  79. package/dist/conversation-index/indexer.d.ts +1 -1
  80. package/dist/conversation-index/search.d.ts +1 -1
  81. package/dist/day-summary.d.ts +1 -1
  82. package/dist/delinearize.d.ts +1 -1
  83. package/dist/direct-answer-wiring.d.ts +1 -1
  84. package/dist/direct-answer.d.ts +1 -1
  85. package/dist/embedding-fallback.d.ts +1 -1
  86. package/dist/enrichment/index.d.ts +1 -1
  87. package/dist/entity-retrieval.d.ts +1 -1
  88. package/dist/entity-retrieval.js +3 -2
  89. package/dist/entity-schema.d.ts +1 -1
  90. package/dist/explicit-capture.d.ts +4 -3
  91. package/dist/extraction-judge-telemetry.d.ts +1 -1
  92. package/dist/extraction-judge-training.d.ts +1 -1
  93. package/dist/extraction-judge.d.ts +1 -1
  94. package/dist/extraction.d.ts +1 -1
  95. package/dist/fallback-llm.d.ts +1 -1
  96. package/dist/identity-continuity.d.ts +1 -1
  97. package/dist/importance.d.ts +1 -1
  98. package/dist/index.d.ts +8 -8
  99. package/dist/index.js +49 -45
  100. package/dist/index.js.map +1 -1
  101. package/dist/intent.d.ts +1 -1
  102. package/dist/lcm/engine.d.ts +1 -1
  103. package/dist/lcm/index.d.ts +1 -1
  104. package/dist/lcm/tools.d.ts +1 -1
  105. package/dist/lifecycle.d.ts +1 -1
  106. package/dist/live-connectors-runner.d.ts +1 -1
  107. package/dist/local-llm.d.ts +1 -1
  108. package/dist/maintenance/memory-governance.d.ts +1 -1
  109. package/dist/maintenance/memory-governance.js +3 -2
  110. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -2
  111. package/dist/maintenance/rebuild-memory-projection.js +4 -3
  112. package/dist/mcp-memory-inspector-app.d.ts +5 -4
  113. package/dist/memory-action-policy.d.ts +1 -1
  114. package/dist/memory-cache.d.ts +1 -1
  115. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  116. package/dist/memory-projection-store.d.ts +1 -1
  117. package/dist/memory-provenance.d.ts +1 -1
  118. package/dist/memory-worth-outcomes.d.ts +1 -1
  119. package/dist/models-json.d.ts +1 -1
  120. package/dist/namespaces/migrate.d.ts +1 -1
  121. package/dist/namespaces/migrate.js +4 -3
  122. package/dist/namespaces/principal.d.ts +1 -1
  123. package/dist/namespaces/search.d.ts +1 -1
  124. package/dist/namespaces/storage.d.ts +1 -1
  125. package/dist/namespaces/storage.js +3 -2
  126. package/dist/native-knowledge.d.ts +1 -1
  127. package/dist/operator-toolkit.d.ts +1 -1
  128. package/dist/operator-toolkit.js +7 -6
  129. package/dist/{orchestrator-BexeSJ2j.d.ts → orchestrator-CoqytbK_.d.ts} +102 -10
  130. package/dist/orchestrator.d.ts +4 -3
  131. package/dist/orchestrator.js +12 -10
  132. package/dist/patterns-cli.d.ts +1 -1
  133. package/dist/policy-runtime.d.ts +1 -1
  134. package/dist/qmd-recall-cache.d.ts +1 -1
  135. package/dist/qmd.d.ts +1 -1
  136. package/dist/recall-disclosure-escalation.d.ts +1 -1
  137. package/dist/recall-explain-renderer.d.ts +1 -1
  138. package/dist/recall-planner-llm.d.ts +1 -1
  139. package/dist/recall-state.d.ts +1 -1
  140. package/dist/recall-tag-filter.d.ts +1 -1
  141. package/dist/recall-xray-cli.d.ts +1 -1
  142. package/dist/recall-xray-renderer.d.ts +1 -1
  143. package/dist/recall-xray.d.ts +1 -1
  144. package/dist/resolve-auth-token.d.ts +1 -1
  145. package/dist/resume-bundles.js +2 -2
  146. package/dist/retrieval-agents.d.ts +1 -1
  147. package/dist/retrieval-tiers.d.ts +1 -1
  148. package/dist/routing/engine.d.ts +1 -1
  149. package/dist/routing/store.d.ts +1 -1
  150. package/dist/search/embed-helper.d.ts +1 -1
  151. package/dist/search/factory.d.ts +1 -1
  152. package/dist/search/index.d.ts +1 -1
  153. package/dist/search/lancedb-backend.d.ts +1 -1
  154. package/dist/search/meilisearch-backend.d.ts +1 -1
  155. package/dist/search/noop-backend.d.ts +1 -1
  156. package/dist/search/orama-backend.d.ts +1 -1
  157. package/dist/search/port.d.ts +1 -1
  158. package/dist/search/remote-backend.d.ts +1 -1
  159. package/dist/{semantic-consolidation-PwkzNfdK.d.ts → semantic-consolidation-BPs6BURk.d.ts} +1 -1
  160. package/dist/semantic-consolidation.d.ts +2 -2
  161. package/dist/semantic-consolidation.js +4 -3
  162. package/dist/semantic-rule-promotion.js +3 -2
  163. package/dist/semantic-rule-verifier.d.ts +1 -1
  164. package/dist/semantic-rule-verifier.js +3 -2
  165. package/dist/session-observer-bands.d.ts +1 -1
  166. package/dist/session-observer-state.d.ts +1 -1
  167. package/dist/shared-context/manager.d.ts +1 -1
  168. package/dist/signal.d.ts +1 -1
  169. package/dist/storage.d.ts +38 -2
  170. package/dist/storage.js +6 -3
  171. package/dist/summarizer.d.ts +1 -1
  172. package/dist/summary-snapshot.d.ts +1 -1
  173. package/dist/temporal-supersession.d.ts +1 -1
  174. package/dist/temporal-validity.d.ts +1 -1
  175. package/dist/threading.d.ts +1 -1
  176. package/dist/tier-migration.d.ts +1 -1
  177. package/dist/tier-routing.d.ts +1 -1
  178. package/dist/topics.d.ts +1 -1
  179. package/dist/transcript.d.ts +1 -1
  180. package/dist/{types-BCF2wqKa.d.ts → types-CpMPD8xl.d.ts} +59 -11
  181. package/dist/types.d.ts +1 -1
  182. package/dist/utility-runtime.d.ts +1 -1
  183. package/dist/verified-recall.js +3 -2
  184. package/package.json +1 -1
  185. package/src/orchestrator.ts +74 -0
  186. package/src/storage.ts +100 -0
  187. package/src/wearables/auto-sync.test.ts +181 -0
  188. package/src/wearables/auto-sync.ts +129 -0
  189. package/src/wearables/cli.ts +6 -0
  190. package/src/wearables/config.test.ts +90 -11
  191. package/src/wearables/config.ts +113 -11
  192. package/src/wearables/memory-gen.test.ts +416 -1
  193. package/src/wearables/memory-gen.ts +381 -23
  194. package/src/wearables/pipeline.test.ts +396 -5
  195. package/src/wearables/pipeline.ts +174 -22
  196. package/src/wearables/service.test.ts +172 -0
  197. package/src/wearables/service.ts +84 -3
  198. package/src/wearables/storage-io.test.ts +81 -0
  199. package/src/wearables/trust.test.ts +123 -0
  200. package/src/wearables/trust.ts +168 -0
  201. package/src/wearables/types.ts +57 -9
  202. package/dist/chunk-3GLCUPXP.js.map +0 -1
  203. package/dist/chunk-UGHUNQ74.js.map +0 -1
  204. /package/dist/{chunk-532VCWYW.js.map → chunk-242XFZ36.js.map} +0 -0
  205. /package/dist/{chunk-XXO5TI3B.js.map → chunk-32U3N7H5.js.map} +0 -0
  206. /package/dist/{chunk-KB4MFBF5.js.map → chunk-3RDYU3JS.js.map} +0 -0
  207. /package/dist/{chunk-57QXN2CS.js.map → chunk-4S3N6HFG.js.map} +0 -0
  208. /package/dist/{chunk-GE7Q7KXP.js.map → chunk-7A2QKUUA.js.map} +0 -0
  209. /package/dist/{chunk-3MNBW7R7.js.map → chunk-C4KKM62E.js.map} +0 -0
  210. /package/dist/{chunk-NKCW223V.js.map → chunk-CMN5AWAZ.js.map} +0 -0
  211. /package/dist/{chunk-JXHMAQYT.js.map → chunk-DOBJH4I6.js.map} +0 -0
  212. /package/dist/{chunk-TZDSNIRO.js.map → chunk-IFVFQRZ2.js.map} +0 -0
  213. /package/dist/{chunk-LQYTQCXM.js.map → chunk-JCLECECB.js.map} +0 -0
  214. /package/dist/{chunk-QDV6VAD4.js.map → chunk-LEG7XWS2.js.map} +0 -0
  215. /package/dist/{chunk-N5RGXWLQ.js.map → chunk-PUEAEQSN.js.map} +0 -0
  216. /package/dist/{chunk-JKCDQBDW.js.map → chunk-UXFOGILU.js.map} +0 -0
  217. /package/dist/{chunk-MVQN73GT.js.map → chunk-VTR3MNYF.js.map} +0 -0
  218. /package/dist/{chunk-KVFYTRMV.js.map → chunk-W25I7G6U.js.map} +0 -0
  219. /package/dist/{chunk-3R2UZV3U.js.map → chunk-X7EJF46S.js.map} +0 -0
  220. /package/dist/{chunk-54KDA6UK.js.map → chunk-XG4NAWAV.js.map} +0 -0
  221. /package/dist/{chunk-P2D2MM47.js.map → chunk-YROCXMCK.js.map} +0 -0
@@ -1,3 +1,10 @@
1
+ import {
2
+ WEARABLE_SOURCE_PREFIX,
3
+ defaultTimezone,
4
+ loadSyncState,
5
+ syncWearableSource,
6
+ wearableSourceLabel
7
+ } from "./chunk-KVDUDYEN.js";
1
8
  import {
2
9
  migrateFromEngram
3
10
  } from "./chunk-4HFJQCJZ.js";
@@ -22,7 +29,7 @@ import {
22
29
  import {
23
30
  CompoundingEngine,
24
31
  defaultTierMigrationCycleBudget
25
- } from "./chunk-JKCDQBDW.js";
32
+ } from "./chunk-UXFOGILU.js";
26
33
  import {
27
34
  SharedContextManager
28
35
  } from "./chunk-DRD2Q7HQ.js";
@@ -168,7 +175,7 @@ import {
168
175
  buildEntityRecallSection,
169
176
  entityRecentTranscriptLookbackHours,
170
177
  readRecentEntityTranscriptEntries
171
- } from "./chunk-LQYTQCXM.js";
178
+ } from "./chunk-JCLECECB.js";
172
179
  import {
173
180
  buildEventOrderRecallSection,
174
181
  shouldRecallEventOrderEvidence
@@ -203,7 +210,7 @@ import {
203
210
  materializeAfterSemanticConsolidation,
204
211
  parseConsolidationResponse,
205
212
  parseOperatorAwareConsolidationResponse
206
- } from "./chunk-3R2UZV3U.js";
213
+ } from "./chunk-X7EJF46S.js";
207
214
  import {
208
215
  normalizeReplaySessionKey
209
216
  } from "./chunk-2PRQG7PV.js";
@@ -212,13 +219,13 @@ import {
212
219
  } from "./chunk-X6IRLNOO.js";
213
220
  import {
214
221
  searchVerifiedEpisodes
215
- } from "./chunk-P2D2MM47.js";
222
+ } from "./chunk-YROCXMCK.js";
216
223
  import {
217
224
  ThreadingManager
218
225
  } from "./chunk-W4RVMTHR.js";
219
226
  import {
220
227
  searchVerifiedSemanticRules
221
- } from "./chunk-57QXN2CS.js";
228
+ } from "./chunk-4S3N6HFG.js";
222
229
  import {
223
230
  searchWorkProductLedgerEntries
224
231
  } from "./chunk-ZRWB5D4H.js";
@@ -237,7 +244,7 @@ import {
237
244
  } from "./chunk-CYEPCZN5.js";
238
245
  import {
239
246
  NamespaceStorageRouter
240
- } from "./chunk-QDV6VAD4.js";
247
+ } from "./chunk-LEG7XWS2.js";
241
248
  import {
242
249
  namespaceIdentityFromToken
243
250
  } from "./chunk-ZFXCQPNO.js";
@@ -286,14 +293,9 @@ import {
286
293
  fallbackLlmRuntimeContextFromConfig
287
294
  } from "./chunk-723OMPUI.js";
288
295
  import {
289
- applyCorrections,
290
- applyOffTheRecord,
291
296
  compileCorrectionRule,
292
- compileCorrectionRules,
293
- compileRedactionPatterns,
294
297
  correctionsFilePath,
295
298
  loadCorrectionsFile,
296
- redactText,
297
299
  saveCorrectionsFile
298
300
  } from "./chunk-NDAH7BJ5.js";
299
301
  import {
@@ -351,26 +353,24 @@ import {
351
353
  } from "./chunk-XL7FK7PJ.js";
352
354
  import {
353
355
  buildChainFollowupGenerator
354
- } from "./chunk-NKCW223V.js";
356
+ } from "./chunk-CMN5AWAZ.js";
355
357
  import {
356
358
  ContentHashIndex,
357
359
  StorageManager,
358
360
  compareEntityTimestamps,
359
- composeDayTranscriptBody,
360
- composeDayTranscriptMeta,
361
361
  fingerprintEntityStructuredFacts,
362
- hashTranscriptBody,
363
- isValidTranscriptDate,
364
- loadSpeakerRegistry,
365
362
  normalizeAttributePairs,
366
363
  normalizeEntityName,
367
- parseDayTranscript,
368
364
  parseEntityFile,
369
- resolveSpeaker,
365
+ stripAttributesSuffix
366
+ } from "./chunk-QYGIQ5NM.js";
367
+ import {
368
+ isValidTranscriptDate,
369
+ loadSpeakerRegistry,
370
+ parseDayTranscript,
370
371
  saveSpeakerRegistry,
371
- serializeDayTranscript,
372
372
  speakerRegistryKey
373
- } from "./chunk-UGHUNQ74.js";
373
+ } from "./chunk-M7XQSUBB.js";
374
374
  import {
375
375
  attachCitation,
376
376
  hasCitationForTemplate,
@@ -380,6 +380,7 @@ import {
380
380
  confidenceTier
381
381
  } from "./chunk-FPNQF475.js";
382
382
  import {
383
+ inferMemoryStatus,
383
384
  isActiveMemoryStatus
384
385
  } from "./chunk-RULE4VG5.js";
385
386
  import {
@@ -423,7 +424,7 @@ import {
423
424
  } from "./chunk-AC5LO7IU.js";
424
425
 
425
426
  // src/orchestrator.ts
426
- import path3 from "path";
427
+ import path2 from "path";
427
428
  import os from "os";
428
429
  import { createHash, randomBytes } from "crypto";
429
430
  import { existsSync } from "fs";
@@ -965,780 +966,6 @@ function getTaxonomyFilePath(memoryDir) {
965
966
  return path.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
966
967
  }
967
968
 
968
- // src/wearables/memory-gen.ts
969
- function memoryStatusForMode(mode) {
970
- return mode === "auto" ? "active" : "pending_review";
971
- }
972
- var WEARABLE_SOURCE_PREFIX = "wearable";
973
- function wearableSourceLabel(sourceId) {
974
- return `${WEARABLE_SOURCE_PREFIX}:${sourceId}`;
975
- }
976
- function wearableDayTag(date) {
977
- return `wearable-day:${date}`;
978
- }
979
- var IMPORTANCE_RANK = {
980
- trivial: 0,
981
- low: 1,
982
- normal: 2,
983
- high: 3,
984
- critical: 4
985
- };
986
- var MAX_EXTRACTION_CHUNK_CHARS = 6e3;
987
- var MIN_CONVERSATION_CHARS = 80;
988
- function buildExtractionTurns(sourceId, date, conversation, registry) {
989
- const headerParts = [
990
- `Wearable transcript (${sourceId}) \u2014 ${date}`,
991
- conversation.title ? `"${conversation.title}"` : void 0,
992
- conversation.location ? `at ${conversation.location}` : void 0
993
- ].filter((part) => typeof part === "string");
994
- const header = `[${headerParts.join(" \u2014 ")}]`;
995
- const lines = [];
996
- for (const segment of conversation.segments) {
997
- const { label } = resolveSpeaker(sourceId, segment, registry);
998
- lines.push(`${label}: ${segment.text}`);
999
- }
1000
- const transcript = lines.join("\n");
1001
- if (transcript.trim().length < MIN_CONVERSATION_CHARS) return [];
1002
- const sessionKey = `wearables:${sourceId}:${date}:${conversation.id}`;
1003
- const timestamp = conversation.startIso;
1004
- const turns = [];
1005
- let chunkLines = [];
1006
- let chunkChars = 0;
1007
- const flush = () => {
1008
- if (chunkLines.length === 0) return;
1009
- turns.push({
1010
- role: "user",
1011
- content: `${header}
1012
- ${chunkLines.join("\n")}`,
1013
- timestamp,
1014
- sourceValidAt: timestamp,
1015
- sessionKey
1016
- });
1017
- chunkLines = [];
1018
- chunkChars = 0;
1019
- };
1020
- for (const line of transcript.split("\n")) {
1021
- if (chunkChars + line.length + 1 > MAX_EXTRACTION_CHUNK_CHARS) flush();
1022
- chunkLines.push(line);
1023
- chunkChars += line.length + 1;
1024
- }
1025
- flush();
1026
- return turns;
1027
- }
1028
- async function generateWearableMemories(sourceId, date, conversations, settings, registry, deps) {
1029
- const result = {
1030
- created: 0,
1031
- skipped: 0,
1032
- skippedByReason: {},
1033
- warnings: []
1034
- };
1035
- if (settings.memoryMode === "off") return result;
1036
- const skip = (reason, count = 1) => {
1037
- result.skipped += count;
1038
- result.skippedByReason[reason] = (result.skippedByReason[reason] ?? 0) + count;
1039
- };
1040
- const candidates = [];
1041
- const seenContent = /* @__PURE__ */ new Set();
1042
- for (const conversation of conversations) {
1043
- const turns = buildExtractionTurns(sourceId, date, conversation, registry);
1044
- if (turns.length === 0) continue;
1045
- let extraction;
1046
- try {
1047
- extraction = await deps.extract(turns);
1048
- } catch (err) {
1049
- result.warnings.push(
1050
- `extraction failed for ${sourceId}/${date} (conversation ${conversation.id}): ${describeErrorForOperator(err)} \u2014 the memory pass for this day retries on the next sync`
1051
- );
1052
- break;
1053
- }
1054
- for (const fact of extraction.facts) {
1055
- const content = fact.content?.trim();
1056
- if (!content) {
1057
- skip("empty");
1058
- continue;
1059
- }
1060
- if (fact.category === "procedure" || fact.category === "reasoning_trace") {
1061
- skip("unsupported-category");
1062
- continue;
1063
- }
1064
- if (typeof fact.confidence === "number" && fact.confidence < settings.minConfidence) {
1065
- skip("below-confidence");
1066
- continue;
1067
- }
1068
- const importance = scoreImportance(content, fact.category, fact.tags ?? []);
1069
- if (IMPORTANCE_RANK[importance.level] < IMPORTANCE_RANK[settings.minImportance]) {
1070
- skip("below-importance");
1071
- continue;
1072
- }
1073
- const dedupKey = content.toLowerCase();
1074
- if (seenContent.has(dedupKey)) {
1075
- skip("duplicate-in-run");
1076
- continue;
1077
- }
1078
- seenContent.add(dedupKey);
1079
- candidates.push({ fact: { ...fact, content }, importance, conversation });
1080
- }
1081
- }
1082
- const novel = [];
1083
- for (const candidate of candidates) {
1084
- if (await deps.writer.hasFactContentHash(candidate.fact.content)) {
1085
- skip("duplicate-existing");
1086
- continue;
1087
- }
1088
- novel.push(candidate);
1089
- }
1090
- novel.sort((a, b) => {
1091
- if (a.importance.score > b.importance.score) return -1;
1092
- if (a.importance.score < b.importance.score) return 1;
1093
- if (a.fact.content < b.fact.content) return -1;
1094
- if (a.fact.content > b.fact.content) return 1;
1095
- return 0;
1096
- });
1097
- const cap = settings.maxMemoriesPerDay;
1098
- const kept = cap > 0 ? novel.slice(0, cap) : novel;
1099
- if (novel.length > kept.length) {
1100
- skip("over-day-cap", novel.length - kept.length);
1101
- }
1102
- const status = memoryStatusForMode(settings.memoryMode);
1103
- for (const candidate of kept) {
1104
- const tags = [
1105
- .../* @__PURE__ */ new Set([
1106
- ...candidate.fact.tags ?? [],
1107
- WEARABLE_SOURCE_PREFIX,
1108
- wearableSourceLabel(sourceId),
1109
- wearableDayTag(date)
1110
- ])
1111
- ];
1112
- await deps.writer.writeMemory(candidate.fact.category, candidate.fact.content, {
1113
- confidence: candidate.fact.confidence,
1114
- tags,
1115
- source: wearableSourceLabel(sourceId),
1116
- importance: candidate.importance,
1117
- validAt: candidate.conversation.startIso,
1118
- structuredAttributes: {
1119
- ...candidate.fact.structuredAttributes ?? {},
1120
- wearableSource: sourceId,
1121
- wearableDate: date,
1122
- wearableConversationId: candidate.conversation.id
1123
- },
1124
- contentHashSource: candidate.fact.content,
1125
- status
1126
- });
1127
- result.created += 1;
1128
- }
1129
- return result;
1130
- }
1131
- async function writeDailyDigestMemory(sourceId, date, conversations, settings, registry, writer) {
1132
- if (settings.memoryMode === "off") return false;
1133
- if (conversations.length === 0) return false;
1134
- const lines = conversations.map((conversation) => {
1135
- const title = conversation.title?.trim() || "Untitled conversation";
1136
- const speakers = new Set(
1137
- conversation.segments.map(
1138
- (segment) => resolveSpeaker(sourceId, segment, registry).label
1139
- )
1140
- );
1141
- return `- ${title} (${speakers.size} speaker${speakers.size === 1 ? "" : "s"})`;
1142
- });
1143
- const content = `Wearable day digest \u2014 ${sourceId}, ${date}: ${conversations.length} recorded conversation${conversations.length === 1 ? "" : "s"}.
1144
- ` + lines.join("\n");
1145
- if (await writer.hasFactContentHash(content)) return false;
1146
- await writer.writeMemory("moment", content, {
1147
- confidence: 0.9,
1148
- tags: [
1149
- WEARABLE_SOURCE_PREFIX,
1150
- wearableSourceLabel(sourceId),
1151
- wearableDayTag(date),
1152
- "daily-digest"
1153
- ],
1154
- source: wearableSourceLabel(sourceId),
1155
- importance: scoreImportance(content, "moment", ["daily-digest"]),
1156
- validAt: `${date}T00:00:00.000Z`,
1157
- structuredAttributes: {
1158
- wearableSource: sourceId,
1159
- wearableDate: date
1160
- },
1161
- contentHashSource: content,
1162
- status: memoryStatusForMode(settings.memoryMode),
1163
- memoryKind: "episode"
1164
- });
1165
- return true;
1166
- }
1167
- async function importNativeMemories(sourceId, memories, alreadyImportedIds, writer) {
1168
- let imported = 0;
1169
- const importedIds = [];
1170
- const seenContent = /* @__PURE__ */ new Set();
1171
- for (const memory of memories) {
1172
- const content = memory.content?.trim();
1173
- if (!content) continue;
1174
- if (alreadyImportedIds.has(memory.id)) continue;
1175
- if (seenContent.has(content) || await writer.hasFactContentHash(content)) {
1176
- importedIds.push(memory.id);
1177
- continue;
1178
- }
1179
- seenContent.add(content);
1180
- await writer.writeMemory("fact", content, {
1181
- confidence: 0.6,
1182
- tags: [
1183
- .../* @__PURE__ */ new Set([
1184
- ...memory.tags ?? [],
1185
- WEARABLE_SOURCE_PREFIX,
1186
- wearableSourceLabel(sourceId),
1187
- "native-import"
1188
- ])
1189
- ],
1190
- source: `${wearableSourceLabel(sourceId)}:native`,
1191
- importance: scoreImportance(content, "fact", memory.tags ?? []),
1192
- validAt: memory.createdIso,
1193
- structuredAttributes: {
1194
- wearableSource: sourceId,
1195
- wearableNativeId: memory.id
1196
- },
1197
- contentHashSource: content,
1198
- status: "pending_review"
1199
- });
1200
- imported += 1;
1201
- importedIds.push(memory.id);
1202
- }
1203
- return { imported, importedIds };
1204
- }
1205
-
1206
- // src/wearables/cleanup.ts
1207
- var MERGE_GAP_MS = 3e4;
1208
- var FILLER_TOKENS = ["um", "uh", "uhm", "umm", "uhh", "erm", "hmm", "mhm"];
1209
- var FILLER_PATTERN = new RegExp(
1210
- // Leading/trailing punctuation around the filler collapses with it so
1211
- // "Um, so we should" -> "so we should" rather than ", so we should".
1212
- `(?:^|\\s)(?:${FILLER_TOKENS.join("|")})[,.]?(?=\\s|$)`,
1213
- "gi"
1214
- );
1215
- function cleanConversation(conversation, settings) {
1216
- let segments = conversation.segments.map((segment) => ({ ...segment }));
1217
- let droppedSegments = 0;
1218
- let mergedSegments = 0;
1219
- if (settings.stripFillers) {
1220
- for (const segment of segments) {
1221
- segment.text = stripFillerTokens(segment.text);
1222
- }
1223
- }
1224
- if (settings.collapseRepeats) {
1225
- for (const segment of segments) {
1226
- segment.text = collapseImmediateRepeats(segment.text);
1227
- }
1228
- }
1229
- for (const segment of segments) {
1230
- segment.text = normalizeWhitespace(segment.text);
1231
- }
1232
- if (settings.dropLowQuality) {
1233
- const kept = [];
1234
- for (const segment of segments) {
1235
- if (isLowQualitySegment(segment.text)) {
1236
- droppedSegments += 1;
1237
- } else {
1238
- kept.push(segment);
1239
- }
1240
- }
1241
- segments = kept;
1242
- } else {
1243
- const kept = segments.filter((segment) => segment.text.length > 0);
1244
- droppedSegments += segments.length - kept.length;
1245
- segments = kept;
1246
- }
1247
- if (settings.mergeSameSpeaker) {
1248
- const merged = [];
1249
- for (const segment of segments) {
1250
- const previous = merged[merged.length - 1];
1251
- if (previous && canMerge(previous, segment)) {
1252
- previous.text = `${previous.text} ${segment.text}`.trim();
1253
- if (segment.endIso) previous.endIso = segment.endIso;
1254
- mergedSegments += 1;
1255
- } else {
1256
- merged.push(segment);
1257
- }
1258
- }
1259
- segments = merged;
1260
- }
1261
- return {
1262
- conversation: { ...conversation, segments },
1263
- droppedSegments,
1264
- mergedSegments
1265
- };
1266
- }
1267
- function canMerge(previous, next) {
1268
- if (previous.speakerKey !== next.speakerKey) return false;
1269
- const previousEnd = previous.endIso ? Date.parse(previous.endIso) : NaN;
1270
- const nextStart = next.startIso ? Date.parse(next.startIso) : NaN;
1271
- if (Number.isNaN(previousEnd) || Number.isNaN(nextStart)) return true;
1272
- return nextStart - previousEnd <= MERGE_GAP_MS;
1273
- }
1274
- function stripFillerTokens(text) {
1275
- return normalizeWhitespace(text.replace(FILLER_PATTERN, " "));
1276
- }
1277
- function collapseImmediateRepeats(text) {
1278
- const words = text.split(/\s+/).filter((word) => word.length > 0);
1279
- if (words.length < 2) return text.trim();
1280
- const out = [];
1281
- let index = 0;
1282
- while (index < words.length) {
1283
- out.push(words[index]);
1284
- index += 1;
1285
- let matched = true;
1286
- while (matched) {
1287
- matched = false;
1288
- for (let size = 4; size >= 1; size--) {
1289
- if (out.length < size || index + size > words.length) continue;
1290
- const tail = out.slice(-size).join(" ").toLowerCase();
1291
- if (!/\p{L}/u.test(tail)) continue;
1292
- const ahead = words.slice(index, index + size).join(" ").toLowerCase();
1293
- if (tail === ahead) {
1294
- index += size;
1295
- matched = true;
1296
- break;
1297
- }
1298
- }
1299
- }
1300
- }
1301
- return out.join(" ");
1302
- }
1303
- function isLowQualitySegment(text) {
1304
- const trimmed = text.trim();
1305
- if (trimmed.length === 0) return true;
1306
- if (/^(.)\1{4,}$/.test(trimmed)) return true;
1307
- const letters = trimmed.replace(/[^\p{L}\p{N}]/gu, "");
1308
- if (letters.length === 0) return true;
1309
- if (trimmed.length >= 12 && letters.length / trimmed.length < 0.3) {
1310
- return true;
1311
- }
1312
- const words = trimmed.toLowerCase().split(/\s+/);
1313
- if (words.length >= 5) {
1314
- const unique = new Set(words);
1315
- if (unique.size === 1) return true;
1316
- }
1317
- return false;
1318
- }
1319
- function normalizeWhitespace(text) {
1320
- return text.replace(/\s+/g, " ").trim();
1321
- }
1322
-
1323
- // src/wearables/sync-state.ts
1324
- import { promises as fsPromises } from "fs";
1325
- import * as path2 from "path";
1326
- var MAX_TRACKED_NATIVE_IDS = 5e3;
1327
- var MAX_TRACKED_DAY_HASHES = 800;
1328
- function syncStateFilePath(memoryDir) {
1329
- return path2.join(memoryDir, "state", "wearables", "sync.json");
1330
- }
1331
- function emptySyncState() {
1332
- return { version: 1, sources: {} };
1333
- }
1334
- async function loadSyncState(memoryDir) {
1335
- const filePath = syncStateFilePath(memoryDir);
1336
- let raw;
1337
- try {
1338
- raw = await fsPromises.readFile(filePath, "utf-8");
1339
- } catch (err) {
1340
- if (err.code === "ENOENT") {
1341
- return emptySyncState();
1342
- }
1343
- throw err;
1344
- }
1345
- let parsed;
1346
- try {
1347
- parsed = JSON.parse(raw);
1348
- } catch {
1349
- return emptySyncState();
1350
- }
1351
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed) || typeof parsed.sources !== "object" || parsed.sources === null) {
1352
- return emptySyncState();
1353
- }
1354
- return { version: 1, sources: parsed.sources };
1355
- }
1356
- async function saveSyncState(memoryDir, state) {
1357
- const filePath = syncStateFilePath(memoryDir);
1358
- await fsPromises.mkdir(path2.dirname(filePath), { recursive: true });
1359
- const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now().toString(36)}`;
1360
- await fsPromises.writeFile(
1361
- tmpPath,
1362
- `${JSON.stringify(state, null, 2)}
1363
- `,
1364
- "utf-8"
1365
- );
1366
- try {
1367
- await fsPromises.rename(tmpPath, filePath);
1368
- } catch (err) {
1369
- await fsPromises.unlink(tmpPath).catch(() => void 0);
1370
- throw err;
1371
- }
1372
- }
1373
- function updateSourceSyncState(state, sourceId, update) {
1374
- const previous = state.sources[sourceId];
1375
- const mergedHashes = {
1376
- ...previous?.dayHashes ?? {},
1377
- ...update.dayHashes
1378
- };
1379
- const hashKeys = Object.keys(mergedHashes).sort();
1380
- while (hashKeys.length > MAX_TRACKED_DAY_HASHES) {
1381
- const oldest = hashKeys.shift();
1382
- if (oldest === void 0) break;
1383
- delete mergedHashes[oldest];
1384
- }
1385
- const mergedMemoryHashes = {
1386
- ...previous?.memoryDayHashes ?? {},
1387
- ...update.memoryDayHashes ?? {}
1388
- };
1389
- for (const day of update.clearMemoryDays ?? []) {
1390
- if (!(day in (update.memoryDayHashes ?? {}))) {
1391
- delete mergedMemoryHashes[day];
1392
- }
1393
- }
1394
- const memoryHashKeys = Object.keys(mergedMemoryHashes).sort();
1395
- while (memoryHashKeys.length > MAX_TRACKED_DAY_HASHES) {
1396
- const oldest = memoryHashKeys.shift();
1397
- if (oldest === void 0) break;
1398
- delete mergedMemoryHashes[oldest];
1399
- }
1400
- const mergedNativeIds = [
1401
- ...previous?.importedNativeMemoryIds ?? [],
1402
- ...update.importedNativeMemoryIds ?? []
1403
- ];
1404
- const dedupedNativeIds = [...new Set(mergedNativeIds)];
1405
- const boundedNativeIds = dedupedNativeIds.length > MAX_TRACKED_NATIVE_IDS ? dedupedNativeIds.slice(dedupedNativeIds.length - MAX_TRACKED_NATIVE_IDS) : dedupedNativeIds;
1406
- const sortedDays = [...update.days].sort();
1407
- const latestDay = sortedDays[sortedDays.length - 1];
1408
- const lastDateSynced = latestDay !== void 0 && (!previous || previous.lastDateSynced < latestDay) ? latestDay : previous?.lastDateSynced ?? latestDay ?? "";
1409
- return {
1410
- version: 1,
1411
- sources: {
1412
- ...state.sources,
1413
- [sourceId]: {
1414
- lastSyncAt: update.syncedAt,
1415
- lastDateSynced,
1416
- dayHashes: mergedHashes,
1417
- memoryDayHashes: mergedMemoryHashes,
1418
- importedNativeMemoryIds: boundedNativeIds
1419
- }
1420
- }
1421
- };
1422
- }
1423
-
1424
- // src/wearables/pipeline.ts
1425
- var MAX_PAGES_PER_DAY = 50;
1426
- var MAX_NATIVE_PAGES = 20;
1427
- var DEFAULT_SYNC_DAYS = 2;
1428
- var MAX_SYNC_DAYS = 90;
1429
- function dateInTimezone(date, timezone) {
1430
- try {
1431
- const parts = new Intl.DateTimeFormat("en-CA", {
1432
- timeZone: timezone,
1433
- year: "numeric",
1434
- month: "2-digit",
1435
- day: "2-digit"
1436
- }).formatToParts(date);
1437
- const get = (type) => parts.find((part) => part.type === type)?.value ?? "";
1438
- return `${get("year")}-${get("month")}-${get("day")}`;
1439
- } catch {
1440
- return date.toISOString().slice(0, 10);
1441
- }
1442
- }
1443
- function resolveSyncDates(options, timezone, now) {
1444
- if (options.date !== void 0) {
1445
- if (!isValidTranscriptDate(options.date)) {
1446
- throw new WearablesInputError(
1447
- `wearables sync: invalid date '${options.date}' \u2014 expected YYYY-MM-DD`
1448
- );
1449
- }
1450
- return [options.date];
1451
- }
1452
- let days = DEFAULT_SYNC_DAYS;
1453
- if (options.days !== void 0) {
1454
- if (!Number.isFinite(options.days) || !Number.isInteger(options.days) || options.days < 1 || options.days > MAX_SYNC_DAYS) {
1455
- throw new WearablesInputError(
1456
- `wearables sync: invalid days '${options.days}' \u2014 expected an integer between 1 and ${MAX_SYNC_DAYS}`
1457
- );
1458
- }
1459
- days = options.days;
1460
- }
1461
- const dates = [];
1462
- let cursor = dateInTimezone(now, timezone);
1463
- for (let count = 0; count < days; count++) {
1464
- dates.unshift(cursor);
1465
- cursor = previousIsoDate(cursor);
1466
- }
1467
- return dates;
1468
- }
1469
- function previousIsoDate(date) {
1470
- const parsed = /* @__PURE__ */ new Date(`${date}T00:00:00Z`);
1471
- parsed.setUTCDate(parsed.getUTCDate() - 1);
1472
- return parsed.toISOString().slice(0, 10);
1473
- }
1474
- async function fetchAllConversationsForDate(connector, date, timezone, signal, warnings) {
1475
- const conversations = [];
1476
- let cursor = void 0;
1477
- for (let page = 0; page < MAX_PAGES_PER_DAY; page++) {
1478
- const result = await connector.fetchConversations({
1479
- date,
1480
- timezone,
1481
- cursor,
1482
- signal
1483
- });
1484
- conversations.push(...result.conversations);
1485
- if (!result.nextCursor) return { conversations, partial: false };
1486
- cursor = result.nextCursor;
1487
- }
1488
- warnings.push(
1489
- `${connector.id}: stopped paginating ${date} after ${MAX_PAGES_PER_DAY} pages \u2014 day may be partially synced (every sync refetches and re-warns until the provider day fits the cap)`
1490
- );
1491
- return { conversations, partial: true };
1492
- }
1493
- var PARTIAL_DAY_MARKER = "\n*Note: pagination safety cap reached during sync \u2014 this day may be incomplete.*\n";
1494
- function emptyDayBody(sourceId, date) {
1495
- return `# ${sourceId} transcript \u2014 ${date}
1496
-
1497
- _No storable conversation content for this day (all segments were elided or dropped)._
1498
- `;
1499
- }
1500
- function cleanDay(raw, sourceId, settings, config, userRedaction, correctionRules) {
1501
- const out = {
1502
- conversations: [],
1503
- segmentsKept: 0,
1504
- segmentsDropped: 0,
1505
- redactions: 0,
1506
- correctionsApplied: 0
1507
- };
1508
- for (const conversation of raw) {
1509
- let current = conversation;
1510
- if (config.offTheRecordEnabled) {
1511
- const otr = applyOffTheRecord(current);
1512
- current = otr.conversation;
1513
- out.segmentsDropped += otr.droppedSegments;
1514
- }
1515
- const cleaned = cleanConversation(current, settings.cleanup);
1516
- current = cleaned.conversation;
1517
- out.segmentsDropped += cleaned.droppedSegments;
1518
- const segments = current.segments.map((segment) => {
1519
- let text = segment.text;
1520
- if (config.redactionEnabled) {
1521
- const redacted = redactText(text, userRedaction);
1522
- text = redacted.text;
1523
- out.redactions += redacted.redactions;
1524
- }
1525
- const corrected = applyCorrections(text, correctionRules, sourceId);
1526
- out.correctionsApplied += corrected.applied;
1527
- return { ...segment, text: corrected.text };
1528
- });
1529
- current = { ...current, segments };
1530
- if (current.segments.length > 0) {
1531
- out.conversations.push(current);
1532
- out.segmentsKept += current.segments.length;
1533
- }
1534
- }
1535
- return out;
1536
- }
1537
- async function syncWearableSource(connector, settings, config, options, deps) {
1538
- const now = deps.now ? deps.now() : /* @__PURE__ */ new Date();
1539
- const timezone = config.timezone ?? defaultTimezone();
1540
- const dates = resolveSyncDates(options, timezone, now);
1541
- const summary = {
1542
- source: connector.id,
1543
- days: dates,
1544
- conversations: 0,
1545
- segmentsKept: 0,
1546
- segmentsDropped: 0,
1547
- redactions: 0,
1548
- correctionsApplied: 0,
1549
- transcriptsWritten: [],
1550
- memoriesCreated: 0,
1551
- memoriesSkipped: 0,
1552
- nativeMemoriesImported: 0,
1553
- warnings: []
1554
- };
1555
- const registry = await loadSpeakerRegistry(deps.memoryDir);
1556
- const stateRules = await loadCorrectionsFile(deps.memoryDir);
1557
- const correctionRules = [
1558
- ...compileCorrectionRules(config.corrections, "wearables.corrections"),
1559
- ...compileCorrectionRules(stateRules, "state corrections")
1560
- ];
1561
- const userRedaction = compileRedactionPatterns(config.redactionPatterns);
1562
- let syncState = await loadSyncState(deps.memoryDir);
1563
- const previousState = syncState.sources[connector.id];
1564
- const dayHashes = {};
1565
- const memoryDayHashes = {};
1566
- const failedMemoryDays = [];
1567
- const importedNativeIds = [];
1568
- for (const date of dates) {
1569
- const fetched = await fetchAllConversationsForDate(
1570
- connector,
1571
- date,
1572
- timezone,
1573
- options.signal,
1574
- summary.warnings
1575
- );
1576
- const cleaned = cleanDay(
1577
- fetched.conversations,
1578
- connector.id,
1579
- settings,
1580
- config,
1581
- userRedaction,
1582
- correctionRules
1583
- );
1584
- summary.conversations += cleaned.conversations.length;
1585
- summary.segmentsKept += cleaned.segmentsKept;
1586
- summary.segmentsDropped += cleaned.segmentsDropped;
1587
- summary.redactions += cleaned.redactions;
1588
- summary.correctionsApplied += cleaned.correctionsApplied;
1589
- if (fetched.conversations.length === 0) {
1590
- const existing = await deps.readDayContentHash(connector.id, date);
1591
- if (existing !== null) {
1592
- summary.warnings.push(
1593
- `${connector.id}: provider returned no conversations for ${date} but a stored transcript exists \u2014 leaving it in place; delete the day file manually if the recordings were intentionally removed upstream`
1594
- );
1595
- }
1596
- continue;
1597
- }
1598
- const allElided = cleaned.conversations.length === 0;
1599
- let body = allElided ? emptyDayBody(connector.id, date) : composeDayTranscriptBody(
1600
- connector.id,
1601
- date,
1602
- timezone,
1603
- cleaned.conversations,
1604
- registry
1605
- );
1606
- if (fetched.partial && !allElided) {
1607
- body += PARTIAL_DAY_MARKER;
1608
- }
1609
- const bodyHash = hashTranscriptBody(body);
1610
- const existingHash = await deps.readDayContentHash(connector.id, date);
1611
- const changed = existingHash !== bodyHash;
1612
- const shouldWrite = changed && (!allElided || existingHash !== null);
1613
- if (shouldWrite) {
1614
- const meta = composeDayTranscriptMeta(
1615
- connector.id,
1616
- date,
1617
- timezone,
1618
- cleaned.conversations,
1619
- registry,
1620
- body,
1621
- now.toISOString()
1622
- );
1623
- await deps.writeDayTranscript(
1624
- connector.id,
1625
- date,
1626
- serializeDayTranscript(meta, body)
1627
- );
1628
- summary.transcriptsWritten.push(date);
1629
- }
1630
- dayHashes[date] = bodyHash;
1631
- if (allElided) continue;
1632
- const memoryPassComplete = previousState?.memoryDayHashes?.[date] === bodyHash;
1633
- if (settings.memoryMode !== "off" && (changed || options.forceMemories === true || !memoryPassComplete)) {
1634
- if (!deps.memoryGen) {
1635
- summary.warnings.push(
1636
- `${connector.id}: memoryMode is '${settings.memoryMode}' but no extraction engine is available in this context \u2014 transcripts synced, memories skipped`
1637
- );
1638
- } else {
1639
- let passClean = false;
1640
- try {
1641
- const generated = await generateWearableMemories(
1642
- connector.id,
1643
- date,
1644
- cleaned.conversations,
1645
- settings,
1646
- registry,
1647
- deps.memoryGen
1648
- );
1649
- summary.memoriesCreated += generated.created;
1650
- summary.memoriesSkipped += generated.skipped;
1651
- summary.warnings.push(...generated.warnings);
1652
- passClean = generated.warnings.length === 0;
1653
- if (config.digestEnabled) {
1654
- const wrote = await writeDailyDigestMemory(
1655
- connector.id,
1656
- date,
1657
- cleaned.conversations,
1658
- settings,
1659
- registry,
1660
- deps.memoryGen.writer
1661
- );
1662
- if (wrote) summary.memoriesCreated += 1;
1663
- }
1664
- } catch (err) {
1665
- passClean = false;
1666
- summary.warnings.push(
1667
- `${connector.id}: memory pass failed for ${date}: ${describeErrorForOperator(err)} \u2014 retries on the next sync`
1668
- );
1669
- }
1670
- if (passClean) {
1671
- memoryDayHashes[date] = bodyHash;
1672
- } else {
1673
- failedMemoryDays.push(date);
1674
- }
1675
- }
1676
- } else if (settings.memoryMode !== "off" && memoryPassComplete) {
1677
- memoryDayHashes[date] = bodyHash;
1678
- }
1679
- }
1680
- if (settings.importNativeMemories === "review" && typeof connector.fetchNativeMemories === "function") {
1681
- if (!deps.memoryGen) {
1682
- summary.warnings.push(
1683
- `${connector.id}: importNativeMemories is enabled but no memory writer is available in this context`
1684
- );
1685
- } else {
1686
- const alreadyImported = new Set(
1687
- previousState?.importedNativeMemoryIds ?? []
1688
- );
1689
- let cursor = void 0;
1690
- for (let page = 0; page < MAX_NATIVE_PAGES; page++) {
1691
- const result = await connector.fetchNativeMemories({
1692
- cursor,
1693
- signal: options.signal
1694
- });
1695
- const imported = await importNativeMemories(
1696
- connector.id,
1697
- result.memories,
1698
- alreadyImported,
1699
- deps.memoryGen.writer
1700
- );
1701
- summary.nativeMemoriesImported += imported.imported;
1702
- importedNativeIds.push(...imported.importedIds);
1703
- for (const id of imported.importedIds) alreadyImported.add(id);
1704
- if (!result.nextCursor) break;
1705
- cursor = result.nextCursor;
1706
- if (page === MAX_NATIVE_PAGES - 1) {
1707
- summary.warnings.push(
1708
- `${connector.id}: stopped native-memory import after ${MAX_NATIVE_PAGES} pages \u2014 remaining items import on the next sync`
1709
- );
1710
- }
1711
- }
1712
- }
1713
- }
1714
- if (summary.transcriptsWritten.length > 0 && deps.afterTranscriptsWritten) {
1715
- try {
1716
- await deps.afterTranscriptsWritten();
1717
- } catch (err) {
1718
- summary.warnings.push(
1719
- `search reindex failed (transcripts are stored and will index on the next update): ${describeErrorForOperator(err)}`
1720
- );
1721
- }
1722
- }
1723
- syncState = updateSourceSyncState(syncState, connector.id, {
1724
- syncedAt: now.toISOString(),
1725
- days: dates,
1726
- dayHashes,
1727
- memoryDayHashes,
1728
- clearMemoryDays: failedMemoryDays,
1729
- importedNativeMemoryIds: importedNativeIds
1730
- });
1731
- await saveSyncState(deps.memoryDir, syncState);
1732
- return summary;
1733
- }
1734
- function defaultTimezone() {
1735
- try {
1736
- return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
1737
- } catch {
1738
- return "UTC";
1739
- }
1740
- }
1741
-
1742
969
  // src/wearables/registry.ts
1743
970
  var registrations = /* @__PURE__ */ new Map();
1744
971
  function registerWearableConnector(registration) {
@@ -1816,12 +1043,15 @@ function isModuleNotFound(err, specifier) {
1816
1043
  function createWearableMemoryWriter(storage) {
1817
1044
  return {
1818
1045
  writeMemory: storage.writeMemory.bind(storage),
1046
+ findWearableMemoryByContent: async (content) => await storage.findWearableMemoryByContent(content),
1047
+ promoteWearableMemory: storage.promoteWearableMemory.bind(storage),
1048
+ demoteWearableMemory: storage.demoteWearableMemory.bind(storage),
1819
1049
  hasFactContentHash: async (content) => {
1820
1050
  if (await storage.hasFactContentHash(content)) return true;
1821
- const needle = content.trim();
1051
+ const needle = stripAttributesSuffix(content);
1822
1052
  const memories = await storage.readAllMemories();
1823
1053
  return memories.some(
1824
- (memory) => typeof memory.frontmatter.source === "string" && memory.frontmatter.source.startsWith(`${WEARABLE_SOURCE_PREFIX}:`) && memory.content.trim() === needle
1054
+ (memory) => typeof memory.frontmatter.source === "string" && memory.frontmatter.source.startsWith(`${WEARABLE_SOURCE_PREFIX}:`) && stripAttributesSuffix(memory.content) === needle
1825
1055
  );
1826
1056
  }
1827
1057
  };
@@ -1919,7 +1149,8 @@ var WearablesService = class {
1919
1149
  }
1920
1150
  const memoryGen = this.deps.extract ? {
1921
1151
  extract: this.deps.extract,
1922
- writer: createWearableMemoryWriter(storage)
1152
+ writer: createWearableMemoryWriter(storage),
1153
+ ...this.deps.judgeFacts !== void 0 ? { judgeFacts: this.deps.judgeFacts } : {}
1923
1154
  } : null;
1924
1155
  const summaries = [];
1925
1156
  for (const [sourceId, settings] of targets) {
@@ -1948,8 +1179,51 @@ Install it alongside Remnic:
1948
1179
  return parseDayTranscript(raw)?.meta.contentHash ?? null;
1949
1180
  },
1950
1181
  writeDayTranscript: (source, date, serialized) => storage.writeWearableDayTranscript(source, date, serialized),
1951
- afterTranscriptsWritten: this.deps.reindexSearch,
1952
- memoryGen
1182
+ afterWrites: this.deps.reindexSearch,
1183
+ memoryGen,
1184
+ // Cross-device corroboration evidence (smart mode): other
1185
+ // sources' stored transcripts for the same day...
1186
+ readOtherSourceDayBodies: async (date, excludeSource) => {
1187
+ const bodies = /* @__PURE__ */ new Map();
1188
+ const days = await storage.listWearableTranscriptDays();
1189
+ for (const entry of days) {
1190
+ if (entry.date !== date || entry.source === excludeSource) continue;
1191
+ if (bodies.size >= 4) break;
1192
+ const raw = await storage.readWearableDayTranscript(entry.source, entry.date);
1193
+ if (raw === null) continue;
1194
+ bodies.set(entry.source, parseDayTranscript(raw)?.body ?? raw);
1195
+ }
1196
+ return bodies;
1197
+ },
1198
+ // ...and existing memories for the support boost. Status
1199
+ // resolves through the canonical inferMemoryStatus so rows
1200
+ // archived via `archivedAt` (or an archive/ path) without an
1201
+ // explicit status never count. Explicit allow-list: active
1202
+ // rows AND pending_review rows — a borderline fact observed
1203
+ // again on a later day is repetition signal and the support
1204
+ // boost is how it earns promotion. Rejected/quarantined/
1205
+ // superseded/archived/forgotten rows never count (CLAUDE.md
1206
+ // rule 53). Bodies feed token matching with the
1207
+ // "[Attributes: ...]" enrichment suffix stripped — attribute
1208
+ // metadata must never grant corroboration.
1209
+ listSupportMemories: async () => {
1210
+ const memories = await storage.readAllMemories();
1211
+ const support = [];
1212
+ for (const memory of memories) {
1213
+ const status = inferMemoryStatus(
1214
+ memory.frontmatter,
1215
+ memory.path
1216
+ );
1217
+ if (status !== "active" && status !== "pending_review") {
1218
+ continue;
1219
+ }
1220
+ support.push({
1221
+ id: memory.frontmatter.id,
1222
+ content: stripAttributesSuffix(memory.content)
1223
+ });
1224
+ }
1225
+ return support;
1226
+ }
1953
1227
  }
1954
1228
  );
1955
1229
  summaries.push(summary);
@@ -2394,7 +1668,7 @@ async function qmdStartupCollectionCheckWithTimeout(promise, controller, label)
2394
1668
  return await Promise.race([checkedPromise, timeoutPromise]);
2395
1669
  }
2396
1670
  function defaultWorkspaceDir() {
2397
- return path3.join(os.homedir(), ".openclaw", "workspace");
1671
+ return path2.join(os.homedir(), ".openclaw", "workspace");
2398
1672
  }
2399
1673
  function sanitizeSessionKeyForFilename(sessionKey) {
2400
1674
  const readable = sessionKey.replace(/[^a-zA-Z0-9._-]/g, "_");
@@ -2703,11 +1977,11 @@ function mergeGraphExpandedResults(primary, expanded) {
2703
1977
  return Array.from(mergedByPath.values());
2704
1978
  }
2705
1979
  function graphPathRelativeToStorage(storageDir, candidatePath) {
2706
- const absolutePath = path3.isAbsolute(candidatePath) ? candidatePath : path3.resolve(storageDir, candidatePath);
2707
- const rel = path3.relative(storageDir, absolutePath);
1980
+ const absolutePath = path2.isAbsolute(candidatePath) ? candidatePath : path2.resolve(storageDir, candidatePath);
1981
+ const rel = path2.relative(storageDir, absolutePath);
2708
1982
  if (!rel || rel === ".") return null;
2709
1983
  if (rel.startsWith("..")) return null;
2710
- return rel.split(path3.sep).join("/");
1984
+ return rel.split(path2.sep).join("/");
2711
1985
  }
2712
1986
  function normalizeGraphActivationScore(score) {
2713
1987
  const bounded = Number.isFinite(score) && score > 0 ? score : 0;
@@ -2849,7 +2123,7 @@ function buildMemoryPathById(allMemsForGraph, storageDir) {
2849
2123
  for (const mem of allMemsForGraph ?? []) {
2850
2124
  const id = mem.frontmatter.id;
2851
2125
  if (!id) continue;
2852
- pathById.set(id, path3.relative(storageDir, mem.path));
2126
+ pathById.set(id, path2.relative(storageDir, mem.path));
2853
2127
  }
2854
2128
  return pathById;
2855
2129
  }
@@ -2857,7 +2131,7 @@ function appendMemoryToGraphContext(options) {
2857
2131
  if (!Array.isArray(options.allMemsForGraph)) return;
2858
2132
  const nowIso = (/* @__PURE__ */ new Date()).toISOString();
2859
2133
  options.allMemsForGraph.push({
2860
- path: path3.join(options.storageDir, options.memoryRelPath),
2134
+ path: path2.join(options.storageDir, options.memoryRelPath),
2861
2135
  content: options.content,
2862
2136
  frontmatter: {
2863
2137
  id: options.memoryId,
@@ -2877,16 +2151,16 @@ function resolvePersistedMemoryRelativePath(options) {
2877
2151
  const persisted = options.pathById.get(options.memoryId);
2878
2152
  if (persisted) return persisted;
2879
2153
  if (options.category === "correction") {
2880
- return path3.join("corrections", `${options.memoryId}.md`);
2154
+ return path2.join("corrections", `${options.memoryId}.md`);
2881
2155
  }
2882
2156
  const subtree = options.category === "procedure" ? "procedures" : options.category === "reasoning_trace" ? "reasoning-traces" : "facts";
2883
2157
  const idParts = options.memoryId.split("-");
2884
2158
  const maybeTimestamp = Number(idParts[1]);
2885
2159
  if (Number.isFinite(maybeTimestamp) && maybeTimestamp > 0) {
2886
2160
  const day = new Date(maybeTimestamp).toISOString().slice(0, 10);
2887
- return path3.join(subtree, day, `${options.memoryId}.md`);
2161
+ return path2.join(subtree, day, `${options.memoryId}.md`);
2888
2162
  }
2889
- return path3.join(subtree, `${options.memoryId}.md`);
2163
+ return path2.join(subtree, `${options.memoryId}.md`);
2890
2164
  }
2891
2165
  var Orchestrator = class _Orchestrator {
2892
2166
  storage;
@@ -3006,6 +2280,7 @@ var Orchestrator = class _Orchestrator {
3006
2280
  consolidationObservers = /* @__PURE__ */ new Set();
3007
2281
  qmdMaintenanceTimer = null;
3008
2282
  wearablesServiceInstance = null;
2283
+ wearablesAutoSyncHandle = null;
3009
2284
  qmdMaintenancePending = false;
3010
2285
  qmdMaintenanceInFlight = false;
3011
2286
  lastQmdEmbedAtMs = 0;
@@ -3080,6 +2355,10 @@ var Orchestrator = class _Orchestrator {
3080
2355
  */
3081
2356
  async destroy() {
3082
2357
  this.abortDeferredInit();
2358
+ if (this.wearablesAutoSyncHandle) {
2359
+ await this.wearablesAutoSyncHandle.stop();
2360
+ this.wearablesAutoSyncHandle = null;
2361
+ }
3083
2362
  if (this.qmdMaintenanceTimer) {
3084
2363
  clearTimeout(this.qmdMaintenanceTimer);
3085
2364
  this.qmdMaintenanceTimer = null;
@@ -3324,7 +2603,7 @@ var Orchestrator = class _Orchestrator {
3324
2603
  this.config = config;
3325
2604
  this.profiler = new ProfilingCollector({
3326
2605
  enabled: config.profilingEnabled,
3327
- storageDir: config.profilingStorageDir || path3.join(config.memoryDir, "profiling"),
2606
+ storageDir: config.profilingStorageDir || path2.join(config.memoryDir, "profiling"),
3328
2607
  maxTraces: config.profilingMaxTraces
3329
2608
  });
3330
2609
  this.storageRouter = new NamespaceStorageRouter(config);
@@ -3359,7 +2638,7 @@ var Orchestrator = class _Orchestrator {
3359
2638
  this.compounding = config.compoundingEnabled ? new CompoundingEngine(config, this.storage) : void 0;
3360
2639
  this.buffer = new SmartBuffer(config, this.storage);
3361
2640
  this.transcript = new TranscriptManager(config);
3362
- this.conversationIndexDir = path3.join(
2641
+ this.conversationIndexDir = path2.join(
3363
2642
  config.memoryDir,
3364
2643
  "conversation-index",
3365
2644
  "chunks"
@@ -3416,7 +2695,7 @@ var Orchestrator = class _Orchestrator {
3416
2695
  this.modelRegistry
3417
2696
  );
3418
2697
  this.threading = new ThreadingManager(
3419
- path3.join(config.memoryDir, "threads"),
2698
+ path2.join(config.memoryDir, "threads"),
3420
2699
  config.threadingGapMinutes
3421
2700
  );
3422
2701
  this.tmtBuilder = new TmtBuilder(config.memoryDir, {
@@ -3714,7 +2993,7 @@ var Orchestrator = class _Orchestrator {
3714
2993
  const files = await readdir(wsDir).catch(() => []);
3715
2994
  for (const f of files) {
3716
2995
  if (!f.startsWith(".compaction-reset-signal-")) continue;
3717
- const fp = path3.join(wsDir, f);
2996
+ const fp = path2.join(wsDir, f);
3718
2997
  const s = await stat(fp).catch(() => null);
3719
2998
  if (s && Date.now() - s.mtimeMs >= COMPACTION_SIGNAL_MAX_AGE_MS) {
3720
2999
  await unlink(fp).catch(() => {
@@ -3969,6 +3248,36 @@ var Orchestrator = class _Orchestrator {
3969
3248
  log.warn(`first-start lifecycle migration failed (non-fatal): ${err}`);
3970
3249
  }
3971
3250
  }
3251
+ if (signal.aborted) return;
3252
+ if (!this.wearablesAutoSyncHandle && this.config.wearables.enabled && this.config.wearables.autoSyncEnabled && Object.values(this.config.wearables.sources).some((source) => source.enabled)) {
3253
+ try {
3254
+ const { startWearablesAutoSync } = await import("./auto-sync-RFADEHIQ.js");
3255
+ if (signal.aborted) return;
3256
+ this.wearablesAutoSyncHandle = startWearablesAutoSync(
3257
+ {
3258
+ intervalMinutes: this.config.wearables.autoSyncIntervalMinutes,
3259
+ days: this.config.wearables.autoSyncDays,
3260
+ deepDays: this.config.wearables.autoSyncDeepDays,
3261
+ ...this.config.wearables.timezone !== void 0 ? { timezone: this.config.wearables.timezone } : {}
3262
+ },
3263
+ {
3264
+ sync: (options) => this.getWearablesService().sync(options),
3265
+ log: {
3266
+ info: (message) => log.info(message),
3267
+ warn: (message) => log.warn(message)
3268
+ }
3269
+ }
3270
+ );
3271
+ log.info(
3272
+ `wearables auto-sync started: every ${this.config.wearables.autoSyncIntervalMinutes}m over ${this.config.wearables.autoSyncDays}d (deep ${this.config.wearables.autoSyncDeepDays}d daily)`
3273
+ );
3274
+ } catch (err) {
3275
+ const { displayErrorDetail } = await import("./runtime/better-sqlite.js");
3276
+ log.warn(
3277
+ `wearables auto-sync failed to start (non-fatal): ${displayErrorDetail(err)}`
3278
+ );
3279
+ }
3280
+ }
3972
3281
  log.info("orchestrator initialized (full \u2014 deferred steps complete)");
3973
3282
  }
3974
3283
  /**
@@ -4076,7 +3385,7 @@ var Orchestrator = class _Orchestrator {
4076
3385
  */
4077
3386
  async autoRegisterDaySummaryCron() {
4078
3387
  const home = resolveHomeDir();
4079
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
3388
+ const jobsPath = path2.join(home, ".openclaw", "cron", "jobs.json");
4080
3389
  try {
4081
3390
  if (!existsSync(jobsPath)) {
4082
3391
  log.debug(
@@ -4100,7 +3409,7 @@ var Orchestrator = class _Orchestrator {
4100
3409
  }
4101
3410
  async autoRegisterNightlyGovernanceCron() {
4102
3411
  const home = resolveHomeDir();
4103
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
3412
+ const jobsPath = path2.join(home, ".openclaw", "cron", "jobs.json");
4104
3413
  try {
4105
3414
  if (!existsSync(jobsPath)) {
4106
3415
  log.debug("nightly governance cron: jobs.json not found, skipping auto-register");
@@ -4122,7 +3431,7 @@ var Orchestrator = class _Orchestrator {
4122
3431
  }
4123
3432
  async autoRegisterProceduralMiningCron() {
4124
3433
  const home = resolveHomeDir();
4125
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
3434
+ const jobsPath = path2.join(home, ".openclaw", "cron", "jobs.json");
4126
3435
  try {
4127
3436
  if (!existsSync(jobsPath)) {
4128
3437
  log.debug("procedural mining cron: jobs.json not found, skipping auto-register");
@@ -4142,7 +3451,7 @@ var Orchestrator = class _Orchestrator {
4142
3451
  }
4143
3452
  async autoRegisterContradictionScanCron() {
4144
3453
  const home = resolveHomeDir();
4145
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
3454
+ const jobsPath = path2.join(home, ".openclaw", "cron", "jobs.json");
4146
3455
  try {
4147
3456
  if (!existsSync(jobsPath)) {
4148
3457
  log.debug("contradiction scan cron: jobs.json not found, skipping auto-register");
@@ -4162,7 +3471,7 @@ var Orchestrator = class _Orchestrator {
4162
3471
  }
4163
3472
  async autoRegisterPatternReinforcementCron() {
4164
3473
  const home = resolveHomeDir();
4165
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
3474
+ const jobsPath = path2.join(home, ".openclaw", "cron", "jobs.json");
4166
3475
  try {
4167
3476
  if (!existsSync(jobsPath)) {
4168
3477
  log.debug("pattern reinforcement cron: jobs.json not found, skipping auto-register");
@@ -4224,7 +3533,7 @@ var Orchestrator = class _Orchestrator {
4224
3533
  }
4225
3534
  async autoRegisterGraphEdgeDecayCron() {
4226
3535
  const home = resolveHomeDir();
4227
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
3536
+ const jobsPath = path2.join(home, ".openclaw", "cron", "jobs.json");
4228
3537
  try {
4229
3538
  if (!existsSync(jobsPath)) {
4230
3539
  log.debug("graph edge decay cron: jobs.json not found, skipping auto-register");
@@ -4281,15 +3590,15 @@ ${doc.content}` : doc.content,
4281
3590
  this.lastFileHygieneRunAtMs = now;
4282
3591
  if (hygiene.rotateEnabled) {
4283
3592
  for (const rel of hygiene.rotatePaths) {
4284
- const abs = path3.isAbsolute(rel) ? rel : path3.join(this.config.workspaceDir, rel);
3593
+ const abs = path2.isAbsolute(rel) ? rel : path2.join(this.config.workspaceDir, rel);
4285
3594
  try {
4286
3595
  const raw = await readFile2(abs, "utf-8");
4287
3596
  if (raw.length > hygiene.rotateMaxBytes) {
4288
- const archiveDir = path3.join(
3597
+ const archiveDir = path2.join(
4289
3598
  this.config.workspaceDir,
4290
3599
  hygiene.archiveDir
4291
3600
  );
4292
- const base = path3.basename(abs);
3601
+ const base = path2.basename(abs);
4293
3602
  const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
4294
3603
  const { newContent } = await rotateMarkdownFileToArchive({
4295
3604
  filePath: abs,
@@ -4314,8 +3623,8 @@ ${doc.content}` : doc.content,
4314
3623
  log.warn(w.message);
4315
3624
  }
4316
3625
  if (hygiene.warningsLogEnabled && warnings.length > 0) {
4317
- const fp = path3.join(this.config.memoryDir, hygiene.warningsLogPath);
4318
- await mkdir2(path3.dirname(fp), { recursive: true });
3626
+ const fp = path2.join(this.config.memoryDir, hygiene.warningsLogPath);
3627
+ await mkdir2(path2.dirname(fp), { recursive: true });
4319
3628
  const stamp = (/* @__PURE__ */ new Date()).toISOString();
4320
3629
  const block = `
4321
3630
 
@@ -4784,16 +4093,16 @@ ${evidenceText}`
4784
4093
  const datesToScan = [yesterday, utcToday].filter(
4785
4094
  (v, i, a) => a.indexOf(v) === i
4786
4095
  );
4787
- const factsBaseDir = path3.join(storage.dir, "facts");
4096
+ const factsBaseDir = path2.join(storage.dir, "facts");
4788
4097
  const MAX_CHARS = 1e5;
4789
4098
  const facts = [];
4790
4099
  for (const date of datesToScan) {
4791
- const factsDir = path3.join(factsBaseDir, date);
4100
+ const factsDir = path2.join(factsBaseDir, date);
4792
4101
  try {
4793
4102
  const entries = await readdir(factsDir, { withFileTypes: true });
4794
4103
  for (const entry of entries) {
4795
4104
  if (!entry.name.endsWith(".md")) continue;
4796
- const fullPath = path3.join(factsDir, entry.name);
4105
+ const fullPath = path2.join(factsDir, entry.name);
4797
4106
  try {
4798
4107
  const raw = await readFile2(fullPath, "utf-8");
4799
4108
  const fmMatch = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
@@ -4809,7 +4118,7 @@ ${evidenceText}`
4809
4118
  facts.push({
4810
4119
  path: fullPath,
4811
4120
  frontmatter: {
4812
- id: fm.id || path3.basename(entry.name, ".md"),
4121
+ id: fm.id || path2.basename(entry.name, ".md"),
4813
4122
  category: fm.category || "fact",
4814
4123
  created: fm.created || "unknown",
4815
4124
  updated: fm.updated || fm.created || "unknown",
@@ -4830,13 +4139,13 @@ ${evidenceText}`
4830
4139
  (a, b) => a.frontmatter.created < b.frontmatter.created ? -1 : 1
4831
4140
  );
4832
4141
  const hourlySummaries = [];
4833
- const hourlyBaseDir = path3.join(storage.dir, "summaries", "hourly");
4142
+ const hourlyBaseDir = path2.join(storage.dir, "summaries", "hourly");
4834
4143
  try {
4835
4144
  const sessionKeys = await readdir(hourlyBaseDir, { withFileTypes: true });
4836
4145
  for (const sk of sessionKeys) {
4837
4146
  if (!sk.isDirectory()) continue;
4838
4147
  for (const date of datesToScan) {
4839
- const summaryFile = path3.join(hourlyBaseDir, sk.name, `${date}.md`);
4148
+ const summaryFile = path2.join(hourlyBaseDir, sk.name, `${date}.md`);
4840
4149
  try {
4841
4150
  const raw = await readFile2(summaryFile, "utf-8");
4842
4151
  if (raw.trim().length > 0) {
@@ -4934,7 +4243,7 @@ ${evidenceText}`
4934
4243
  }
4935
4244
  async getLastGraphRecallSnapshot(namespace) {
4936
4245
  const storage = await this.getStorage(namespace);
4937
- const snapshotPath = path3.join(
4246
+ const snapshotPath = path2.join(
4938
4247
  storage.dir,
4939
4248
  "state",
4940
4249
  "last_graph_recall.json"
@@ -4973,7 +4282,7 @@ ${evidenceText}`
4973
4282
  }
4974
4283
  async getLastIntentSnapshot(namespace) {
4975
4284
  const storage = await this.getStorage(namespace);
4976
- const snapshotPath = path3.join(storage.dir, "state", "last_intent.json");
4285
+ const snapshotPath = path2.join(storage.dir, "state", "last_intent.json");
4977
4286
  try {
4978
4287
  const raw = await readFile2(snapshotPath, "utf-8");
4979
4288
  const parsed = JSON.parse(raw);
@@ -5006,7 +4315,7 @@ ${evidenceText}`
5006
4315
  }
5007
4316
  async getLastQmdRecallSnapshot(namespace) {
5008
4317
  const storage = await this.getStorage(namespace);
5009
- const snapshotPath = path3.join(
4318
+ const snapshotPath = path2.join(
5010
4319
  storage.dir,
5011
4320
  "state",
5012
4321
  "last_qmd_recall.json"
@@ -5159,7 +4468,7 @@ ${r.snippet.trim()}
5159
4468
  const entries = await readdir(dir, { withFileTypes: true });
5160
4469
  let total = 0;
5161
4470
  for (const entry of entries) {
5162
- const fullPath = path3.join(dir, entry.name);
4471
+ const fullPath = path2.join(dir, entry.name);
5163
4472
  if (entry.isDirectory()) {
5164
4473
  total += await this.countConversationChunkDocs(fullPath);
5165
4474
  continue;
@@ -6055,7 +5364,7 @@ ${r.snippet.trim()}
6055
5364
  0
6056
5365
  );
6057
5366
  seedPaths.push(
6058
- ...seedRelativePaths.map((rel) => path3.join(storage.dir, rel))
5367
+ ...seedRelativePaths.map((rel) => path2.join(storage.dir, rel))
6059
5368
  );
6060
5369
  const seedSet = new Set(seedRelativePaths);
6061
5370
  const expanded = await this.graphIndexFor(storage).spreadingActivation(
@@ -6066,7 +5375,7 @@ ${r.snippet.trim()}
6066
5375
  if (expanded.length === 0) continue;
6067
5376
  for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
6068
5377
  if (seedSet.has(candidate.path)) continue;
6069
- const memoryPath = path3.resolve(storage.dir, candidate.path);
5378
+ const memoryPath = path2.resolve(storage.dir, candidate.path);
6070
5379
  const memory = await storage.readMemoryByPath(memoryPath);
6071
5380
  if (!memory) continue;
6072
5381
  if (isArtifactMemoryPath(memory.path)) continue;
@@ -6090,7 +5399,7 @@ ${r.snippet.trim()}
6090
5399
  path: memory.path,
6091
5400
  score,
6092
5401
  namespace,
6093
- seed: path3.resolve(storage.dir, candidate.seed),
5402
+ seed: path2.resolve(storage.dir, candidate.seed),
6094
5403
  hopDepth: candidate.hopDepth,
6095
5404
  decayedWeight: candidate.decayedWeight,
6096
5405
  graphType: candidate.graphType,
@@ -6111,12 +5420,12 @@ ${r.snippet.trim()}
6111
5420
  }
6112
5421
  async recordLastGraphRecallSnapshot(options) {
6113
5422
  try {
6114
- const snapshotPath = path3.join(
5423
+ const snapshotPath = path2.join(
6115
5424
  options.storage.dir,
6116
5425
  "state",
6117
5426
  "last_graph_recall.json"
6118
5427
  );
6119
- await mkdir2(path3.dirname(snapshotPath), { recursive: true });
5428
+ await mkdir2(path2.dirname(snapshotPath), { recursive: true });
6120
5429
  const now = (/* @__PURE__ */ new Date()).toISOString();
6121
5430
  const totalSeedCount = options.seedPaths.length;
6122
5431
  const totalExpandedCount = options.expandedPaths.length;
@@ -6150,12 +5459,12 @@ ${r.snippet.trim()}
6150
5459
  }
6151
5460
  async recordLastIntentSnapshot(options) {
6152
5461
  try {
6153
- const snapshotPath = path3.join(
5462
+ const snapshotPath = path2.join(
6154
5463
  options.storage.dir,
6155
5464
  "state",
6156
5465
  "last_intent.json"
6157
5466
  );
6158
- await mkdir2(path3.dirname(snapshotPath), { recursive: true });
5467
+ await mkdir2(path2.dirname(snapshotPath), { recursive: true });
6159
5468
  await writeFile2(
6160
5469
  snapshotPath,
6161
5470
  JSON.stringify(options.snapshot, null, 2),
@@ -6167,12 +5476,12 @@ ${r.snippet.trim()}
6167
5476
  }
6168
5477
  async recordLastQmdRecallSnapshot(options) {
6169
5478
  try {
6170
- const snapshotPath = path3.join(
5479
+ const snapshotPath = path2.join(
6171
5480
  options.storage.dir,
6172
5481
  "state",
6173
5482
  "last_qmd_recall.json"
6174
5483
  );
6175
- await mkdir2(path3.dirname(snapshotPath), { recursive: true });
5484
+ await mkdir2(path2.dirname(snapshotPath), { recursive: true });
6176
5485
  await writeFile2(
6177
5486
  snapshotPath,
6178
5487
  JSON.stringify(options.snapshot, null, 2),
@@ -6187,8 +5496,8 @@ ${r.snippet.trim()}
6187
5496
  const stateDir = await this.resolveStateDirForNamespace(
6188
5497
  options.namespace
6189
5498
  );
6190
- const snapshotPath = path3.join(stateDir, "last_intent.json");
6191
- await mkdir2(path3.dirname(snapshotPath), { recursive: true });
5499
+ const snapshotPath = path2.join(stateDir, "last_intent.json");
5500
+ await mkdir2(path2.dirname(snapshotPath), { recursive: true });
6192
5501
  await writeFile2(
6193
5502
  snapshotPath,
6194
5503
  JSON.stringify(options.snapshot, null, 2),
@@ -6200,12 +5509,12 @@ ${r.snippet.trim()}
6200
5509
  }
6201
5510
  async resolveStateDirForNamespace(namespace) {
6202
5511
  if (!this.config.namespacesEnabled) {
6203
- return path3.join(this.config.memoryDir, "state");
5512
+ return path2.join(this.config.memoryDir, "state");
6204
5513
  }
6205
5514
  if (namespace !== this.config.defaultNamespace) {
6206
- return path3.join(this.config.memoryDir, "namespaces", namespace, "state");
5515
+ return path2.join(this.config.memoryDir, "namespaces", namespace, "state");
6207
5516
  }
6208
- const candidate = path3.join(
5517
+ const candidate = path2.join(
6209
5518
  this.config.memoryDir,
6210
5519
  "namespaces",
6211
5520
  this.config.defaultNamespace
@@ -6213,11 +5522,11 @@ ${r.snippet.trim()}
6213
5522
  try {
6214
5523
  const candidateStat = await stat(candidate);
6215
5524
  if (candidateStat.isDirectory()) {
6216
- return path3.join(candidate, "state");
5525
+ return path2.join(candidate, "state");
6217
5526
  }
6218
5527
  } catch {
6219
5528
  }
6220
- return path3.join(this.config.memoryDir, "state");
5529
+ return path2.join(this.config.memoryDir, "state");
6221
5530
  }
6222
5531
  buildGraphRecallRankedResults(results, sourceLabelResolver, limit = 64) {
6223
5532
  return results.slice(0, limit).map((result) => ({
@@ -6603,7 +5912,7 @@ ${r.snippet.trim()}
6603
5912
  const graphExpandedResultPaths = /* @__PURE__ */ new Set();
6604
5913
  const graphSourceLabelsForPath = (resultPath) => {
6605
5914
  const labels = [];
6606
- const normalizedPath = resultPath.split(path3.sep).join("/");
5915
+ const normalizedPath = resultPath.split(path2.sep).join("/");
6607
5916
  const isEntityPath = normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/");
6608
5917
  if (graphBaselinePaths.has(resultPath)) labels.push("baseline");
6609
5918
  if (graphExpandedResultPaths.has(resultPath))
@@ -7918,11 +7227,11 @@ ${formatted}`;
7918
7227
  if (!this.config.compactionResetEnabled) return null;
7919
7228
  const workspaceDir = compactionWorkspaceDir || this.config.workspaceDir || defaultWorkspaceDir();
7920
7229
  const safeSessionKey = sanitizeSessionKeyForFilename(effectiveSessionKey);
7921
- const signalPath = path3.join(
7230
+ const signalPath = path2.join(
7922
7231
  workspaceDir,
7923
7232
  `.compaction-reset-signal-${safeSessionKey}`
7924
7233
  );
7925
- const bootPath = path3.join(workspaceDir, "BOOT.md");
7234
+ const bootPath = path2.join(workspaceDir, "BOOT.md");
7926
7235
  try {
7927
7236
  const signalStat = await stat(signalPath).catch(() => null);
7928
7237
  if (!signalStat) return null;
@@ -9798,6 +9107,21 @@ _Context: ${topQuestion.context}_`
9798
9107
  config: this.config.wearables,
9799
9108
  getStorage: async () => await this.getStorageForNamespace(this.bulkImportWriteNamespace()),
9800
9109
  extract: (turns) => this.extraction.extract(turns),
9110
+ // Smart memoryMode runs candidates through the SAME extraction
9111
+ // judge (cache + defer counters included) the live extraction
9112
+ // pipeline uses, so wearable facts get identical LLM-as-judge
9113
+ // durability gating.
9114
+ judgeFacts: (candidates) => judgeFactDurability(
9115
+ candidates,
9116
+ this.config,
9117
+ this.localLlm,
9118
+ new FallbackLlmClient(
9119
+ this.config.gatewayConfig,
9120
+ fallbackLlmRuntimeContextFromConfig(this.config)
9121
+ ),
9122
+ this.judgeVerdictCache,
9123
+ this.judgeDeferCounts
9124
+ ),
9801
9125
  searchBackend: {
9802
9126
  search: async (query, maxResults) => {
9803
9127
  if (!this.qmd.isAvailable()) return null;
@@ -10388,7 +9712,7 @@ ${normalized}`).digest("hex");
10388
9712
  );
10389
9713
  this.tierMigrationInFlight = true;
10390
9714
  try {
10391
- const coldStorage = new StorageManager(path3.join(storage.dir, "cold"));
9715
+ const coldStorage = new StorageManager(path2.join(storage.dir, "cold"));
10392
9716
  const [hotMemories, coldMemories] = await Promise.all([
10393
9717
  storage.readAllMemories(),
10394
9718
  coldStorage.readAllMemories()
@@ -11591,7 +10915,7 @@ ${normalized}`).digest("hex");
11591
10915
  const allMems = allMemsForGraph ?? [];
11592
10916
  for (const m of allMems) {
11593
10917
  if (m.frontmatter.entityRef === entityRef) {
11594
- const rel = path3.relative(storage.dir, m.path);
10918
+ const rel = path2.relative(storage.dir, m.path);
11595
10919
  if (rel !== memoryRelPath) entitySiblings.push(rel);
11596
10920
  }
11597
10921
  }
@@ -11891,7 +11215,7 @@ ${normalized}`).digest("hex");
11891
11215
  }
11892
11216
  if (this.config.semanticConsolidationEnabled) {
11893
11217
  try {
11894
- const stateFilePath = path3.join(
11218
+ const stateFilePath = path2.join(
11895
11219
  this.config.memoryDir,
11896
11220
  "state",
11897
11221
  "semantic-consolidation-last-run.json"
@@ -11939,7 +11263,7 @@ ${normalized}`).digest("hex");
11939
11263
  );
11940
11264
  }
11941
11265
  if (semResult.errors === 0 || semResult.memoriesArchived > 0) {
11942
- const stateDir = path3.join(this.config.memoryDir, "state");
11266
+ const stateDir = path2.join(this.config.memoryDir, "state");
11943
11267
  await mkdir2(stateDir, { recursive: true });
11944
11268
  await writeFile2(
11945
11269
  stateFilePath,
@@ -12434,12 +11758,12 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
12434
11758
  protectedCategories: this.config.lifecycleProtectedCategories
12435
11759
  }
12436
11760
  };
12437
- const metricsPath = path3.join(
11761
+ const metricsPath = path2.join(
12438
11762
  storage.dir,
12439
11763
  "state",
12440
11764
  "lifecycle-metrics.json"
12441
11765
  );
12442
- await mkdir2(path3.dirname(metricsPath), { recursive: true });
11766
+ await mkdir2(path2.dirname(metricsPath), { recursive: true });
12443
11767
  await writeFile2(metricsPath, JSON.stringify(metrics, null, 2), "utf-8");
12444
11768
  }
12445
11769
  /**
@@ -12967,7 +12291,7 @@ ${lines.join("\n\n")}`;
12967
12291
  nsMap = buildMemoryWorthCounterMap(memories);
12968
12292
  this.memoryWorthCounterCache.set(ns, { at: nowMs, counters: nsMap });
12969
12293
  }
12970
- for (const [path4, c] of nsMap) counters.set(path4, c);
12294
+ for (const [path3, c] of nsMap) counters.set(path3, c);
12971
12295
  } catch (err) {
12972
12296
  log.debug("memory-worth: failed to read namespace, skipping", {
12973
12297
  namespace: ns,
@@ -13138,12 +12462,12 @@ ${lines.join("\n\n")}`;
13138
12462
  */
13139
12463
  semanticDedupScopeFor(targetStorage) {
13140
12464
  if (!this.config.namespacesEnabled) return {};
13141
- const memoryDir = path3.resolve(this.config.memoryDir);
13142
- const storageDir = path3.resolve(targetStorage.dir);
12465
+ const memoryDir = path2.resolve(this.config.memoryDir);
12466
+ const storageDir = path2.resolve(targetStorage.dir);
13143
12467
  if (storageDir === memoryDir) {
13144
12468
  return { pathExcludePrefixes: ["namespaces/"] };
13145
12469
  }
13146
- let rel = path3.relative(memoryDir, storageDir);
12470
+ let rel = path2.relative(memoryDir, storageDir);
13147
12471
  if (!rel || rel.startsWith("..")) {
13148
12472
  log.debug(
13149
12473
  `semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
@@ -13162,7 +12486,7 @@ ${lines.join("\n\n")}`;
13162
12486
  if (hits.length === 0) return [];
13163
12487
  const results = [];
13164
12488
  for (const hit of hits) {
13165
- const fullPath = path3.isAbsolute(hit.path) ? hit.path : path3.join(this.config.memoryDir, hit.path);
12489
+ const fullPath = path2.isAbsolute(hit.path) ? hit.path : path2.join(this.config.memoryDir, hit.path);
13166
12490
  const memory = await this.storage.readMemoryByPath(fullPath);
13167
12491
  if (!memory) continue;
13168
12492
  results.push({
@@ -13805,8 +13129,8 @@ ${lines.join("\n\n")}`;
13805
13129
  }
13806
13130
  namespaceFromStorageDir(storageDir) {
13807
13131
  if (!this.config.namespacesEnabled) return this.config.defaultNamespace;
13808
- const resolvedStorageDir = path3.resolve(storageDir);
13809
- const resolvedMemoryDir = path3.resolve(this.config.memoryDir);
13132
+ const resolvedStorageDir = path2.resolve(storageDir);
13133
+ const resolvedMemoryDir = path2.resolve(this.config.memoryDir);
13810
13134
  if (resolvedStorageDir === resolvedMemoryDir)
13811
13135
  return this.config.defaultNamespace;
13812
13136
  const m = resolvedStorageDir.match(/[\\/]namespaces[\\/]([^\\/]+)$/);
@@ -13846,27 +13170,6 @@ export {
13846
13170
  saveTaxonomy,
13847
13171
  getTaxonomyDir,
13848
13172
  getTaxonomyFilePath,
13849
- memoryStatusForMode,
13850
- WEARABLE_SOURCE_PREFIX,
13851
- wearableSourceLabel,
13852
- wearableDayTag,
13853
- buildExtractionTurns,
13854
- generateWearableMemories,
13855
- writeDailyDigestMemory,
13856
- importNativeMemories,
13857
- cleanConversation,
13858
- stripFillerTokens,
13859
- collapseImmediateRepeats,
13860
- isLowQualitySegment,
13861
- syncStateFilePath,
13862
- emptySyncState,
13863
- loadSyncState,
13864
- saveSyncState,
13865
- updateSourceSyncState,
13866
- dateInTimezone,
13867
- resolveSyncDates,
13868
- syncWearableSource,
13869
- defaultTimezone,
13870
13173
  registerWearableConnector,
13871
13174
  getWearableConnector,
13872
13175
  listWearableConnectors,
@@ -13903,4 +13206,4 @@ export {
13903
13206
  resolvePersistedMemoryRelativePath,
13904
13207
  Orchestrator
13905
13208
  };
13906
- //# sourceMappingURL=chunk-3GLCUPXP.js.map
13209
+ //# sourceMappingURL=chunk-WLZBVYC6.js.map