@vellumai/assistant 0.7.0 → 0.7.2

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 (989) hide show
  1. package/ARCHITECTURE.md +38 -56
  2. package/Dockerfile +2 -0
  3. package/README.md +3 -4
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +88 -142
  5. package/bun.lock +29 -26
  6. package/docs/architecture/security.md +38 -16
  7. package/docs/plugins.md +7 -9
  8. package/knip.json +2 -0
  9. package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
  10. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +39 -1
  11. package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
  12. package/node_modules/@vellumai/service-contracts/package.json +2 -0
  13. package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
  14. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
  15. package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
  16. package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
  17. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
  18. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
  19. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +9 -5
  20. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
  21. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
  22. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
  23. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  24. package/node_modules/@vellumai/slack-text/package.json +18 -0
  25. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  26. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  27. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  28. package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
  29. package/node_modules/@vellumai/twilio-client/package.json +18 -0
  30. package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
  31. package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
  32. package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
  33. package/openapi.yaml +869 -129
  34. package/package.json +8 -3
  35. package/scripts/generate-openapi.ts +16 -111
  36. package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
  37. package/src/__tests__/anthropic-provider.test.ts +56 -13
  38. package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
  39. package/src/__tests__/app-bundler.test.ts +170 -1
  40. package/src/__tests__/app-control-flow.test.ts +374 -0
  41. package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
  42. package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
  43. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  44. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  45. package/src/__tests__/app-executors.test.ts +30 -43
  46. package/src/__tests__/approval-cascade.test.ts +0 -15
  47. package/src/__tests__/approval-routes-http.test.ts +29 -23
  48. package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
  49. package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
  50. package/src/__tests__/assistant-event-hub.test.ts +235 -79
  51. package/src/__tests__/assistant-event.test.ts +10 -5
  52. package/src/__tests__/assistant-events-sse-hardening.test.ts +44 -17
  53. package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -36
  54. package/src/__tests__/background-shell-host-bash.test.ts +46 -56
  55. package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
  56. package/src/__tests__/btw-routes.test.ts +13 -4
  57. package/src/__tests__/call-controller.test.ts +50 -2
  58. package/src/__tests__/call-domain.test.ts +0 -2
  59. package/src/__tests__/call-routes-http.test.ts +0 -2
  60. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  61. package/src/__tests__/channel-approval-routes.test.ts +10 -296
  62. package/src/__tests__/channel-approvals.test.ts +25 -17
  63. package/src/__tests__/channel-guardian.test.ts +100 -146
  64. package/src/__tests__/channel-readiness-service.test.ts +59 -1
  65. package/src/__tests__/checker.test.ts +23 -38
  66. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  67. package/src/__tests__/compaction-events.test.ts +2 -0
  68. package/src/__tests__/config-loader-backfill.test.ts +90 -155
  69. package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
  70. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  71. package/src/__tests__/config-schema.test.ts +6 -48
  72. package/src/__tests__/config-set-platform-guard.test.ts +48 -4
  73. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +2 -2
  74. package/src/__tests__/config-watcher.test.ts +14 -2
  75. package/src/__tests__/connection-policy.test.ts +1 -52
  76. package/src/__tests__/contacts-write.test.ts +2 -64
  77. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  78. package/src/__tests__/context-search-memory-source.test.ts +120 -1
  79. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  80. package/src/__tests__/context-search-pkb-source.test.ts +49 -0
  81. package/src/__tests__/context-search-workspace-source.test.ts +9 -22
  82. package/src/__tests__/context-window-manager.test.ts +46 -0
  83. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  84. package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
  85. package/src/__tests__/conversation-agent-loop.test.ts +980 -13
  86. package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
  87. package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
  88. package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
  89. package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
  90. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
  91. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  92. package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
  93. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  94. package/src/__tests__/conversation-lifecycle.test.ts +40 -4
  95. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
  96. package/src/__tests__/conversation-process-callsite.test.ts +79 -2
  97. package/src/__tests__/conversation-queue.test.ts +3 -8
  98. package/src/__tests__/conversation-routes-disk-view.test.ts +7 -161
  99. package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -104
  100. package/src/__tests__/conversation-routes-slash-commands.test.ts +76 -66
  101. package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
  102. package/src/__tests__/conversation-slash-commands.test.ts +24 -8
  103. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  104. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  105. package/src/__tests__/conversation-starter-routes.test.ts +79 -2
  106. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
  107. package/src/__tests__/conversation-surfaces-app-control.test.ts +317 -0
  108. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  109. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  110. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  111. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
  112. package/src/__tests__/conversation-usage.test.ts +253 -3
  113. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
  114. package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
  115. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  116. package/src/__tests__/credential-health-service.test.ts +68 -0
  117. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  118. package/src/__tests__/credential-security-invariants.test.ts +1 -5
  119. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  120. package/src/__tests__/credentials-cli.test.ts +5 -12
  121. package/src/__tests__/cu-unified-flow.test.ts +206 -27
  122. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  123. package/src/__tests__/daemon-credential-client.test.ts +102 -17
  124. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  125. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  126. package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
  127. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  128. package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
  129. package/src/__tests__/document-conversations.test.ts +332 -0
  130. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  131. package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
  132. package/src/__tests__/emit-event-signal.test.ts +4 -6
  133. package/src/__tests__/events-client-registration.test.ts +193 -49
  134. package/src/__tests__/filing-service.test.ts +58 -7
  135. package/src/__tests__/first-greeting.test.ts +156 -150
  136. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  137. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  138. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  139. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  140. package/src/__tests__/guardian-dispatch.test.ts +1 -1
  141. package/src/__tests__/guardian-grant-minting.test.ts +7 -2
  142. package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
  143. package/src/__tests__/guardian-routing-state.test.ts +1 -1
  144. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
  145. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +30 -11
  146. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -84
  147. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  148. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  149. package/src/__tests__/heartbeat-service.test.ts +1007 -8
  150. package/src/__tests__/helpers/call-route-handler.ts +7 -1
  151. package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
  152. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  153. package/src/__tests__/host-app-control-proxy.test.ts +602 -0
  154. package/src/__tests__/host-app-control-routes.test.ts +263 -0
  155. package/src/__tests__/host-bash-proxy.test.ts +270 -147
  156. package/src/__tests__/host-bash-routes.test.ts +294 -0
  157. package/src/__tests__/host-browser-proxy.test.ts +126 -198
  158. package/src/__tests__/host-browser-routes.test.ts +50 -54
  159. package/src/__tests__/host-cu-proxy.test.ts +78 -144
  160. package/src/__tests__/host-cu-routes-targeted.test.ts +300 -0
  161. package/src/__tests__/host-file-edit-tool.test.ts +47 -1
  162. package/src/__tests__/host-file-proxy-targeted.test.ts +339 -0
  163. package/src/__tests__/host-file-proxy.test.ts +62 -122
  164. package/src/__tests__/host-file-read-tool.test.ts +59 -21
  165. package/src/__tests__/host-file-routes-targeted.test.ts +262 -0
  166. package/src/__tests__/host-file-write-tool.test.ts +42 -1
  167. package/src/__tests__/host-proxy-base.test.ts +312 -0
  168. package/src/__tests__/host-shell-tool.test.ts +53 -70
  169. package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
  170. package/src/__tests__/host-transfer-proxy-targeted.test.ts +583 -0
  171. package/src/__tests__/host-transfer-proxy.test.ts +145 -56
  172. package/src/__tests__/host-transfer-routes-targeted.test.ts +447 -0
  173. package/src/__tests__/http-user-message-parity.test.ts +1 -6
  174. package/src/__tests__/identity-intro-cache.test.ts +29 -0
  175. package/src/__tests__/identity-routes.test.ts +103 -1
  176. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  177. package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
  178. package/src/__tests__/injector-chain.test.ts +10 -5
  179. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  180. package/src/__tests__/inline-command-runner.test.ts +0 -67
  181. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -13
  182. package/src/__tests__/install-skill-routing.test.ts +1 -13
  183. package/src/__tests__/integration-status.test.ts +85 -5
  184. package/src/__tests__/intent-routing.test.ts +0 -1
  185. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
  186. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
  187. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  188. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  189. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  190. package/src/__tests__/llm-resolver.test.ts +80 -12
  191. package/src/__tests__/llm-usage-store.test.ts +269 -4
  192. package/src/__tests__/log-export-routes.test.ts +89 -0
  193. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  194. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -11
  195. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  196. package/src/__tests__/mcp-auth-routes.test.ts +197 -0
  197. package/src/__tests__/mcp-cli.test.ts +338 -2
  198. package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
  199. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  200. package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
  201. package/src/__tests__/migration-export-http.test.ts +33 -26
  202. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  203. package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
  204. package/src/__tests__/migration-import-commit-http.test.ts +172 -21
  205. package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
  206. package/src/__tests__/migration-import-from-url.test.ts +20 -6
  207. package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
  208. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  209. package/src/__tests__/migration-transport.test.ts +115 -23
  210. package/src/__tests__/migration-validate-http.test.ts +105 -80
  211. package/src/__tests__/migration-wizard.test.ts +133 -27
  212. package/src/__tests__/mock-gateway-ipc.ts +1 -0
  213. package/src/__tests__/non-member-access-request.test.ts +1 -1
  214. package/src/__tests__/notification-guardian-path.test.ts +1 -1
  215. package/src/__tests__/oauth-cli.test.ts +0 -2
  216. package/src/__tests__/oauth-store.test.ts +19 -0
  217. package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
  218. package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
  219. package/src/__tests__/platform-bash-auto-approve.test.ts +26 -21
  220. package/src/__tests__/prechat-onboarding-contract.test.ts +34 -8
  221. package/src/__tests__/pricing.test.ts +68 -4
  222. package/src/__tests__/process-message-background-slack.test.ts +333 -0
  223. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  224. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  225. package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
  226. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  227. package/src/__tests__/public-ingress-urls.test.ts +97 -0
  228. package/src/__tests__/reaction-persistence.test.ts +9 -6
  229. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  230. package/src/__tests__/recording-handler.test.ts +64 -81
  231. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  232. package/src/__tests__/relay-server.test.ts +18 -13
  233. package/src/__tests__/require-fresh-approval.test.ts +13 -23
  234. package/src/__tests__/retry-backoff.test.ts +87 -0
  235. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  236. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
  237. package/src/__tests__/runtime-events-sse.test.ts +13 -18
  238. package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
  239. package/src/__tests__/schedule-retry.test.ts +715 -0
  240. package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
  241. package/src/__tests__/search-skills-unified.test.ts +9 -15
  242. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  243. package/src/__tests__/secret-ingress-http.test.ts +1 -4
  244. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  245. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  246. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  247. package/src/__tests__/secret-response-routing.test.ts +29 -15
  248. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
  249. package/src/__tests__/secret-scanner.test.ts +2 -545
  250. package/src/__tests__/send-endpoint-busy.test.ts +12 -24
  251. package/src/__tests__/settings-routes.test.ts +1 -1
  252. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  253. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -57
  254. package/src/__tests__/skill-feature-flags.test.ts +43 -41
  255. package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
  256. package/src/__tests__/skill-load-inline-command.test.ts +0 -51
  257. package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
  258. package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
  259. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -12
  260. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  261. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
  262. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  263. package/src/__tests__/slack-channel-config.test.ts +9 -14
  264. package/src/__tests__/slack-inbound-verification.test.ts +1 -62
  265. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  266. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  267. package/src/__tests__/subagent-notify-parent.test.ts +80 -83
  268. package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
  269. package/src/__tests__/system-prompt.test.ts +115 -14
  270. package/src/__tests__/telegram-config.test.ts +0 -1
  271. package/src/__tests__/terminal-tools.test.ts +0 -89
  272. package/src/__tests__/test-preload.ts +8 -0
  273. package/src/__tests__/thread-backfill.test.ts +945 -31
  274. package/src/__tests__/tool-approval-handler.test.ts +3 -4
  275. package/src/__tests__/tool-audit-listener.test.ts +48 -0
  276. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
  277. package/src/__tests__/tool-execute-pipeline.test.ts +0 -7
  278. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -17
  279. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
  280. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -8
  281. package/src/__tests__/tool-executor.test.ts +12 -20
  282. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  283. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  284. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  285. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  286. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
  287. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
  288. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  289. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  290. package/src/__tests__/twilio-config.test.ts +3 -16
  291. package/src/__tests__/twilio-routes.test.ts +3 -5
  292. package/src/__tests__/twilio-validation.test.ts +93 -0
  293. package/src/__tests__/usage-attribution.test.ts +247 -0
  294. package/src/__tests__/usage-cli.test.ts +143 -0
  295. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  296. package/src/__tests__/usage-routes.test.ts +150 -0
  297. package/src/__tests__/validation-results-screen.test.ts +39 -16
  298. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  299. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +47 -138
  300. package/src/__tests__/verification-control-plane-policy.test.ts +6 -11
  301. package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
  302. package/src/__tests__/voice-session-bridge.test.ts +5 -5
  303. package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
  304. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  305. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  306. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  307. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
  308. package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
  309. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
  310. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
  311. package/src/acp/index.ts +0 -15
  312. package/src/acp/session-manager.ts +37 -34
  313. package/src/agent/loop.ts +16 -1
  314. package/src/approvals/AGENTS.md +4 -0
  315. package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
  316. package/src/approvals/guardian-request-resolvers.ts +10 -2
  317. package/src/backup/__tests__/paths.test.ts +0 -22
  318. package/src/backup/__tests__/restore.test.ts +94 -177
  319. package/src/backup/paths.ts +2 -15
  320. package/src/backup/restore.ts +107 -231
  321. package/src/browser-session/events.ts +0 -9
  322. package/src/bundler/app-bundler.ts +51 -3
  323. package/src/calls/call-store.ts +1 -34
  324. package/src/calls/guardian-question-copy.ts +0 -108
  325. package/src/calls/relay-server.ts +4 -68
  326. package/src/calls/twilio-config.ts +2 -17
  327. package/src/calls/twilio-rest.ts +31 -141
  328. package/src/calls/twilio-routes.ts +12 -13
  329. package/src/calls/voice-session-bridge.ts +7 -38
  330. package/src/channels/types.ts +8 -42
  331. package/src/cli/commands/__tests__/backup.test.ts +6 -277
  332. package/src/cli/commands/__tests__/cache.test.ts +152 -5
  333. package/src/cli/commands/__tests__/gateway.test.ts +288 -0
  334. package/src/cli/commands/__tests__/memory-v2.test.ts +18 -28
  335. package/src/cli/commands/__tests__/trust.test.ts +21 -387
  336. package/src/cli/commands/__tests__/webhooks.test.ts +0 -1
  337. package/src/cli/commands/backup.ts +6 -331
  338. package/src/cli/commands/cache-fs.ts +8 -0
  339. package/src/cli/commands/cache.ts +153 -82
  340. package/src/cli/commands/clients.ts +64 -7
  341. package/src/cli/commands/completions.ts +3 -3
  342. package/src/cli/commands/contacts.ts +304 -76
  343. package/src/cli/commands/conversations.ts +2 -5
  344. package/src/cli/commands/credentials.ts +15 -7
  345. package/src/cli/commands/domain.ts +66 -15
  346. package/src/cli/commands/gateway.ts +183 -0
  347. package/src/cli/commands/keys.ts +13 -7
  348. package/src/cli/commands/mcp.ts +116 -156
  349. package/src/cli/commands/memory-v2.ts +320 -53
  350. package/src/cli/commands/oauth/shared.ts +2 -29
  351. package/src/cli/commands/pending.ts +102 -0
  352. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  353. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -2
  354. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -2
  355. package/src/cli/commands/platform/__tests__/status.test.ts +13 -15
  356. package/src/cli/commands/platform/disconnect.ts +5 -4
  357. package/src/cli/commands/platform/index.ts +0 -18
  358. package/src/cli/commands/skills.ts +77 -35
  359. package/src/cli/commands/trust.ts +70 -430
  360. package/src/cli/commands/usage.ts +25 -16
  361. package/src/cli/lib/daemon-credential-client.ts +115 -19
  362. package/src/cli/program.ts +4 -0
  363. package/src/cli.ts +0 -21
  364. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  365. package/src/config/assistant-feature-flags.ts +67 -10
  366. package/src/config/bundled-skills/acp/SKILL.md +6 -0
  367. package/src/config/bundled-skills/acp/TOOLS.json +1 -22
  368. package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
  369. package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
  370. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
  371. package/src/config/bundled-skills/app-control/SKILL.md +75 -0
  372. package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
  373. package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
  374. package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
  375. package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
  376. package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
  377. package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
  378. package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
  379. package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
  380. package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
  381. package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
  382. package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
  383. package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
  384. package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
  385. package/src/config/bundled-skills/document/TOOLS.json +0 -8
  386. package/src/config/bundled-skills/followups/TOOLS.json +0 -12
  387. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  388. package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
  389. package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
  390. package/src/config/bundled-skills/messaging/TOOLS.json +14 -44
  391. package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
  392. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +19 -4
  393. package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
  394. package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
  395. package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
  396. package/src/config/bundled-skills/settings/SKILL.md +4 -0
  397. package/src/config/bundled-skills/settings/TOOLS.json +0 -12
  398. package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
  399. package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
  400. package/src/config/bundled-skills/subagent/SKILL.md +6 -2
  401. package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
  402. package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
  403. package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
  404. package/src/config/bundled-tool-registry.ts +21 -0
  405. package/src/config/env-registry.ts +12 -4
  406. package/src/config/env.ts +22 -26
  407. package/src/config/feature-flag-registry.json +40 -152
  408. package/src/config/llm-callsite-catalog.ts +12 -0
  409. package/src/config/llm-context-resolution.ts +80 -0
  410. package/src/config/llm-resolver.ts +58 -22
  411. package/src/config/loader.ts +76 -102
  412. package/src/config/sanitize-for-transfer.ts +2 -0
  413. package/src/config/schema.ts +2 -158
  414. package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
  415. package/src/config/schemas/__tests__/memory-v2.test.ts +8 -4
  416. package/src/config/schemas/call-site-catalog.ts +271 -0
  417. package/src/config/schemas/calls.ts +5 -14
  418. package/src/config/schemas/heartbeat.ts +63 -0
  419. package/src/config/schemas/inference.ts +1 -1
  420. package/src/config/schemas/ingress.ts +11 -7
  421. package/src/config/schemas/llm.ts +34 -11
  422. package/src/config/schemas/memory-lifecycle.ts +77 -24
  423. package/src/config/schemas/memory-retrieval.ts +2 -2
  424. package/src/config/schemas/memory-v2.ts +57 -4
  425. package/src/config/schemas/platform.ts +6 -0
  426. package/src/config/schemas/security.ts +1 -42
  427. package/src/config/schemas/services.ts +7 -21
  428. package/src/config/schemas/skills.ts +5 -11
  429. package/src/config/schemas/tts.ts +1 -1
  430. package/src/config/seed-inference-profiles.ts +117 -0
  431. package/src/config/skills.ts +0 -90
  432. package/src/config/types.ts +3 -6
  433. package/src/contacts/contact-store.ts +0 -47
  434. package/src/contacts/contacts-write.ts +1 -132
  435. package/src/context/window-manager.ts +43 -5
  436. package/src/credential-execution/feature-gates.ts +10 -10
  437. package/src/credential-execution/process-manager.ts +46 -51
  438. package/src/credential-health/credential-health-service.ts +21 -16
  439. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
  440. package/src/daemon/__tests__/conversation-tool-setup.test.ts +126 -5
  441. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
  442. package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
  443. package/src/daemon/config-watcher.ts +4 -3
  444. package/src/daemon/connection-policy.ts +1 -26
  445. package/src/daemon/conversation-agent-loop-handlers.ts +74 -7
  446. package/src/daemon/conversation-agent-loop.ts +309 -64
  447. package/src/daemon/conversation-history.ts +8 -8
  448. package/src/daemon/conversation-launch.ts +20 -135
  449. package/src/daemon/conversation-lifecycle.ts +8 -1
  450. package/src/daemon/conversation-messaging.ts +1 -0
  451. package/src/daemon/conversation-process.ts +97 -172
  452. package/src/daemon/conversation-runtime-assembly.ts +219 -76
  453. package/src/daemon/conversation-slash.ts +47 -5
  454. package/src/daemon/conversation-store.ts +7 -31
  455. package/src/daemon/conversation-surfaces.ts +144 -29
  456. package/src/daemon/conversation-tool-setup.ts +18 -87
  457. package/src/daemon/conversation-usage.ts +36 -0
  458. package/src/daemon/conversation.ts +134 -231
  459. package/src/daemon/daemon-control.ts +3 -71
  460. package/src/daemon/daemon-skill-host.ts +8 -11
  461. package/src/daemon/dictation-profile-store.ts +2 -26
  462. package/src/daemon/doordash-steps.ts +1 -1
  463. package/src/daemon/first-greeting.ts +44 -156
  464. package/src/daemon/handlers/config-channels.ts +12 -12
  465. package/src/daemon/handlers/config-ingress.ts +4 -165
  466. package/src/daemon/handlers/config-model.ts +1 -1
  467. package/src/daemon/handlers/config-voice.ts +0 -42
  468. package/src/daemon/handlers/conversations.ts +11 -190
  469. package/src/daemon/handlers/recording.ts +26 -158
  470. package/src/daemon/handlers/shared.ts +27 -72
  471. package/src/daemon/handlers/skills.ts +42 -93
  472. package/src/daemon/host-app-control-proxy.ts +293 -0
  473. package/src/daemon/host-bash-proxy.ts +124 -92
  474. package/src/daemon/host-browser-proxy.ts +111 -88
  475. package/src/daemon/host-cu-proxy.ts +100 -104
  476. package/src/daemon/host-file-proxy.ts +136 -91
  477. package/src/daemon/host-proxy-base.ts +294 -0
  478. package/src/daemon/host-proxy-preactivation.ts +82 -0
  479. package/src/daemon/host-transfer-proxy.ts +303 -147
  480. package/src/daemon/lifecycle.ts +164 -132
  481. package/src/daemon/message-protocol.ts +3 -8
  482. package/src/daemon/message-types/contacts.ts +23 -1
  483. package/src/daemon/message-types/conversations.ts +18 -8
  484. package/src/daemon/message-types/host-app-control.ts +150 -0
  485. package/src/daemon/message-types/host-bash.ts +5 -0
  486. package/src/daemon/message-types/host-cu.ts +3 -0
  487. package/src/daemon/message-types/host-file.ts +5 -0
  488. package/src/daemon/message-types/host-transfer.ts +4 -0
  489. package/src/daemon/message-types/messages.ts +10 -9
  490. package/src/daemon/message-types/schedules.ts +8 -3
  491. package/src/daemon/message-types/skills.ts +2 -2
  492. package/src/daemon/message-types/workspace.ts +1 -1
  493. package/src/daemon/process-message.ts +119 -239
  494. package/src/daemon/server.ts +13 -462
  495. package/src/daemon/shutdown-handlers.ts +2 -5
  496. package/src/daemon/tool-setup-types.ts +51 -0
  497. package/src/daemon/tool-side-effects.ts +126 -108
  498. package/src/daemon/trust-context.ts +13 -0
  499. package/src/daemon/wake-target-adapter.ts +4 -9
  500. package/src/events/domain-events.ts +0 -8
  501. package/src/events/tool-audit-listener.ts +5 -2
  502. package/src/events/tool-domain-event-publisher.ts +0 -10
  503. package/src/events/tool-metrics-listener.ts +0 -17
  504. package/src/events/tool-trace-listener.ts +0 -14
  505. package/src/filing/filing-service.ts +13 -1
  506. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +21 -9
  507. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +216 -0
  508. package/src/heartbeat/heartbeat-run-store.ts +236 -0
  509. package/src/heartbeat/heartbeat-service.ts +303 -54
  510. package/src/home/__tests__/feed-writer.test.ts +0 -4
  511. package/src/home/__tests__/post-connect-feed.test.ts +99 -0
  512. package/src/home/__tests__/relationship-state-writer.test.ts +41 -9
  513. package/src/home/__tests__/suggested-prompts.test.ts +89 -0
  514. package/src/home/feed-writer.ts +1 -2
  515. package/src/home/post-connect-feed.ts +68 -0
  516. package/src/home/relationship-state-writer.ts +33 -95
  517. package/src/home/suggested-prompts.ts +46 -10
  518. package/src/inbound/public-ingress-urls.ts +32 -34
  519. package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
  520. package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
  521. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
  522. package/src/ipc/assistant-server.ts +17 -11
  523. package/src/ipc/cli-client.ts +32 -1
  524. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
  525. package/src/ipc/routes/route-adapter.ts +1 -1
  526. package/src/ipc/routes/trust-rules.test.ts +0 -95
  527. package/src/ipc/skill-ipc-types.ts +41 -0
  528. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
  529. package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
  530. package/src/ipc/skill-routes/events.ts +12 -23
  531. package/src/ipc/skill-routes/identity.ts +4 -17
  532. package/src/ipc/skill-routes/index.ts +1 -1
  533. package/src/ipc/skill-server.ts +6 -39
  534. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
  535. package/src/live-voice/live-voice-metrics.ts +10 -10
  536. package/src/live-voice/protocol.ts +4 -13
  537. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
  538. package/src/mcp/manager.ts +0 -5
  539. package/src/mcp/mcp-auth-orchestrator.ts +213 -0
  540. package/src/mcp/mcp-auth-state.ts +133 -0
  541. package/src/mcp/mcp-oauth-provider.ts +19 -0
  542. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  543. package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
  544. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  545. package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
  546. package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
  547. package/src/memory/anisotropy.test.ts +247 -0
  548. package/src/memory/anisotropy.ts +443 -0
  549. package/src/memory/app-git-service.ts +0 -32
  550. package/src/memory/app-store.ts +154 -0
  551. package/src/memory/attachments-store.ts +6 -0
  552. package/src/memory/auto-analysis-constants.ts +17 -0
  553. package/src/memory/auto-analysis-guard.ts +5 -15
  554. package/src/memory/canonical-guardian-store.ts +7 -7
  555. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
  556. package/src/memory/context-search/agent-protocol.ts +6 -6
  557. package/src/memory/context-search/agent-runner.ts +32 -7
  558. package/src/memory/context-search/sources/memory-v2.ts +590 -0
  559. package/src/memory/context-search/sources/memory.ts +5 -0
  560. package/src/memory/context-search/sources/pkb.ts +10 -1
  561. package/src/memory/context-search/sources/workspace.ts +3 -2
  562. package/src/memory/conversation-crud.ts +30 -5
  563. package/src/memory/conversation-disk-view.ts +1 -5
  564. package/src/memory/conversation-key-store.ts +2 -15
  565. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  566. package/src/memory/db-connection.ts +62 -0
  567. package/src/memory/db-init.ts +18 -0
  568. package/src/memory/embedding-backend.ts +12 -42
  569. package/src/memory/embedding-gemini.ts +0 -2
  570. package/src/memory/embedding-local.ts +6 -6
  571. package/src/memory/embedding-ollama.ts +6 -6
  572. package/src/memory/embedding-openai.ts +6 -6
  573. package/src/memory/embedding-types.ts +21 -0
  574. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +49 -8
  575. package/src/memory/graph/conversation-graph-memory.ts +35 -36
  576. package/src/memory/graph/graph-search.ts +8 -0
  577. package/src/memory/graph/injection.test.ts +2 -2
  578. package/src/memory/graph/injection.ts +1 -1
  579. package/src/memory/graph/retriever.ts +28 -0
  580. package/src/memory/graph/tools.ts +1 -1
  581. package/src/memory/guardian-action-store.ts +0 -83
  582. package/src/memory/guardian-approvals.ts +0 -48
  583. package/src/memory/indexer.ts +1 -15
  584. package/src/memory/job-handlers/conversation-starters.ts +36 -53
  585. package/src/memory/job-utils.ts +0 -6
  586. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
  587. package/src/memory/jobs/embed-concept-page.ts +28 -2
  588. package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
  589. package/src/memory/jobs-store.ts +66 -23
  590. package/src/memory/jobs-worker.ts +114 -79
  591. package/src/memory/llm-request-log-store.ts +0 -41
  592. package/src/memory/llm-usage-store.ts +129 -43
  593. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  594. package/src/memory/migrations/233-document-conversations.ts +54 -0
  595. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  596. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  597. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  598. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  599. package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
  600. package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
  601. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  602. package/src/memory/migrations/index.ts +19 -0
  603. package/src/memory/migrations/registry.ts +32 -0
  604. package/src/memory/pkb/pkb-search.ts +7 -0
  605. package/src/memory/qdrant-client.ts +50 -20
  606. package/src/memory/raw-query.ts +2 -68
  607. package/src/memory/schema/conversations.ts +7 -0
  608. package/src/memory/schema/infrastructure.ts +40 -0
  609. package/src/memory/search/semantic.ts +12 -16
  610. package/src/memory/sparse-tokenize.ts +49 -0
  611. package/src/memory/tool-usage-store.ts +2 -0
  612. package/src/memory/usage-buckets.ts +40 -1
  613. package/src/memory/usage-grouped-buckets.ts +127 -0
  614. package/src/memory/v2/__tests__/activation.test.ts +361 -180
  615. package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
  616. package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
  617. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  618. package/src/memory/v2/__tests__/injection.test.ts +424 -33
  619. package/src/memory/v2/__tests__/migration.test.ts +64 -36
  620. package/src/memory/v2/__tests__/page-store.test.ts +191 -8
  621. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  622. package/src/memory/v2/__tests__/sim.test.ts +166 -6
  623. package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
  624. package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
  625. package/src/memory/v2/__tests__/static-context.test.ts +152 -0
  626. package/src/memory/v2/activation.ts +215 -163
  627. package/src/memory/v2/backfill-jobs.ts +15 -100
  628. package/src/memory/v2/consolidation-job.ts +17 -17
  629. package/src/memory/v2/constants.ts +7 -0
  630. package/src/memory/v2/edge-index.ts +191 -0
  631. package/src/memory/v2/injection.ts +241 -84
  632. package/src/memory/v2/migration.ts +57 -64
  633. package/src/memory/v2/now-text.ts +2 -3
  634. package/src/memory/v2/page-store.ts +168 -31
  635. package/src/memory/v2/prompts/consolidation.ts +385 -88
  636. package/src/memory/v2/prompts/sweep.ts +3 -3
  637. package/src/memory/v2/qdrant.ts +99 -1
  638. package/src/memory/v2/sim.ts +126 -16
  639. package/src/memory/v2/skill-qdrant.ts +12 -3
  640. package/src/memory/v2/skill-store.ts +71 -8
  641. package/src/memory/v2/sparse-bm25.ts +245 -0
  642. package/src/memory/v2/static-context.ts +63 -0
  643. package/src/memory/v2/types.ts +10 -20
  644. package/src/memory/validation.ts +0 -11
  645. package/src/messaging/draft-store.ts +0 -6
  646. package/src/messaging/provider-types.ts +8 -0
  647. package/src/messaging/provider.ts +7 -0
  648. package/src/messaging/providers/gmail/client.ts +1 -121
  649. package/src/messaging/providers/gmail/types.ts +0 -49
  650. package/src/messaging/providers/outlook/client.ts +0 -73
  651. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  652. package/src/messaging/providers/slack/adapter.ts +123 -52
  653. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  654. package/src/messaging/providers/slack/backfill.ts +89 -11
  655. package/src/messaging/providers/slack/client.ts +10 -124
  656. package/src/messaging/providers/slack/message-metadata.ts +12 -2
  657. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  658. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  659. package/src/messaging/providers/slack/types.ts +1 -32
  660. package/src/notifications/README.md +10 -10
  661. package/src/notifications/broadcaster.ts +1 -1
  662. package/src/notifications/guardian-question-mode.ts +5 -5
  663. package/src/oauth/connect-orchestrator.ts +4 -0
  664. package/src/oauth/connection-resolver.test.ts +8 -0
  665. package/src/oauth/connection-resolver.ts +8 -16
  666. package/src/oauth/credential-token-resolver.ts +95 -0
  667. package/src/oauth/manual-token-connection.ts +26 -34
  668. package/src/oauth/oauth-store.ts +6 -4
  669. package/src/outbound-proxy/certs.ts +0 -7
  670. package/src/outbound-proxy/index.ts +1 -59
  671. package/src/outbound-proxy/logging.ts +1 -1
  672. package/src/outbound-proxy/policy.ts +6 -5
  673. package/src/outbound-proxy/router.ts +2 -1
  674. package/src/permissions/approval-policy.test.ts +6 -275
  675. package/src/permissions/approval-policy.ts +0 -51
  676. package/src/permissions/approval-provenance.test.ts +184 -0
  677. package/src/permissions/approval-provenance.ts +70 -0
  678. package/src/permissions/checker.test.ts +0 -1
  679. package/src/permissions/checker.ts +7 -18
  680. package/src/permissions/gateway-threshold-reader.ts +6 -1
  681. package/src/permissions/prompter.ts +43 -3
  682. package/src/permissions/secret-prompter.ts +25 -48
  683. package/src/permissions/types.ts +33 -0
  684. package/src/permissions/workspace-policy.ts +0 -5
  685. package/src/platform/sync-identity.ts +0 -8
  686. package/src/plugins/defaults/injectors.ts +69 -2
  687. package/src/plugins/defaults/overflow-reduce.ts +3 -2
  688. package/src/plugins/types.ts +8 -0
  689. package/src/prompts/bootstrap-cleanup.ts +27 -0
  690. package/src/prompts/system-prompt.ts +37 -88
  691. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  692. package/src/prompts/templates/SOUL.md +13 -1
  693. package/src/prompts/update-bulletin-job.ts +2 -0
  694. package/src/providers/__tests__/retry-callsite.test.ts +138 -1
  695. package/src/providers/anthropic/client.ts +72 -33
  696. package/src/providers/call-site-routing.ts +42 -3
  697. package/src/providers/gemini/client.ts +18 -2
  698. package/src/providers/managed-proxy/context.ts +0 -5
  699. package/src/providers/model-catalog.ts +105 -19
  700. package/src/providers/openai/chat-completions-provider.ts +6 -0
  701. package/src/providers/openai/responses-provider.ts +7 -1
  702. package/src/providers/provider-send-message.ts +45 -2
  703. package/src/providers/ratelimit.ts +7 -2
  704. package/src/providers/registry.ts +14 -9
  705. package/src/providers/retry.ts +96 -8
  706. package/src/providers/speech-to-text/provider-catalog.ts +7 -8
  707. package/src/providers/types.ts +13 -0
  708. package/src/providers/usage-tracking.ts +96 -0
  709. package/src/runtime/AGENTS.md +10 -6
  710. package/src/runtime/__tests__/agent-wake.test.ts +89 -0
  711. package/src/runtime/agent-wake.ts +39 -2
  712. package/src/runtime/assistant-event-hub.ts +570 -52
  713. package/src/runtime/assistant-event.ts +2 -6
  714. package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
  715. package/src/runtime/auth/context.ts +0 -9
  716. package/src/runtime/auth/middleware.ts +1 -97
  717. package/src/runtime/auth/route-policy.ts +30 -9
  718. package/src/runtime/auth/token-service.ts +0 -11
  719. package/src/runtime/btw-sidechain.ts +2 -3
  720. package/src/runtime/channel-approvals.ts +6 -2
  721. package/src/runtime/channel-invite-transport.ts +2 -48
  722. package/src/runtime/channel-invite-transports/email.ts +1 -1
  723. package/src/runtime/channel-invite-transports/slack.ts +1 -1
  724. package/src/runtime/channel-invite-transports/telegram.ts +1 -1
  725. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  726. package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
  727. package/src/runtime/channel-invite-types.ts +54 -0
  728. package/src/runtime/channel-readiness-service.ts +32 -13
  729. package/src/runtime/channel-verification-service.ts +3 -5
  730. package/src/runtime/http-errors.ts +0 -34
  731. package/src/runtime/http-router.ts +6 -3
  732. package/src/runtime/http-server.ts +16 -402
  733. package/src/runtime/http-types.ts +5 -5
  734. package/src/runtime/interactive-ui.ts +0 -1
  735. package/src/runtime/middleware/auth.ts +0 -20
  736. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  737. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  738. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  739. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  740. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
  741. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
  742. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
  743. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  744. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  745. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +296 -80
  746. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  747. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
  748. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  749. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
  750. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
  751. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
  752. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
  753. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +421 -0
  754. package/src/runtime/migrations/migration-transport.ts +49 -16
  755. package/src/runtime/migrations/migration-wizard.ts +2 -2
  756. package/src/runtime/migrations/origin-mode.ts +40 -0
  757. package/src/runtime/migrations/vbundle-builder.ts +457 -136
  758. package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -11
  759. package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
  760. package/src/runtime/migrations/vbundle-importer.ts +251 -74
  761. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  762. package/src/runtime/migrations/vbundle-streaming-importer.ts +329 -38
  763. package/src/runtime/migrations/vbundle-streaming-validator.ts +203 -28
  764. package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
  765. package/src/runtime/migrations/vbundle-validator.ts +328 -41
  766. package/src/runtime/pending-interactions.ts +48 -13
  767. package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
  768. package/src/runtime/routes/__tests__/backup-routes.test.ts +49 -168
  769. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +333 -0
  770. package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
  771. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
  772. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  773. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  774. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  775. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  776. package/src/runtime/routes/acp-routes.test.ts +0 -3
  777. package/src/runtime/routes/acp-routes.ts +3 -7
  778. package/src/runtime/routes/app-management-routes.ts +18 -9
  779. package/src/runtime/routes/approval-interception-types.ts +13 -0
  780. package/src/runtime/routes/approval-routes.ts +55 -14
  781. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
  782. package/src/runtime/routes/avatar-routes.ts +3 -5
  783. package/src/runtime/routes/backup-routes.ts +15 -38
  784. package/src/runtime/routes/browser-routes.ts +1 -15
  785. package/src/runtime/routes/btw-routes.ts +14 -37
  786. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  787. package/src/runtime/routes/channel-readiness-routes.ts +3 -7
  788. package/src/runtime/routes/channel-route-shared.ts +2 -28
  789. package/src/runtime/routes/client-routes.ts +46 -12
  790. package/src/runtime/routes/consolidation-routes.ts +115 -0
  791. package/src/runtime/routes/contact-prompt-routes.ts +183 -0
  792. package/src/runtime/routes/conversation-list-routes.ts +12 -29
  793. package/src/runtime/routes/conversation-management-routes.ts +14 -51
  794. package/src/runtime/routes/conversation-query-routes.ts +156 -9
  795. package/src/runtime/routes/conversation-routes.ts +72 -539
  796. package/src/runtime/routes/conversation-starter-routes.ts +19 -40
  797. package/src/runtime/routes/document-pdf-renderer.ts +165 -0
  798. package/src/runtime/routes/documents-routes.ts +83 -18
  799. package/src/runtime/routes/errors.ts +19 -4
  800. package/src/runtime/routes/events-routes.ts +68 -94
  801. package/src/runtime/routes/filing-routes.ts +18 -1
  802. package/src/runtime/routes/gateway-log-routes.ts +79 -0
  803. package/src/runtime/routes/guardian-action-routes.ts +4 -9
  804. package/src/runtime/routes/guardian-approval-interception.ts +2 -8
  805. package/src/runtime/routes/heartbeat-routes.ts +103 -38
  806. package/src/runtime/routes/host-app-control-routes.ts +134 -0
  807. package/src/runtime/routes/host-bash-routes.ts +37 -6
  808. package/src/runtime/routes/host-browser-routes.ts +96 -25
  809. package/src/runtime/routes/host-cu-routes.ts +48 -13
  810. package/src/runtime/routes/host-file-routes.ts +35 -11
  811. package/src/runtime/routes/host-transfer-routes.ts +73 -37
  812. package/src/runtime/routes/http-adapter.ts +1 -0
  813. package/src/runtime/routes/identity-intro-cache.ts +30 -0
  814. package/src/runtime/routes/identity-routes.ts +93 -49
  815. package/src/runtime/routes/inbound-message-handler.ts +581 -146
  816. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -95
  817. package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
  818. package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
  819. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
  820. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
  821. package/src/runtime/routes/index.ts +12 -0
  822. package/src/runtime/routes/integrations/slack/channel.ts +0 -24
  823. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  824. package/src/runtime/routes/mcp-auth-routes.ts +132 -0
  825. package/src/runtime/routes/memory-item-routes.ts +10 -12
  826. package/src/runtime/routes/memory-v2-routes.ts +451 -16
  827. package/src/runtime/routes/migration-routes.ts +284 -31
  828. package/src/runtime/routes/playground/guard.ts +1 -1
  829. package/src/runtime/routes/playground/index.ts +0 -2
  830. package/src/runtime/routes/recording-routes.ts +4 -24
  831. package/src/runtime/routes/rename-conversation-routes.ts +2 -6
  832. package/src/runtime/routes/schedule-routes.ts +10 -6
  833. package/src/runtime/routes/secret-routes.ts +87 -18
  834. package/src/runtime/routes/settings-routes.ts +29 -28
  835. package/src/runtime/routes/skills-routes.ts +12 -31
  836. package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
  837. package/src/runtime/routes/task-routes.ts +6 -6
  838. package/src/runtime/routes/trust-rules-routes.ts +3 -94
  839. package/src/runtime/routes/types.ts +4 -4
  840. package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
  841. package/src/runtime/routes/usage-routes.ts +87 -10
  842. package/src/runtime/routes/user-routes.ts +17 -31
  843. package/src/runtime/routes/work-items-routes.ts +1 -4
  844. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
  845. package/src/runtime/services/analyze-conversation.ts +7 -17
  846. package/src/runtime/services/conversation-serializer.ts +2 -4
  847. package/src/runtime/verification-outbound-actions.ts +1 -1
  848. package/src/runtime/verification-rate-limiter.ts +1 -1
  849. package/src/runtime/verification-templates.ts +4 -7
  850. package/src/schedule/integration-status.ts +66 -2
  851. package/src/schedule/recurrence-engine.ts +4 -1
  852. package/src/schedule/retry-backoff.ts +18 -0
  853. package/src/schedule/retry-policy.ts +82 -0
  854. package/src/schedule/schedule-recovery.ts +64 -0
  855. package/src/schedule/schedule-store.ts +106 -18
  856. package/src/schedule/scheduler-types.ts +25 -0
  857. package/src/schedule/scheduler.ts +63 -38
  858. package/src/security/oauth-callback-registry.ts +8 -0
  859. package/src/security/secret-scanner.ts +14 -547
  860. package/src/security/secure-keys.ts +31 -11
  861. package/src/security/token-manager.ts +7 -3
  862. package/src/sequence/analytics.ts +5 -5
  863. package/src/sequence/engine.ts +1 -1
  864. package/src/signals/cancel.ts +16 -25
  865. package/src/signals/conversation-undo.ts +2 -27
  866. package/src/signals/emit-event.ts +1 -2
  867. package/src/signals/user-message.ts +108 -22
  868. package/src/skills/catalog-files.ts +2 -8
  869. package/src/skills/catalog-install.ts +1 -0
  870. package/src/skills/clawhub.ts +2 -2
  871. package/src/skills/include-graph.ts +5 -5
  872. package/src/skills/inline-command-runner.ts +1 -7
  873. package/src/skills/remote-skill-policy.ts +5 -5
  874. package/src/skills/skill-file-provider.ts +1 -1
  875. package/src/skills/skill-file-types.ts +13 -0
  876. package/src/skills/skillssh-audit-types.ts +28 -0
  877. package/src/skills/skillssh-registry.ts +8 -21
  878. package/src/subagent/manager.ts +67 -84
  879. package/src/tasks/task-store.ts +1 -28
  880. package/src/telemetry/types.ts +8 -0
  881. package/src/telemetry/usage-telemetry-reporter.test.ts +59 -15
  882. package/src/telemetry/usage-telemetry-reporter.ts +4 -5
  883. package/src/tools/acp/spawn.test.ts +1 -2
  884. package/src/tools/acp/steer.test.ts +1 -2
  885. package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
  886. package/src/tools/apps/executors.ts +56 -69
  887. package/src/tools/browser/__tests__/browser-status.test.ts +55 -135
  888. package/src/tools/browser/browser-execution.ts +31 -147
  889. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +145 -70
  890. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
  891. package/src/tools/browser/cdp-client/factory.ts +62 -91
  892. package/src/tools/browser/cdp-client/index.ts +1 -27
  893. package/src/tools/computer-use/definitions.ts +42 -20
  894. package/src/tools/executor.ts +46 -31
  895. package/src/tools/host-filesystem/edit.ts +29 -2
  896. package/src/tools/host-filesystem/read.ts +29 -2
  897. package/src/tools/host-filesystem/transfer.test.ts +45 -42
  898. package/src/tools/host-filesystem/transfer.ts +35 -4
  899. package/src/tools/host-filesystem/write.ts +29 -2
  900. package/src/tools/host-terminal/host-shell.ts +62 -3
  901. package/src/tools/network/script-proxy/index.ts +1 -10
  902. package/src/tools/permission-checker.ts +66 -1
  903. package/src/tools/schedule/create.ts +6 -0
  904. package/src/tools/schedule/list.ts +2 -0
  905. package/src/tools/schedule/update.ts +10 -0
  906. package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
  907. package/src/tools/shared/filesystem/path-policy.ts +25 -1
  908. package/src/tools/skills/load.ts +0 -32
  909. package/src/tools/skills/sandbox-runner.ts +1 -6
  910. package/src/tools/skills/skill-tool-factory.ts +32 -0
  911. package/src/tools/terminal/safe-env.ts +1 -0
  912. package/src/tools/terminal/shell.ts +2 -78
  913. package/src/tools/tool-approval-handler.ts +1 -5
  914. package/src/tools/types.ts +16 -39
  915. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  916. package/src/tts/provider-catalog.ts +1 -1
  917. package/src/usage/actors.ts +2 -1
  918. package/src/usage/attribution.ts +185 -0
  919. package/src/usage/pricing.ts +166 -0
  920. package/src/usage/types.ts +14 -0
  921. package/src/util/json.ts +13 -0
  922. package/src/util/logger.ts +3 -3
  923. package/src/util/pricing.ts +50 -3
  924. package/src/work-items/work-item-runner.ts +15 -42
  925. package/src/workspace/hatched-date.ts +86 -0
  926. package/src/workspace/migrations/003-seed-device-id.ts +1 -1
  927. package/src/workspace/migrations/006-services-config.ts +8 -5
  928. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
  929. package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
  930. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
  931. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
  932. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
  933. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
  934. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +6 -4
  935. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
  936. package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
  937. package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
  938. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +54 -0
  939. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  940. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  941. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  942. package/src/workspace/migrations/AGENTS.md +1 -1
  943. package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
  944. package/src/workspace/migrations/registry.ts +8 -0
  945. package/src/workspace/migrations/utils.ts +21 -0
  946. package/src/workspace/provider-commit-message-generator.ts +3 -3
  947. package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -904
  948. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -296
  949. package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -431
  950. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  951. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  952. package/src/__tests__/secret-detection-handler.test.ts +0 -67
  953. package/src/__tests__/secret-scanner-executor.test.ts +0 -450
  954. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  955. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  956. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  957. package/src/__tests__/twilio-rest.test.ts +0 -34
  958. package/src/backup/__tests__/backup-key.test.ts +0 -152
  959. package/src/backup/__tests__/backup-worker.test.ts +0 -754
  960. package/src/backup/__tests__/offsite-writer.test.ts +0 -641
  961. package/src/backup/__tests__/stream-crypt.test.ts +0 -228
  962. package/src/backup/backup-key.ts +0 -137
  963. package/src/backup/backup-worker.ts +0 -438
  964. package/src/backup/offsite-writer.ts +0 -222
  965. package/src/backup/stream-crypt.ts +0 -263
  966. package/src/context/__tests__/microcompact.test.ts +0 -805
  967. package/src/context/microcompact.ts +0 -443
  968. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  969. package/src/daemon/message-types/pairing.ts +0 -58
  970. package/src/events/tool-notification-listener.ts +0 -17
  971. package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
  972. package/src/memory/v2/__tests__/edges.test.ts +0 -435
  973. package/src/memory/v2/edges.ts +0 -217
  974. package/src/outbound-proxy/config.ts +0 -94
  975. package/src/outbound-proxy/health.ts +0 -62
  976. package/src/outbound-proxy/types.ts +0 -150
  977. package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
  978. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  979. package/src/runtime/__tests__/client-registry.test.ts +0 -271
  980. package/src/runtime/capability-tokens.ts +0 -190
  981. package/src/runtime/chrome-extension-registry.ts +0 -368
  982. package/src/runtime/client-registry.ts +0 -254
  983. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
  984. package/src/signals/mcp-reload.ts +0 -18
  985. package/src/tools/secret-detection-handler.ts +0 -269
  986. package/src/tools/terminal/backends/native.ts +0 -327
  987. package/src/tools/terminal/backends/types.ts +0 -37
  988. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  989. package/src/tools/terminal/sandbox.ts +0 -40
