@ouro.bot/cli 0.1.0-alpha.52 → 0.1.0-alpha.521

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 (383) hide show
  1. package/README.md +133 -19
  2. package/RepairGuide.ouro/agent.json +5 -0
  3. package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
  4. package/RepairGuide.ouro/psyche/SOUL.md +55 -0
  5. package/RepairGuide.ouro/skills/diagnose-bootstrap-drift.md +54 -0
  6. package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
  7. package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
  8. package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
  9. package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
  10. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
  11. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
  12. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
  13. package/changelog.json +3361 -0
  14. package/dist/arc/attention-types.js +8 -0
  15. package/dist/arc/cares.js +140 -0
  16. package/dist/arc/episodes.js +117 -0
  17. package/dist/arc/intentions.js +133 -0
  18. package/dist/arc/json-store.js +117 -0
  19. package/dist/arc/obligations.js +237 -0
  20. package/dist/arc/packets.js +193 -0
  21. package/dist/arc/presence.js +185 -0
  22. package/dist/arc/task-lifecycle.js +65 -0
  23. package/dist/heart/active-work.js +837 -26
  24. package/dist/heart/agent-entry.js +58 -3
  25. package/dist/heart/attachments/image-normalize.js +194 -0
  26. package/dist/heart/attachments/materialize.js +97 -0
  27. package/dist/heart/attachments/originals.js +88 -0
  28. package/dist/heart/attachments/render.js +29 -0
  29. package/dist/heart/attachments/sources/adapter.js +2 -0
  30. package/dist/heart/attachments/sources/bluebubbles.js +156 -0
  31. package/dist/heart/attachments/sources/cli-local-file.js +78 -0
  32. package/dist/heart/attachments/sources/index.js +16 -0
  33. package/dist/heart/attachments/store.js +103 -0
  34. package/dist/heart/attachments/types.js +93 -0
  35. package/dist/heart/auth/auth-flow.js +427 -0
  36. package/dist/heart/background-operations.js +281 -0
  37. package/dist/heart/bundle-state.js +168 -0
  38. package/dist/heart/commitments.js +111 -0
  39. package/dist/heart/config-registry.js +304 -0
  40. package/dist/heart/config.js +119 -129
  41. package/dist/heart/core.js +948 -243
  42. package/dist/heart/cross-chat-delivery.js +3 -18
  43. package/dist/heart/daemon/agent-config-check.js +512 -0
  44. package/dist/heart/daemon/agent-discovery.js +102 -3
  45. package/dist/heart/daemon/agent-service.js +360 -0
  46. package/dist/heart/daemon/agentic-repair.js +554 -0
  47. package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
  48. package/dist/heart/daemon/boot-sync-probe.js +197 -0
  49. package/dist/heart/daemon/cadence.js +70 -0
  50. package/dist/heart/daemon/cli-defaults.js +643 -0
  51. package/dist/heart/daemon/cli-exec.js +7476 -0
  52. package/dist/heart/daemon/cli-help.js +493 -0
  53. package/dist/heart/daemon/cli-parse.js +1557 -0
  54. package/dist/heart/daemon/cli-render-doctor.js +57 -0
  55. package/dist/heart/daemon/cli-render.js +649 -0
  56. package/dist/heart/daemon/cli-types.js +8 -0
  57. package/dist/heart/daemon/connect-bay.js +323 -0
  58. package/dist/heart/daemon/daemon-cli.js +29 -1631
  59. package/dist/heart/daemon/daemon-entry.js +404 -3
  60. package/dist/heart/daemon/daemon-health.js +183 -0
  61. package/dist/heart/daemon/daemon-rollup.js +58 -0
  62. package/dist/heart/daemon/daemon-runtime-sync.js +190 -12
  63. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  64. package/dist/heart/daemon/daemon.js +758 -60
  65. package/dist/heart/daemon/dns-workflow.js +394 -0
  66. package/dist/heart/daemon/doctor-types.js +8 -0
  67. package/dist/heart/daemon/doctor.js +837 -0
  68. package/dist/heart/daemon/drift-detection.js +146 -0
  69. package/dist/heart/daemon/health-monitor.js +92 -1
  70. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  71. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  72. package/dist/heart/daemon/http-health-probe.js +80 -0
  73. package/dist/heart/daemon/human-command-screens.js +234 -0
  74. package/dist/heart/daemon/human-readiness.js +114 -0
  75. package/dist/heart/daemon/inner-status.js +102 -0
  76. package/dist/heart/daemon/interactive-repair.js +394 -0
  77. package/dist/heart/daemon/launchd.js +25 -5
  78. package/dist/heart/daemon/log-tailer.js +82 -12
  79. package/dist/heart/daemon/logs-prune.js +110 -0
  80. package/dist/heart/daemon/message-router.js +2 -2
  81. package/dist/heart/daemon/os-cron-deps.js +134 -0
  82. package/dist/heart/daemon/ouro-bot-entry.js +4 -2
  83. package/dist/heart/daemon/ouro-entry.js +3 -1
  84. package/dist/heart/daemon/process-manager.js +381 -26
  85. package/dist/heart/daemon/provider-discovery.js +137 -0
  86. package/dist/heart/daemon/provider-ping-progress.js +83 -0
  87. package/dist/heart/daemon/pulse.js +475 -0
  88. package/dist/heart/daemon/readiness-repair.js +365 -0
  89. package/dist/heart/daemon/run-hooks.js +2 -0
  90. package/dist/heart/daemon/runtime-logging.js +67 -16
  91. package/dist/heart/daemon/runtime-metadata.js +73 -0
  92. package/dist/heart/daemon/runtime-mode.js +67 -0
  93. package/dist/heart/daemon/safe-mode.js +161 -0
  94. package/dist/heart/daemon/sense-manager.js +259 -37
  95. package/dist/heart/daemon/session-id-resolver.js +131 -0
  96. package/dist/heart/daemon/skill-management-installer.js +94 -0
  97. package/dist/heart/daemon/socket-client.js +109 -4
  98. package/dist/heart/daemon/stale-bundle-prune.js +96 -0
  99. package/dist/heart/daemon/startup-tui.js +330 -0
  100. package/dist/heart/daemon/task-scheduler.js +3 -25
  101. package/dist/heart/daemon/terminal-ui.js +499 -0
  102. package/dist/heart/daemon/thoughts.js +162 -17
  103. package/dist/heart/daemon/up-progress.js +366 -0
  104. package/dist/heart/daemon/vault-items.js +56 -0
  105. package/dist/heart/delegation.js +1 -1
  106. package/dist/heart/habits/habit-migration.js +189 -0
  107. package/dist/heart/habits/habit-parser.js +140 -0
  108. package/dist/heart/habits/habit-runtime-state.js +100 -0
  109. package/dist/heart/habits/habit-scheduler.js +372 -0
  110. package/dist/heart/{daemon → hatch}/hatch-flow.js +52 -117
  111. package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
  112. package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
  113. package/dist/heart/{daemon → hatch}/specialist-tools.js +35 -12
  114. package/dist/heart/identity.js +205 -66
  115. package/dist/heart/kept-notes.js +357 -0
  116. package/dist/heart/kicks.js +1 -1
  117. package/dist/heart/machine-identity.js +161 -0
  118. package/dist/heart/mail-import-discovery.js +353 -0
  119. package/dist/heart/mcp/mcp-server.js +653 -0
  120. package/dist/heart/migrate-config.js +100 -0
  121. package/dist/heart/model-capabilities.js +19 -0
  122. package/dist/heart/outlook/outlook-http-hooks.js +66 -0
  123. package/dist/heart/outlook/outlook-http-response.js +7 -0
  124. package/dist/heart/outlook/outlook-http-routes.js +244 -0
  125. package/dist/heart/outlook/outlook-http-static.js +103 -0
  126. package/dist/heart/outlook/outlook-http-transport.js +116 -0
  127. package/dist/heart/outlook/outlook-http.js +99 -0
  128. package/dist/heart/outlook/outlook-read.js +31 -0
  129. package/dist/heart/outlook/outlook-types.js +27 -0
  130. package/dist/heart/outlook/outlook-view.js +195 -0
  131. package/dist/heart/outlook/readers/agent-machine.js +382 -0
  132. package/dist/heart/outlook/readers/continuity-readers.js +336 -0
  133. package/dist/heart/outlook/readers/mail.js +362 -0
  134. package/dist/heart/outlook/readers/runtime-readers.js +650 -0
  135. package/dist/heart/outlook/readers/sessions.js +232 -0
  136. package/dist/heart/outlook/readers/shared.js +111 -0
  137. package/dist/heart/platform.js +81 -0
  138. package/dist/heart/provider-attempt.js +134 -0
  139. package/dist/heart/provider-binding-resolver.js +255 -0
  140. package/dist/heart/provider-credentials.js +425 -0
  141. package/dist/heart/provider-failover.js +301 -0
  142. package/dist/heart/provider-models.js +81 -0
  143. package/dist/heart/provider-ping.js +262 -0
  144. package/dist/heart/provider-state.js +216 -0
  145. package/dist/heart/provider-visibility.js +188 -0
  146. package/dist/heart/providers/anthropic-token.js +131 -0
  147. package/dist/heart/providers/anthropic.js +139 -52
  148. package/dist/heart/providers/azure.js +97 -13
  149. package/dist/heart/providers/error-classification.js +127 -0
  150. package/dist/heart/providers/github-copilot.js +145 -0
  151. package/dist/heart/providers/minimax-vlm.js +189 -0
  152. package/dist/heart/providers/minimax.js +26 -8
  153. package/dist/heart/providers/openai-codex.js +55 -40
  154. package/dist/heart/runtime-capability-check.js +170 -0
  155. package/dist/heart/runtime-credentials.js +367 -0
  156. package/dist/heart/sense-truth.js +11 -4
  157. package/dist/heart/session-activity.js +43 -22
  158. package/dist/heart/session-events.js +1149 -0
  159. package/dist/heart/session-playback-cli-main.js +5 -0
  160. package/dist/heart/session-playback-cli.js +36 -0
  161. package/dist/heart/session-playback.js +231 -0
  162. package/dist/heart/session-stats-cli-main.js +5 -0
  163. package/dist/heart/session-stats.js +182 -0
  164. package/dist/heart/session-transcript.js +243 -0
  165. package/dist/heart/start-of-turn-packet.js +345 -0
  166. package/dist/heart/streaming.js +44 -27
  167. package/dist/heart/sync-classification.js +176 -0
  168. package/dist/heart/sync.js +449 -0
  169. package/dist/heart/target-resolution.js +9 -5
  170. package/dist/heart/tempo.js +93 -0
  171. package/dist/heart/temporal-view.js +41 -0
  172. package/dist/heart/timeouts.js +101 -0
  173. package/dist/heart/tool-activity-callbacks.js +36 -0
  174. package/dist/heart/tool-description.js +139 -0
  175. package/dist/heart/tool-friction.js +55 -0
  176. package/dist/heart/tool-loop.js +200 -0
  177. package/dist/heart/turn-context.js +381 -0
  178. package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
  179. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  180. package/dist/heart/versioning/ouro-path-installer.js +425 -0
  181. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  182. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  183. package/dist/heart/{daemon → versioning}/update-checker.js +5 -1
  184. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  185. package/dist/mailroom/attention.js +167 -0
  186. package/dist/mailroom/autonomy.js +209 -0
  187. package/dist/mailroom/blob-store.js +606 -0
  188. package/dist/mailroom/body-cache.js +61 -0
  189. package/dist/mailroom/core.js +672 -0
  190. package/dist/mailroom/entry.js +160 -0
  191. package/dist/mailroom/file-store.js +426 -0
  192. package/dist/mailroom/mbox-import.js +382 -0
  193. package/dist/mailroom/outbound.js +380 -0
  194. package/dist/mailroom/policy.js +263 -0
  195. package/dist/mailroom/reader.js +228 -0
  196. package/dist/mailroom/search-cache.js +182 -0
  197. package/dist/mailroom/search-relevance.js +319 -0
  198. package/dist/mailroom/smtp-ingress.js +176 -0
  199. package/dist/mailroom/source-state.js +176 -0
  200. package/dist/mailroom/thread.js +109 -0
  201. package/dist/mailroom/travel-extract.js +89 -0
  202. package/dist/mind/bundle-manifest.js +7 -1
  203. package/dist/mind/context.js +165 -101
  204. package/dist/mind/diary-integrity.js +60 -0
  205. package/dist/mind/{memory.js → diary.js} +74 -93
  206. package/dist/mind/embedding-provider.js +60 -0
  207. package/dist/mind/file-state.js +179 -0
  208. package/dist/mind/friends/channel.js +30 -0
  209. package/dist/mind/friends/resolver.js +54 -2
  210. package/dist/mind/friends/store-file.js +39 -3
  211. package/dist/mind/friends/types.js +2 -2
  212. package/dist/mind/journal-index.js +161 -0
  213. package/dist/mind/note-search.js +268 -0
  214. package/dist/mind/obligation-steering.js +221 -0
  215. package/dist/mind/pending.js +4 -0
  216. package/dist/mind/prompt-refresh.js +3 -2
  217. package/dist/mind/prompt.js +942 -122
  218. package/dist/mind/provenance-trust.js +26 -0
  219. package/dist/mind/scrutiny.js +173 -0
  220. package/dist/nerves/cli-logging.js +7 -1
  221. package/dist/nerves/coverage/audit-rules.js +15 -6
  222. package/dist/nerves/coverage/audit.js +28 -2
  223. package/dist/nerves/coverage/cli.js +1 -1
  224. package/dist/nerves/coverage/contract.js +5 -5
  225. package/dist/nerves/coverage/file-completeness.js +139 -5
  226. package/dist/nerves/coverage/run-artifacts.js +1 -1
  227. package/dist/nerves/event-buffer.js +111 -0
  228. package/dist/nerves/index.js +224 -4
  229. package/dist/nerves/observation.js +20 -0
  230. package/dist/nerves/redact.js +79 -0
  231. package/dist/nerves/review/cli-main.js +5 -0
  232. package/dist/nerves/review/cli.js +156 -0
  233. package/dist/nerves/review/core.js +152 -0
  234. package/dist/nerves/runtime.js +5 -1
  235. package/dist/outlook-ui/assets/index-BPr5vNuM.css +1 -0
  236. package/dist/outlook-ui/assets/index-Cm51CY9W.js +61 -0
  237. package/dist/outlook-ui/index.html +15 -0
  238. package/dist/repertoire/ado-client.js +15 -56
  239. package/dist/repertoire/ado-semantic.js +11 -10
  240. package/dist/repertoire/api-client.js +97 -0
  241. package/dist/repertoire/bitwarden-store.js +816 -0
  242. package/dist/repertoire/bundle-templates.js +72 -0
  243. package/dist/repertoire/bw-installer.js +180 -0
  244. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  245. package/dist/repertoire/coding/context-pack.js +330 -0
  246. package/dist/repertoire/coding/feedback.js +197 -30
  247. package/dist/repertoire/coding/manager.js +158 -9
  248. package/dist/repertoire/coding/spawner.js +55 -9
  249. package/dist/repertoire/coding/tools.js +170 -7
  250. package/dist/repertoire/commerce-errors.js +109 -0
  251. package/dist/repertoire/commerce-self-test.js +156 -0
  252. package/dist/repertoire/credential-access.js +111 -0
  253. package/dist/repertoire/duffel-client.js +185 -0
  254. package/dist/repertoire/github-client.js +14 -55
  255. package/dist/repertoire/graph-client.js +11 -52
  256. package/dist/repertoire/guardrails.js +396 -0
  257. package/dist/repertoire/mcp-client.js +255 -0
  258. package/dist/repertoire/mcp-manager.js +305 -0
  259. package/dist/repertoire/mcp-tools.js +63 -0
  260. package/dist/repertoire/shell-sessions.js +133 -0
  261. package/dist/repertoire/skills.js +15 -24
  262. package/dist/repertoire/stripe-client.js +131 -0
  263. package/dist/repertoire/tasks/board.js +31 -5
  264. package/dist/repertoire/tasks/fix.js +182 -0
  265. package/dist/repertoire/tasks/index.js +16 -4
  266. package/dist/repertoire/tasks/lifecycle.js +2 -2
  267. package/dist/repertoire/tasks/parser.js +3 -2
  268. package/dist/repertoire/tasks/scanner.js +194 -37
  269. package/dist/repertoire/tasks/transitions.js +16 -78
  270. package/dist/repertoire/tool-results.js +29 -0
  271. package/dist/repertoire/tools-attachments.js +317 -0
  272. package/dist/repertoire/tools-base.js +47 -1075
  273. package/dist/repertoire/tools-bluebubbles.js +1 -0
  274. package/dist/repertoire/tools-bridge.js +142 -0
  275. package/dist/repertoire/tools-bundle.js +984 -0
  276. package/dist/repertoire/tools-config.js +185 -0
  277. package/dist/repertoire/tools-continuity.js +248 -0
  278. package/dist/repertoire/tools-credential.js +381 -0
  279. package/dist/repertoire/tools-files.js +342 -0
  280. package/dist/repertoire/tools-flight.js +224 -0
  281. package/dist/repertoire/tools-flow.js +119 -0
  282. package/dist/repertoire/tools-github.js +1 -7
  283. package/dist/repertoire/tools-mail.js +1477 -0
  284. package/dist/repertoire/tools-notes.js +421 -0
  285. package/dist/repertoire/tools-session.js +750 -0
  286. package/dist/repertoire/tools-shell.js +120 -0
  287. package/dist/repertoire/tools-stripe.js +180 -0
  288. package/dist/repertoire/tools-surface.js +243 -0
  289. package/dist/repertoire/tools-teams.js +9 -39
  290. package/dist/repertoire/tools-travel.js +125 -0
  291. package/dist/repertoire/tools-trip.js +422 -0
  292. package/dist/repertoire/tools-user-profile.js +144 -0
  293. package/dist/repertoire/tools-vault.js +40 -0
  294. package/dist/repertoire/tools.js +108 -100
  295. package/dist/repertoire/travel-api-client.js +360 -0
  296. package/dist/repertoire/user-profile.js +131 -0
  297. package/dist/repertoire/vault-setup.js +246 -0
  298. package/dist/repertoire/vault-unlock.js +561 -0
  299. package/dist/scripts/claude-code-hook.js +41 -0
  300. package/dist/scripts/claude-code-stop-hook.js +47 -0
  301. package/dist/senses/attention-queue.js +116 -0
  302. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  303. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  304. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
  305. package/dist/senses/bluebubbles/entry.js +77 -0
  306. package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
  307. package/dist/senses/bluebubbles/index.js +1947 -0
  308. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
  309. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
  310. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
  311. package/dist/senses/bluebubbles/processed-log.js +111 -0
  312. package/dist/senses/bluebubbles/replay.js +129 -0
  313. package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +2 -2
  314. package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
  315. package/dist/senses/cli/bracketed-paste.js +82 -0
  316. package/dist/senses/cli/image-paste.js +287 -0
  317. package/dist/senses/cli/image-ref-navigation.js +75 -0
  318. package/dist/senses/cli/ink-app.js +156 -0
  319. package/dist/senses/cli/inline-diff.js +64 -0
  320. package/dist/senses/cli/input-keys.js +174 -0
  321. package/dist/senses/cli/kill-ring.js +86 -0
  322. package/dist/senses/cli/message-list.js +51 -0
  323. package/dist/senses/cli/ouro-tui.js +607 -0
  324. package/dist/senses/cli/spinner-imperative.js +135 -0
  325. package/dist/senses/cli/spinner.js +101 -0
  326. package/dist/senses/cli/status-line.js +60 -0
  327. package/dist/senses/cli/streaming-markdown.js +526 -0
  328. package/dist/senses/cli/tool-display.js +85 -0
  329. package/dist/senses/cli/tool-render.js +85 -0
  330. package/dist/senses/cli/tui-store.js +240 -0
  331. package/dist/senses/cli/virtual-list.js +35 -0
  332. package/dist/senses/cli-entry.js +60 -8
  333. package/dist/senses/cli-layout.js +187 -0
  334. package/dist/senses/cli.js +520 -209
  335. package/dist/senses/commands.js +66 -3
  336. package/dist/senses/habit-turn-message.js +108 -0
  337. package/dist/senses/inner-dialog-worker.js +175 -21
  338. package/dist/senses/inner-dialog.js +330 -27
  339. package/dist/senses/mail-entry.js +66 -0
  340. package/dist/senses/mail.js +379 -0
  341. package/dist/senses/pipeline.js +569 -182
  342. package/dist/senses/proactive-content-guard.js +51 -0
  343. package/dist/senses/shared-turn.js +248 -0
  344. package/dist/senses/surface-tool.js +68 -0
  345. package/dist/senses/teams-entry.js +60 -8
  346. package/dist/senses/teams.js +387 -98
  347. package/dist/senses/trust-gate.js +100 -5
  348. package/dist/trips/core.js +138 -0
  349. package/dist/trips/store.js +146 -0
  350. package/package.json +38 -7
  351. package/skills/agent-commerce.md +106 -0
  352. package/skills/browser-navigation.md +117 -0
  353. package/skills/commerce-setup-guide.md +116 -0
  354. package/skills/commerce-setup.md +84 -0
  355. package/skills/configure-dev-tools.md +101 -0
  356. package/skills/travel-planning.md +138 -0
  357. package/dist/heart/daemon/ouro-path-installer.js +0 -178
  358. package/dist/heart/daemon/subagent-installer.js +0 -166
  359. package/dist/heart/session-recall.js +0 -116
  360. package/dist/mind/associative-recall.js +0 -209
  361. package/dist/senses/bluebubbles-entry.js +0 -13
  362. package/dist/senses/bluebubbles.js +0 -1177
  363. package/dist/senses/debug-activity.js +0 -148
  364. package/subagents/README.md +0 -86
  365. package/subagents/work-doer.md +0 -237
  366. package/subagents/work-merger.md +0 -618
  367. package/subagents/work-planner.md +0 -390
  368. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  369. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  370. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  371. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  372. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  373. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  374. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  375. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  376. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  377. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  378. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  379. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  380. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  381. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  382. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  383. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -33,52 +33,25 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.__memoryTestUtils = void 0;
