@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
package/dist/types.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import './types-BliCnURB.js';
2
2
  import './index-DJ9QWMw-.js';
3
- export { y as AccessTrackingEntry, A as ActiveRecallChatType, d as ActiveRecallModelFallbackPolicy, b as ActiveRecallPromptStyle, a as ActiveRecallQueryMode, c as ActiveRecallThinking, a6 as AgentAccessAuthToken, b2 as AgentAccessHttpConfig, b3 as AgentDefaultsConfig, b4 as AgentPersona, f as AgentPersonaModelConfig, b5 as BehaviorLoopAdjustment, e as BehaviorLoopPolicyState, b6 as BehaviorSignalDirection, B as BehaviorSignalEvent, b7 as BehaviorSignalType, aH as BootstrapOptions, aI as BootstrapResult, V as BriefingActiveThread, b8 as BriefingCalendarSourceError, aO as BriefingConfig, Q as BriefingFocus, O as BriefingFollowup, aP as BriefingOpenCommitment, X as BriefingRecentEntity, W as BriefingResult, N as BriefingSections, aQ as BriefingWindow, b9 as BufferEntryState, k as BufferState, o as BufferSurpriseEvent, Y as BufferTurn, U as CalendarEvent, S as CalendarSource, ba as CaptureMode, $ as Checkpoint, bb as CodexCliReasoningEffort, bc as CodexCompactionFlushMode, aR as CodexCompatConfig, bd as CodexConnectorConfig, aG as CodingContext, aL as CodingModeConfig, be as CompressionGuidelineActivationState, a8 as CompressionGuidelineOptimizerActionSummary, a7 as CompressionGuidelineOptimizerEventCounts, a9 as CompressionGuidelineOptimizerRuleUpdate, bf as CompressionGuidelineOptimizerSourceWindow, C as CompressionGuidelineOptimizerState, bg as ConfidenceTier, bh as ConsolidationAction, bi as ConsolidationItem, aJ as ConsolidationObservation, ag as ConsolidationResult, s as ContinuityImprovementLoop, r as ContinuityIncidentCloseInput, p as ContinuityIncidentOpenInput, q as ContinuityIncidentRecord, bj as ContinuityIncidentState, bk as ContinuityLoopCadence, u as ContinuityLoopReviewInput, bl as ContinuityLoopStatus, t as ContinuityLoopUpsertInput, bm as ContradictionScanConfig, as as ConversationThread, bn as CronConversationRecallMode, bo as CronRecallMode, aS as DEFAULT_RECALL_DISCLOSURE, ah as DaySummaryResult, bp as DreamingConfig, bq as DreamingNarrativePromptStyle, br as DreamsDeepSleepConfig, bs as DreamsLightSleepConfig, au as DreamsPhase, bt as DreamsPhaseStatus, bu as DreamsPhasesConfig, bv as DreamsRemConfig, av as DreamsRunResult, at as DreamsStatusResult, bw as EngramTraceEvent, w as EntityActivityEntry, x as EntityFile, ab as EntityMention, v as EntityRelationship, ac as EntitySchemaDefinition, ad as EntitySchemaSectionDefinition, E as EntityStructuredSection, aK as EntityTimelineEntry, aT as ExtractedFact, bx as ExtractedProcedureStep, by as ExtractedQuestion, bz as ExtractedReasoningTrace, bA as ExtractedReasoningTraceStep, bB as ExtractedRelationship, bC as ExtractionPassSource, af as ExtractionResult, F as FileHygieneConfig, G as GatewayConfig, bD as GitHubLiveConnectorConfig, bE as GmailLiveConnectorConfig, bF as GoogleDriveLiveConnectorConfig, bG as HeartbeatConfig, bH as HeartbeatDetectionMode, a0 as HourlySummary, J as IdentityInjectionMode, ae as ImportanceLevel, I as ImportanceScore, a2 as LifecycleState, L as LiveConnectorsConfig, bI as LlmTraceCallback, bJ as LlmTraceEvent, ak as MemoryActionEligibilityContext, aU as MemoryActionEligibilitySource, m as MemoryActionEvent, bK as MemoryActionOutcome, bL as MemoryActionPolicyDecision, al as MemoryActionPolicyResult, bM as MemoryActionStatus, aa as MemoryActionType, M as MemoryCategory, g as MemoryFile, i as MemoryFrontmatter, ai as MemoryIntent, n as MemoryLifecycleEvent, am as MemoryLifecycleEventType, an as MemoryLifecycleStateSummary, h as MemoryLink, bN as MemoryLinkType, aV as MemoryObservation, bO as MemoryOsPresetName, z as MemoryProjectionCurrentState, aW as MemoryScope, j as MemoryStatus, D as MemorySummary, l as MetaState, bP as ModelApi, bQ as ModelDefinitionConfig, bR as ModelProviderAuthMode, ao as ModelProviderConfig, bS as NamespacePolicy, ap as NativeKnowledgeConfig, bT as NativeKnowledgeFolderRuleConfig, bU as NativeKnowledgeObsidianVaultConfig, bV as NativeKnowledgeOpenClawWorkspaceConfig, bW as NotionLiveConnectorConfig, P as PluginConfig, a4 as PolicyClass, bX as PrincipalFromSessionKeyMode, bY as PrincipalRule, bZ as ProceduralConfig, aj as QmdSearchExplain, Z as QmdSearchResult, b_ as QuestionEntry, aX as RECALL_DISCLOSURE_LEVELS, b$ as ReasoningEffort, K as RecallDisclosure, c0 as RecallPipelineConfig, H as RecallPlanMode, c1 as RecallSectionConfig, R as RecallTierExplain, c2 as RecallTraceEvent, c3 as RelevanceFeedback, aq as RetrievalTier, c4 as SPECULATIVE_TTL_DAYS, c5 as ScoredEntity, a5 as SecretRef, c6 as SemanticChunkingConfigShape, a1 as SessionObserverBandConfig, c7 as SignalLevel, ar as SignalScanResult, c8 as SlotBehaviorConfig, c9 as SlotMismatchMode, T as TopicScore, _ as TranscriptEntry, ca as TriggerMode, a3 as VerificationState, cb as confidenceTier, b1 as isRecallDisclosure } from './types-BCF2wqKa.js';
3
+ export { y as AccessTrackingEntry, A as ActiveRecallChatType, d as ActiveRecallModelFallbackPolicy, b as ActiveRecallPromptStyle, a as ActiveRecallQueryMode, c as ActiveRecallThinking, a7 as AgentAccessAuthToken, b2 as AgentAccessHttpConfig, b3 as AgentDefaultsConfig, b4 as AgentPersona, f as AgentPersonaModelConfig, b5 as BehaviorLoopAdjustment, e as BehaviorLoopPolicyState, b6 as BehaviorSignalDirection, B as BehaviorSignalEvent, b7 as BehaviorSignalType, aH as BootstrapOptions, aI as BootstrapResult, V as BriefingActiveThread, b8 as BriefingCalendarSourceError, aO as BriefingConfig, Q as BriefingFocus, O as BriefingFollowup, aP as BriefingOpenCommitment, X as BriefingRecentEntity, W as BriefingResult, N as BriefingSections, aQ as BriefingWindow, b9 as BufferEntryState, k as BufferState, o as BufferSurpriseEvent, Y as BufferTurn, U as CalendarEvent, S as CalendarSource, ba as CaptureMode, $ as Checkpoint, bb as CodexCliReasoningEffort, bc as CodexCompactionFlushMode, aR as CodexCompatConfig, bd as CodexConnectorConfig, aG as CodingContext, aL as CodingModeConfig, be as CompressionGuidelineActivationState, a9 as CompressionGuidelineOptimizerActionSummary, a8 as CompressionGuidelineOptimizerEventCounts, aa as CompressionGuidelineOptimizerRuleUpdate, bf as CompressionGuidelineOptimizerSourceWindow, C as CompressionGuidelineOptimizerState, bg as ConfidenceTier, bh as ConsolidationAction, bi as ConsolidationItem, aJ as ConsolidationObservation, ag as ConsolidationResult, s as ContinuityImprovementLoop, r as ContinuityIncidentCloseInput, p as ContinuityIncidentOpenInput, q as ContinuityIncidentRecord, bj as ContinuityIncidentState, bk as ContinuityLoopCadence, u as ContinuityLoopReviewInput, bl as ContinuityLoopStatus, t as ContinuityLoopUpsertInput, bm as ContradictionScanConfig, as as ConversationThread, bn as CronConversationRecallMode, bo as CronRecallMode, aS as DEFAULT_RECALL_DISCLOSURE, ah as DaySummaryResult, bp as DreamingConfig, bq as DreamingNarrativePromptStyle, br as DreamsDeepSleepConfig, bs as DreamsLightSleepConfig, au as DreamsPhase, bt as DreamsPhaseStatus, bu as DreamsPhasesConfig, bv as DreamsRemConfig, av as DreamsRunResult, at as DreamsStatusResult, bw as EngramTraceEvent, w as EntityActivityEntry, x as EntityFile, ac as EntityMention, v as EntityRelationship, ad as EntitySchemaDefinition, ae as EntitySchemaSectionDefinition, E as EntityStructuredSection, aK as EntityTimelineEntry, aT as ExtractedFact, bx as ExtractedProcedureStep, by as ExtractedQuestion, bz as ExtractedReasoningTrace, bA as ExtractedReasoningTraceStep, bB as ExtractedRelationship, bC as ExtractionPassSource, af as ExtractionResult, F as FileHygieneConfig, G as GatewayConfig, bD as GitHubLiveConnectorConfig, bE as GmailLiveConnectorConfig, bF as GoogleDriveLiveConnectorConfig, bG as HeartbeatConfig, bH as HeartbeatDetectionMode, a0 as HourlySummary, J as IdentityInjectionMode, a5 as ImportanceLevel, I as ImportanceScore, a2 as LifecycleState, L as LiveConnectorsConfig, bI as LlmTraceCallback, bJ as LlmTraceEvent, ak as MemoryActionEligibilityContext, aU as MemoryActionEligibilitySource, m as MemoryActionEvent, bK as MemoryActionOutcome, bL as MemoryActionPolicyDecision, al as MemoryActionPolicyResult, bM as MemoryActionStatus, ab as MemoryActionType, M as MemoryCategory, g as MemoryFile, j as MemoryFrontmatter, ai as MemoryIntent, n as MemoryLifecycleEvent, am as MemoryLifecycleEventType, an as MemoryLifecycleStateSummary, i as MemoryLink, bN as MemoryLinkType, aV as MemoryObservation, bO as MemoryOsPresetName, z as MemoryProjectionCurrentState, aW as MemoryScope, h as MemoryStatus, D as MemorySummary, l as MetaState, bP as ModelApi, bQ as ModelDefinitionConfig, bR as ModelProviderAuthMode, ao as ModelProviderConfig, bS as NamespacePolicy, ap as NativeKnowledgeConfig, bT as NativeKnowledgeFolderRuleConfig, bU as NativeKnowledgeObsidianVaultConfig, bV as NativeKnowledgeOpenClawWorkspaceConfig, bW as NotionLiveConnectorConfig, P as PluginConfig, a4 as PolicyClass, bX as PrincipalFromSessionKeyMode, bY as PrincipalRule, bZ as ProceduralConfig, aj as QmdSearchExplain, Z as QmdSearchResult, b_ as QuestionEntry, aX as RECALL_DISCLOSURE_LEVELS, b$ as ReasoningEffort, K as RecallDisclosure, c0 as RecallPipelineConfig, H as RecallPlanMode, c1 as RecallSectionConfig, R as RecallTierExplain, c2 as RecallTraceEvent, c3 as RelevanceFeedback, aq as RetrievalTier, c4 as SPECULATIVE_TTL_DAYS, c5 as ScoredEntity, a6 as SecretRef, c6 as SemanticChunkingConfigShape, a1 as SessionObserverBandConfig, c7 as SignalLevel, ar as SignalScanResult, c8 as SlotBehaviorConfig, c9 as SlotMismatchMode, T as TopicScore, _ as TranscriptEntry, ca as TriggerMode, a3 as VerificationState, cb as confidenceTier, b1 as isRecallDisclosure } from './types-CpMPD8xl.js';
@@ -1,5 +1,5 @@
1
1
  import { TierRoutingPolicy } from './tier-routing.js';