@@ -6,15 +6,15 @@
6
6
  // Implements §5 of the design doc:
7
7
  //
8
8
  // 1. Hydrate prior activation state for the conversation.
9
- // 2. Read edges.json (the topology source of truth).
9
+ // 2. Build the in-memory edge index from concept-page frontmatter.
10
10
  // 3. Select the per-turn candidate set (prior-state survivors ∪ ANN top-K).
11
11
  // 4. Compute own activation A_o over the candidates.
12
- // 5. Apply 2-hop spreading activation with neighborhood normalization → A.
12
+ // 5. Apply 2-hop spreading activation along directed edges (incoming) → A.
13
13
  // 6. Pick top-K by activation; subtract everInjected to get the injection delta.
14
14
  // 7. If no new slugs, render nothing — caller leaves the prior cached
15
15
  // attachments on prior user messages exactly as Anthropic prompt caching
16
16
  // requires.
17
- // 8. Otherwise render a `<memory __injected>` block scoped to the *new* slugs
17
+ // 8. Otherwise render a `<memory>` block scoped to the *new* slugs
18
18
  // ordered by activation (descending) and persist the updated state +
19
19
  // everInjected list (with `currentTurn` annotated) so future turns can
20
20
  // append-inject cache-stably.
@@ -24,23 +24,30 @@
24
24
  // cached prefix bytes-identical across turns.
