@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
@@ -0,0 +1,1164 @@
1
+ import {
2
+ getVerdictKind
3
+ } from "./chunk-K47C6M2C.js";
4
+ import {
5
+ scoreImportance
6
+ } from "./chunk-JXS5PDQ7.js";
7
+ import {
8
+ applyCorrections,
9
+ applyOffTheRecord,
10
+ compileCorrectionRules,
11
+ compileRedactionPatterns,
12
+ loadCorrectionsFile,
13
+ redactText
14
+ } from "./chunk-NDAH7BJ5.js";
15
+ import {
16
+ WearablesInputError,
17
+ describeErrorForOperator
18
+ } from "./chunk-7WV3F5DQ.js";
19
+ import {
20
+ composeDayTranscriptBody,
21
+ composeDayTranscriptMeta,
22
+ hashTranscriptBody,
23
+ isValidTranscriptDate,
24
+ loadSpeakerRegistry,
25
+ resolveSpeaker,
26
+ serializeDayTranscript
27
+ } from "./chunk-M7XQSUBB.js";
28
+ import {
29
+ countRecallTokenOverlap,
30
+ normalizeRecallTokens
31
+ } from "./chunk-ZBJMUXZH.js";
32
+
33
+ // src/wearables/trust.ts
34
+ var TRUST_JUDGE_ACCEPT_BOOST = 0.15;
35
+ var TRUST_CROSS_SOURCE_BOOST = 0.15;
36
+ var TRUST_SUPPORTING_MEMORY_BOOST = 0.1;
37
+ var MIN_FACT_TOKENS = 4;
38
+ var CROSS_SOURCE_COVERAGE = 0.6;
39
+ var MEMORY_SUPPORT_COVERAGE = 0.7;
40
+ var MAX_MEMORIES_SCANNED = 5e3;
41
+ function computeTrustScore(input) {
42
+ const confidence = typeof input.extractionConfidence === "number" && Number.isFinite(input.extractionConfidence) ? Math.min(1, Math.max(0, input.extractionConfidence)) : 0.7;
43
+ let trust = confidence * Math.min(1, Math.max(0, input.sourceTrust));
44
+ if (input.judgeVerdict === "accept") trust += TRUST_JUDGE_ACCEPT_BOOST;
45
+ if (input.evidence.corroboratedBySources.length > 0) {
46
+ trust += TRUST_CROSS_SOURCE_BOOST;
47
+ }
48
+ if (input.evidence.supportingMemoryId !== void 0) {
49
+ trust += TRUST_SUPPORTING_MEMORY_BOOST;
50
+ }
51
+ return Math.min(1, Math.max(0, trust));
52
+ }
53
+ function tokenizeDayBody(body) {
54
+ return new Set(normalizeRecallTokens(body));
55
+ }
56
+ function findCorroboration(factText, context) {
57
+ const factTokens = normalizeRecallTokens(factText);
58
+ const evidence = { corroboratedBySources: [] };
59
+ if (factTokens.length < MIN_FACT_TOKENS) return evidence;
60
+ const factTokenSet = new Set(factTokens);
61
+ for (const [sourceId, dayTokens] of context.otherSourceDayTokens) {
62
+ let matches = 0;
63
+ for (const token of factTokenSet) {
64
+ if (dayTokens.has(token)) matches += 1;
65
+ }
66
+ if (matches / factTokenSet.size >= CROSS_SOURCE_COVERAGE) {
67
+ evidence.corroboratedBySources.push(sourceId);
68
+ }
69
+ }
70
+ evidence.corroboratedBySources.sort();
71
+ let scanned = 0;
72
+ for (const memory of context.existingMemories) {
73
+ if (scanned >= MAX_MEMORIES_SCANNED) break;
74
+ scanned += 1;
75
+ const matches = countRecallTokenOverlap(factTokenSet, memory.content);
76
+ if (matches / factTokenSet.size >= MEMORY_SUPPORT_COVERAGE) {
77
+ evidence.supportingMemoryId = memory.id;
78
+ break;
79
+ }
80
+ }
81
+ return evidence;
82
+ }
83
+ function decideSmart(trust, judgeVerdict, thresholds) {
84
+ if (judgeVerdict === "reject") {
85
+ return { outcome: "drop", reason: "judge-rejected", trust };
86
+ }
87
+ if (judgeVerdict === "defer") {
88
+ return { outcome: "review", reason: "judge-deferred", trust };
89
+ }
90
+ if (trust >= thresholds.autoApproveTrust) {
91
+ return { outcome: "active", reason: "auto-approved", trust };
92
+ }
93
+ if (trust >= thresholds.reviewTrust) {
94
+ return { outcome: "review", reason: "queued-for-review", trust };
95
+ }
96
+ return { outcome: "drop", reason: "below-trust", trust };
97
+ }
98
+
99
+ // src/wearables/memory-gen.ts
100
+ function memoryStatusForMode(mode) {
101
+ return mode === "auto" || mode === "smart" ? "active" : "pending_review";
102
+ }
103
+ var WEARABLE_SOURCE_PREFIX = "wearable";
104
+ function wearableSourceLabel(sourceId) {
105
+ return `${WEARABLE_SOURCE_PREFIX}:${sourceId}`;
106
+ }
107
+ function wearableDayTag(date) {
108
+ return `wearable-day:${date}`;
109
+ }
110
+ var IMPORTANCE_RANK = {
111
+ trivial: 0,
112
+ low: 1,
113
+ normal: 2,
114
+ high: 3,
115
+ critical: 4
116
+ };
117
+ var MAX_EXTRACTION_CHUNK_CHARS = 6e3;
118
+ var MIN_CONVERSATION_CHARS = 80;
119
+ function buildExtractionTurns(sourceId, date, conversation, registry) {
120
+ const headerParts = [
121
+ `Wearable transcript (${sourceId}) \u2014 ${date}`,
122
+ conversation.title ? `"${conversation.title}"` : void 0,
123
+ conversation.location ? `at ${conversation.location}` : void 0
124
+ ].filter((part) => typeof part === "string");
125
+ const header = `[${headerParts.join(" \u2014 ")}]`;
126
+ const lines = [];
127
+ for (const segment of conversation.segments) {
128
+ const { label } = resolveSpeaker(sourceId, segment, registry);
129
+ lines.push(`${label}: ${segment.text}`);
130
+ }
131
+ const transcript = lines.join("\n");
132
+ if (transcript.trim().length < MIN_CONVERSATION_CHARS) return [];
133
+ const sessionKey = `wearables:${sourceId}:${date}:${conversation.id}`;
134
+ const timestamp = conversation.startIso;
135
+ const turns = [];
136
+ let chunkLines = [];
137
+ let chunkChars = 0;
138
+ const flush = () => {
139
+ if (chunkLines.length === 0) return;
140
+ turns.push({
141
+ role: "user",
142
+ content: `${header}
143
+ ${chunkLines.join("\n")}`,
144
+ timestamp,
145
+ sourceValidAt: timestamp,
146
+ sessionKey
147
+ });
148
+ chunkLines = [];
149
+ chunkChars = 0;
150
+ };
151
+ for (const line of transcript.split("\n")) {
152
+ if (chunkChars + line.length + 1 > MAX_EXTRACTION_CHUNK_CHARS) flush();
153
+ chunkLines.push(line);
154
+ chunkChars += line.length + 1;
155
+ }
156
+ flush();
157
+ return turns;
158
+ }
159
+ async function scoreCandidates(novel, settings, deps, result) {
160
+ const scored = /* @__PURE__ */ new Map();
161
+ if (novel.length === 0) return scored;
162
+ let verdicts;
163
+ if (deps.judgeFacts) {
164
+ const judgeCandidates = novel.map((candidate) => ({
165
+ text: candidate.fact.content,
166
+ category: candidate.fact.category,
167
+ confidence: typeof candidate.fact.confidence === "number" ? candidate.fact.confidence : 0.7,
168
+ tags: candidate.fact.tags ?? [],
169
+ importanceLevel: candidate.importance.level
170
+ }));
171
+ try {
172
+ const judgeResult = await deps.judgeFacts(judgeCandidates);
173
+ verdicts = /* @__PURE__ */ new Map();
174
+ for (const [index, verdict] of judgeResult.verdicts) {
175
+ verdicts.set(index, getVerdictKind(verdict));
176
+ }
177
+ } catch (err) {
178
+ result.warnings.push(
179
+ `extraction judge unavailable for this pass: ${describeErrorForOperator(err)} \u2014 trust scoring continued without judge verdicts`
180
+ );
181
+ }
182
+ }
183
+ const corroboration = deps.corroboration ?? {
184
+ otherSourceDayTokens: /* @__PURE__ */ new Map(),
185
+ existingMemories: []
186
+ };
187
+ novel.forEach((candidate, index) => {
188
+ const evidence = findCorroboration(candidate.fact.content, corroboration);
189
+ const verdict = verdicts?.get(index);
190
+ const trust = computeTrustScore({
191
+ extractionConfidence: candidate.fact.confidence,
192
+ sourceTrust: settings.sourceTrust,
193
+ judgeVerdict: verdict,
194
+ evidence
195
+ });
196
+ scored.set(index, { trust, ...verdict !== void 0 ? { verdict } : {}, evidence });
197
+ });
198
+ return scored;
199
+ }
200
+ async function generateWearableMemories(sourceId, date, conversations, settings, registry, deps) {
201
+ const result = {
202
+ created: 0,
203
+ promoted: 0,
204
+ demoted: 0,
205
+ skipped: 0,
206
+ skippedByReason: {},
207
+ warnings: [],
208
+ completed: true
209
+ };
210
+ if (settings.memoryMode === "off") return result;
211
+ const skip = (reason, count = 1) => {
212
+ result.skipped += count;
213
+ result.skippedByReason[reason] = (result.skippedByReason[reason] ?? 0) + count;
214
+ };
215
+ const candidates = [];
216
+ const seenContent = /* @__PURE__ */ new Set();
217
+ for (const conversation of conversations) {
218
+ const turns = buildExtractionTurns(sourceId, date, conversation, registry);
219
+ if (turns.length === 0) continue;
220
+ let extraction;
221
+ try {
222
+ extraction = await deps.extract(turns);
223
+ } catch (err) {
224
+ result.warnings.push(
225
+ `extraction failed for ${sourceId}/${date} (conversation ${conversation.id}): ${describeErrorForOperator(err)} \u2014 the memory pass for this day retries on the next sync`
226
+ );
227
+ result.completed = false;
228
+ break;
229
+ }
230
+ for (const fact of extraction.facts) {
231
+ const content = fact.content?.trim();
232
+ if (!content) {
233
+ skip("empty");
234
+ continue;
235
+ }
236
+ if (fact.category === "procedure" || fact.category === "reasoning_trace") {
237
+ skip("unsupported-category");
238
+ continue;
239
+ }
240
+ if (settings.memoryMode !== "smart" && typeof fact.confidence === "number" && fact.confidence < settings.minConfidence) {
241
+ skip("below-confidence");
242
+ continue;
243
+ }
244
+ const importance = scoreImportance(content, fact.category, fact.tags ?? []);
245
+ if (IMPORTANCE_RANK[importance.level] < IMPORTANCE_RANK[settings.minImportance]) {
246
+ skip("below-importance");
247
+ continue;
248
+ }
249
+ const dedupKey = content.toLowerCase();
250
+ if (seenContent.has(dedupKey)) {
251
+ skip("duplicate-in-run");
252
+ continue;
253
+ }
254
+ seenContent.add(dedupKey);
255
+ candidates.push({ fact: { ...fact, content }, importance, conversation });
256
+ }
257
+ }
258
+ const novel = [];
259
+ const promotable = [];
260
+ for (const candidate of candidates) {
261
+ if (await deps.writer.hasFactContentHash(candidate.fact.content)) {
262
+ if (settings.memoryMode === "smart" && deps.writer.findWearableMemoryByContent !== void 0 && deps.writer.promoteWearableMemory !== void 0) {
263
+ promotable.push(candidate);
264
+ } else {
265
+ skip("duplicate-existing");
266
+ }
267
+ continue;
268
+ }
269
+ novel.push(candidate);
270
+ }
271
+ if (promotable.length > 0) {
272
+ const promoteScores = await scoreCandidates(promotable, settings, deps, result);
273
+ for (const [index, candidate] of promotable.entries()) {
274
+ const scored = promoteScores.get(index);
275
+ const decision = scored ? decideSmart(scored.trust, scored.verdict, settings) : void 0;
276
+ if (!scored || !decision) {
277
+ skip("duplicate-existing");
278
+ continue;
279
+ }
280
+ if (scored.verdict === "reject") {
281
+ if (deps.writer.demoteWearableMemory !== void 0) {
282
+ const existingForDemote = await deps.writer.findWearableMemoryByContent(
283
+ candidate.fact.content
284
+ );
285
+ if (existingForDemote && existingForDemote.status === "pending_review" && await deps.writer.demoteWearableMemory(existingForDemote.id, {
286
+ trustScore: scored.trust.toFixed(3),
287
+ trustDecision: "demoted-by-rejection",
288
+ judgeVerdict: "reject"
289
+ })) {
290
+ result.demoted += 1;
291
+ continue;
292
+ }
293
+ }
294
+ skip("duplicate-existing");
295
+ continue;
296
+ }
297
+ if (decision.outcome !== "active") {
298
+ skip("duplicate-existing");
299
+ continue;
300
+ }
301
+ const existing = await deps.writer.findWearableMemoryByContent(
302
+ candidate.fact.content
303
+ );
304
+ if (!existing || existing.status !== "pending_review") {
305
+ skip("duplicate-existing");
306
+ continue;
307
+ }
308
+ const promoted = await deps.writer.promoteWearableMemory(
309
+ existing.id,
310
+ {
311
+ trustScore: scored.trust.toFixed(3),
312
+ trustDecision: "promoted-by-corroboration",
313
+ ...scored.verdict !== void 0 ? { judgeVerdict: scored.verdict } : {},
314
+ ...scored.evidence.corroboratedBySources.length > 0 ? { corroboratedBySources: scored.evidence.corroboratedBySources.join(",") } : {},
315
+ ...scored.evidence.supportingMemoryId !== void 0 ? { supportingMemoryId: scored.evidence.supportingMemoryId } : {}
316
+ },
317
+ scored.trust
318
+ );
319
+ if (promoted) {
320
+ result.promoted += 1;
321
+ } else {
322
+ skip("duplicate-existing");
323
+ }
324
+ }
325
+ }
326
+ let trustById = /* @__PURE__ */ new Map();
327
+ if (settings.memoryMode === "smart") {
328
+ trustById = await scoreCandidates(novel, settings, deps, result);
329
+ }
330
+ const modeStatus = memoryStatusForMode(settings.memoryMode);
331
+ const writable = [];
332
+ novel.forEach((candidate, index) => {
333
+ if (settings.memoryMode !== "smart") {
334
+ writable.push({ candidate, index, status: modeStatus, trustAttributes: {} });
335
+ return;
336
+ }
337
+ const scored = trustById.get(index);
338
+ if (!scored) return;
339
+ const decision = decideSmart(scored.trust, scored.verdict, settings);
340
+ if (decision.outcome === "drop") {
341
+ skip(decision.reason);
342
+ return;
343
+ }
344
+ writable.push({
345
+ candidate,
346
+ index,
347
+ status: decision.outcome === "active" ? "active" : "pending_review",
348
+ trustAttributes: {
349
+ trustScore: scored.trust.toFixed(3),
350
+ trustDecision: decision.reason,
351
+ ...scored.verdict !== void 0 ? { judgeVerdict: scored.verdict } : {},
352
+ ...scored.evidence.corroboratedBySources.length > 0 ? { corroboratedBySources: scored.evidence.corroboratedBySources.join(",") } : {},
353
+ ...scored.evidence.supportingMemoryId !== void 0 ? { supportingMemoryId: scored.evidence.supportingMemoryId } : {}
354
+ }
355
+ });
356
+ });
357
+ const strength = (entry) => settings.memoryMode === "smart" ? trustById.get(entry.index)?.trust ?? 0 : entry.candidate.importance.score;
358
+ writable.sort((a, b) => {
359
+ const sa = strength(a);
360
+ const sb = strength(b);
361
+ if (sa > sb) return -1;
362
+ if (sa < sb) return 1;
363
+ if (a.candidate.fact.content < b.candidate.fact.content) return -1;
364
+ if (a.candidate.fact.content > b.candidate.fact.content) return 1;
365
+ return 0;
366
+ });
367
+ const cap = settings.maxMemoriesPerDay;
368
+ const kept = cap > 0 ? writable.slice(0, cap) : writable;
369
+ if (writable.length > kept.length) {
370
+ skip("over-day-cap", writable.length - kept.length);
371
+ }
372
+ for (const { candidate, index, status, trustAttributes } of kept) {
373
+ const tags = [
374
+ .../* @__PURE__ */ new Set([
375
+ ...candidate.fact.tags ?? [],
376
+ WEARABLE_SOURCE_PREFIX,
377
+ wearableSourceLabel(sourceId),
378
+ wearableDayTag(date)
379
+ ])
380
+ ];
381
+ await deps.writer.writeMemory(candidate.fact.category, candidate.fact.content, {
382
+ confidence: settings.memoryMode === "smart" ? trustById.get(index)?.trust : candidate.fact.confidence,
383
+ tags,
384
+ source: wearableSourceLabel(sourceId),
385
+ importance: candidate.importance,
386
+ validAt: candidate.conversation.startIso,
387
+ structuredAttributes: {
388
+ ...candidate.fact.structuredAttributes ?? {},
389
+ wearableSource: sourceId,
390
+ wearableDate: date,
391
+ wearableConversationId: candidate.conversation.id,
392
+ ...trustAttributes
393
+ },
394
+ contentHashSource: candidate.fact.content,
395
+ status
396
+ });
397
+ result.created += 1;
398
+ }
399
+ return result;
400
+ }
401
+ async function writeDailyDigestMemory(sourceId, date, conversations, settings, registry, writer) {
402
+ if (settings.memoryMode === "off") return false;
403
+ if (conversations.length === 0) return false;
404
+ const lines = conversations.map((conversation) => {
405
+ const title = conversation.title?.trim() || "Untitled conversation";
406
+ const speakers = new Set(
407
+ conversation.segments.map(
408
+ (segment) => resolveSpeaker(sourceId, segment, registry).label
409
+ )
410
+ );
411
+ return `- ${title} (${speakers.size} speaker${speakers.size === 1 ? "" : "s"})`;
412
+ });
413
+ const content = `Wearable day digest \u2014 ${sourceId}, ${date}: ${conversations.length} recorded conversation${conversations.length === 1 ? "" : "s"}.
414
+ ` + lines.join("\n");
415
+ if (await writer.hasFactContentHash(content)) return false;
416
+ await writer.writeMemory("moment", content, {
417
+ confidence: 0.9,
418
+ tags: [
419
+ WEARABLE_SOURCE_PREFIX,
420
+ wearableSourceLabel(sourceId),
421
+ wearableDayTag(date),
422
+ "daily-digest"
423
+ ],
424
+ source: wearableSourceLabel(sourceId),
425
+ importance: scoreImportance(content, "moment", ["daily-digest"]),
426
+ validAt: `${date}T00:00:00.000Z`,
427
+ structuredAttributes: {
428
+ wearableSource: sourceId,
429
+ wearableDate: date
430
+ },
431
+ contentHashSource: content,
432
+ status: memoryStatusForMode(settings.memoryMode),
433
+ memoryKind: "episode"
434
+ });
435
+ return true;
436
+ }
437
+ var NATIVE_TRUST_FACTOR = 0.9;
438
+ async function importNativeMemories(sourceId, memories, alreadyImportedIds, settings, deps) {
439
+ let imported = 0;
440
+ const importedIds = [];
441
+ const warnings = [];
442
+ const seenContent = /* @__PURE__ */ new Set();
443
+ const smart = settings.importNativeMemories === "smart";
444
+ const novel = [];
445
+ for (const memory of memories) {
446
+ const content = memory.content?.trim();
447
+ if (!content) continue;
448
+ if (alreadyImportedIds.has(memory.id)) continue;
449
+ if (seenContent.has(content) || await deps.writer.hasFactContentHash(content)) {
450
+ importedIds.push(memory.id);
451
+ continue;
452
+ }
453
+ seenContent.add(content);
454
+ novel.push({ ...memory, content });
455
+ }
456
+ let verdicts;
457
+ if (smart && deps.judgeFacts && novel.length > 0) {
458
+ try {
459
+ const judgeResult = await deps.judgeFacts(
460
+ novel.map((memory) => ({
461
+ text: memory.content,
462
+ category: "fact",
463
+ confidence: 0.7,
464
+ tags: memory.tags ?? []
465
+ }))
466
+ );
467
+ verdicts = /* @__PURE__ */ new Map();
468
+ for (const [index, verdict] of judgeResult.verdicts) {
469
+ verdicts.set(index, getVerdictKind(verdict));
470
+ }
471
+ } catch (err) {
472
+ warnings.push(
473
+ `extraction judge unavailable for native import: ${describeErrorForOperator(err)} \u2014 trust scoring continued without judge verdicts`
474
+ );
475
+ }
476
+ }
477
+ const corroboration = deps.corroboration ?? {
478
+ otherSourceDayTokens: /* @__PURE__ */ new Map(),
479
+ existingMemories: []
480
+ };
481
+ for (const [index, memory] of novel.entries()) {
482
+ const content = memory.content;
483
+ let status = "pending_review";
484
+ let trustAttributes = {};
485
+ let confidence = 0.6;
486
+ if (smart) {
487
+ const evidence = findCorroboration(content, corroboration);
488
+ const verdict = verdicts?.get(index);
489
+ const trust = computeTrustScore({
490
+ extractionConfidence: void 0,
491
+ sourceTrust: settings.sourceTrust * NATIVE_TRUST_FACTOR,
492
+ judgeVerdict: verdict,
493
+ evidence
494
+ });
495
+ const decision = decideSmart(trust, verdict, settings);
496
+ if (decision.outcome === "drop") {
497
+ continue;
498
+ }
499
+ status = decision.outcome === "active" ? "active" : "pending_review";
500
+ confidence = trust;
501
+ trustAttributes = {
502
+ trustScore: trust.toFixed(3),
503
+ trustDecision: decision.reason,
504
+ ...verdict !== void 0 ? { judgeVerdict: verdict } : {},
505
+ ...evidence.corroboratedBySources.length > 0 ? { corroboratedBySources: evidence.corroboratedBySources.join(",") } : {},
506
+ ...evidence.supportingMemoryId !== void 0 ? { supportingMemoryId: evidence.supportingMemoryId } : {}
507
+ };
508
+ }
509
+ await deps.writer.writeMemory("fact", content, {
510
+ confidence,
511
+ tags: [
512
+ .../* @__PURE__ */ new Set([
513
+ ...memory.tags ?? [],
514
+ WEARABLE_SOURCE_PREFIX,
515
+ wearableSourceLabel(sourceId),
516
+ "native-import"
517
+ ])
518
+ ],
519
+ source: `${wearableSourceLabel(sourceId)}:native`,
520
+ importance: scoreImportance(content, "fact", memory.tags ?? []),
521
+ validAt: memory.createdIso,
522
+ structuredAttributes: {
523
+ wearableSource: sourceId,
524
+ wearableNativeId: memory.id,
525
+ ...trustAttributes
526
+ },
527
+ contentHashSource: content,
528
+ status
529
+ });
530
+ imported += 1;
531
+ importedIds.push(memory.id);
532
+ }
533
+ return { imported, importedIds, warnings };
534
+ }
535
+
536
+ // src/wearables/cleanup.ts
537
+ var MERGE_GAP_MS = 3e4;
538
+ var FILLER_TOKENS = ["um", "uh", "uhm", "umm", "uhh", "erm", "hmm", "mhm"];
539
+ var FILLER_PATTERN = new RegExp(
540
+ // Leading/trailing punctuation around the filler collapses with it so
541
+ // "Um, so we should" -> "so we should" rather than ", so we should".
542
+ `(?:^|\\s)(?:${FILLER_TOKENS.join("|")})[,.]?(?=\\s|$)`,
543
+ "gi"
544
+ );
545
+ function cleanConversation(conversation, settings) {
546
+ let segments = conversation.segments.map((segment) => ({ ...segment }));
547
+ let droppedSegments = 0;
548
+ let mergedSegments = 0;
549
+ if (settings.stripFillers) {
550
+ for (const segment of segments) {
551
+ segment.text = stripFillerTokens(segment.text);
552
+ }
553
+ }
554
+ if (settings.collapseRepeats) {
555
+ for (const segment of segments) {
556
+ segment.text = collapseImmediateRepeats(segment.text);
557
+ }
558
+ }
559
+ for (const segment of segments) {
560
+ segment.text = normalizeWhitespace(segment.text);
561
+ }
562
+ if (settings.dropLowQuality) {
563
+ const kept = [];
564
+ for (const segment of segments) {
565
+ if (isLowQualitySegment(segment.text)) {
566
+ droppedSegments += 1;
567
+ } else {
568
+ kept.push(segment);
569
+ }
570
+ }
571
+ segments = kept;
572
+ } else {
573
+ const kept = segments.filter((segment) => segment.text.length > 0);
574
+ droppedSegments += segments.length - kept.length;
575
+ segments = kept;
576
+ }
577
+ if (settings.mergeSameSpeaker) {
578
+ const merged = [];
579
+ for (const segment of segments) {
580
+ const previous = merged[merged.length - 1];
581
+ if (previous && canMerge(previous, segment)) {
582
+ previous.text = `${previous.text} ${segment.text}`.trim();
583
+ if (segment.endIso) previous.endIso = segment.endIso;
584
+ mergedSegments += 1;
585
+ } else {
586
+ merged.push(segment);
587
+ }
588
+ }
589
+ segments = merged;
590
+ }
591
+ return {
592
+ conversation: { ...conversation, segments },
593
+ droppedSegments,
594
+ mergedSegments
595
+ };
596
+ }
597
+ function canMerge(previous, next) {
598
+ if (previous.speakerKey !== next.speakerKey) return false;
599
+ const previousEnd = previous.endIso ? Date.parse(previous.endIso) : NaN;
600
+ const nextStart = next.startIso ? Date.parse(next.startIso) : NaN;
601
+ if (Number.isNaN(previousEnd) || Number.isNaN(nextStart)) return true;
602
+ return nextStart - previousEnd <= MERGE_GAP_MS;
603
+ }
604
+ function stripFillerTokens(text) {
605
+ return normalizeWhitespace(text.replace(FILLER_PATTERN, " "));
606
+ }
607
+ function collapseImmediateRepeats(text) {
608
+ const words = text.split(/\s+/).filter((word) => word.length > 0);
609
+ if (words.length < 2) return text.trim();
610
+ const out = [];
611
+ let index = 0;
612
+ while (index < words.length) {
613
+ out.push(words[index]);
614
+ index += 1;
615
+ let matched = true;
616
+ while (matched) {
617
+ matched = false;
618
+ for (let size = 4; size >= 1; size--) {
619
+ if (out.length < size || index + size > words.length) continue;
620
+ const tail = out.slice(-size).join(" ").toLowerCase();
621
+ if (!/\p{L}/u.test(tail)) continue;
622
+ const ahead = words.slice(index, index + size).join(" ").toLowerCase();
623
+ if (tail === ahead) {
624
+ index += size;
625
+ matched = true;
626
+ break;
627
+ }
628
+ }
629
+ }
630
+ }
631
+ return out.join(" ");
632
+ }
633
+ function isLowQualitySegment(text) {
634
+ const trimmed = text.trim();
635
+ if (trimmed.length === 0) return true;
636
+ if (/^(.)\1{4,}$/.test(trimmed)) return true;
637
+ const letters = trimmed.replace(/[^\p{L}\p{N}]/gu, "");
638
+ if (letters.length === 0) return true;
639
+ if (trimmed.length >= 12 && letters.length / trimmed.length < 0.3) {
640
+ return true;
641
+ }
642
+ const words = trimmed.toLowerCase().split(/\s+/);
643
+ if (words.length >= 5) {
644
+ const unique = new Set(words);
645
+ if (unique.size === 1) return true;
646
+ }
647
+ return false;
648
+ }
649
+ function normalizeWhitespace(text) {
650
+ return text.replace(/\s+/g, " ").trim();
651
+ }
652
+
653
+ // src/wearables/sync-state.ts
654
+ import { promises as fsPromises } from "fs";
655
+ import * as path from "path";
656
+ var MAX_TRACKED_NATIVE_IDS = 5e3;
657
+ var MAX_TRACKED_DAY_HASHES = 800;
658
+ function syncStateFilePath(memoryDir) {
659
+ return path.join(memoryDir, "state", "wearables", "sync.json");
660
+ }
661
+ function emptySyncState() {
662
+ return { version: 1, sources: {} };
663
+ }
664
+ async function loadSyncState(memoryDir) {
665
+ const filePath = syncStateFilePath(memoryDir);
666
+ let raw;
667
+ try {
668
+ raw = await fsPromises.readFile(filePath, "utf-8");
669
+ } catch (err) {
670
+ if (err.code === "ENOENT") {
671
+ return emptySyncState();
672
+ }
673
+ throw err;
674
+ }
675
+ let parsed;
676
+ try {
677
+ parsed = JSON.parse(raw);
678
+ } catch {
679
+ return emptySyncState();
680
+ }
681
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed) || typeof parsed.sources !== "object" || parsed.sources === null) {
682
+ return emptySyncState();
683
+ }
684
+ return { version: 1, sources: parsed.sources };
685
+ }
686
+ async function saveSyncState(memoryDir, state) {
687
+ const filePath = syncStateFilePath(memoryDir);
688
+ await fsPromises.mkdir(path.dirname(filePath), { recursive: true });
689
+ const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now().toString(36)}`;
690
+ await fsPromises.writeFile(
691
+ tmpPath,
692
+ `${JSON.stringify(state, null, 2)}
693
+ `,
694
+ "utf-8"
695
+ );
696
+ try {
697
+ await fsPromises.rename(tmpPath, filePath);
698
+ } catch (err) {
699
+ await fsPromises.unlink(tmpPath).catch(() => void 0);
700
+ throw err;
701
+ }
702
+ }
703
+ function updateSourceSyncState(state, sourceId, update) {
704
+ const previous = state.sources[sourceId];
705
+ const mergedHashes = {
706
+ ...previous?.dayHashes ?? {},
707
+ ...update.dayHashes
708
+ };
709
+ const hashKeys = Object.keys(mergedHashes).sort();
710
+ while (hashKeys.length > MAX_TRACKED_DAY_HASHES) {
711
+ const oldest = hashKeys.shift();
712
+ if (oldest === void 0) break;
713
+ delete mergedHashes[oldest];
714
+ }
715
+ const mergedMemoryHashes = {
716
+ ...previous?.memoryDayHashes ?? {},
717
+ ...update.memoryDayHashes ?? {}
718
+ };
719
+ for (const day of update.clearMemoryDays ?? []) {
720
+ if (!(day in (update.memoryDayHashes ?? {}))) {
721
+ delete mergedMemoryHashes[day];
722
+ }
723
+ }
724
+ const memoryHashKeys = Object.keys(mergedMemoryHashes).sort();
725
+ while (memoryHashKeys.length > MAX_TRACKED_DAY_HASHES) {
726
+ const oldest = memoryHashKeys.shift();
727
+ if (oldest === void 0) break;
728
+ delete mergedMemoryHashes[oldest];
729
+ }
730
+ const mergedNativeIds = [
731
+ ...previous?.importedNativeMemoryIds ?? [],
732
+ ...update.importedNativeMemoryIds ?? []
733
+ ];
734
+ const dedupedNativeIds = [...new Set(mergedNativeIds)];
735
+ const boundedNativeIds = dedupedNativeIds.length > MAX_TRACKED_NATIVE_IDS ? dedupedNativeIds.slice(dedupedNativeIds.length - MAX_TRACKED_NATIVE_IDS) : dedupedNativeIds;
736
+ const sortedDays = [...update.days].sort();
737
+ const latestDay = sortedDays[sortedDays.length - 1];
738
+ const lastDateSynced = latestDay !== void 0 && (!previous || previous.lastDateSynced < latestDay) ? latestDay : previous?.lastDateSynced ?? latestDay ?? "";
739
+ return {
740
+ version: 1,
741
+ sources: {
742
+ ...state.sources,
743
+ [sourceId]: {
744
+ lastSyncAt: update.syncedAt,
745
+ lastDateSynced,
746
+ dayHashes: mergedHashes,
747
+ memoryDayHashes: mergedMemoryHashes,
748
+ importedNativeMemoryIds: boundedNativeIds
749
+ }
750
+ }
751
+ };
752
+ }
753
+
754
+ // src/wearables/pipeline.ts
755
+ var PAGE_SAFETY_CEILING = 1e4;
756
+ var DEFAULT_SYNC_DAYS = 2;
757
+ var MAX_SYNC_DAYS = 90;
758
+ function dateInTimezone(date, timezone) {
759
+ try {
760
+ const parts = new Intl.DateTimeFormat("en-CA", {
761
+ timeZone: timezone,
762
+ year: "numeric",
763
+ month: "2-digit",
764
+ day: "2-digit"
765
+ }).formatToParts(date);
766
+ const get = (type) => parts.find((part) => part.type === type)?.value ?? "";
767
+ return `${get("year")}-${get("month")}-${get("day")}`;
768
+ } catch {
769
+ return date.toISOString().slice(0, 10);
770
+ }
771
+ }
772
+ function resolveSyncDates(options, timezone, now) {
773
+ if (options.date !== void 0) {
774
+ if (!isValidTranscriptDate(options.date)) {
775
+ throw new WearablesInputError(
776
+ `wearables sync: invalid date '${options.date}' \u2014 expected YYYY-MM-DD`
777
+ );
778
+ }
779
+ return [options.date];
780
+ }
781
+ let days = DEFAULT_SYNC_DAYS;
782
+ if (options.days !== void 0) {
783
+ if (!Number.isFinite(options.days) || !Number.isInteger(options.days) || options.days < 1 || options.days > MAX_SYNC_DAYS) {
784
+ throw new WearablesInputError(
785
+ `wearables sync: invalid days '${options.days}' \u2014 expected an integer between 1 and ${MAX_SYNC_DAYS}`
786
+ );
787
+ }
788
+ days = options.days;
789
+ }
790
+ const dates = [];
791
+ let cursor = dateInTimezone(now, timezone);
792
+ for (let count = 0; count < days; count++) {
793
+ dates.unshift(cursor);
794
+ cursor = previousIsoDate(cursor);
795
+ }
796
+ return dates;
797
+ }
798
+ function previousIsoDate(date) {
799
+ const parsed = /* @__PURE__ */ new Date(`${date}T00:00:00Z`);
800
+ parsed.setUTCDate(parsed.getUTCDate() - 1);
801
+ return parsed.toISOString().slice(0, 10);
802
+ }
803
+ async function fetchAllConversationsForDate(connector, date, timezone, signal, warnings) {
804
+ const byId = /* @__PURE__ */ new Map();
805
+ let cursor = void 0;
806
+ const seenCursors = /* @__PURE__ */ new Set();
807
+ const collect = () => [...byId.values()];
808
+ for (let page = 0; page < PAGE_SAFETY_CEILING; page++) {
809
+ const result = await connector.fetchConversations({
810
+ date,
811
+ timezone,
812
+ cursor,
813
+ signal
814
+ });
815
+ for (const conversation of result.conversations) {
816
+ byId.set(conversation.id, conversation);
817
+ }
818
+ if (!result.nextCursor) return { conversations: collect(), partial: false };
819
+ if (seenCursors.has(result.nextCursor)) {
820
+ warnings.push(
821
+ `${connector.id}: provider pagination repeated cursor on ${date} \u2014 stopped to avoid an infinite loop; day may be partially synced (every sync refetches and re-warns while the provider misbehaves)`
822
+ );
823
+ return { conversations: collect(), partial: true };
824
+ }
825
+ seenCursors.add(result.nextCursor);
826
+ cursor = result.nextCursor;
827
+ }
828
+ warnings.push(
829
+ `${connector.id}: stopped paginating ${date} after the ${PAGE_SAFETY_CEILING}-page safety ceiling \u2014 day may be partially synced (every sync refetches and re-warns while this persists)`
830
+ );
831
+ return { conversations: collect(), partial: true };
832
+ }
833
+ var PARTIAL_DAY_MARKER = "\n*Note: pagination safety cap reached during sync \u2014 this day may be incomplete.*\n";
834
+ function emptyDayBody(sourceId, date) {
835
+ return `# ${sourceId} transcript \u2014 ${date}
836
+
837
+ _No storable conversation content for this day (all segments were elided or dropped)._
838
+ `;
839
+ }
840
+ function cleanDay(raw, sourceId, settings, config, userRedaction, correctionRules) {
841
+ const out = {
842
+ conversations: [],
843
+ segmentsKept: 0,
844
+ segmentsDropped: 0,
845
+ redactions: 0,
846
+ correctionsApplied: 0
847
+ };
848
+ for (const conversation of raw) {
849
+ let current = conversation;
850
+ if (config.offTheRecordEnabled) {
851
+ const otr = applyOffTheRecord(current);
852
+ current = otr.conversation;
853
+ out.segmentsDropped += otr.droppedSegments;
854
+ }
855
+ const cleaned = cleanConversation(current, settings.cleanup);
856
+ current = cleaned.conversation;
857
+ out.segmentsDropped += cleaned.droppedSegments;
858
+ const segments = current.segments.map((segment) => {
859
+ let text = segment.text;
860
+ if (config.redactionEnabled) {
861
+ const redacted = redactText(text, userRedaction);
862
+ text = redacted.text;
863
+ out.redactions += redacted.redactions;
864
+ }
865
+ const corrected = applyCorrections(text, correctionRules, sourceId);
866
+ out.correctionsApplied += corrected.applied;
867
+ return { ...segment, text: corrected.text };
868
+ });
869
+ current = { ...current, segments };
870
+ if (current.segments.length > 0) {
871
+ out.conversations.push(current);
872
+ out.segmentsKept += current.segments.length;
873
+ }
874
+ }
875
+ return out;
876
+ }
877
+ async function syncWearableSource(connector, settings, config, options, deps) {
878
+ const now = deps.now ? deps.now() : /* @__PURE__ */ new Date();
879
+ const timezone = config.timezone ?? defaultTimezone();
880
+ const dates = resolveSyncDates(options, timezone, now);
881
+ const summary = {
882
+ source: connector.id,
883
+ days: dates,
884
+ conversations: 0,
885
+ segmentsKept: 0,
886
+ segmentsDropped: 0,
887
+ redactions: 0,
888
+ correctionsApplied: 0,
889
+ transcriptsWritten: [],
890
+ memoriesCreated: 0,
891
+ memoriesPromoted: 0,
892
+ memoriesDemoted: 0,
893
+ memoriesSkipped: 0,
894
+ nativeMemoriesImported: 0,
895
+ warnings: []
896
+ };
897
+ const registry = await loadSpeakerRegistry(deps.memoryDir);
898
+ const stateRules = await loadCorrectionsFile(deps.memoryDir);
899
+ const correctionRules = [
900
+ ...compileCorrectionRules(config.corrections, "wearables.corrections"),
901
+ ...compileCorrectionRules(stateRules, "state corrections")
902
+ ];
903
+ const userRedaction = compileRedactionPatterns(config.redactionPatterns);
904
+ let syncState = await loadSyncState(deps.memoryDir);
905
+ const previousState = syncState.sources[connector.id];
906
+ const dayHashes = {};
907
+ const memoryDayHashes = {};
908
+ const failedMemoryDays = [];
909
+ const importedNativeIds = [];
910
+ for (const date of dates) {
911
+ const fetched = await fetchAllConversationsForDate(
912
+ connector,
913
+ date,
914
+ timezone,
915
+ options.signal,
916
+ summary.warnings
917
+ );
918
+ const cleaned = cleanDay(
919
+ fetched.conversations,
920
+ connector.id,
921
+ settings,
922
+ config,
923
+ userRedaction,
924
+ correctionRules
925
+ );
926
+ summary.conversations += cleaned.conversations.length;
927
+ summary.segmentsKept += cleaned.segmentsKept;
928
+ summary.segmentsDropped += cleaned.segmentsDropped;
929
+ summary.redactions += cleaned.redactions;
930
+ summary.correctionsApplied += cleaned.correctionsApplied;
931
+ if (fetched.conversations.length === 0) {
932
+ const existing = await deps.readDayContentHash(connector.id, date);
933
+ if (existing !== null) {
934
+ summary.warnings.push(
935
+ `${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`
936
+ );
937
+ }
938
+ continue;
939
+ }
940
+ const allElided = cleaned.conversations.length === 0;
941
+ let body = allElided ? emptyDayBody(connector.id, date) : composeDayTranscriptBody(
942
+ connector.id,
943
+ date,
944
+ timezone,
945
+ cleaned.conversations,
946
+ registry
947
+ );
948
+ if (fetched.partial && !allElided) {
949
+ body += PARTIAL_DAY_MARKER;
950
+ }
951
+ const bodyHash = hashTranscriptBody(body);
952
+ const existingHash = await deps.readDayContentHash(connector.id, date);
953
+ const changed = existingHash !== bodyHash;
954
+ const shouldWrite = changed && (!allElided || existingHash !== null);
955
+ if (shouldWrite) {
956
+ const meta = composeDayTranscriptMeta(
957
+ connector.id,
958
+ date,
959
+ timezone,
960
+ cleaned.conversations,
961
+ registry,
962
+ body,
963
+ now.toISOString()
964
+ );
965
+ await deps.writeDayTranscript(
966
+ connector.id,
967
+ date,
968
+ serializeDayTranscript(meta, body)
969
+ );
970
+ summary.transcriptsWritten.push(date);
971
+ }
972
+ dayHashes[date] = bodyHash;
973
+ if (allElided) continue;
974
+ const needsSmartContext = settings.memoryMode === "smart" || settings.importNativeMemories === "smart";
975
+ const memoryPassComplete = previousState?.memoryDayHashes?.[date] === bodyHash;
976
+ if (settings.memoryMode !== "off" && (changed || options.forceMemories === true || !memoryPassComplete)) {
977
+ if (!deps.memoryGen) {
978
+ summary.warnings.push(
979
+ `${connector.id}: memoryMode is '${settings.memoryMode}' but no extraction engine is available in this context \u2014 transcripts synced, memories skipped`
980
+ );
981
+ } else {
982
+ let passClean = false;
983
+ try {
984
+ const corroboration = needsSmartContext ? await buildCorroborationContext(connector.id, date, deps) : void 0;
985
+ const dayMemoryGen = {
986
+ ...deps.memoryGen,
987
+ ...corroboration !== void 0 ? { corroboration } : {}
988
+ };
989
+ const generated = await generateWearableMemories(
990
+ connector.id,
991
+ date,
992
+ cleaned.conversations,
993
+ settings,
994
+ registry,
995
+ dayMemoryGen
996
+ );
997
+ summary.memoriesCreated += generated.created;
998
+ summary.memoriesPromoted += generated.promoted;
999
+ summary.memoriesDemoted += generated.demoted;
1000
+ summary.memoriesSkipped += generated.skipped;
1001
+ summary.warnings.push(...generated.warnings);
1002
+ passClean = generated.completed;
1003
+ if (config.digestEnabled) {
1004
+ const wrote = await writeDailyDigestMemory(
1005
+ connector.id,
1006
+ date,
1007
+ cleaned.conversations,
1008
+ settings,
1009
+ registry,
1010
+ deps.memoryGen.writer
1011
+ );
1012
+ if (wrote) summary.memoriesCreated += 1;
1013
+ }
1014
+ } catch (err) {
1015
+ passClean = false;
1016
+ summary.warnings.push(
1017
+ `${connector.id}: memory pass failed for ${date}: ${describeErrorForOperator(err)} \u2014 retries on the next sync`
1018
+ );
1019
+ }
1020
+ if (passClean) {
1021
+ memoryDayHashes[date] = bodyHash;
1022
+ } else {
1023
+ failedMemoryDays.push(date);
1024
+ }
1025
+ }
1026
+ } else if (settings.memoryMode !== "off" && memoryPassComplete) {
1027
+ memoryDayHashes[date] = bodyHash;
1028
+ }
1029
+ }
1030
+ if (settings.importNativeMemories !== "off" && typeof connector.fetchNativeMemories === "function") {
1031
+ if (!deps.memoryGen) {
1032
+ summary.warnings.push(
1033
+ `${connector.id}: importNativeMemories is enabled but no memory writer is available in this context`
1034
+ );
1035
+ } else {
1036
+ const alreadyImported = new Set(
1037
+ previousState?.importedNativeMemoryIds ?? []
1038
+ );
1039
+ const nativeCorroboration = settings.importNativeMemories === "smart" ? {
1040
+ otherSourceDayTokens: /* @__PURE__ */ new Map(),
1041
+ existingMemories: deps.listSupportMemories ? await deps.listSupportMemories() : []
1042
+ } : void 0;
1043
+ const nativeMemoryGen = {
1044
+ ...deps.memoryGen,
1045
+ ...nativeCorroboration !== void 0 ? { corroboration: nativeCorroboration } : {}
1046
+ };
1047
+ let cursor = void 0;
1048
+ const seenNativeCursors = /* @__PURE__ */ new Set();
1049
+ for (let page = 0; page < PAGE_SAFETY_CEILING; page++) {
1050
+ const result = await connector.fetchNativeMemories({
1051
+ cursor,
1052
+ signal: options.signal
1053
+ });
1054
+ const imported = await importNativeMemories(
1055
+ connector.id,
1056
+ result.memories,
1057
+ alreadyImported,
1058
+ settings,
1059
+ nativeMemoryGen
1060
+ );
1061
+ summary.warnings.push(...imported.warnings);
1062
+ summary.nativeMemoriesImported += imported.imported;
1063
+ importedNativeIds.push(...imported.importedIds);
1064
+ for (const id of imported.importedIds) alreadyImported.add(id);
1065
+ if (!result.nextCursor) break;
1066
+ if (seenNativeCursors.has(result.nextCursor)) {
1067
+ summary.warnings.push(
1068
+ `${connector.id}: provider pagination repeated cursor during native-memory import \u2014 stopped to avoid an infinite loop; remaining items import on the next sync`
1069
+ );
1070
+ break;
1071
+ }
1072
+ seenNativeCursors.add(result.nextCursor);
1073
+ cursor = result.nextCursor;
1074
+ if (page === PAGE_SAFETY_CEILING - 1) {
1075
+ summary.warnings.push(
1076
+ `${connector.id}: stopped native-memory import at the ${PAGE_SAFETY_CEILING}-page safety ceiling \u2014 remaining items import on the next sync`
1077
+ );
1078
+ }
1079
+ }
1080
+ }
1081
+ }
1082
+ const wroteAnything = summary.transcriptsWritten.length > 0 || summary.memoriesCreated > 0 || summary.memoriesPromoted > 0 || summary.memoriesDemoted > 0 || summary.nativeMemoriesImported > 0;
1083
+ if (wroteAnything && deps.afterWrites) {
1084
+ try {
1085
+ await deps.afterWrites();
1086
+ } catch (err) {
1087
+ summary.warnings.push(
1088
+ `search reindex failed (writes are stored and will index on the next update): ${describeErrorForOperator(err)}`
1089
+ );
1090
+ }
1091
+ }
1092
+ syncState = updateSourceSyncState(syncState, connector.id, {
1093
+ syncedAt: now.toISOString(),
1094
+ days: dates,
1095
+ dayHashes,
1096
+ memoryDayHashes,
1097
+ clearMemoryDays: failedMemoryDays,
1098
+ importedNativeMemoryIds: importedNativeIds
1099
+ });
1100
+ if (summary.transcriptsWritten.length > 0) {
1101
+ const cleared = {};
1102
+ for (const [otherId, otherState] of Object.entries(syncState.sources)) {
1103
+ if (otherId === connector.id || otherState.memoryDayHashes === void 0) {
1104
+ cleared[otherId] = otherState;
1105
+ continue;
1106
+ }
1107
+ const memoryDays = { ...otherState.memoryDayHashes };
1108
+ let touched = false;
1109
+ for (const date of summary.transcriptsWritten) {
1110
+ if (date in memoryDays) {
1111
+ delete memoryDays[date];
1112
+ touched = true;
1113
+ }
1114
+ }
1115
+ cleared[otherId] = touched ? { ...otherState, memoryDayHashes: memoryDays } : otherState;
1116
+ }
1117
+ syncState = { version: 1, sources: cleared };
1118
+ }
1119
+ await saveSyncState(deps.memoryDir, syncState);
1120
+ return summary;
1121
+ }
1122
+ async function buildCorroborationContext(sourceId, date, deps) {
1123
+ const otherSourceDayTokens = /* @__PURE__ */ new Map();
1124
+ if (deps.readOtherSourceDayBodies) {
1125
+ const bodies = await deps.readOtherSourceDayBodies(date, sourceId);
1126
+ for (const [otherSource, body] of bodies) {
1127
+ otherSourceDayTokens.set(otherSource, tokenizeDayBody(body));
1128
+ }
1129
+ }
1130
+ const existingMemories = deps.listSupportMemories ? await deps.listSupportMemories() : [];
1131
+ return { otherSourceDayTokens, existingMemories };
1132
+ }
1133
+ function defaultTimezone() {
1134
+ try {
1135
+ return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
1136
+ } catch {
1137
+ return "UTC";
1138
+ }
1139
+ }
1140
+
1141
+ export {
1142
+ memoryStatusForMode,
1143
+ WEARABLE_SOURCE_PREFIX,
1144
+ wearableSourceLabel,
1145
+ wearableDayTag,
1146
+ buildExtractionTurns,
1147
+ generateWearableMemories,
1148
+ writeDailyDigestMemory,
1149
+ importNativeMemories,
1150
+ cleanConversation,
1151
+ stripFillerTokens,
1152
+ collapseImmediateRepeats,
1153
+ isLowQualitySegment,
1154
+ syncStateFilePath,
1155
+ emptySyncState,
1156
+ loadSyncState,
1157
+ saveSyncState,
1158
+ updateSourceSyncState,
1159
+ dateInTimezone,
1160
+ resolveSyncDates,
1161
+ syncWearableSource,
1162
+ defaultTimezone
1163
+ };
1164
+ //# sourceMappingURL=chunk-KVDUDYEN.js.map