37
- exports.ensureMemoryStorePaths = ensureMemoryStorePaths;
38
- exports.appendFactsWithDedup = appendFactsWithDedup;
39
- exports.readMemoryFacts = readMemoryFacts;
40
- exports.saveMemoryFact = saveMemoryFact;
36
+ exports.ensureDiaryStorePaths = ensureDiaryStorePaths;
37
+ exports.appendEntriesWithDedup = appendEntriesWithDedup;
38
+ exports.resolveDiaryRoot = resolveDiaryRoot;
39
+ exports.readDiaryEntries = readDiaryEntries;
40
+ exports.saveDiaryEntry = saveDiaryEntry;
41
41
  exports.backfillEmbeddings = backfillEmbeddings;
42
- exports.searchMemoryFacts = searchMemoryFacts;
42
+ exports.searchDiaryEntries = searchDiaryEntries;
43
43
  const fs = __importStar(require("fs"));
44
44
  const path = __importStar(require("path"));
45
45
  const crypto_1 = require("crypto");
46
- const config_1 = require("../heart/config");
47
46
  const identity_1 = require("../heart/identity");
48
47
  const runtime_1 = require("../nerves/runtime");
48
+ const note_search_1 = require("./note-search");
49
+ const diary_integrity_1 = require("./diary-integrity");
50
+ const embedding_provider_1 = require("./embedding-provider");
49
51
  const DEDUP_THRESHOLD = 0.6;