25
25
 
26
26
  import type { AssistantConfig } from "../../config/types.js";
27
+ import { getLogger } from "../../util/logger.js";
27
28
  import { getWorkspaceDir } from "../../util/platform.js";
28
29
  import type { DrizzleDb } from "../db-connection.js";
30
+ import {
31
+ type MemoryV2ConceptRowRecord,
32
+ type MemoryV2SkillRowRecord,
33
+ recordMemoryV2ActivationLog,
34
+ } from "../memory-v2-activation-log-store.js";
29
35
  import {
30
36
  computeOwnActivation,
31
37
  computeSkillActivation,
32
38
  selectCandidates,
33
39
  selectInjections,
34
- selectSkillCandidates,
35
40
  selectSkillInjections,
36
41
  spreadActivation,
37
42
  } from "./activation.js";
38
43
  import { hydrate, save } from "./activation-store.js";
39
- import { readEdges } from "./edges.js";
40
- import { readPage } from "./page-store.js";
41
- import { getSkillCapability } from "./skill-store.js";
44
+ import { getEdgeIndex } from "./edge-index.js";
45
+ import { readPage, renderPageContent } from "./page-store.js";
46
+ import { getAllSkillIds, getSkillCapability } from "./skill-store.js";
42
47
  import type { ActivationState, EverInjectedEntry } from "./types.js";