2
- import './types-BCF2wqKa.js';
2
+ import './types-CpMPD8xl.js';
3
3
  import './types-BliCnURB.js';
4
4
  import './index-DJ9QWMw-.js';
5
5
  import './lifecycle.js';
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  searchVerifiedEpisodes
3
- } from "./chunk-P2D2MM47.js";
3
+ } from "./chunk-YROCXMCK.js";
4
4
  import "./chunk-HQ6NIBL6.js";
5
- import "./chunk-UGHUNQ74.js";
5
+ import "./chunk-QYGIQ5NM.js";
6
+ import "./chunk-M7XQSUBB.js";
6
7
  import "./chunk-5UZXUTVO.js";
7
8
  import "./chunk-J6A3CX5N.js";
8
9
  import "./chunk-FPNQF475.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "9.3.629",
3
+ "version": "9.3.631",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1700,6 +1700,7 @@ export class Orchestrator {
1700
1700
  >();
1701
1701
  private qmdMaintenanceTimer: NodeJS.Timeout | null = null;
1702
1702
  private wearablesServiceInstance: WearablesService | null = null;
1703
+ private wearablesAutoSyncHandle: { stop(): Promise<void> } | null = null;
1703
1704
  private qmdMaintenancePending = false;
1704
1705
  private qmdMaintenanceInFlight = false;
1705
1706
  private lastQmdEmbedAtMs = 0;
@@ -1781,6 +1782,12 @@ export class Orchestrator {
1781
1782
  */
1782
1783
  async destroy(): Promise<void> {
1783
1784
  this.abortDeferredInit();
1785
+ if (this.wearablesAutoSyncHandle) {
1786
+ // Aborts in-flight provider fetches and waits for the tick to
1787
+ // settle, so nothing is writing or reindexing past destroy().
1788
+ await this.wearablesAutoSyncHandle.stop();
1789
+ this.wearablesAutoSyncHandle = null;
1790
+ }
1784
1791
  if (this.qmdMaintenanceTimer) {
1785
1792
  clearTimeout(this.qmdMaintenanceTimer);
1786
1793
  this.qmdMaintenanceTimer = null;
@@ -2957,6 +2964,57 @@ export class Orchestrator {
2957
2964
  }
2958
2965
  }
2959
2966
 
2967
+ // Wearables auto-sync: in-process periodic transcript refresh for
2968
+ // long-lived hosts (default on). Today's transcript keeps growing
2969
+ // while the wearable records; a once-per-local-day deep pass picks
2970
+ // up late uploads and provider re-processing. Static config gate —
2971
+ // sources can't appear at runtime, so checking once here is safe.
2972
+ // The timer is unref'd, so one-shot CLI runs exit naturally without
2973
+ // ever ticking; idempotent across stop/start cycles via the handle
2974
+ // guard. Non-fatal: a failure to start must not break init.
2975
+ if (signal.aborted) return;
2976
+ if (
2977
+ !this.wearablesAutoSyncHandle &&
2978
+ this.config.wearables.enabled &&
2979
+ this.config.wearables.autoSyncEnabled &&
2980
+ Object.values(this.config.wearables.sources).some((source) => source.enabled)
2981
+ ) {
2982
+ try {
2983
+ const { startWearablesAutoSync } = await import("./wearables/auto-sync.js");
2984
+ // Re-check after the await: destroy() may have aborted while
2985
+ // the import was in flight, having found no handle to stop —
2986
+ // starting now would leave a live interval on a destroyed
2987
+ // orchestrator (Cursor review on PR #1464). Handle creation
2988
+ // below is synchronous, so no further window exists.
2989
+ if (signal.aborted) return;
2990
+ this.wearablesAutoSyncHandle = startWearablesAutoSync(
2991
+ {
2992
+ intervalMinutes: this.config.wearables.autoSyncIntervalMinutes,
2993
+ days: this.config.wearables.autoSyncDays,
2994
+ deepDays: this.config.wearables.autoSyncDeepDays,
2995
+ ...(this.config.wearables.timezone !== undefined
2996
+ ? { timezone: this.config.wearables.timezone }
2997
+ : {}),
2998
+ },
2999
+ {
3000
+ sync: (options) => this.getWearablesService().sync(options),
3001
+ log: {
3002
+ info: (message) => log.info(message),
3003
+ warn: (message) => log.warn(message),
3004
+ },
3005
+ },
3006
+ );
3007
+ log.info(
3008
+ `wearables auto-sync started: every ${this.config.wearables.autoSyncIntervalMinutes}m over ${this.config.wearables.autoSyncDays}d (deep ${this.config.wearables.autoSyncDeepDays}d daily)`,
3009
+ );
3010
+ } catch (err) {
3011
+ const { displayErrorDetail } = await import("./runtime/better-sqlite.js");
3012
+ log.warn(
3013
+ `wearables auto-sync failed to start (non-fatal): ${displayErrorDetail(err)}`,
3014
+ );
3015
+ }
3016
+ }
3017
+
2960
3018
  log.info("orchestrator initialized (full — deferred steps complete)");
2961
3019
  }
2962
3020
 
@@ -10807,6 +10865,22 @@ export class Orchestrator {
10807
10865
  getStorage: async () =>
10808
10866
  await this.getStorageForNamespace(this.bulkImportWriteNamespace()),
10809
10867
  extract: (turns) => this.extraction.extract(turns),
10868
+ // Smart memoryMode runs candidates through the SAME extraction
10869
+ // judge (cache + defer counters included) the live extraction
10870
+ // pipeline uses, so wearable facts get identical LLM-as-judge
10871
+ // durability gating.
10872
+ judgeFacts: (candidates) =>
10873
+ judgeFactDurability(
10874
+ candidates,
10875
+ this.config,
10876
+ this.localLlm,
10877
+ new FallbackLlmClient(
10878
+ this.config.gatewayConfig,
10879
+ fallbackLlmRuntimeContextFromConfig(this.config),
10880
+ ),
10881
+ this.judgeVerdictCache,
10882
+ this.judgeDeferCounts,
10883
+ ),
10810
10884
  searchBackend: {
10811
10885
  search: async (query, maxResults) => {
10812
10886
  if (!this.qmd.isAvailable()) return null;
package/src/storage.ts CHANGED
@@ -1168,6 +1168,27 @@ export class ContentHashIndex {
1168
1168
  * normalizeAttributePairs({ foo: "bar", BAZ: "qux" })
1169
1169
  * // → "baz: qux; foo: bar"
1170
1170
  */
1171
+ /**
1172
+ * Remove the "[Attributes: ...]" suffix `writeMemory` appends to the
1173
+ * stored body when structuredAttributes are present, yielding the raw
1174
+ * fact text for content comparison. Inverse companion of
1175
+ * `normalizeAttributePairs` enrichment. String operations, not regex —
1176
+ * CodeQL js/polynomial-redos on a suffix-anchored pattern over
1177
+ * library-supplied content.
1178
+ */
1179
+ export function stripAttributesSuffix(content: string): string {
1180
+ const trimmed = content.trimEnd();
1181
+ if (!trimmed.endsWith("]")) return content.trim();
1182
+ const marker = "\n[Attributes: ";
1183
+ const markerIndex = trimmed.lastIndexOf(marker);
1184
+ if (markerIndex === -1) return content.trim();
1185
+ // The block must be the FINAL line and contain no "]" before the
1186
+ // closing bracket (mirrors the shape normalizeAttributePairs emits).
1187
+ const inner = trimmed.slice(markerIndex + marker.length, -1);
1188
+ if (inner.includes("]") || inner.includes("\n")) return content.trim();
1189
+ return trimmed.slice(0, markerIndex).trim();
1190
+ }
1191
+
1171
1192
  export function normalizeAttributePairs(pairs: Record<string, string>): string {
1172
1193
  return Object.entries(pairs)
1173
1194
  .map(([k, v]) => [k.trim().toLowerCase(), v.trim()] as [string, string])
@@ -2596,6 +2617,85 @@ export class StorageManager {
2596
2617
  return days;
2597
2618
  }
2598
2619
 
2620
+ /**
2621
+ * Locate a wearable-sourced memory by exact (trimmed) content,
2622
+ * ignoring the "[Attributes: ...]" suffix writeMemory appends for
2623
+ * structuredAttributes — callers pass the raw fact text. Used by the
2624
+ * smart trust pipeline to find an earlier borderline write when the
2625
+ * same fact re-extracts with stronger evidence.
2626
+ */
2627
+ async findWearableMemoryByContent(
2628
+ content: string,
2629
+ ): Promise<{ id: string; status: MemoryStatus | undefined } | null> {
2630
+ const needle = stripAttributesSuffix(content);
2631
+ const memories = await this.readAllMemories();
2632
+ for (const memory of memories) {
2633
+ if (
2634
+ typeof memory.frontmatter.source === "string" &&
2635
+ memory.frontmatter.source.startsWith("wearable:") &&
2636
+ stripAttributesSuffix(memory.content) === needle
2637
+ ) {
2638
+ return { id: memory.frontmatter.id, status: memory.frontmatter.status };
2639
+ }
2640
+ }
2641
+ return null;
2642
+ }
2643
+
2644
+ /**
2645
+ * Promote a pending_review wearable memory to active in place,
2646
+ * merging updated trust evidence into structuredAttributes. Returns
2647
+ * false when the memory is missing or no longer pending_review (a
2648
+ * concurrent review decision wins).
2649
+ */
2650
+ async promoteWearableMemory(
2651
+ id: string,
2652
+ attributeUpdates: Record<string, string>,
2653
+ confidence?: number,
2654
+ ): Promise<boolean> {
2655
+ const memories = await this.readAllMemories();
2656
+ const memory = memories.find((entry) => entry.frontmatter.id === id);
2657
+ if (!memory) return false;
2658
+ if (memory.frontmatter.status !== "pending_review") return false;
2659
+ return this.writeMemoryFrontmatter(memory, {
2660
+ status: "active",
2661
+ // Keep frontmatter confidence in step with the re-scored trust —
2662
+ // new smart writes persist trust as confidence, and a promoted
2663
+ // row must not keep its stale borderline value.
2664
+ ...(typeof confidence === "number" && Number.isFinite(confidence)
2665
+ ? { confidence: Math.min(1, Math.max(0, confidence)) }
2666
+ : {}),
2667
+ structuredAttributes: {
2668
+ ...(memory.frontmatter.structuredAttributes ?? {}),
2669
+ ...attributeUpdates,
2670
+ },
2671
+ });
2672
+ }
2673
+
2674
+ /**
2675
+ * Demote a pending_review wearable memory to rejected when a re-pass
2676
+ * produced an explicit judge-reject verdict, merging the evidence.
2677
+ * Returns false when the memory is missing or no longer
2678
+ * pending_review — active rows are NEVER auto-demoted (operator
2679
+ * approvals and accrued recall signals win; contradiction scans and
2680
+ * supersession own active-row retirement).
2681
+ */
2682
+ async demoteWearableMemory(
2683
+ id: string,
2684
+ attributeUpdates: Record<string, string>,
2685
+ ): Promise<boolean> {
2686
+ const memories = await this.readAllMemories();
2687
+ const memory = memories.find((entry) => entry.frontmatter.id === id);
2688
+ if (!memory) return false;
2689
+ if (memory.frontmatter.status !== "pending_review") return false;
2690
+ return this.writeMemoryFrontmatter(memory, {
2691
+ status: "rejected",
2692
+ structuredAttributes: {
2693
+ ...(memory.frontmatter.structuredAttributes ?? {}),
2694
+ ...attributeUpdates,
2695
+ },
2696
+ });
2697
+ }
2698
+
2599
2699
  private get factsDir(): string {
2600
2700
  return path.join(this.baseDir, "facts");
2601
2701
  }
@@ -0,0 +1,181 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ import { startWearablesAutoSync } from "./auto-sync.js";
5
+
6
+ function makeDeps(overrides: { failTimes?: number } = {}) {
7
+ const calls: Array<{ days: number }> = [];
8
+ const warnings: string[] = [];
9
+ let remainingFailures = overrides.failTimes ?? 0;
10
+ let nowIso = "2026-06-12T10:00:00.000Z";
11
+ return {
12
+ calls,
13
+ warnings,
14
+ setNow(iso: string) {
15
+ nowIso = iso;
16
+ },
17
+ deps: {
18
+ sync: async (options: { days: number }) => {
19
+ if (remainingFailures > 0) {
20
+ remainingFailures -= 1;
21
+ throw new Error("provider down");
22
+ }
23
+ calls.push(options);
24
+ return [];
25
+ },
26
+ log: {
27
+ info: () => {},
28
+ warn: (message: string) => {
29
+ warnings.push(message);
30
+ },
31
+ },
32
+ now: () => new Date(nowIso),
33
+ },
34
+ };
35
+ }
36
+
37
+ const SETTINGS = {
38
+ intervalMinutes: 15,
39
+ days: 2,
40
+ deepDays: 7,
41
+ timezone: "UTC",
42
+ };
43
+
44
+ test("first tick runs the deep window, same-day ticks run the shallow window", async () => {
45
+ const { calls, deps } = makeDeps();
46
+ const handle = startWearablesAutoSync(SETTINGS, deps);
47
+ try {
48
+ await handle.tick();
49
+ await handle.tick();
50
+ await handle.tick();
51
+ assert.deepEqual(
52
+ calls.map((call) => call.days),
53
+ [7, 2, 2],
54
+ "deep once, then shallow for the rest of the day",
55
+ );
56
+ } finally {
57
+ handle.stop();
58
+ }
59
+ });
60
+
61
+ test("a new local day triggers the deep pass again", async () => {
62
+ const { calls, deps, setNow } = makeDeps();
63
+ const handle = startWearablesAutoSync(SETTINGS, deps);
64
+ try {
65
+ await handle.tick();
66
+ await handle.tick();
67
+ setNow("2026-06-13T00:05:00.000Z");
68
+ await handle.tick();
69
+ await handle.tick();
70
+ assert.deepEqual(
71
+ calls.map((call) => call.days),
72
+ [7, 2, 7, 2],
73
+ );
74
+ } finally {
75
+ handle.stop();
76
+ }
77
+ });
78
+
79
+ test("a failed deep pass retries deep on the next tick, never throws", async () => {
80
+ const { calls, warnings, deps } = makeDeps({ failTimes: 1 });
81
+ const handle = startWearablesAutoSync(SETTINGS, deps);
82
+ try {
83
+ await handle.tick();
84
+ assert.equal(calls.length, 0, "first tick failed");
85
+ assert.equal(warnings.length, 1);
86
+ assert.match(warnings[0], /retrying on the next tick/);
87
+ await handle.tick();
88
+ assert.deepEqual(
89
+ calls.map((call) => call.days),
90
+ [7],
91
+ "deep window retries — a failure must not consume the daily deep slot",
92
+ );
93
+ } finally {
94
+ handle.stop();
95
+ }
96
+ });
97
+
98
+ test("deepDays 0 disables the deep pass entirely", async () => {
99
+ const { calls, deps } = makeDeps();
100
+ const handle = startWearablesAutoSync({ ...SETTINGS, deepDays: 0 }, deps);
101
+ try {
102
+ await handle.tick();
103
+ await handle.tick();
104
+ assert.deepEqual(
105
+ calls.map((call) => call.days),
106
+ [2, 2],
107
+ );
108
+ } finally {
109
+ handle.stop();
110
+ }
111
+ });
112
+
113
+ test("overlapping ticks are skipped, not stacked", async () => {
114
+ const calls: Array<{ days: number }> = [];
115
+ let release: (() => void) | null = null;
116
+ const handle = startWearablesAutoSync(SETTINGS, {
117
+ sync: async (options) => {
118
+ calls.push(options);
119
+ await new Promise<void>((resolve) => {
120
+ release = resolve;
121
+ });
122
+ return [];
123
+ },
124
+ log: { info: () => {}, warn: () => {} },
125
+ now: () => new Date("2026-06-12T10:00:00.000Z"),
126
+ });
127
+ try {
128
+ const first = handle.tick();
129
+ const second = handle.tick();
130
+ await second;
131
+ assert.equal(calls.length, 1, "second tick is a no-op while the first runs");
132
+ release!();
133
+ await first;
134
+ } finally {
135
+ handle.stop();
136
+ }
137
+ });
138
+
139
+ test("stop() prevents any further ticks", async () => {
140
+ const { calls, deps } = makeDeps();
141
+ const handle = startWearablesAutoSync(SETTINGS, deps);
142
+ await handle.stop();
143
+ await handle.tick();
144
+ assert.equal(calls.length, 0);
145
+ });
146
+
147
+ test("stop() aborts the in-flight sync and awaits its settlement", async () => {
148
+ const warnings: string[] = [];
149
+ let sawSignal: AbortSignal | undefined;
150
+ let syncSettled = false;
151
+ const handle = startWearablesAutoSync(SETTINGS, {
152
+ sync: async (options) => {
153
+ sawSignal = options.signal;
154
+ // Hang until the shutdown abort arrives, like a slow provider.
155
+ await new Promise<void>((_resolve, reject) => {
156
+ options.signal!.addEventListener("abort", () =>
157
+ reject(new Error("aborted")),
158
+ );
159
+ }).finally(() => {
160
+ syncSettled = true;
161
+ });
162
+ },
163
+ log: {
164
+ info: () => {},
165
+ warn: (message: string) => {
166
+ warnings.push(message);
167
+ },
168
+ },
169
+ now: () => new Date("2026-06-12T10:00:00.000Z"),
170
+ });
171
+ const inFlight = handle.tick();
172
+ assert.ok(sawSignal instanceof AbortSignal, "sync receives the abort signal");
173
+ await handle.stop();
174
+ assert.equal(syncSettled, true, "stop() resolves only after the tick settled");
175
+ assert.equal(
176
+ warnings.length,
177
+ 0,
178
+ "an abort raised by shutdown is intentional, never warned",
179
+ );
180
+ await inFlight;
181
+ });
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Wearables auto-sync — in-process periodic transcript refresh.
3
+ *
4
+ * Every tick re-syncs a short rolling window ending today for ALL
5
+ * enabled sources, so the current day's transcript keeps growing while
6
+ * the wearable records and provider-side revisions of recent days flow
7
+ * in without operator action. Once per local day the window deepens to
8
+ * `autoSyncDeepDays` to pick up late uploads and provider reprocessing
9
+ * further back (phones syncing hours later, re-diarized transcripts).
10
+ *
11
+ * Day fetches are unconditional within the window — existing day files
12
+ * are always re-fetched and re-composed; the content-hash skip in the
13
+ * pipeline keeps unchanged days write-free, so a tick on a quiet day
14
+ * is read-only. The timer is unref'd: it never keeps a one-shot CLI
15
+ * process alive, and long-lived hosts stop it via the returned handle.
16
+ */
17
+
18
+ import { describeErrorForOperator } from "./errors.js";
19
+ import { dateInTimezone, defaultTimezone } from "./pipeline.js";
20
+
21
+ export interface WearablesAutoSyncSettings {
22
+ /** Minutes between ticks. */
23
+ intervalMinutes: number;
24
+ /** Rolling window (days ending today) refreshed on a normal tick. */
25
+ days: number;
26
+ /**
27
+ * Window for the once-per-local-day deep pass. 0 disables the deep
28
+ * pass; otherwise must be >= `days` (validated at config parse).
29
+ */
30
+ deepDays: number;
31
+ /** IANA timezone used to detect the local-day rollover. */
32
+ timezone?: string;
33
+ }
34
+
35
+ export interface WearablesAutoSyncDeps {
36
+ /** Run a sync across all enabled sources (WearablesService.sync). */
37
+ sync(options: { days: number; signal?: AbortSignal }): Promise<unknown>;
38
+ log: { info(message: string): void; warn(message: string): void };
39
+ /** Clock injection for tests. */
40
+ now?: () => Date;
41
+ }
42
+
43
+ export interface WearablesAutoSyncHandle {
44
+ /** Run one scheduler tick now (first-run hook and test seam). */
45
+ tick(): Promise<void>;
46
+ /**
47
+ * Stop the scheduler: clears the timer, aborts the in-flight sync's
48
+ * provider fetches via AbortSignal, and resolves once the in-flight
49
+ * tick has fully settled — after `await stop()` nothing is writing
50
+ * or reindexing anymore. The handle is single-use; a restarted host
51
+ * starts a fresh one.
52
+ */
53
+ stop(): Promise<void>;
54
+ }
55
+
56
+ /**
57
+ * Start the periodic refresh. The first tick fires after one full
58
+ * interval rather than at start — gateways on low-power hardware can
59
+ * restart-loop during setup (issue #462), and an immediate fetch on
60
+ * every restart would hammer provider APIs. Operators who want an
61
+ * instant refresh run `wearables sync` (or call `tick()`).
62
+ */
63
+ export function startWearablesAutoSync(
64
+ settings: WearablesAutoSyncSettings,
65
+ deps: WearablesAutoSyncDeps,
66
+ ): WearablesAutoSyncHandle {
67
+ let inFlight: Promise<void> | null = null;
68
+ let stopped = false;
69
+ let lastDeepDate: string | null = null;
70
+ // Aborting cancels the in-flight sync's provider fetches promptly on
71
+ // shutdown — without it, a slow tick would keep writing/reindexing
72
+ // after orchestrator.destroy() while a restarted host starts a
73
+ // second scheduler (Kilo review on PR #1464).
74
+ const abortController = new AbortController();
75
+
76
+ const tick = async (): Promise<void> => {
77
+ // Overlap guard: a slow provider or large deep window must never
78
+ // stack a second sync on top of a running one. The skipped call
79
+ // resolves immediately — it must NOT await the running tick, or a
80
+ // caller holding both promises could deadlock itself.
81
+ if (inFlight || stopped) return;
82
+ const run = (async () => {
83
+ try {
84
+ const now = deps.now ? deps.now() : new Date();
85
+ const today = dateInTimezone(now, settings.timezone ?? defaultTimezone());
86
+ const deep = settings.deepDays > 0 && lastDeepDate !== today;
87
+ const days = deep ? settings.deepDays : settings.days;
88
+ await deps.sync({ days, signal: abortController.signal });
89
+ // Mark the deep pass done only AFTER it succeeded — a failed
90
+ // deep pass retries on the next tick instead of silently
91
+ // waiting for tomorrow (CLAUDE.md rule 25's "confirm before
92
+ // consuming the one-shot" shape).
93
+ if (deep) lastDeepDate = today;
94
+ deps.log.info(
95
+ `wearables auto-sync: refreshed ${days}-day window${deep ? " (daily deep pass)" : ""}`,
96
+ );
97
+ } catch (err) {
98
+ // An abort raised by stop() is intentional shutdown, not a
99
+ // failure — warning about it would be noise in every clean
100
+ // shutdown log.
101
+ if (!stopped) {
102
+ deps.log.warn(
103
+ `wearables auto-sync failed: ${describeErrorForOperator(err)} — retrying on the next tick`,
104
+ );
105
+ }
106
+ } finally {
107
+ inFlight = null;
108
+ }
109
+ })();
110
+ inFlight = run;
111
+ await run;
112
+ };
113
+
114
+ const timer = setInterval(() => {
115
+ void tick();
116
+ }, settings.intervalMinutes * 60_000);
117
+ timer.unref?.();
118
+
119
+ return {
120
+ tick,
121
+ stop: async () => {
122
+ stopped = true;
123
+ clearInterval(timer);
124
+ abortController.abort();
125
+ // tick() never rejects (all paths caught), so this only waits.
126
+ if (inFlight) await inFlight;
127
+ },
128
+ };
129
+ }
@@ -125,6 +125,12 @@ function renderSyncSummary(summary: WearableSyncSummary): string {
125
125
  ` transcripts written: ${summary.transcriptsWritten.length > 0 ? summary.transcriptsWritten.join(", ") : "(none — unchanged)"}`,
126
126
  ` memories created: ${summary.memoriesCreated} (skipped ${summary.memoriesSkipped})`,
127
127
  ];
128
+ if (summary.memoriesPromoted > 0) {
129
+ lines.push(` memories promoted: ${summary.memoriesPromoted}`);
130
+ }
131
+ if (summary.memoriesDemoted > 0) {
132
+ lines.push(` memories demoted: ${summary.memoriesDemoted}`);
133
+ }
128
134
  if (summary.nativeMemoriesImported > 0) {
129
135
  lines.push(` native memories queued: ${summary.nativeMemoriesImported}`);
130
136
  }