52
+ const SEMANTIC_DEDUP_THRESHOLD = 0.95;
50
53
  const ENTITY_TOKEN = /[a-z0-9]+/g;
51
- const DEFAULT_EMBEDDING_MODEL = "text-embedding-3-small";
52
- class OpenAIEmbeddingProvider {
53
- apiKey;
54
- model;
55
- constructor(apiKey, model = DEFAULT_EMBEDDING_MODEL) {
56
- this.apiKey = apiKey;
57
- this.model = model;
58
- }
59
- async embed(texts) {
60
- const response = await fetch("https://api.openai.com/v1/embeddings", {
61
- method: "POST",
62
- headers: {
63
- Authorization: `Bearer ${this.apiKey}`,
64
- "Content-Type": "application/json",
65
- },
66
- body: JSON.stringify({
67
- model: this.model,
68
- input: texts,
69
- }),
70
- });
71
- if (!response.ok) {
72
- throw new Error(`embedding request failed: ${response.status} ${response.statusText}`);
73
- }
74
- const payload = (await response.json());
75
- if (!payload.data || payload.data.length !== texts.length) {
76
- throw new Error("embedding response missing expected vectors");
77
- }
78
- return payload.data.map((entry) => entry.embedding);
79
- }
80
- }
81
- function ensureMemoryStorePaths(rootDir) {
54
+ function ensureDiaryStorePaths(rootDir) {
82
55
  const factsPath = path.join(rootDir, "facts.jsonl");
83
56
  const entitiesPath = path.join(rootDir, "entities.json");
84
57
  const dailyDir = path.join(rootDir, "daily");
@@ -90,8 +63,8 @@ function ensureMemoryStorePaths(rootDir) {
90
63
  fs.writeFileSync(entitiesPath, "{}\n", "utf8");
91
64
  (0, runtime_1.emitNervesEvent)({
92
65
  component: "mind",
93
- event: "mind.memory_paths_ready",
94
- message: "memory store paths ready",
66
+ event: "mind.diary_paths_ready",
67
+ message: "diary store paths ready",
95
68
  meta: { rootDir },
96
69
  });
97
70
  return { rootDir, factsPath, entitiesPath, dailyDir };
@@ -114,7 +87,7 @@ function overlapScore(left, right) {
114
87
  }
115
88
  return common / Math.min(leftWords.size, rightWords.size);
116
89
  }
117
- function readExistingFacts(factsPath) {
90
+ function readExistingEntries(factsPath) {
118
91
  if (!fs.existsSync(factsPath))
119
92
  return [];
120
93
  const raw = fs.readFileSync(factsPath, "utf8").trim();
@@ -177,13 +150,24 @@ function appendDailyFact(dailyDir, fact) {
177
150
  const dayPath = path.join(dailyDir, `${day}.jsonl`);
178
151
  fs.appendFileSync(dayPath, `${JSON.stringify(fact)}\n`, "utf8");
179
152
  }
180
- function appendFactsWithDedup(stores, incoming) {
181
- const existing = readExistingFacts(stores.factsPath);
153
+ function appendEntriesWithDedup(stores, incoming, options) {
154
+ const existing = readExistingEntries(stores.factsPath);
182
155
  const all = [...existing];
183
156
  let added = 0;
184
157
  let skipped = 0;
158
+ const semanticThreshold = options?.semanticThreshold;
185
159
  for (const fact of incoming) {
186
- const duplicate = all.some((prior) => overlapScore(prior.text, fact.text) > DEDUP_THRESHOLD);
160
+ const duplicate = all.some((prior) => {
161
+ if (overlapScore(prior.text, fact.text) > DEDUP_THRESHOLD)
162
+ return true;
163
+ if (semanticThreshold !== undefined &&
164
+ Array.isArray(fact.embedding) && fact.embedding.length > 0 &&
165
+ Array.isArray(prior.embedding) && prior.embedding.length > 0 &&
166
+ fact.embedding.length === prior.embedding.length) {
167
+ return (0, note_search_1.cosineSimilarity)(fact.embedding, prior.embedding) > semanticThreshold;
168
+ }
169
+ return false;
170
+ });
187
171
  if (duplicate) {
188
172
  skipped++;
189
173
  continue;
@@ -196,44 +180,20 @@ function appendFactsWithDedup(stores, incoming) {
196
180
  }
197
181
  (0, runtime_1.emitNervesEvent)({
198
182
  component: "mind",
199
- event: "mind.memory_write",
200
- message: "memory write completed",
183
+ event: "mind.diary_write",
184
+ message: "diary write completed",
201
185
  meta: { added, skipped },
202
186
  });
203
187
  return { added, skipped };
204
188
  }
205
- function cosineSimilarity(left, right) {
206
- if (left.length === 0 || right.length === 0 || left.length !== right.length)
207
- return 0;
208
- let dot = 0;
209
- let leftNorm = 0;
210
- let rightNorm = 0;
211
- for (let i = 0; i < left.length; i += 1) {
212
- dot += left[i] * right[i];
213
- leftNorm += left[i] * left[i];
214
- rightNorm += right[i] * right[i];
215
- }
216
- if (leftNorm === 0 || rightNorm === 0)
217
- return 0;
218
- return dot / (Math.sqrt(leftNorm) * Math.sqrt(rightNorm));
219
- }
220
- exports.__memoryTestUtils = {
221
- cosineSimilarity,
222
- };
223
- function createDefaultEmbeddingProvider() {
224
- const apiKey = (0, config_1.getOpenAIEmbeddingsApiKey)().trim();
225
- if (!apiKey)
226
- return null;
227
- return new OpenAIEmbeddingProvider(apiKey);
228
- }
229
189
  async function buildEmbedding(text, embeddingProvider) {
230
- const provider = embeddingProvider ?? createDefaultEmbeddingProvider();
190
+ const provider = embeddingProvider ?? (0, embedding_provider_1.createDefaultEmbeddingProvider)();
231
191
  if (!provider) {
232
192
  (0, runtime_1.emitNervesEvent)({
233
193
  level: "warn",
234
194
  component: "mind",
235
- event: "mind.memory_embedding_unavailable",
236
- message: "embedding provider unavailable for memory write",
195
+ event: "mind.diary_embedding_unavailable",
196
+ message: "embedding provider unavailable for diary write",
237
197
  meta: { reason: "missing_openai_embeddings_key" },
238
198
  });
239
199
  return [];
@@ -246,8 +206,8 @@ async function buildEmbedding(text, embeddingProvider) {
246
206
  (0, runtime_1.emitNervesEvent)({
247
207
  level: "warn",
248
208
  component: "mind",
249
- event: "mind.memory_embedding_unavailable",
250
- message: "embedding provider unavailable for memory write",
209
+ event: "mind.diary_embedding_unavailable",
210
+ message: "embedding provider unavailable for diary write",
251
211
  meta: {
252
212
  reason: error instanceof Error ? error.message : String(error),
253
213
  },
@@ -255,13 +215,19 @@ async function buildEmbedding(text, embeddingProvider) {
255
215
  return [];
256
216
  }
257
217
  }
258
- function readMemoryFacts(memoryRoot = path.join((0, identity_1.getAgentRoot)(), "psyche", "memory")) {
259
- return readExistingFacts(path.join(memoryRoot, "facts.jsonl"));
218
+ function resolveDiaryRoot(explicitRoot) {
219
+ if (explicitRoot)
220
+ return explicitRoot;
221
+ const agentRoot = (0, identity_1.getAgentRoot)();
222
+ return path.join(agentRoot, "diary");
260
223
  }
261
- async function saveMemoryFact(options) {
224
+ function readDiaryEntries(diaryRoot) {
225
+ return readExistingEntries(path.join(resolveDiaryRoot(diaryRoot), "facts.jsonl"));
226
+ }
227
+ async function saveDiaryEntry(options) {
262
228
  const text = options.text.trim();
263
- const memoryRoot = options.memoryRoot ?? path.join((0, identity_1.getAgentRoot)(), "psyche", "memory");
264
- const stores = ensureMemoryStorePaths(memoryRoot);
229
+ const diaryRoot = resolveDiaryRoot(options.diaryRoot);
230
+ const stores = ensureDiaryStorePaths(diaryRoot);
265
231
  const embedding = await buildEmbedding(text, options.embeddingProvider);
266
232
  const fact = {
267
233
  id: options.idFactory ? options.idFactory() : (0, crypto_1.randomUUID)(),
@@ -270,24 +236,39 @@ async function saveMemoryFact(options) {
270
236
  about: options.about?.trim() || undefined,
271
237
  createdAt: (options.now ?? (() => new Date()))().toISOString(),
272
238
  embedding,
239
+ ...(options.provenance ? { provenance: options.provenance } : {}),
273
240
  };
274
- return appendFactsWithDedup(stores, [fact]);
241
+ const integrity = (0, diary_integrity_1.detectSuspiciousContent)(text);
242
+ if (integrity.suspicious) {
243
+ (0, runtime_1.emitNervesEvent)({
244
+ level: "warn",
245
+ component: "mind",
246
+ event: "mind.diary_integrity_warning",
247
+ message: "suspicious content detected in diary entry",
248
+ meta: {
249
+ patterns: integrity.patterns,
250
+ textPreview: text.slice(0, 200),
251
+ entryId: fact.id,
252
+ },
253
+ });
254
+ }
255
+ return appendEntriesWithDedup(stores, [fact], { semanticThreshold: SEMANTIC_DEDUP_THRESHOLD });
275
256
  }
276
257
  async function backfillEmbeddings(options) {
277
- const memoryRoot = options?.memoryRoot ?? path.join((0, identity_1.getAgentRoot)(), "psyche", "memory");
278
- const factsPath = path.join(memoryRoot, "facts.jsonl");
258
+ const diaryRoot = resolveDiaryRoot(options?.diaryRoot);
259
+ const factsPath = path.join(diaryRoot, "facts.jsonl");
279
260
  if (!fs.existsSync(factsPath))
280
261
  return { total: 0, backfilled: 0, failed: 0 };
281
- const facts = readExistingFacts(factsPath);
262
+ const facts = readExistingEntries(factsPath);
282
263
  const needsEmbedding = facts.filter((f) => !Array.isArray(f.embedding) || f.embedding.length === 0);
283
264
  if (needsEmbedding.length === 0)
284
265
  return { total: facts.length, backfilled: 0, failed: 0 };
285
- const provider = options?.embeddingProvider ?? createDefaultEmbeddingProvider();
266
+ const provider = options?.embeddingProvider ?? (0, embedding_provider_1.createDefaultEmbeddingProvider)();
286
267
  if (!provider) {
287
268
  (0, runtime_1.emitNervesEvent)({
288
269
  level: "warn",
289
270
  component: "mind",
290
- event: "mind.memory_backfill_skipped",
271
+ event: "mind.diary_backfill_skipped",
291
272
  message: "embedding provider unavailable for backfill",
292
273
  meta: { needsEmbedding: needsEmbedding.length },
293
274
  });
@@ -313,7 +294,7 @@ async function backfillEmbeddings(options) {
313
294
  (0, runtime_1.emitNervesEvent)({
314
295
  level: "warn",
315
296
  component: "mind",
316
- event: "mind.memory_backfill_batch_error",
297
+ event: "mind.diary_backfill_batch_error",
317
298
  message: "embedding backfill batch failed",
318
299
  meta: {
319
300
  batchStart: i,
@@ -328,7 +309,7 @@ async function backfillEmbeddings(options) {
328
309
  fs.writeFileSync(factsPath, lines, "utf8");
329
310
  (0, runtime_1.emitNervesEvent)({
330
311
  component: "mind",
331
- event: "mind.memory_backfill_complete",
312
+ event: "mind.diary_backfill_complete",
332
313
  message: "embedding backfill completed",
333
314
  meta: { total: facts.length, backfilled, failed },
334
315
  });
@@ -348,7 +329,7 @@ function uniqueFacts(facts) {
348
329
  }
349
330
  return unique;
350
331
  }
351
- async function searchMemoryFacts(query, facts, embeddingProvider) {
332
+ async function searchDiaryEntries(query, facts, embeddingProvider) {
352
333
  const trimmed = query.trim();
353
334
  if (!trimmed)
354
335
  return [];
@@ -358,7 +339,7 @@ async function searchMemoryFacts(query, facts, embeddingProvider) {
358
339
  if (embeddedFacts.length === 0) {
359
340
  return substringFallback();
360
341
  }
361
- const provider = embeddingProvider ?? createDefaultEmbeddingProvider();
342
+ const provider = embeddingProvider ?? (0, embedding_provider_1.createDefaultEmbeddingProvider)();
362
343
  if (!provider) {
363
344
  return substringFallback();
364
345
  }
@@ -372,7 +353,7 @@ async function searchMemoryFacts(query, facts, embeddingProvider) {
372
353
  .filter((fact) => fact.embedding.length === queryEmbedding.length)
373
354
  .map((fact) => ({
374
355
  fact,
375
- score: cosineSimilarity(queryEmbedding, fact.embedding),
356
+ score: (0, note_search_1.cosineSimilarity)(queryEmbedding, fact.embedding),
376
357
  }))
377
358
  .filter((entry) => entry.score > 0)
378
359
  .sort((left, right) => right.score - left.score)
@@ -384,8 +365,8 @@ async function searchMemoryFacts(query, facts, embeddingProvider) {
384
365
  (0, runtime_1.emitNervesEvent)({
385
366
  level: "warn",
386
367
  component: "mind",
387
- event: "mind.memory_embedding_unavailable",
388
- message: "embedding provider unavailable for memory search",
368
+ event: "mind.diary_embedding_unavailable",
369
+ message: "embedding provider unavailable for diary search",
389
370
  meta: {
390
371
  reason: error instanceof Error ? error.message : String(error),
391
372
  },
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ /**
3
+ * Shared OpenAI embedding provider.
4
+ *
5
+ * Both diary.ts and note-search.ts need to call the OpenAI embeddings
6
+ * API. This module provides the shared implementation so neither duplicates
7
+ * the fetch logic.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.OpenAIEmbeddingProvider = void 0;
11
+ exports.createDefaultEmbeddingProvider = createDefaultEmbeddingProvider;
12
+ const config_1 = require("../heart/config");
13
+ const runtime_1 = require("../nerves/runtime");
14
+ const DEFAULT_EMBEDDING_MODEL = "text-embedding-3-small";
15
+ class OpenAIEmbeddingProvider {
16
+ apiKey;
17
+ model;
18
+ constructor(apiKey, model = DEFAULT_EMBEDDING_MODEL) {
19
+ this.apiKey = apiKey;
20
+ this.model = model;
21
+ }
22
+ async embed(texts) {
23
+ const response = await fetch("https://api.openai.com/v1/embeddings", {
24
+ method: "POST",
25
+ headers: {
26
+ Authorization: `Bearer ${this.apiKey}`,
27
+ "Content-Type": "application/json",
28
+ },
29
+ body: JSON.stringify({
30
+ model: this.model,
31
+ input: texts,
32
+ }),
33
+ });
34
+ if (!response.ok) {
35
+ throw new Error(`embedding request failed: ${response.status} ${response.statusText}`);
36
+ }
37
+ const payload = (await response.json());
38
+ if (!payload.data || payload.data.length !== texts.length) {
39
+ throw new Error("embedding response missing expected vectors");
40
+ }
41
+ return payload.data.map((entry) => entry.embedding);
42
+ }
43
+ }
44
+ exports.OpenAIEmbeddingProvider = OpenAIEmbeddingProvider;
45
+ /**
46
+ * Create a default embedding provider from the configured API key.
47
+ * Returns null if no key is configured.
48
+ */
49
+ function createDefaultEmbeddingProvider() {
50
+ const apiKey = (0, config_1.getOpenAIEmbeddingsApiKey)().trim();
51
+ if (!apiKey)
52
+ return null;
53
+ (0, runtime_1.emitNervesEvent)({
54
+ component: "mind",
55
+ event: "mind.embedding_provider_created",
56
+ message: "default embedding provider created",
57
+ meta: { model: DEFAULT_EMBEDDING_MODEL },
58
+ });
59
+ return new OpenAIEmbeddingProvider(apiKey);
60
+ }
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fileStateCache = exports.FileStateCache = void 0;
4
+ exports.contentHash = contentHash;
5
+ const crypto_1 = require("crypto");
6
+ const fs_1 = require("fs");
7
+ const runtime_1 = require("../nerves/runtime");
8
+ /** Compute sha256 hex hash of content */
9
+ function contentHash(content) {
10
+ return (0, crypto_1.createHash)("sha256").update(content).digest("hex");
11
+ }
12
+ /**
13
+ * Session-scoped LRU cache tracking file reads.
14
+ * Stores content hashes (not full content) to limit stored content.
15
+ * Keyed by absolute file path.
16
+ *
17
+ * Also maintains a separate snapshot list for future rewind support.
18
+ * Snapshots are indexed by content hash and linked to conversation messages.
19
+ */
20
+ class FileStateCache {
21
+ entries;
22
+ maxSize;
23
+ snapshots = [];
24
+ maxSnapshots = 100;
25
+ constructor(maxSize = 50) {
26
+ this.entries = new Map();
27
+ this.maxSize = maxSize;
28
+ }
29
+ /**
30
+ * Record a file read. Computes content hash and stores metadata.
31
+ */
32
+ record(filePath, content, mtime, offset, limit, messageId) {
33
+ // If key already exists, delete it so re-insertion moves it to end (most recent)
34
+ if (this.entries.has(filePath)) {
35
+ this.entries.delete(filePath);
36
+ }
37
+ const hash = contentHash(content);
38
+ const fullRead = offset === undefined && limit === undefined;
39
+ this.entries.set(filePath, {
40
+ hash,
41
+ mtime,
42
+ offset: fullRead ? undefined : offset,
43
+ limit: fullRead ? undefined : limit,
44
+ fullRead,
45
+ recordedAt: Date.now(),
46
+ messageId,
47
+ });
48
+ (0, runtime_1.emitNervesEvent)({
49
+ component: "mind",
50
+ event: "mind.file_state.record",
51
+ message: "recorded file state",
52
+ meta: { path: filePath, hash, fullRead },
53
+ });
54
+ // Evict LRU (first entry in Map iteration order) if over capacity
55
+ if (this.entries.size > this.maxSize) {
56
+ const firstKey = this.entries.keys().next().value;
57
+ this.entries.delete(firstKey);
58
+ }
59
+ }
60
+ /**
61
+ * Get the cached state for a file path. Also promotes it in LRU order.
62
+ */
63
+ get(filePath) {
64
+ const entry = this.entries.get(filePath);
65
+ if (entry === undefined)
66
+ return undefined;
67
+ // Promote to most-recently-used by re-inserting
68
+ this.entries.delete(filePath);
69
+ this.entries.set(filePath, entry);
70
+ (0, runtime_1.emitNervesEvent)({
71
+ component: "mind",
72
+ event: "mind.file_state.get",
73
+ message: "retrieved file state",
74
+ meta: { path: filePath, hash: entry.hash },
75
+ });
76
+ return entry;
77
+ }
78
+ /**
79
+ * Check if a file has been modified since the last recorded read.
80
+ * Uses mtime as primary signal, content hash as fallback for cloud sync / touch scenarios.
81
+ * Returns { stale: false } if the path is not in cache or the file cannot be stat'd.
82
+ */
83
+ isStale(filePath) {
84
+ const entry = this.entries.get(filePath);
85
+ if (entry === undefined)
86
+ return { stale: false };
87
+ let currentMtime;
88
+ try {
89
+ currentMtime = (0, fs_1.statSync)(filePath).mtimeMs;
90
+ }
91
+ catch {
92
+ // File doesn't exist or can't be stat'd -- no basis for staleness
93
+ return { stale: false };
94
+ }
95
+ // Fast path: mtime unchanged means not stale
96
+ if (currentMtime === entry.mtime)
97
+ return { stale: false };
98
+ // mtime differs -- check content hash as fallback (handles touch / cloud sync)
99
+ try {
100
+ const currentContent = (0, fs_1.readFileSync)(filePath, "utf-8");
101
+ const currentHash = contentHash(currentContent);
102
+ if (currentHash === entry.hash)
103
+ return { stale: false };
104
+ (0, runtime_1.emitNervesEvent)({
105
+ component: "mind",
106
+ event: "mind.file_state.stale_detected",
107
+ message: "file staleness detected",
108
+ meta: { path: filePath, previousHash: entry.hash, currentHash },
109
+ });
110
+ return { stale: true, reason: `file modified since last read (mtime and content differ)` };
111
+ }
112
+ catch {
113
+ // Can't read file -- treat as not stale (file may have been deleted)
114
+ return { stale: false };
115
+ }
116
+ }
117
+ /**
118
+ * Create a pre-edit snapshot of the current cache state for a file.
119
+ * Snapshots are stored separately from the LRU cache for future rewind support.
120
+ * Returns undefined if the path is not in cache.
121
+ */
122
+ snapshot(filePath) {
123
+ const entry = this.entries.get(filePath);
124
+ if (entry === undefined)
125
+ return undefined;
126
+ const snap = {
127
+ filePath,
128
+ hash: entry.hash,
129
+ mtime: entry.mtime,
130
+ messageId: entry.messageId,
131
+ createdAt: Date.now(),
132
+ };
133
+ this.snapshots.push(snap);
134
+ (0, runtime_1.emitNervesEvent)({
135
+ component: "mind",
136
+ event: "mind.file_state.snapshot_created",
137
+ message: "created file state snapshot",
138
+ meta: { path: filePath, hash: snap.hash },
139
+ });
140
+ // Evict oldest snapshots if over capacity
141
+ if (this.snapshots.length > this.maxSnapshots) {
142
+ this.snapshots = this.snapshots.slice(this.snapshots.length - this.maxSnapshots);
143
+ }
144
+ return snap;
145
+ }
146
+ /**
147
+ * Get all snapshots in creation order.
148
+ */
149
+ getSnapshots() {
150
+ return this.snapshots;
151
+ }
152
+ /**
153
+ * Look up a snapshot by content hash. Returns the first match.
154
+ */
155
+ lookupSnapshotByHash(hash) {
156
+ return this.snapshots.find(s => s.hash === hash);
157
+ }
158
+ /**
159
+ * Clear all snapshots.
160
+ */
161
+ clearSnapshots() {
162
+ this.snapshots = [];
163
+ }
164
+ /**
165
+ * Clear all cached entries (does not clear snapshots).
166
+ */
167
+ clear() {
168
+ (0, runtime_1.emitNervesEvent)({
169
+ component: "mind",
170
+ event: "mind.file_state.clear",
171
+ message: "cleared file state cache",
172
+ meta: { entryCount: this.entries.size },
173
+ });
174
+ this.entries.clear();
175
+ }
176
+ }
177
+ exports.FileStateCache = FileStateCache;
178
+ /** Session-scoped singleton instance used by tool handlers */
179
+ exports.fileStateCache = new FileStateCache();
@@ -2,10 +2,22 @@
2
2
  // Channel capabilities -- hardcoded const map keyed by channel identifier.
3
3
  // Pure lookup, no I/O, cannot fail. Unknown channel gets minimal defaults.
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.channelToFacing = channelToFacing;
5
6
  exports.getChannelCapabilities = getChannelCapabilities;
6
7
  exports.isRemoteChannel = isRemoteChannel;
7
8
  exports.getAlwaysOnSenseNames = getAlwaysOnSenseNames;
8
9
  const runtime_1 = require("../../nerves/runtime");
10
+ const AGENT_FACING_CHANNELS = new Set(["inner", "mcp"]);
11
+ function channelToFacing(channel) {
12
+ const facing = channel && AGENT_FACING_CHANNELS.has(channel) ? "agent" : "human";
13
+ (0, runtime_1.emitNervesEvent)({
14
+ component: "channels",
15
+ event: "channel.facing_lookup",
16
+ message: "channel facing lookup",
17
+ meta: { channel: channel ?? "undefined", facing },
18
+ });
19
+ return facing;
20
+ }
9
21
  const CHANNEL_CAPABILITIES = {
10
22
  cli: {
11
23
  channel: "cli",
@@ -34,6 +46,15 @@ const CHANNEL_CAPABILITIES = {
34
46
  supportsRichCards: false,
35
47
  maxMessageLength: Infinity,
36
48
  },
49
+ mail: {
50
+ channel: "mail",
51
+ senseType: "open",
52
+ availableIntegrations: [],
53
+ supportsMarkdown: false,
54
+ supportsStreaming: false,
55
+ supportsRichCards: false,
56
+ maxMessageLength: Infinity,
57
+ },
37
58
  inner: {
38
59
  channel: "inner",
39
60
  senseType: "internal",
@@ -43,6 +64,15 @@ const CHANNEL_CAPABILITIES = {
43
64
  supportsRichCards: false,
44
65
  maxMessageLength: Infinity,
45
66
  },
67
+ mcp: {
68
+ channel: "mcp",
69
+ senseType: "local",
70
+ availableIntegrations: [],
71
+ supportsMarkdown: true,
72
+ supportsStreaming: false,
73
+ supportsRichCards: false,
74
+ maxMessageLength: Infinity,
75
+ },
46
76
  };
47
77
  const DEFAULT_CAPABILITIES = {
48
78
  channel: "cli",
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  // FriendResolver -- resolves external identity into a FriendRecord + channel capabilities.
3
3
  // Created per-request (per-incoming-message), per-friend.
4
- // Replaces the old ContextResolver: no authority checker, no separate memory resolution.
4
+ // Replaces the old ContextResolver: no authority checker, no separate note resolution.
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.FriendResolver = void 0;
7
7
  const crypto_1 = require("crypto");
@@ -31,6 +31,43 @@ class FriendResolver {
31
31
  }
32
32
  if (existing)
33
33
  return existing;
34
+ // Migration: local provider previously used "${username}@${hostname}" format.
35
+ // If no exact match, try finding a friend with old-format external ID.
36
+ /* v8 ignore start -- migration path: only fires when legacy hostname-format friend exists @preserve */
37
+ if (this.params.provider === "local" && !this.params.externalId.includes("@")) {
38
+ try {
39
+ const all = typeof this.store.listAll === "function" ? await this.store.listAll() : [];
40
+ /* v8 ignore start -- migration path: only fires when legacy hostname-format friend exists @preserve */
41
+ const migrationMatch = all.find((f) => f.externalIds.some((eid) => eid.provider === "local" && eid.externalId.startsWith(this.params.externalId + "@")));
42
+ if (migrationMatch) {
43
+ const now = new Date().toISOString();
44
+ migrationMatch.externalIds.push({
45
+ provider: this.params.provider,
46
+ externalId: this.params.externalId,
47
+ linkedAt: now,
48
+ });
49
+ migrationMatch.updatedAt = now;
50
+ try {
51
+ await this.store.put(migrationMatch.id, migrationMatch);
52
+ }
53
+ catch {
54
+ // best-effort persist
55
+ }
56
+ (0, runtime_1.emitNervesEvent)({
57
+ component: "friends",
58
+ event: "friends.local_id_migrated",
59
+ message: `migrated local friend identity from hostname format to username-only`,
60
+ meta: { friendId: migrationMatch.id, newExternalId: this.params.externalId },
61
+ });
62
+ return migrationMatch;
63
+ }
64
+ /* v8 ignore stop */
65
+ }
66
+ catch {
67
+ // fall through to create new
68
+ }
69
+ }
70
+ /* v8 ignore stop */
34
71
  // First encounter -- create new FriendRecord
35
72
  const now = new Date().toISOString();
36
73
  const externalId = {
@@ -50,6 +87,21 @@ class FriendResolver {
50
87
  hasAnyFriends = false;
51
88
  }
52
89
  const isFirstImprint = !hasAnyFriends;
90
+ // BlueBubbles group chats route through here as `imessage-handle` with an
91
+ // externalId of the form `group:any;+;<chatHash>`. When the harness auto-
92
+ // creates the group friend at stranger trust, we mark the record so that
93
+ // the trust gate can surface the relationship for explicit acknowledgment
94
+ // later instead of letting messages accumulate silently.
95
+ const isImessageGroup = this.params.provider === "imessage-handle" &&
96
+ typeof this.params.externalId === "string" &&
97
+ this.params.externalId.startsWith("group:");
98
+ const notes = {};
99
+ if (this.params.displayName !== "Unknown") {
100
+ notes.name = { value: this.params.displayName, savedAt: now };
101
+ }
102
+ if (isImessageGroup && !isFirstImprint) {
103
+ notes.autoCreatedGroup = { value: "true", savedAt: now };
104
+ }
53
105
  const friend = {
54
106
  id: (0, crypto_1.randomUUID)(),
55
107
  name: this.params.displayName,
@@ -59,7 +111,7 @@ class FriendResolver {
59
111
  externalIds: [externalId],
60
112
  tenantMemberships,
61
113
  toolPreferences: {},
62
- notes: this.params.displayName !== "Unknown" ? { name: { value: this.params.displayName, savedAt: now } } : {},
114
+ notes,
63
115
  totalTokens: 0,
64
116
  createdAt: now,
65
117
  updatedAt: now,