43
48
 
49
+ const log = getLogger("memory-v2-injection");
50
+
44
51
  // ---------------------------------------------------------------------------
45
52
  // Public types
46
53
  // ---------------------------------------------------------------------------
@@ -49,7 +56,7 @@ import type { ActivationState, EverInjectedEntry } from "./types.js";
49
56
  * Discriminator the wiring layer (`conversation-graph-memory.ts`) sets to
50
57
  * tell the v2 injector which call site is asking. Both modes currently share
51
58
  * the same block layout (mirroring v1 which also wraps both flows in
52
- * `<memory __injected>...</memory>`); the parameter exists so future tuning
59
+ * `<memory>...</memory>`); the parameter exists so future tuning
53
60
  * can shape the conversation-start block without touching the call site.
54
61
  */
55
62
  export type InjectMemoryV2Mode = "context-load" | "per-turn";
@@ -81,10 +88,11 @@ export interface InjectMemoryV2BlockParams {
81
88
 
82
89
  export interface InjectMemoryV2BlockResult {
83
90
  /**
84
- * Rendered `<memory __injected>` block, ready to prepend to the current
85
- * user message — or `null` when nothing new is eligible for injection.
86
- * `null` is the cache-stable default: the caller adds nothing to the new
87
- * user message and prior attachments stay byte-identical.
91
+ * Inner content for the `<memory>` block, ready for the caller to wrap
92
+ * exactly once at injection time — or `null` when nothing new is eligible
93
+ * for injection. `null` is the cache-stable default: the caller adds
94
+ * nothing to the new user message and prior attachments stay
95
+ * byte-identical.
88
96
  */
89
97
  block: string | null;
90
98
  /**
@@ -127,12 +135,14 @@ export async function injectMemoryV2Block(
127
135
  // with an effective empty prior state so the first turn can still inject.
128
136
  const priorState = await hydrate(database, conversationId);
129
137
 
130
- // (2) Topology. `readEdges` returns the canonical empty index when the
131
- // file is missing (fresh workspace pre-consolidation).
132
- const edgesIdx = await readEdges(workspaceDir);
138
+ // (2) Topology. `getEdgeIndex` walks concept-page frontmatter and caches
139
+ // the result module-locally; an empty workspace yields an empty index.
140
+ const edgeIndex = await getEdgeIndex(workspaceDir);
133
141
 
134
142
  // (3) Candidate set: prior-state survivors above epsilon ∪ ANN top-50.
135
- const candidates = await selectCandidates({
143
+ // `selectCandidates` also returns `fromPrior` / `fromAnn` provenance sets so
144
+ // telemetry can attribute each candidate back to its source.
145
+ const { candidates, fromPrior, fromAnn } = await selectCandidates({
136
146
  priorState,
137
147
  userText: userMessage,
138
148
  assistantText: assistantMessage,
@@ -141,46 +151,51 @@ export async function injectMemoryV2Block(
141
151
  });
142
152
 
143
153
  // (4) Own activation: A_o = d·prev + c_user·sim_u + c_a·sim_a + c_now·sim_n.
144
- const ownActivation = await computeOwnActivation({
145
- candidates,
146
- priorState,
147
- userText: userMessage,
148
- assistantText: assistantMessage,
149
- nowText,
150
- config,
151
- });
154
+ const { activation: ownActivation, breakdown: ownBreakdown } =
155
+ await computeOwnActivation({
156
+ candidates,
157
+ priorState,
158
+ userText: userMessage,
159
+ assistantText: assistantMessage,
160
+ nowText,
161
+ config,
162
+ });
152
163
 
153
164
  // (5) Spreading activation across the edge graph (k, hops from config).
154
165
  const { k, hops, top_k, epsilon } = config.memory.v2;
155
- const finalActivation = spreadActivation(ownActivation, edgesIdx, k, hops);
166
+ const { final: finalActivation, contribution: spreadContribution } =
167
+ spreadActivation(ownActivation, edgeIndex, k, hops);
156
168
 
157
- // (6) Pick top-K by activation; subtract everInjected for the injection delta.
169
+ // (6) Pick top-K by activation. Per-turn turns subtract everInjected for the
170
+ // injection delta (cache-stable append-only); context-load renders the
171
+ // entire top-K because it's a fresh load (turn 1 / post-compaction) where
172
+ // prior cached attachments don't exist or have been thrown away. The user
173
+ // message gets a complete top-K dump alongside the static
174
+ // essentials/threads/recent block, then per-turn turns just add deltas.
175
+ const mode = params.mode ?? "per-turn";
158
176
  const priorEverInjected: readonly EverInjectedEntry[] =
159
177
  priorState?.everInjected ?? [];
160
- const { toInject } = selectInjections({
178
+ const { topNow, toInject } = selectInjections({
161
179
  A: finalActivation,
162
180
  priorEverInjected,
163
181
  topK: top_k,
164
182
  });
183
+ const slugsToRender = mode === "context-load" ? topNow : toInject;
165
184
 
166
185
  // (6b) Skill pipeline — a sibling pipeline to the concept-page one above.
167
- // Skills are stateless: no decay carry-over, no spread, no `everInjected`
168
- // dedup. The top-K relevant skills are re-presented every turn so the
169
- // agent can drop and pick them up freely.
170
- const skillCandidates = await selectSkillCandidates({
171
- userText: userMessage,
172
- assistantText: assistantMessage,
173
- nowText,
174
- config,
175
- topK: config.memory.v2.top_k_skills,
176
- });
177
- const skillActivation = await computeSkillActivation({
178
- candidates: skillCandidates,
179
- userText: userMessage,
180
- assistantText: assistantMessage,
181
- nowText,
182
- config,
183
- });
186
+ // Skills are stateless (no decay, no spread, no `everInjected` dedup) and
187
+ // the catalog is small, so every known skill is scored every turn. The
188
+ // top-K injection slate is re-presented every turn so the agent can drop
189
+ // and pick skills up freely; the inspector renders the full ranked list.
190
+ const skillCandidates = new Set(getAllSkillIds());
191
+ const { activation: skillActivation, breakdown: skillBreakdown } =
192
+ await computeSkillActivation({
193
+ candidates: skillCandidates,
194
+ userText: userMessage,
195
+ assistantText: assistantMessage,
196
+ nowText,
197
+ config,
198
+ });
184
199
  const { topNow: topSkillIds } = selectSkillInjections({
185
200
  A: skillActivation,
186
201
  topK: config.memory.v2.top_k_skills,
@@ -195,14 +210,20 @@ export async function injectMemoryV2Block(
195
210
  if (value > epsilon) nextState[slug] = value;
196
211
  }
197
212
 
198
- // Append the freshly injected slugs to everInjected (with their turn) so
199
- // future turns can subtract them. We append rather than reset so that
200
- // compaction-driven eviction (`evictCompactedTurns`) is the only path that
201
- // can re-enable a previously-injected slug. Skills do NOT enter
202
- // `everInjected` they are stateless and re-presented every turn.
213
+ // Mark every rendered slug as ever-injected so future per-turn deltas don't
214
+ // re-attach the same content. On context-load this is the full top-K (we
215
+ // just rendered all of them); on per-turn it's just the newly added slugs.
216
+ // We append rather than reset so that compaction-driven eviction
217
+ // (`evictCompactedTurns`) is the only path that can re-enable a previously-
218
+ // injected slug. Skills do NOT enter `everInjected` — they are stateless
219
+ // and re-presented every turn.
220
+ const everInjectedSet = new Set(priorEverInjected.map((entry) => entry.slug));
221
+ const newlyInjected = slugsToRender.filter(
222
+ (slug) => !everInjectedSet.has(slug),
223
+ );
203
224
  const nextEverInjected: EverInjectedEntry[] = [
204
225
  ...priorEverInjected,
205
- ...toInject.map((slug) => ({ slug, turn: currentTurn })),
226
+ ...newlyInjected.map((slug) => ({ slug, turn: currentTurn })),
206
227
  ];
207
228
 
208
229
  const nextActivationState: ActivationState = {
@@ -215,78 +236,212 @@ export async function injectMemoryV2Block(
215
236
 
216
237
  await save(database, conversationId, nextActivationState);
217
238
 
218
- // (7) Cache-stable empty path: nothing new since the last turn AND no
219
- // ranked skills to surface.
220
- if (toInject.length === 0 && topSkillIds.length === 0) {
221
- return { block: null, toInject: [] };
239
+ // Render before recording telemetry so the activation log can mark slugs
240
+ // whose backing file is gone — those are no-op renders that would otherwise
241
+ // be indistinguishable from successful "injected" rows in the log.
242
+ // `renderInjectionBlock` itself short-circuits on empty inputs.
243
+ const { block, missingSlugs } = await renderInjectionBlock(
244
+ workspaceDir,
245
+ slugsToRender,
246
+ topSkillIds,
247
+ );
248
+ const missingSlugSet = new Set(missingSlugs);
249
+ if (missingSlugs.length > 0) {
250
+ log.warn(
251
+ {
252
+ conversationId,
253
+ turn: currentTurn,
254
+ missingSlugs,
255
+ renderedCount: slugsToRender.length - missingSlugs.length,
256
+ },
257
+ "Memory v2 injection skipped slugs whose page was missing on disk — Qdrant index may be stale; consider reembed",
258
+ );
222
259
  }
223
260
 
224
- // (8) Render. `toInject` is already activation-descending (selectInjections
225
- // returns it as a filter of the sorted `topNow`), so it doubles as our
226
- // render order. Prior slugs sit unchanged on prior user messages. Skills
227
- // are appended after concept-page sections under the same header.
228
- const block = await renderInjectionBlock(workspaceDir, toInject, topSkillIds);
261
+ // Record per-turn activation telemetry. Failures are warn-logged and never
262
+ // block memory injection.
263
+ const toInjectSet = new Set(toInject);
264
+ const renderedSet = new Set(slugsToRender);
265
+ const topSkillIdSet = new Set(topSkillIds);
266
+ const conceptRows: MemoryV2ConceptRowRecord[] = [...candidates].map(
267
+ (slug) => {
268
+ const breakdown = ownBreakdown.get(slug);
269
+ const inPrior = fromPrior.has(slug);
270
+ const inAnn = fromAnn.has(slug);
271
+ // Status reflects what was rendered for *this* turn:
272
+ // - context-load: cache was wiped (turn 1 / post-compaction), so
273
+ // `slugsToRender = topNow` and every rendered slug is freshly
274
+ // injected on this turn. `in_context` is unreachable because there
275
+ // is no prior cached attachment for the inspector to point at.
276
+ // - per-turn: cached attachments from prior turns are still on the
277
+ // user message, so prior-everInjected slugs are `in_context` and
278
+ // the delta (`toInject`) is `injected`.
279
+ // `page_missing` overrides any "would-have-been-injected" status when
280
+ // `readPage` returned null for the slug — telemetry surfaces stale
281
+ // ANN/edge entries instead of silently masquerading as a successful
282
+ // injection.
283
+ let status: MemoryV2ConceptRowRecord["status"];
284
+ if (mode === "context-load") {
285
+ status = renderedSet.has(slug) ? "injected" : "not_injected";
286
+ } else if (everInjectedSet.has(slug)) {
287
+ status = "in_context";
288
+ } else if (toInjectSet.has(slug)) {
289
+ status = "injected";
290
+ } else {
291
+ status = "not_injected";
292
+ }
293
+ if (status === "injected" && missingSlugSet.has(slug)) {
294
+ status = "page_missing";
295
+ }
296
+ return {
297
+ slug,
298
+ finalActivation: finalActivation.get(slug) ?? 0,
299
+ ownActivation: ownActivation.get(slug) ?? 0,
300
+ priorActivation: breakdown?.priorContribution ?? 0,
301
+ simUser: breakdown?.simUser ?? 0,
302
+ simAssistant: breakdown?.simAssistant ?? 0,
303
+ simNow: breakdown?.simNow ?? 0,
304
+ spreadContribution: spreadContribution.get(slug) ?? 0,
305
+ source:
306
+ inPrior && inAnn ? "both" : inPrior ? "prior_state" : "ann_top50",
307
+ status,
308
+ };
309
+ },
310
+ );
311
+ conceptRows.sort((a, b) => b.finalActivation - a.finalActivation);
229
312
 
230
- return { block, toInject };
313
+ const skillRows: MemoryV2SkillRowRecord[] = [...skillCandidates].map((id) => {
314
+ const breakdown = skillBreakdown.get(id);
315
+ return {
316
+ id,
317
+ activation: skillActivation.get(id) ?? 0,
318
+ simUser: breakdown?.simUser ?? 0,
319
+ simAssistant: breakdown?.simAssistant ?? 0,
320
+ simNow: breakdown?.simNow ?? 0,
321
+ status: topSkillIdSet.has(id) ? "injected" : "not_injected",
322
+ };
323
+ });
324
+ skillRows.sort((a, b) => b.activation - a.activation);
325
+
326
+ const v2Cfg = config.memory.v2;
327
+ try {
328
+ recordMemoryV2ActivationLog({
329
+ conversationId,
330
+ turn: currentTurn,
331
+ mode,
332
+ concepts: conceptRows,
333
+ skills: skillRows,
334
+ config: {
335
+ d: v2Cfg.d,
336
+ c_user: v2Cfg.c_user,
337
+ c_assistant: v2Cfg.c_assistant,
338
+ c_now: v2Cfg.c_now,
339
+ k: v2Cfg.k,
340
+ hops: v2Cfg.hops,
341
+ top_k: v2Cfg.top_k,
342
+ top_k_skills: v2Cfg.top_k_skills,
343
+ epsilon: v2Cfg.epsilon,
344
+ },
345
+ });
346
+ } catch (err) {
347
+ log.warn(
348
+ { err, conversationId, turn: currentTurn },
349
+ "Failed to record memory v2 activation telemetry — continuing",
350
+ );
351
+ }
352
+
353
+ return { block, toInject: newlyInjected };
231
354
  }
232
355
 
233
356
  // ---------------------------------------------------------------------------
234
357
  // Internal helpers
235
358
  // ---------------------------------------------------------------------------
236
359
 
360
+ interface RenderInjectionBlockResult {
361
+ /**
362
+ * Inner content for the `<memory>` block (concept-page sections + optional
363
+ * skills suffix), or `null` when both the concept-page list and the skill
364
+ * list collapse to empty after cache misses (no on-disk pages, no
365
+ * resolvable skill ids). Returned unwrapped so the caller can wrap it
366
+ * exactly once at injection time, matching v1's contract: callers that
367
+ * cache the value (`lastInjectedBlock`) or persist it (`memoryInjectedBlock`
368
+ * in message metadata) re-wrap on use, and storing the wrapped form here
369
+ * caused a double wrap on reinject after compaction and on rehydrate from
370
+ * DB.
371
+ */
372
+ block: string | null;
373
+ /**
374
+ * Slugs that `readPage` returned null for. Surfaced so the caller can
375
+ * mark them in the activation log (`status: "page_missing"`) and emit
376
+ * a warning — silent drops here previously masked stale Qdrant /
377
+ * edge-index entries that pointed at pages no longer on disk.
378
+ */
379
+ missingSlugs: string[];
380
+ }
381
+
237
382
  /**
238
- * Render the `<memory __injected>` block for a list of slugs and a list of
239
- * ranked skill ids.
383
+ * Render the inner content of the `<memory>` block for a list of slugs and
384
+ * a list of ranked skill ids. The caller wraps the result in
385
+ * `<memory>...</memory>` exactly once at injection time.
240
386
  *
241
387
  * Concept pages are read in parallel via `readPage`. Pages whose file has
242
388
  * gone missing between selection and render (e.g. consolidation deleted
243
- * them) are silently dropped the activation state still records them in
244
- * `everInjected` so we don't keep re-attempting on every turn.
389
+ * them, folder reorg renamed the slug) are dropped from the rendered
390
+ * block but reported back via `missingSlugs` so callers can surface the
391
+ * divergence.
245
392
  *
246
393
  * Skill ids are looked up via `getSkillCapability`. Ids that the cache no
247
394
  * longer knows (e.g. uninstalled mid-run) are silently dropped, mirroring
248
395
  * the missing-pages behavior.
249
396
  *
250
397
  * The block shape is the §5 layout from the design doc, with an optional
251
- * trailing skills subsection:
398
+ * trailing skills subsection. Each concept-page section reproduces the page
399
+ * as it lives on disk — frontmatter (`edges`, `ref_files`) plus body — so
400
+ * the agent sees the page's edges and any referenced media paths alongside
401
+ * the prose:
252
402
  *
253
- * <memory __injected>
254
- * ## What I Remember Right Now
255
403
  * ### <slug-1>
404
+ * ---
405
+ * edges:
406
+ * - <neighbor-slug>
407
+ * ref_files:
408
+ * - <path/to/asset>
409
+ * ---
256
410
  * <body-1>
257
411
  *
258
412
  * ### <slug-2>
413
+ * ---
414
+ * edges: []
415
+ * ref_files: []
416
+ * ---
259
417
  * <body-2>
260
418
  *
261
419
  * ### Skills You Can Use
262
420
  * - <skill-1 content>
263
421
  * - <skill-2 content>
264
- * </memory>
265
- *
266
- * The same `## What I Remember Right Now` header wraps the block whether
267
- * the skills section is alone, the concept-page sections are alone, or
268
- * both are present — keeping the renderer one shape.
269
- *
270
- * Returns `null` when both lists collapse to empty after cache misses so
271
- * the caller can fall through to its empty-block path instead of attaching
272
- * a header with no contents.
273
422
  */
274
423
  async function renderInjectionBlock(
275
424
  workspaceDir: string,
276
425
  slugs: string[],
277
426
  skillIds: string[],
278
- ): Promise<string | null> {
427
+ ): Promise<RenderInjectionBlockResult> {
279
428
  const pages = await Promise.all(
280
429
  slugs.map(async (slug) => {
281
430
  const page = await readPage(workspaceDir, slug);
282
- return page ? { slug, body: page.body.trim() } : null;
431
+ return { slug, page };
283
432
  }),
284
433
  );
285
434
 
286
435
  const sections: string[] = [];
287
- for (const entry of pages) {
288
- if (!entry || entry.body.length === 0) continue;
289
- sections.push(`### ${entry.slug}\n${entry.body}`);
436
+ const missingSlugs: string[] = [];
437
+ for (const { slug, page } of pages) {
438
+ if (!page) {
439
+ missingSlugs.push(slug);
440
+ continue;
441
+ }
442
+ const content = renderPageContent(page).trim();
443
+ if (content.length === 0) continue;
444
+ sections.push(`### ${slug}\n${content}`);
290
445
  }
291
446
 
292
447
  // v2's skills collection is skills-only, so the activation suffix always applies.
@@ -300,8 +455,10 @@ async function renderInjectionBlock(
300
455
  sections.push(`### Skills You Can Use\n${skillLines.join("\n")}`);
301
456
  }
302
457
 
303
- if (sections.length === 0) return null;
458
+ if (sections.length === 0) return { block: null, missingSlugs };
304
459
 
305
- const inner = `## What I Remember Right Now\n\n${sections.join("\n\n")}`;
306
- return `<memory __injected>\n${inner}\n</memory>`;
460
+ return {
461
+ block: sections.join("\n\n"),
462
+ missingSlugs,
463
+ };
307
464
  }
@@ -5,9 +5,9 @@
5
5
  * synthesizes a concept page per cluster via the configured LLM, promotes
6
6
  * high-significance nodes to `essentials.md` / active follow-ups to
7
7
  * `threads.md` / low-significance episodes to `archive/migrated-<date>.md`,
8
- * collapses v1 weighted directional edges into the v2 unweighted-undirected
9
- * `memory/edges.json`, and enqueues `embed_concept_page` jobs for each new
10
- * page. A sentinel file at `memory/.v2-state/.migration-complete-v1-to-v2`
8
+ * preserves v1 weighted directional edges as outgoing-edge entries on each
9
+ * source page's frontmatter, and enqueues `embed_concept_page` jobs for each
10
+ * new page. A sentinel file at `memory/.v2-state/.migration-complete-v1-to-v2`
11
11
  * gates re-runs — `force: true` is required to overwrite.
12
12
  *
13
13
  * The migration is structured as a sequence of small helpers — `gatherV1State`,
@@ -31,9 +31,8 @@ import type { Provider } from "../../providers/types.js";
31
31
  import { getLogger } from "../../util/logger.js";
32
32
  import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
33
33
  import { enqueueMemoryJob } from "../jobs-store.js";
34
- import { writeEdges } from "./edges.js";
35
34
  import { slugify, writePage } from "./page-store.js";
36
- import type { ConceptPage, EdgesIndex } from "./types.js";
35
+ import type { ConceptPage } from "./types.js";
37
36
 
38
37
  const log = getLogger("memory-v2-migration");
39
38
 
@@ -56,7 +55,6 @@ export interface MigrationResult {
56
55
  threadsLines: number;
57
56
  archiveLines: number;
58
57
  embedsEnqueued: number;
59
- rebuildEdgesJobId: string;
60
58
  sentinelWritten: boolean;
61
59
  }
62
60
 
@@ -86,8 +84,9 @@ export interface V1Item {
86
84
  }
87
85
 
88
86
  /**
89
- * v1 weighted directional edge collapsed in stage 5 into v2's unweighted
90
- * undirected canonical pairs.
87
+ * v1 weighted directional edge. v2 preserves direction (an edge A→B in v1
88
+ * becomes an outgoing-edge entry on A's page in v2), so the migration just
89
+ * has to map node ids to slugs and group by source.
91
90
  */
92
91
  export interface V1Edge {
93
92
  sourceNodeId: string;
@@ -409,31 +408,38 @@ function formatPromotionLine(item: V1Item): string {
409
408
  }
410
409
 
411
410
  // ---------------------------------------------------------------------------
412
- // Stage 5 — Collapse v1 edges into v2 edges.json
411
+ // Stage 5 — Map v1 edges to per-page outgoing edges
413
412
  // ---------------------------------------------------------------------------
414
413
 
415
414
  /**
416
- * Map every v1 graph-node id to a v2 concept-page slug, then rewrite v1
417
- * edges as canonical v2 tuples. Edges with either endpoint missing from
418
- * `slugMap` are dropped silently — those endpoints didn't survive
419
- * synthesis (e.g. their cluster produced no usable page).
415
+ * Map every v1 graph-node id to a v2 concept-page slug and group v1 edges by
416
+ * source slug. Edges with either endpoint missing from `slugMap` are dropped
417
+ * silently — those endpoints didn't survive synthesis (e.g. their cluster
418
+ * produced no usable page). Self-loops are dropped; duplicate `(source, target)`
419
+ * pairs collapse via the `Set<string>`.
420
420
  *
421
- * The returned `EdgesIndex` is canonicalized + deduped by `writeEdges`'s
422
- * own write-time normalization, so callers can pass it straight through.
421
+ * The returned map keys are source slugs and the values are sets of target
422
+ * slugs i.e. each entry is a page's outgoing-edge list. The runner writes
423
+ * these into the source page's frontmatter.
423
424
  */
424
425
  export function collapseEdges(
425
426
  v1Edges: V1Edge[],
426
427
  slugMap: Map<string, string>,
427
- ): EdgesIndex {
428
- const tuples: [string, string][] = [];
428
+ ): Map<string, Set<string>> {
429
+ const outgoing = new Map<string, Set<string>>();
429
430
  for (const edge of v1Edges) {
430
- const a = slugMap.get(edge.sourceNodeId);
431
- const b = slugMap.get(edge.targetNodeId);
432
- if (!a || !b) continue;
433
- if (a === b) continue;
434
- tuples.push([a, b]);
431
+ const from = slugMap.get(edge.sourceNodeId);
432
+ const to = slugMap.get(edge.targetNodeId);
433
+ if (!from || !to) continue;
434
+ if (from === to) continue;
435
+ let targets = outgoing.get(from);
436
+ if (!targets) {
437
+ targets = new Set<string>();
438
+ outgoing.set(from, targets);
439
+ }
440
+ targets.add(to);
435
441
  }
436
- return { version: 1, edges: tuples };
442
+ return outgoing;
437
443
  }
438
444
 
439
445
  // ---------------------------------------------------------------------------
@@ -476,8 +482,8 @@ export interface RunMemoryV2MigrationParams {
476
482
  * Re-runs are gated by the sentinel file
477
483
  * `memory/.v2-state/.migration-complete-v1-to-v2`. Without `force: true`, a
478
484
  * second invocation throws `MigrationAlreadyAppliedError` without mutating
479
- * anything; with `force: true`, the migration overwrites pages and
480
- * `edges.json` and re-appends to the prose files.
485
+ * anything; with `force: true`, the migration overwrites pages and re-appends
486
+ * to the prose files.
481
487
  */
482
488
  export class MigrationAlreadyAppliedError extends Error {
483
489
  constructor() {
@@ -548,41 +554,46 @@ export async function runMemoryV2Migration(
548
554
  }
549
555
  }
550
556
 
557
+ // Resolve outgoing edges per source slug, then attach them to each page's
558
+ // frontmatter before writing. The page is the source of truth for its own
559
+ // outgoing edges — there is no separate edges-index file.
560
+ const outgoingBySource = collapseEdges(v1Edges, slugMap);
561
+ const finalizedPages: ConceptPage[] = pages.map((page) => {
562
+ const targets = outgoingBySource.get(page.slug);
563
+ if (!targets || targets.size === 0) return page;
564
+ return {
565
+ ...page,
566
+ frontmatter: {
567
+ ...page.frontmatter,
568
+ edges: [...targets].sort(),
569
+ },
570
+ };
571
+ });
572
+
551
573
  // Page writes hit different filenames so they're safe to fan out.
552
- await Promise.all(pages.map((page) => writePage(workspaceDir, page)));
574
+ await Promise.all(
575
+ finalizedPages.map((page) => writePage(workspaceDir, page)),
576
+ );
553
577
 
554
578
  const promotions = derivePromotions(items);
555
579
  await appendPromotions(workspaceDir, promotions);
556
580
 
557
- const edgesIdx = collapseEdges(v1Edges, slugMap);
558
- await writeEdges(workspaceDir, edgesIdx);
559
-
560
- const embedsEnqueued = enqueueEmbeds(pages.map((p) => p.slug));
561
-
562
- // Page bodies are written with empty `edges:` frontmatter (the schema is a
563
- // derived view of `edges.json`). Without this enqueue the frontmatter would
564
- // stay empty until the next consolidation run, but consolidation bails on an
565
- // empty buffer — so a freshly-migrated workspace can sit indefinitely with
566
- // out-of-date frontmatter. The rebuild-edges job propagates `edges.json` into
567
- // every page's frontmatter and is idempotent, so pairing it with the
568
- // migration is safe even when nothing else has run yet.
569
- const rebuildEdgesJobId = enqueueMemoryJob("memory_v2_rebuild_edges", {});
581
+ const embedsEnqueued = enqueueEmbeds(finalizedPages.map((p) => p.slug));
570
582
 
571
583
  await writeSentinel(workspaceDir);
572
584
 
573
- // Re-read after writeEdges so the count reflects post-canonicalization
574
- // dedup (collapseEdges can produce duplicate tuples when v1 had multiple
575
- // weighted edges between the same pair).
576
- const finalEdges = await readPersistedEdgeCount(workspaceDir);
585
+ let edgesWritten = 0;
586
+ for (const targets of outgoingBySource.values()) {
587
+ edgesWritten += targets.size;
588
+ }
577
589
 
578
590
  return {
579
- pagesCreated: pages.length,
580
- edgesWritten: finalEdges,
591
+ pagesCreated: finalizedPages.length,
592
+ edgesWritten,
581
593
  essentialsLines: promotions.essentials.length,
582
594
  threadsLines: promotions.threads.length,
583
595
  archiveLines: promotions.archive.length,
584
596
  embedsEnqueued,
585
- rebuildEdgesJobId,
586
597
  sentinelWritten: true,
587
598
  };
588
599
  }
@@ -634,21 +645,3 @@ async function writeSentinel(workspaceDir: string): Promise<void> {
634
645
  await mkdir(join(workspaceDir, "memory", ".v2-state"), { recursive: true });
635
646
  await writeFile(sentinelPath, `${new Date().toISOString()}\n`, "utf-8");
636
647
  }
637
-
638
- /**
639
- * Read `memory/edges.json` after writing and return the edge count. Used
640
- * only to populate the result summary — the file has already been
641
- * canonicalized by `writeEdges`, so this is just a count, not validation.
642
- */
643
- async function readPersistedEdgeCount(workspaceDir: string): Promise<number> {
644
- try {
645
- const raw = await readFile(
646
- join(workspaceDir, "memory", "edges.json"),
647
- "utf-8",
648
- );
649
- const parsed = JSON.parse(raw) as { edges?: unknown[] };
650
- return Array.isArray(parsed.edges) ? parsed.edges.length : 0;
651
- } catch {
652
- return 0;
653
- }
654
- }