@vellumai/assistant 0.5.16 → 0.6.1

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 (592) hide show
  1. package/AGENTS.md +4 -0
  2. package/ARCHITECTURE.md +69 -16
  3. package/Dockerfile +2 -5
  4. package/bun.lock +6 -2
  5. package/docker-entrypoint.sh +32 -1
  6. package/docs/architecture/integrations.md +1 -1
  7. package/docs/architecture/memory.md +21 -24
  8. package/knip.json +2 -1
  9. package/openapi.yaml +1198 -83
  10. package/package.json +5 -1
  11. package/src/__tests__/actor-token-service.test.ts +68 -0
  12. package/src/__tests__/agent-loop.test.ts +0 -32
  13. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  14. package/src/__tests__/anthropic-provider.test.ts +217 -98
  15. package/src/__tests__/app-compiler.test.ts +120 -0
  16. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  17. package/src/__tests__/app-executors.test.ts +47 -1
  18. package/src/__tests__/app-source-watcher.test.ts +159 -0
  19. package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -2
  20. package/src/__tests__/call-conversation-messages.test.ts +2 -6
  21. package/src/__tests__/call-domain.test.ts +2 -6
  22. package/src/__tests__/call-pointer-messages.test.ts +2 -14
  23. package/src/__tests__/call-recovery.test.ts +2 -6
  24. package/src/__tests__/call-routes-http.test.ts +2 -6
  25. package/src/__tests__/call-store.test.ts +2 -6
  26. package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
  27. package/src/__tests__/canonical-guardian-store.test.ts +2 -6
  28. package/src/__tests__/channel-delivery-store.test.ts +2 -6
  29. package/src/__tests__/channel-retry-sweep.test.ts +2 -6
  30. package/src/__tests__/checker.test.ts +63 -9
  31. package/src/__tests__/clawhub.test.ts +54 -24
  32. package/src/__tests__/cli-command-risk-guard.test.ts +14 -0
  33. package/src/__tests__/config-schema.test.ts +6 -1
  34. package/src/__tests__/config-set-platform-guard.test.ts +302 -0
  35. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
  36. package/src/__tests__/contacts-tools.test.ts +31 -0
  37. package/src/__tests__/context-overflow-reducer.test.ts +86 -0
  38. package/src/__tests__/context-token-estimator.test.ts +175 -10
  39. package/src/__tests__/conversation-agent-loop-overflow.test.ts +13 -6
  40. package/src/__tests__/conversation-agent-loop.test.ts +13 -51
  41. package/src/__tests__/conversation-attachments.test.ts +2 -6
  42. package/src/__tests__/conversation-attention-store.test.ts +2 -6
  43. package/src/__tests__/conversation-clear-safety.test.ts +2 -6
  44. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
  45. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
  46. package/src/__tests__/conversation-disk-view.test.ts +2 -6
  47. package/src/__tests__/conversation-error.test.ts +33 -2
  48. package/src/__tests__/conversation-fork-crud.test.ts +2 -6
  49. package/src/__tests__/conversation-history-web-search.test.ts +6 -1
  50. package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
  51. package/src/__tests__/conversation-media-retry.test.ts +91 -0
  52. package/src/__tests__/conversation-runtime-assembly.test.ts +653 -832
  53. package/src/__tests__/conversation-runtime-workspace.test.ts +1 -93
  54. package/src/__tests__/conversation-starter-routes.test.ts +20 -11
  55. package/src/__tests__/conversation-store.test.ts +2 -6
  56. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +17 -4
  57. package/src/__tests__/conversation-usage.test.ts +2 -6
  58. package/src/__tests__/conversation-wipe.test.ts +13 -414
  59. package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -12
  60. package/src/__tests__/conversation-workspace-injection.test.ts +25 -26
  61. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
  62. package/src/__tests__/copy-composer-tc-templates.test.ts +335 -0
  63. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
  64. package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
  65. package/src/__tests__/credential-security-e2e.test.ts +2 -0
  66. package/src/__tests__/date-context.test.ts +76 -210
  67. package/src/__tests__/db-schedule-syntax-migration.test.ts +16 -1
  68. package/src/__tests__/file-list-tool.test.ts +219 -0
  69. package/src/__tests__/first-greeting.test.ts +1 -1
  70. package/src/__tests__/followup-tools.test.ts +2 -6
  71. package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
  72. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
  73. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
  74. package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
  75. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
  76. package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
  77. package/src/__tests__/guardian-action-store.test.ts +2 -6
  78. package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
  79. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
  80. package/src/__tests__/guardian-dispatch.test.ts +2 -6
  81. package/src/__tests__/guardian-grant-minting.test.ts +2 -14
  82. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
  83. package/src/__tests__/guardian-routing-invariants.test.ts +192 -6
  84. package/src/__tests__/guardian-routing-state.test.ts +2 -6
  85. package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
  86. package/src/__tests__/heartbeat-service.test.ts +180 -3
  87. package/src/__tests__/identity-routes.test.ts +328 -0
  88. package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
  89. package/src/__tests__/injection-block.test.ts +178 -0
  90. package/src/__tests__/install-meta.test.ts +506 -0
  91. package/src/__tests__/install-skill-routing.test.ts +293 -0
  92. package/src/__tests__/invite-redemption-service.test.ts +2 -6
  93. package/src/__tests__/invite-routes-http.test.ts +2 -6
  94. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +17 -28
  95. package/src/__tests__/list-messages-attachments.test.ts +2 -6
  96. package/src/__tests__/list-messages-tool-merge.test.ts +300 -0
  97. package/src/__tests__/llm-context-normalization.test.ts +18 -18
  98. package/src/__tests__/llm-context-route-provider.test.ts +103 -6
  99. package/src/__tests__/llm-request-log-turn-query.test.ts +164 -6
  100. package/src/__tests__/llm-usage-store.test.ts +2 -6
  101. package/src/__tests__/log-export-workspace.test.ts +74 -111
  102. package/src/__tests__/managed-store.test.ts +38 -11
  103. package/src/__tests__/mcp-abort-signal.test.ts +5 -0
  104. package/src/__tests__/mcp-client-auth.test.ts +5 -0
  105. package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
  106. package/src/__tests__/memory-recall-log-store.test.ts +134 -6
  107. package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
  108. package/src/__tests__/migration-export-streaming.test.ts +304 -0
  109. package/src/__tests__/migration-import-commit-http.test.ts +11 -10
  110. package/src/__tests__/mock-fetch.ts +87 -0
  111. package/src/__tests__/non-member-access-request.test.ts +2 -6
  112. package/src/__tests__/notification-decision-recipient-context.test.ts +282 -0
  113. package/src/__tests__/notification-guardian-path.test.ts +2 -6
  114. package/src/__tests__/oauth-cli.test.ts +364 -2
  115. package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
  116. package/src/__tests__/onboarding-template-contract.test.ts +62 -14
  117. package/src/__tests__/outlook-attachments.test.ts +301 -0
  118. package/src/__tests__/outlook-automation-tools.test.ts +425 -0
  119. package/src/__tests__/outlook-categories.test.ts +212 -0
  120. package/src/__tests__/outlook-client-automation.test.ts +246 -0
  121. package/src/__tests__/outlook-compose-tools.test.ts +325 -0
  122. package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
  123. package/src/__tests__/outlook-email-watcher.test.ts +322 -0
  124. package/src/__tests__/outlook-follow-up.test.ts +196 -0
  125. package/src/__tests__/outlook-messaging-provider.test.ts +498 -3
  126. package/src/__tests__/outlook-trash.test.ts +77 -0
  127. package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
  128. package/src/__tests__/parser.test.ts +32 -0
  129. package/src/__tests__/permission-checker-host-gate.test.ts +452 -0
  130. package/src/__tests__/permission-controls-v2-flag.test.ts +55 -0
  131. package/src/__tests__/permission-mode-sse.test.ts +418 -0
  132. package/src/__tests__/permission-mode-store.test.ts +277 -0
  133. package/src/__tests__/permission-mode.test.ts +101 -0
  134. package/src/__tests__/platform-bash-auto-approve.test.ts +359 -0
  135. package/src/__tests__/platform-callback-registration.test.ts +4 -4
  136. package/src/__tests__/playbook-execution.test.ts +76 -80
  137. package/src/__tests__/playbook-tools.test.ts +5 -7
  138. package/src/__tests__/profiler-routes.test.ts +502 -0
  139. package/src/__tests__/profiler-run-store.test.ts +441 -0
  140. package/src/__tests__/provider-error-scenarios.test.ts +21 -0
  141. package/src/__tests__/proxy-approval-callback.test.ts +4 -75
  142. package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
  143. package/src/__tests__/registry.test.ts +3 -3
  144. package/src/__tests__/require-fresh-approval.test.ts +64 -2
  145. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
  146. package/src/__tests__/runtime-events-sse.test.ts +2 -6
  147. package/src/__tests__/sandbox-host-parity.test.ts +5 -4
  148. package/src/__tests__/schedule-store.test.ts +2 -6
  149. package/src/__tests__/schedule-tools.test.ts +2 -6
  150. package/src/__tests__/scheduler-recurrence.test.ts +1 -5
  151. package/src/__tests__/scheduler-reuse-conversation.test.ts +368 -0
  152. package/src/__tests__/scoped-approval-grants.test.ts +2 -6
  153. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
  154. package/src/__tests__/scrub-corrupted-image-attachments.test.ts +278 -0
  155. package/src/__tests__/search-skills-unified.test.ts +422 -0
  156. package/src/__tests__/secret-onetime-send.test.ts +2 -0
  157. package/src/__tests__/send-endpoint-busy.test.ts +44 -9
  158. package/src/__tests__/sequence-store.test.ts +2 -6
  159. package/src/__tests__/server-history-render.test.ts +2 -6
  160. package/src/__tests__/set-permission-mode.test.ts +274 -0
  161. package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
  162. package/src/__tests__/skill-feature-flags.test.ts +6 -6
  163. package/src/__tests__/skill-load-feature-flag.test.ts +23 -11
  164. package/src/__tests__/skill-memory.test.ts +2 -741
  165. package/src/__tests__/skills-uninstall.test.ts +2 -2
  166. package/src/__tests__/skills.test.ts +1 -1
  167. package/src/__tests__/slack-inbound-verification.test.ts +2 -6
  168. package/src/__tests__/strip-memory-injections.test.ts +187 -0
  169. package/src/__tests__/subagent-detail.test.ts +84 -0
  170. package/src/__tests__/subagent-disposal.test.ts +308 -0
  171. package/src/__tests__/subagent-manager-notify.test.ts +19 -10
  172. package/src/__tests__/subagent-notify-parent.test.ts +390 -0
  173. package/src/__tests__/subagent-role-registry.test.ts +108 -0
  174. package/src/__tests__/subagent-tool-filtering.test.ts +71 -0
  175. package/src/__tests__/subagent-tools.test.ts +464 -4
  176. package/src/__tests__/system-prompt-ask-mode.test.ts +139 -0
  177. package/src/__tests__/task-compiler.test.ts +2 -6
  178. package/src/__tests__/task-management-tools.test.ts +2 -6
  179. package/src/__tests__/task-memory-cleanup.test.ts +185 -241
  180. package/src/__tests__/task-runner.test.ts +2 -6
  181. package/src/__tests__/task-scheduler.test.ts +2 -6
  182. package/src/__tests__/terminal-tools.test.ts +17 -27
  183. package/src/__tests__/test-preload.ts +7 -0
  184. package/src/__tests__/tool-approval-handler.test.ts +2 -6
  185. package/src/__tests__/tool-executor.test.ts +4 -26
  186. package/src/__tests__/tool-grant-request-escalation.test.ts +2 -6
  187. package/src/__tests__/tool-side-effects-slack-dm.test.ts +277 -0
  188. package/src/__tests__/top-level-renderer.test.ts +10 -13
  189. package/src/__tests__/trust-store.test.ts +1 -1
  190. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +2 -6
  191. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +118 -8
  192. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -6
  193. package/src/__tests__/trusted-contact-verification.test.ts +2 -6
  194. package/src/__tests__/turn-boundary-resolution.test.ts +2 -6
  195. package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -6
  196. package/src/__tests__/usage-routes.test.ts +2 -6
  197. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  198. package/src/__tests__/voice-invite-redemption.test.ts +2 -6
  199. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -6
  200. package/src/__tests__/voice-session-bridge.test.ts +2 -6
  201. package/src/__tests__/volume-security-guard.test.ts +2 -0
  202. package/src/__tests__/workspace-lifecycle.test.ts +29 -1
  203. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -6
  204. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +2 -6
  205. package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
  206. package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +387 -0
  207. package/src/__tests__/workspace-policy.test.ts +1 -1
  208. package/src/agent/attachments.ts +7 -2
  209. package/src/agent/image-optimize.ts +165 -0
  210. package/src/agent/loop.ts +7 -15
  211. package/src/approvals/guardian-request-resolvers.ts +24 -0
  212. package/src/avatar/traits-png-sync.ts +3 -3
  213. package/src/bundler/app-compiler.ts +179 -2
  214. package/src/bundler/package-resolver.ts +3 -5
  215. package/src/cli/__tests__/notifications.test.ts +1 -2
  216. package/src/cli/__tests__/run-assistant-command.ts +29 -0
  217. package/src/cli/commands/__tests__/email-download.test.ts +245 -0
  218. package/src/cli/commands/__tests__/email-list.test.ts +192 -0
  219. package/src/cli/commands/__tests__/email-register.test.ts +186 -0
  220. package/src/cli/commands/__tests__/email-send.test.ts +291 -0
  221. package/src/cli/commands/__tests__/email-status.test.ts +181 -0
  222. package/src/cli/commands/__tests__/email-unregister.test.ts +139 -0
  223. package/src/cli/commands/__tests__/routes.test.ts +562 -0
  224. package/src/cli/commands/avatar.ts +3 -3
  225. package/src/cli/commands/config.ts +26 -13
  226. package/src/cli/commands/conversations.ts +1 -8
  227. package/src/cli/commands/doctor.ts +2 -2
  228. package/src/cli/commands/email.ts +584 -835
  229. package/src/cli/commands/memory.ts +37 -84
  230. package/src/cli/commands/notifications.ts +7 -2
  231. package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
  232. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
  233. package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
  234. package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
  235. package/src/cli/commands/oauth/connect.ts +25 -11
  236. package/src/cli/commands/oauth/mode.ts +7 -0
  237. package/src/cli/commands/oauth/shared.ts +39 -3
  238. package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
  239. package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
  240. package/src/cli/commands/platform/__tests__/status.test.ts +5 -5
  241. package/src/cli/commands/platform/index.ts +16 -16
  242. package/src/cli/commands/routes.ts +396 -0
  243. package/src/cli/commands/skills.ts +218 -36
  244. package/src/cli/commands/trust.ts +2 -2
  245. package/src/cli/lib/daemon-credential-client.ts +2 -3
  246. package/src/cli/program.ts +2 -0
  247. package/src/cli.ts +1 -120
  248. package/src/config/bundled-skills/acp/TOOLS.json +1 -1
  249. package/src/config/bundled-skills/app-builder/SKILL.md +4 -1
  250. package/src/config/bundled-skills/contacts/SKILL.md +0 -1
  251. package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
  252. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
  253. package/src/config/bundled-skills/gmail/SKILL.md +4 -12
  254. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
  255. package/src/config/bundled-skills/messaging/SKILL.md +17 -18
  256. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
  257. package/src/config/bundled-skills/outlook/SKILL.md +189 -0
  258. package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
  259. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
  260. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
  261. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
  262. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
  263. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
  264. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
  265. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
  266. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
  267. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
  268. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
  269. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
  270. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
  271. package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
  272. package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
  273. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
  274. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
  275. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
  276. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
  277. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
  278. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
  279. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
  280. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
  281. package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
  282. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
  283. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
  284. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
  285. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
  286. package/src/config/bundled-skills/schedule/SKILL.md +22 -2
  287. package/src/config/bundled-skills/schedule/TOOLS.json +8 -0
  288. package/src/config/bundled-skills/settings/tools/avatar-get.ts +3 -13
  289. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +2 -4
  290. package/src/config/bundled-skills/settings/tools/avatar-update.ts +5 -2
  291. package/src/config/bundled-skills/slack/SKILL.md +3 -7
  292. package/src/config/bundled-skills/subagent/SKILL.md +43 -3
  293. package/src/config/bundled-skills/subagent/TOOLS.json +29 -4
  294. package/src/config/bundled-tool-registry.ts +56 -4
  295. package/src/config/env-registry.ts +78 -8
  296. package/src/config/feature-flag-registry.json +38 -125
  297. package/src/config/schema.ts +8 -0
  298. package/src/config/schemas/filing.ts +51 -0
  299. package/src/config/schemas/heartbeat.ts +15 -12
  300. package/src/config/schemas/memory-lifecycle.ts +12 -0
  301. package/src/config/schemas/platform.ts +8 -0
  302. package/src/config/schemas/security.ts +14 -0
  303. package/src/config/schemas/timeouts.ts +1 -1
  304. package/src/config/skills.ts +18 -7
  305. package/src/context/token-estimator.ts +25 -18
  306. package/src/context/window-manager.ts +6 -2
  307. package/src/credential-execution/process-manager.ts +3 -1
  308. package/src/daemon/app-source-watcher.ts +93 -0
  309. package/src/daemon/config-watcher.ts +79 -1
  310. package/src/daemon/context-overflow-reducer.ts +46 -2
  311. package/src/daemon/conversation-agent-loop-handlers.ts +143 -82
  312. package/src/daemon/conversation-agent-loop.ts +236 -108
  313. package/src/daemon/conversation-error.ts +31 -8
  314. package/src/daemon/conversation-history.ts +4 -19
  315. package/src/daemon/conversation-lifecycle.ts +36 -9
  316. package/src/daemon/conversation-media-retry.ts +85 -7
  317. package/src/daemon/conversation-notifiers.ts +4 -1
  318. package/src/daemon/conversation-process.ts +13 -7
  319. package/src/daemon/conversation-runtime-assembly.ts +305 -306
  320. package/src/daemon/conversation-tool-setup.ts +44 -14
  321. package/src/daemon/conversation-workspace.ts +1 -2
  322. package/src/daemon/conversation.ts +59 -2
  323. package/src/daemon/daemon-control.ts +8 -2
  324. package/src/daemon/date-context.ts +26 -53
  325. package/src/daemon/first-greeting.ts +1 -1
  326. package/src/daemon/handlers/conversations.ts +4 -7
  327. package/src/daemon/handlers/shared.test.ts +143 -0
  328. package/src/daemon/handlers/shared.ts +85 -17
  329. package/src/daemon/handlers/skills.ts +416 -209
  330. package/src/daemon/lifecycle.ts +212 -131
  331. package/src/daemon/main.ts +5 -1
  332. package/src/daemon/message-types/conversations.ts +29 -7
  333. package/src/daemon/message-types/messages.ts +12 -2
  334. package/src/daemon/message-types/schedules.ts +1 -0
  335. package/src/daemon/message-types/settings.ts +6 -0
  336. package/src/daemon/message-types/skills.ts +97 -36
  337. package/src/daemon/profiler-run-store.ts +557 -0
  338. package/src/daemon/providers-setup.ts +5 -0
  339. package/src/daemon/server.ts +100 -11
  340. package/src/daemon/shutdown-handlers.ts +5 -0
  341. package/src/daemon/tool-side-effects.ts +50 -8
  342. package/src/export/transcript-formatter.ts +148 -0
  343. package/src/filing/filing-service.ts +228 -0
  344. package/src/heartbeat/heartbeat-service.ts +97 -7
  345. package/src/hooks/cli.ts +2 -2
  346. package/src/hooks/runner.ts +15 -38
  347. package/src/inbound/platform-callback-registration.ts +14 -14
  348. package/src/mcp/client.ts +6 -0
  349. package/src/mcp/mcp-oauth-provider.ts +149 -27
  350. package/src/memory/admin.ts +42 -75
  351. package/src/memory/app-store.ts +69 -0
  352. package/src/memory/conversation-bootstrap.ts +3 -1
  353. package/src/memory/conversation-crud.ts +211 -288
  354. package/src/memory/conversation-group-migration.ts +157 -0
  355. package/src/memory/conversation-queries.ts +61 -13
  356. package/src/memory/conversation-title-service.ts +1 -0
  357. package/src/memory/db-init.ts +194 -361
  358. package/src/memory/embed.ts +73 -0
  359. package/src/memory/embedding-backend.ts +8 -14
  360. package/src/memory/embedding-runtime-manager.ts +12 -114
  361. package/src/memory/fingerprint.ts +2 -2
  362. package/src/memory/graph/bootstrap.ts +521 -0
  363. package/src/memory/graph/capability-seed.ts +449 -0
  364. package/src/memory/graph/consolidation.ts +725 -0
  365. package/src/memory/graph/conversation-graph-memory.ts +659 -0
  366. package/src/memory/graph/decay.test.ts +208 -0
  367. package/src/memory/graph/decay.ts +195 -0
  368. package/src/memory/graph/extraction-job.ts +74 -0
  369. package/src/memory/graph/extraction.test.ts +936 -0
  370. package/src/memory/graph/extraction.ts +1297 -0
  371. package/src/memory/graph/graph-memory-state-store.ts +37 -0
  372. package/src/memory/graph/graph-search.ts +280 -0
  373. package/src/memory/graph/image-ref-utils.ts +29 -0
  374. package/src/memory/graph/injection.test.ts +513 -0
  375. package/src/memory/graph/injection.ts +469 -0
  376. package/src/memory/graph/inspect.ts +543 -0
  377. package/src/memory/graph/narrative.ts +267 -0
  378. package/src/memory/graph/pattern-scan.ts +269 -0
  379. package/src/memory/graph/retriever.ts +1111 -0
  380. package/src/memory/graph/scoring.test.ts +548 -0
  381. package/src/memory/graph/scoring.ts +232 -0
  382. package/src/memory/graph/serendipity.ts +65 -0
  383. package/src/memory/graph/store.test.ts +1098 -0
  384. package/src/memory/graph/store.ts +838 -0
  385. package/src/memory/graph/tool-handlers.ts +301 -0
  386. package/src/memory/graph/tools.ts +97 -0
  387. package/src/memory/graph/triggers.test.ts +487 -0
  388. package/src/memory/graph/triggers.ts +223 -0
  389. package/src/memory/graph/types.ts +295 -0
  390. package/src/memory/group-crud.ts +191 -0
  391. package/src/memory/indexer.ts +37 -19
  392. package/src/memory/job-handlers/cleanup.ts +32 -42
  393. package/src/memory/job-handlers/conversation-starters.ts +91 -53
  394. package/src/memory/job-handlers/embedding.ts +5 -31
  395. package/src/memory/job-handlers/index-maintenance.ts +23 -11
  396. package/src/memory/job-handlers/summarization.ts +32 -17
  397. package/src/memory/job-utils.ts +1 -1
  398. package/src/memory/jobs-store.ts +21 -31
  399. package/src/memory/jobs-worker.ts +180 -129
  400. package/src/memory/llm-request-log-store.ts +96 -12
  401. package/src/memory/memory-recall-log-store.ts +49 -5
  402. package/src/memory/message-content.ts +1 -0
  403. package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
  404. package/src/memory/migrations/203-drop-memory-items-tables.ts +55 -0
  405. package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
  406. package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
  407. package/src/memory/migrations/206-memory-graph-node-edits.ts +19 -0
  408. package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +131 -0
  409. package/src/memory/migrations/207-conversation-graph-memory-state.ts +20 -0
  410. package/src/memory/migrations/208-conversations-last-message-at.ts +35 -0
  411. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +85 -0
  412. package/src/memory/migrations/210-schedule-reuse-conversation.ts +13 -0
  413. package/src/memory/migrations/211-memory-recall-logs-query-context.ts +21 -0
  414. package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +19 -0
  415. package/src/memory/migrations/index.ts +12 -0
  416. package/src/memory/migrations/registry.ts +16 -0
  417. package/src/memory/qdrant-client.ts +44 -17
  418. package/src/memory/schema/conversations.ts +14 -0
  419. package/src/memory/schema/index.ts +1 -0
  420. package/src/memory/schema/infrastructure.ts +8 -1
  421. package/src/memory/schema/memory-core.ts +0 -51
  422. package/src/memory/schema/memory-graph.ts +154 -0
  423. package/src/memory/search/semantic.ts +47 -91
  424. package/src/memory/task-memory-cleanup.ts +58 -61
  425. package/src/messaging/providers/outlook/adapter.ts +8 -1
  426. package/src/messaging/providers/outlook/client.ts +299 -0
  427. package/src/messaging/providers/outlook/types.ts +118 -0
  428. package/src/notifications/adapters/macos.ts +1 -0
  429. package/src/notifications/copy-composer.ts +95 -0
  430. package/src/notifications/decision-engine.ts +35 -0
  431. package/src/notifications/signal.ts +16 -0
  432. package/src/oauth/seed-providers.ts +2 -1
  433. package/src/permissions/checker.ts +36 -4
  434. package/src/permissions/defaults.ts +4 -4
  435. package/src/permissions/permission-mode-store.ts +180 -0
  436. package/src/permissions/permission-mode.ts +31 -0
  437. package/src/permissions/workspace-policy.ts +10 -1
  438. package/src/playbooks/playbook-compiler.ts +19 -18
  439. package/src/playbooks/types.ts +4 -3
  440. package/src/prompts/system-prompt.ts +62 -36
  441. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +100 -0
  442. package/src/prompts/templates/BOOTSTRAP.md +70 -165
  443. package/src/prompts/templates/HEARTBEAT.md +3 -1
  444. package/src/prompts/templates/SOUL.md +25 -4
  445. package/src/prompts/templates/UPDATES.md +8 -0
  446. package/src/providers/anthropic/client.ts +136 -220
  447. package/src/providers/gemini/client.ts +1 -1
  448. package/src/providers/openai/client.ts +1 -1
  449. package/src/providers/registry.ts +1 -1
  450. package/src/providers/retry.ts +19 -3
  451. package/src/runtime/actor-trust-resolver.ts +5 -1
  452. package/src/runtime/auth/route-policy.ts +30 -0
  453. package/src/runtime/guardian-reply-router.ts +5 -1
  454. package/src/runtime/http-server.ts +55 -5
  455. package/src/runtime/http-types.ts +12 -1
  456. package/src/runtime/middleware/auth.ts +20 -0
  457. package/src/runtime/migrations/vbundle-builder.ts +389 -3
  458. package/src/runtime/migrations/vbundle-importer.ts +8 -6
  459. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +378 -0
  460. package/src/runtime/routes/app-management-routes.ts +1 -11
  461. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +26 -0
  462. package/src/runtime/routes/archive-utils.ts +29 -0
  463. package/src/runtime/routes/attachment-routes.test.ts +106 -0
  464. package/src/runtime/routes/attachment-routes.ts +106 -16
  465. package/src/runtime/routes/avatar-routes.ts +2 -9
  466. package/src/runtime/routes/brain-graph-routes.ts +21 -22
  467. package/src/runtime/routes/btw-routes.ts +22 -1
  468. package/src/runtime/routes/conversation-analysis-routes.ts +173 -0
  469. package/src/runtime/routes/conversation-management-routes.ts +3 -14
  470. package/src/runtime/routes/conversation-query-routes.ts +49 -3
  471. package/src/runtime/routes/conversation-routes.ts +264 -44
  472. package/src/runtime/routes/conversation-starter-routes.ts +2 -2
  473. package/src/runtime/routes/debug-routes.ts +1 -1
  474. package/src/runtime/routes/global-search-routes.ts +21 -19
  475. package/src/runtime/routes/group-routes.ts +207 -0
  476. package/src/runtime/routes/guardian-action-routes.ts +21 -10
  477. package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
  478. package/src/runtime/routes/heartbeat-routes.ts +4 -10
  479. package/src/runtime/routes/identity-routes.ts +53 -18
  480. package/src/runtime/routes/inbound-message-handler.ts +19 -0
  481. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
  482. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
  483. package/src/runtime/routes/llm-context-normalization.ts +14 -10
  484. package/src/runtime/routes/log-export-routes.ts +23 -275
  485. package/src/runtime/routes/memory-item-routes.test.ts +170 -247
  486. package/src/runtime/routes/memory-item-routes.ts +341 -388
  487. package/src/runtime/routes/migration-routes.ts +18 -7
  488. package/src/runtime/routes/profiler-routes.ts +350 -0
  489. package/src/runtime/routes/schedule-routes.ts +28 -11
  490. package/src/runtime/routes/settings-routes.ts +95 -8
  491. package/src/runtime/routes/skills-routes.ts +103 -37
  492. package/src/runtime/routes/subagents-routes.ts +28 -7
  493. package/src/runtime/routes/user-route-dispatcher.ts +223 -0
  494. package/src/runtime/routes/user-routes.ts +41 -0
  495. package/src/runtime/routes/work-items-routes.test.ts +2 -6
  496. package/src/runtime/routes/workspace-routes.ts +0 -1
  497. package/src/schedule/schedule-store.ts +30 -0
  498. package/src/schedule/scheduler.ts +52 -18
  499. package/src/security/oauth2.ts +1 -1
  500. package/src/security/secure-keys.ts +4 -8
  501. package/src/shared/provider-env-vars.ts +19 -0
  502. package/src/skills/catalog-cache.ts +5 -0
  503. package/src/skills/catalog-install.ts +25 -16
  504. package/src/skills/clawhub.ts +134 -154
  505. package/src/skills/install-meta.ts +208 -0
  506. package/src/skills/managed-store.ts +29 -18
  507. package/src/skills/skill-memory.ts +12 -229
  508. package/src/skills/skillssh-registry.ts +19 -17
  509. package/src/subagent/index.ts +13 -3
  510. package/src/subagent/manager.ts +308 -29
  511. package/src/subagent/types.ts +68 -0
  512. package/src/tasks/task-runner.ts +7 -5
  513. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
  514. package/src/tools/apps/executors.ts +29 -4
  515. package/src/tools/browser/runtime-check.ts +3 -1
  516. package/src/tools/filesystem/list.ts +93 -0
  517. package/src/tools/memory/register.ts +63 -46
  518. package/src/tools/permission-checker.ts +85 -1
  519. package/src/tools/registry.ts +4 -0
  520. package/src/tools/schedule/create.ts +3 -0
  521. package/src/tools/schedule/list.ts +1 -0
  522. package/src/tools/schedule/update.ts +6 -0
  523. package/src/tools/shared/filesystem/errors.ts +5 -0
  524. package/src/tools/shared/filesystem/file-ops-service.ts +90 -2
  525. package/src/tools/shared/filesystem/image-read.ts +22 -85
  526. package/src/tools/shared/filesystem/types.ts +17 -0
  527. package/src/tools/shared/shell-output.ts +31 -2
  528. package/src/tools/subagent/abort.ts +12 -2
  529. package/src/tools/subagent/message.ts +9 -2
  530. package/src/tools/subagent/notify-parent.ts +79 -0
  531. package/src/tools/subagent/read.ts +29 -8
  532. package/src/tools/subagent/resolve.ts +21 -0
  533. package/src/tools/subagent/spawn.ts +2 -0
  534. package/src/tools/subagent/status.ts +11 -1
  535. package/src/tools/system/avatar-generator.ts +3 -3
  536. package/src/tools/system/register.ts +23 -0
  537. package/src/tools/system/set-permission-mode.ts +103 -0
  538. package/src/tools/terminal/parser.ts +30 -5
  539. package/src/tools/terminal/safe-env.ts +17 -1
  540. package/src/tools/tool-manifest.ts +9 -3
  541. package/src/tools/types.ts +2 -0
  542. package/src/util/browser.ts +25 -10
  543. package/src/util/bun-runtime.ts +172 -0
  544. package/src/util/logger.ts +1 -1
  545. package/src/util/platform.ts +50 -17
  546. package/src/watcher/providers/outlook-calendar.ts +343 -0
  547. package/src/watcher/providers/outlook.ts +198 -0
  548. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +2 -2
  549. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +2 -2
  550. package/src/workspace/migrations/025-remove-oauth-app-setup-skills.ts +76 -0
  551. package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
  552. package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
  553. package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +270 -0
  554. package/src/workspace/migrations/029-seed-pkb.ts +84 -0
  555. package/src/workspace/migrations/registry.ts +10 -0
  556. package/src/workspace/top-level-renderer.ts +5 -9
  557. package/src/__tests__/cli-memory.test.ts +0 -372
  558. package/src/__tests__/clipboard.test.ts +0 -88
  559. package/src/__tests__/context-memory-e2e.test.ts +0 -415
  560. package/src/__tests__/journal-context.test.ts +0 -268
  561. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
  562. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
  563. package/src/__tests__/memory-query-builder.test.ts +0 -59
  564. package/src/__tests__/memory-recall-quality.test.ts +0 -1046
  565. package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
  566. package/src/__tests__/memory-regressions.test.ts +0 -3696
  567. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
  568. package/src/cli/cli-memory.ts +0 -176
  569. package/src/daemon/conversation-memory.ts +0 -207
  570. package/src/memory/conversation-starters-cadence.ts +0 -74
  571. package/src/memory/items-extractor.ts +0 -860
  572. package/src/memory/job-handlers/batch-extraction.ts +0 -753
  573. package/src/memory/job-handlers/extraction.ts +0 -40
  574. package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -355
  575. package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
  576. package/src/memory/journal-memory.ts +0 -224
  577. package/src/memory/query-builder.ts +0 -47
  578. package/src/memory/query-expansion.ts +0 -83
  579. package/src/memory/retriever.test.ts +0 -1592
  580. package/src/memory/retriever.ts +0 -1331
  581. package/src/memory/search/formatting.test.ts +0 -140
  582. package/src/memory/search/formatting.ts +0 -262
  583. package/src/memory/search/mmr.ts +0 -139
  584. package/src/memory/search/ranking.ts +0 -15
  585. package/src/memory/search/staleness.ts +0 -40
  586. package/src/memory/search/tier-classifier.ts +0 -18
  587. package/src/memory/search/types.ts +0 -121
  588. package/src/prompts/journal-context.ts +0 -154
  589. package/src/tools/memory/definitions.ts +0 -69
  590. package/src/tools/memory/handlers.test.ts +0 -562
  591. package/src/tools/memory/handlers.ts +0 -434
  592. package/src/util/clipboard.ts +0 -34
@@ -2,9 +2,21 @@
2
2
  * OAuthClientProvider implementation for MCP servers.
3
3
  *
4
4
  * Uses secure-keys (credential store) for persistent credential storage
5
- * and a loopback HTTP server for the browser callback.
5
+ * and either a loopback HTTP server or the gateway callback registry
6
+ * for the browser callback.
7
+ *
8
+ * Two callback transports:
9
+ *
10
+ * 1. **Loopback** (default) — starts a temporary HTTP server on localhost.
11
+ * Works when the daemon runs on the user's machine (desktop app).
12
+ *
13
+ * 2. **Gateway** — routes callbacks through the platform's public ingress
14
+ * URL and the in-memory oauth-callback-registry. Used when the daemon
15
+ * runs inside Docker/platform where localhost is unreachable from the
16
+ * user's browser.
6
17
  */
7
18
 
19
+ import { randomBytes } from "node:crypto";
8
20
  import { createServer, type Server } from "node:http";
9
21
 
10
22
  import type {
@@ -22,8 +34,8 @@ import {
22
34
  getSecureKeyAsync,
23
35
  setSecureKeyAsync,
24
36
  } from "../security/secure-keys.js";
37
+ import { openInHostBrowser } from "../util/browser.js";
25
38
  import { getLogger } from "../util/logger.js";
26
- import { isLinux, isMacOS } from "../util/platform.js";
27
39
 
28
40
  const log = getLogger("mcp-oauth");
29
41
 
@@ -46,24 +58,41 @@ export interface McpOAuthCallbackResult {
46
58
  codePromise: Promise<string>;
47
59
  }
48
60
 
61
+ /** Which callback transport to use for receiving the OAuth redirect. */
62
+ export type McpOAuthCallbackTransport = "loopback" | "gateway";
63
+
49
64
  export class McpOAuthProvider implements OAuthClientProvider {
50
65
  private readonly serverId: string;
51
66
  private readonly serverUrl: string;
52
67
  private readonly interactive: boolean;
68
+ private readonly callbackTransport: McpOAuthCallbackTransport;
53
69
  private _codeVerifier: string | undefined;
70
+ private _state: string | undefined;
54
71
  private _redirectUrl: string | undefined;
55
72
  private _codePromise: Promise<string> | null = null;
56
73
  private callbackServer: Server | null = null;
57
74
  private callbackTimeout: ReturnType<typeof setTimeout> | null = null;
75
+ /** Deferred resolver/rejector for the gateway code promise. */
76
+ private _gatewayCodeResolve: ((code: string) => void) | undefined;
77
+ private _gatewayCodeReject: ((err: Error) => void) | undefined;
58
78
 
59
79
  /**
60
80
  * @param interactive When true (e.g. `mcp auth` CLI), opens browser for OAuth.
61
81
  * When false (daemon), logs a message instead.
82
+ * @param callbackTransport Which transport to use for the OAuth redirect.
83
+ * - `"loopback"` (default): localhost HTTP server — for desktop clients.
84
+ * - `"gateway"`: platform ingress + callback registry — for Docker/platform.
62
85
  */
63
- constructor(serverId: string, serverUrl: string, interactive = false) {
86
+ constructor(
87
+ serverId: string,
88
+ serverUrl: string,
89
+ interactive = false,
90
+ callbackTransport: McpOAuthCallbackTransport = "loopback",
91
+ ) {
64
92
  this.serverId = serverId;
65
93
  this.serverUrl = serverUrl;
66
94
  this.interactive = interactive;
95
+ this.callbackTransport = callbackTransport;
67
96
  }
68
97
 
69
98
  // --- redirectUrl ---
@@ -161,6 +190,26 @@ export class McpOAuthProvider implements OAuthClientProvider {
161
190
  return this._codeVerifier;
162
191
  }
163
192
 
193
+ // --- State (CSRF token for OAuth) ---
194
+
195
+ /**
196
+ * Return a `state` value for the authorization URL.
197
+ *
198
+ * The MCP SDK calls `provider.state?.()` and, when the return value is
199
+ * truthy, appends it as the `state` query parameter. For the **gateway**
200
+ * transport the state is mandatory because it is the key used by the
201
+ * `oauth-callback-registry` to route the redirect back to this flow.
202
+ * For the **loopback** transport the state is optional (the loopback
203
+ * server matches on the callback URL itself), but we generate one anyway
204
+ * for defense-in-depth.
205
+ */
206
+ async state(): Promise<string> {
207
+ if (!this._state) {
208
+ this._state = randomBytes(16).toString("hex");
209
+ }
210
+ return this._state;
211
+ }
212
+
164
213
  // --- Discovery State ---
165
214
 
166
215
  async discoveryState(): Promise<OAuthDiscoveryState | undefined> {
@@ -191,6 +240,35 @@ export class McpOAuthProvider implements OAuthClientProvider {
191
240
  async redirectToAuthorization(authorizationUrl: URL): Promise<void> {
192
241
  const url = authorizationUrl.toString();
193
242
 
243
+ // For gateway transport, extract the SDK-generated `state` from the
244
+ // authorization URL and register it with the callback registry now.
245
+ if (
246
+ this.callbackTransport === "gateway" &&
247
+ this._gatewayCodeResolve &&
248
+ this._gatewayCodeReject
249
+ ) {
250
+ const sdkState = authorizationUrl.searchParams.get("state");
251
+ if (sdkState) {
252
+ // Dynamic import to avoid circular deps
253
+ const { registerPendingCallback } =
254
+ await import("../security/oauth-callback-registry.js");
255
+ registerPendingCallback(
256
+ sdkState,
257
+ this._gatewayCodeResolve,
258
+ this._gatewayCodeReject,
259
+ );
260
+ log.info(
261
+ { serverId: this.serverId, state: sdkState },
262
+ "MCP OAuth gateway callback registered with SDK state",
263
+ );
264
+ } else {
265
+ log.warn(
266
+ { serverId: this.serverId },
267
+ "Authorization URL missing state parameter — gateway callback may not resolve",
268
+ );
269
+ }
270
+ }
271
+
194
272
  if (!this.interactive) {
195
273
  // Daemon mode — don't open browser, just log guidance
196
274
  log.info(
@@ -208,28 +286,8 @@ export class McpOAuthProvider implements OAuthClientProvider {
208
286
  `[MCP] Opening browser for OAuth authorization of "${this.serverId}"...`,
209
287
  );
210
288
 
211
- try {
212
- const { execFile } = await import("node:child_process");
213
- const onError = (err: Error | null) => {
214
- if (err) {
215
- log.warn({ err }, "Failed to open browser");
216
- console.log(`[MCP] Please open this URL in your browser:\n${url}`);
217
- }
218
- };
219
- if (isMacOS()) {
220
- execFile("open", [url], onError);
221
- } else if (isLinux()) {
222
- execFile("xdg-open", [url], onError);
223
- } else {
224
- log.warn(
225
- "Unsupported platform for browser open — please visit the URL manually",
226
- );
227
- console.log(`[MCP] Please open this URL in your browser:\n${url}`);
228
- }
229
- } catch (err) {
230
- log.warn({ err }, "Failed to open browser");
231
- console.log(`[MCP] Please open this URL in your browser:\n${url}`);
232
- }
289
+ await openInHostBrowser(url);
290
+ console.log(`[MCP] If the browser did not open, visit this URL:\n${url}`);
233
291
  }
234
292
 
235
293
  // --- Invalidate Credentials ---
@@ -272,6 +330,7 @@ export class McpOAuthProvider implements OAuthClientProvider {
272
330
  }
273
331
  if (scope === "all" || scope === "verifier") {
274
332
  this._codeVerifier = undefined;
333
+ this._state = undefined;
275
334
  }
276
335
  if (scope === "all" || scope === "discovery") {
277
336
  const result = await deleteSecureKeyAsync(discoveryKey(this.serverId));
@@ -292,10 +351,64 @@ export class McpOAuthProvider implements OAuthClientProvider {
292
351
  // --- Callback Server ---
293
352
 
294
353
  /**
295
- * Start a loopback HTTP server to receive the OAuth callback.
296
- * Returns a promise that resolves with the authorization code.
354
+ * Start listening for the OAuth callback.
355
+ *
356
+ * - **Loopback transport**: starts a temporary HTTP server on localhost.
357
+ * - **Gateway transport**: registers a pending callback with the
358
+ * oauth-callback-registry and resolves a public redirect URL via
359
+ * the platform callback registration system.
360
+ *
361
+ * Returns a promise that resolves with the authorization code promise.
297
362
  */
298
363
  startCallbackServer(): Promise<McpOAuthCallbackResult> {
364
+ if (this.callbackTransport === "gateway") {
365
+ return this.startGatewayCallback();
366
+ }
367
+ return this.startLoopbackServer();
368
+ }
369
+
370
+ /**
371
+ * Gateway transport: resolve the public redirect URL and create a
372
+ * deferred code promise. The actual `registerPendingCallback` call
373
+ * is deferred until `redirectToAuthorization` where we can extract
374
+ * the SDK-generated `state` parameter from the authorization URL.
375
+ */
376
+ private async startGatewayCallback(): Promise<McpOAuthCallbackResult> {
377
+ const { resolveCallbackUrl } =
378
+ await import("../inbound/platform-callback-registration.js");
379
+ const { getOAuthCallbackUrl } =
380
+ await import("../inbound/public-ingress-urls.js");
381
+ const { loadConfig } = await import("../config/loader.js");
382
+
383
+ const appConfig = loadConfig();
384
+ const redirectUrl = await resolveCallbackUrl(
385
+ () => getOAuthCallbackUrl(appConfig),
386
+ "webhooks/oauth/callback",
387
+ "mcp_oauth",
388
+ );
389
+
390
+ this._redirectUrl = redirectUrl;
391
+
392
+ // Create a deferred promise — it will be wired to the callback
393
+ // registry in redirectToAuthorization() once we know the SDK's state.
394
+ const codePromise = new Promise<string>((resolve, reject) => {
395
+ this._gatewayCodeResolve = resolve;
396
+ this._gatewayCodeReject = reject;
397
+ });
398
+ this._codePromise = codePromise;
399
+
400
+ log.info(
401
+ { serverId: this.serverId, redirectUrl },
402
+ "MCP OAuth gateway callback prepared (awaiting state from auth URL)",
403
+ );
404
+
405
+ return { codePromise };
406
+ }
407
+
408
+ /**
409
+ * Loopback transport: start a temporary HTTP server on localhost.
410
+ */
411
+ private startLoopbackServer(): Promise<McpOAuthCallbackResult> {
299
412
  return new Promise((resolveSetup, rejectSetup) => {
300
413
  let settled = false;
301
414
  let listening = false;
@@ -423,6 +536,15 @@ export class McpOAuthProvider implements OAuthClientProvider {
423
536
  this.callbackServer.close();
424
537
  this.callbackServer = null;
425
538
  }
539
+ // Gateway transport cleanup — reject the deferred promise so callers
540
+ // awaiting codePromise don't hang indefinitely.
541
+ if (this._gatewayCodeReject) {
542
+ this._gatewayCodeReject(
543
+ new Error("MCP OAuth gateway callback cancelled"),
544
+ );
545
+ this._gatewayCodeResolve = undefined;
546
+ this._gatewayCodeReject = undefined;
547
+ }
426
548
  }
427
549
  }
428
550
 
@@ -6,16 +6,21 @@ import { deleteMemoryCheckpoint } from "./checkpoints.js";
6
6
  import { getConversationMemoryScopeId } from "./conversation-crud.js";
7
7
  import { getDb, rawGet } from "./db.js";
8
8
  import { getMemoryBackendStatus } from "./embedding-backend.js";
9
- import { enqueueBackfillJob, enqueueRebuildIndexJob, MIN_SEGMENT_CHARS } from "./indexer.js";
9
+ import { handleRecall, type RecallResult } from "./graph/tool-handlers.js";
10
10
  import {
11
- enqueueCleanupStaleSupersededItemsJob,
12
- enqueueMemoryJob,
13
- getMemoryJobCounts,
14
- } from "./jobs-store.js";
11
+ enqueueBackfillJob,
12
+ enqueueRebuildIndexJob,
13
+ MIN_SEGMENT_CHARS,
14
+ } from "./indexer.js";
15
+ import { enqueueMemoryJob, getMemoryJobCounts } from "./jobs-store.js";
15
16
  import { withQdrantBreaker } from "./qdrant-circuit-breaker.js";
16
17
  import { getQdrantClient } from "./qdrant-client.js";
17
- import { queryMemoryForCli } from "./retriever.js";
18
- import { conversations, memorySegments, memorySummaries, messages } from "./schema.js";
18
+ import {
19
+ conversations,
20
+ memorySegments,
21
+ memorySummaries,
22
+ messages,
23
+ } from "./schema.js";
19
24
 
20
25
  const log = getLogger("memory-admin");
21
26
 
@@ -27,47 +32,22 @@ export interface MemorySystemStatus {
27
32
  model: string | null;
28
33
  counts: {
29
34
  segments: number;
30
- items: number;
35
+ graphNodes: number;
31
36
  summaries: number;
32
37
  embeddings: number;
33
38
  };
34
- cleanup: {
35
- supersededBacklog: number;
36
- supersededCompleted24h: number;
37
- };
38
39
  jobs: Record<string, number>;
39
40
  }
40
41
 
41
- interface CleanupStatsRow {
42
- superseded_backlog: number | null;
43
- superseded_completed_24h: number | null;
44
- }
45
-
46
42
  export async function getMemorySystemStatus(): Promise<MemorySystemStatus> {
47
43
  const config = getConfig();
48
44
  const backend = await getMemoryBackendStatus(config);
49
45
  const counts = {
50
46
  segments: countTable("memory_segments"),
51
- items: countTable("memory_items"),
47
+ graphNodes: countTable("memory_graph_nodes"),
52
48
  summaries: countTable("memory_summaries"),
53
49
  embeddings: countTable("memory_embeddings"),
54
50
  };
55
- const throughputWindowStartMs = Date.now() - 24 * 60 * 60 * 1000;
56
- const cleanupStats = rawGet<CleanupStatsRow>(
57
- `
58
- SELECT
59
- SUM(CASE
60
- WHEN type = 'cleanup_stale_superseded_items' AND status IN ('pending', 'running')
61
- THEN 1 ELSE 0 END
62
- ) AS superseded_backlog,
63
- SUM(CASE
64
- WHEN type = 'cleanup_stale_superseded_items' AND status = 'completed' AND updated_at >= ?
65
- THEN 1 ELSE 0 END
66
- ) AS superseded_completed_24h
67
- FROM memory_jobs
68
- `,
69
- throughputWindowStartMs,
70
- );
71
51
  return {
72
52
  enabled: backend.enabled,
73
53
  degraded: backend.degraded,
@@ -75,10 +55,6 @@ export async function getMemorySystemStatus(): Promise<MemorySystemStatus> {
75
55
  provider: backend.provider,
76
56
  model: backend.model,
77
57
  counts,
78
- cleanup: {
79
- supersededBacklog: cleanupStats?.superseded_backlog ?? 0,
80
- supersededCompleted24h: cleanupStats?.superseded_completed_24h ?? 0,
81
- },
82
58
  jobs: getMemoryJobCounts(),
83
59
  };
84
60
 
@@ -99,20 +75,12 @@ export function requestMemoryRebuildIndex(): string {
99
75
  return id;
100
76
  }
101
77
 
102
- export function requestMemoryCleanup(retentionMs?: number): {
103
- staleSupersededItemsJobId: string;
104
- } {
105
- const staleSupersededItemsJobId =
106
- enqueueCleanupStaleSupersededItemsJob(retentionMs);
107
- log.info(
108
- { staleSupersededItemsJobId, retentionMs },
109
- "Queued memory cleanup jobs",
110
- );
111
- return { staleSupersededItemsJobId };
112
- }
113
-
114
- export async function queryMemory(query: string, conversationId: string) {
115
- return queryMemoryForCli(query, conversationId, getConfig());
78
+ export async function queryMemory(
79
+ query: string,
80
+ _conversationId: string,
81
+ ): Promise<RecallResult> {
82
+ const config = getConfig();
83
+ return handleRecall({ query }, config, "default");
116
84
  }
117
85
 
118
86
  // ── Short segment cleanup ─────────────────────────────────────────────
@@ -128,9 +96,9 @@ export interface CleanupShortSegmentsResult {
128
96
  * These short fragments waste embedding budget, retrieval slots, and
129
97
  * injection tokens.
130
98
  */
131
- export async function cleanupShortSegments(
132
- opts?: { dryRun?: boolean },
133
- ): Promise<CleanupShortSegmentsResult> {
99
+ export async function cleanupShortSegments(opts?: {
100
+ dryRun?: boolean;
101
+ }): Promise<CleanupShortSegmentsResult> {
134
102
  const db = getDb();
135
103
 
136
104
  const shortSegments = db
@@ -151,18 +119,22 @@ export async function cleanupShortSegments(
151
119
  await withQdrantBreaker(() => qdrant.deleteByTarget("segment", row.id));
152
120
  } catch (err) {
153
121
  // Keep the SQLite row so the target ID is preserved for retry
154
- log.warn({ segmentId: row.id, err }, "Qdrant deletion failed — skipping SQLite deletion to preserve target ID");
122
+ log.warn(
123
+ { segmentId: row.id, err },
124
+ "Qdrant deletion failed — skipping SQLite deletion to preserve target ID",
125
+ );
155
126
  failed++;
156
127
  continue;
157
128
  }
158
129
 
159
- db.delete(memorySegments)
160
- .where(eq(memorySegments.id, row.id))
161
- .run();
130
+ db.delete(memorySegments).where(eq(memorySegments.id, row.id)).run();
162
131
  removed++;
163
132
  }
164
133
 
165
- log.info({ removed, failed, threshold: MIN_SEGMENT_CHARS }, "Cleaned up short segments");
134
+ log.info(
135
+ { removed, failed, threshold: MIN_SEGMENT_CHARS },
136
+ "Cleaned up short segments",
137
+ );
166
138
  return { removed, failed };
167
139
  }
168
140
 
@@ -194,7 +166,7 @@ export function findReextractTargets(limit: number): ReextractTarget[] {
194
166
  .from(conversations)
195
167
  .leftJoin(messages, eq(messages.conversationId, conversations.id))
196
168
  .where(
197
- sql`${conversations.conversationType} NOT IN ('background', 'private')`,
169
+ sql`${conversations.conversationType} NOT IN ('background', 'private', 'scheduled')`,
198
170
  )
199
171
  .groupBy(conversations.id)
200
172
  .orderBy(desc(sql`count(${messages.id})`))
@@ -238,25 +210,21 @@ export function findReextractTarget(
238
210
  /**
239
211
  * Queue re-extraction for a set of conversations.
240
212
  * Resets extraction checkpoints and clears extraction summaries so the
241
- * batch extraction handler processes all messages from scratch with
213
+ * graph extraction handler processes all messages from scratch with
242
214
  * expanded supersession context.
243
215
  */
244
- export function requestReextract(
245
- targets: ReextractTarget[],
246
- ): { jobIds: string[] } {
216
+ export function requestReextract(targets: ReextractTarget[]): {
217
+ jobIds: string[];
218
+ } {
247
219
  const db = getDb();
248
220
  const jobIds: string[] = [];
249
221
 
250
222
  for (const target of targets) {
251
223
  const { conversationId } = target;
252
224
 
253
- // Reset batch extraction checkpoints
254
- deleteMemoryCheckpoint(
255
- `batch_extract:${conversationId}:last_message_id`,
256
- );
257
- deleteMemoryCheckpoint(
258
- `batch_extract:${conversationId}:pending_count`,
259
- );
225
+ // Reset graph extraction checkpoints
226
+ deleteMemoryCheckpoint(`graph_extract:${conversationId}:last_ts`);
227
+ deleteMemoryCheckpoint(`graph_extract:${conversationId}:pending_count`);
260
228
 
261
229
  // Clear the extraction summary so it starts fresh
262
230
  db.delete(memorySummaries)
@@ -268,12 +236,11 @@ export function requestReextract(
268
236
  )
269
237
  .run();
270
238
 
271
- // Resolve scope and enqueue with fullReextract flag
239
+ // Resolve scope and enqueue re-extraction
272
240
  const scopeId = getConversationMemoryScopeId(conversationId);
273
- const jobId = enqueueMemoryJob("batch_extract", {
241
+ const jobId = enqueueMemoryJob("graph_extract", {
274
242
  conversationId,
275
243
  scopeId,
276
- fullReextract: true,
277
244
  });
278
245
  jobIds.push(jobId);
279
246
 
@@ -216,6 +216,8 @@ export function generateAppDirName(
216
216
 
217
217
  /** Cache of id -> dirName mappings to avoid repeated filesystem scans. */
218
218
  const idToDirNameCache = new Map<string, string>();
219
+ /** Reverse cache: dirName -> id. */
220
+ const dirNameToIdCache = new Map<string, string>();
219
221
 
220
222
  /**
221
223
  * Resolve an app's directory name and path from its ID.
@@ -265,12 +267,79 @@ export function getAppDirPath(appId: string): string {
265
267
  return resolveAppDir(appId).appDir;
266
268
  }
267
269
 
270
+ /**
271
+ * Resolve an app ID from its directory name (slug).
272
+ * Checks caches first, then reads the JSON definition file directly.
273
+ */
274
+ export function resolveAppIdByDirName(dirName: string): string | null {
275
+ const cached = dirNameToIdCache.get(dirName);
276
+ if (cached) return cached;
277
+
278
+ // Check forward cache (reverse iteration)
279
+ for (const [id, dn] of idToDirNameCache) {
280
+ if (dn === dirName) {
281
+ dirNameToIdCache.set(dirName, id);
282
+ return id;
283
+ }
284
+ }
285
+
286
+ // Read the JSON definition file directly
287
+ const dir = getAppsDir();
288
+ const jsonPath = join(dir, `${dirName}.json`);
289
+ if (existsSync(jsonPath)) {
290
+ try {
291
+ const raw = readFileSync(jsonPath, "utf-8");
292
+ const parsed = JSON.parse(raw) as { id?: string; dirName?: string };
293
+ if (parsed.id) {
294
+ dirNameToIdCache.set(dirName, parsed.id);
295
+ idToDirNameCache.set(parsed.id, dirName);
296
+ return parsed.id;
297
+ }
298
+ } catch {
299
+ // skip malformed files
300
+ }
301
+ }
302
+
303
+ return null;
304
+ }
305
+
306
+ /**
307
+ * Extract app ID from an absolute file path if it falls within the apps
308
+ * directory and targets a source file (not records/ or dist/).
309
+ */
310
+ export function resolveAppIdFromPath(filePath: string): string | null {
311
+ let appsDir: string;
312
+ try {
313
+ appsDir = getAppsDir();
314
+ } catch {
315
+ return null;
316
+ }
317
+ if (!filePath.startsWith(appsDir + "/")) return null;
318
+
319
+ const relPath = filePath.slice(appsDir.length + 1);
320
+ const slashIdx = relPath.indexOf("/");
321
+ if (slashIdx === -1) return null; // file directly in apps/ (e.g. the .json definition)
322
+
323
+ const dirName = relPath.slice(0, slashIdx);
324
+ const innerPath = relPath.slice(slashIdx + 1);
325
+
326
+ // Skip non-source directories
327
+ if (innerPath.startsWith("records/") || innerPath.startsWith("dist/")) {
328
+ return null;
329
+ }
330
+
331
+ return resolveAppIdByDirName(dirName);
332
+ }
333
+
268
334
  /** Invalidate the id->dirName cache for a specific app or all apps. */
269
335
  function invalidateDirNameCache(appId?: string): void {
270
336
  if (appId) {
337
+ const dirName = idToDirNameCache.get(appId);
271
338
  idToDirNameCache.delete(appId);
339
+ if (dirName) dirNameToIdCache.delete(dirName);
272
340
  } else {
273
341
  idToDirNameCache.clear();
342
+ dirNameToIdCache.clear();
274
343
  }
275
344
  }
276
345
 
@@ -6,11 +6,12 @@ import {
6
6
  } from "./conversation-title-service.js";
7
7
 
8
8
  export interface BootstrapConversationOptions {
9
- conversationType?: "standard" | "private" | "background";
9
+ conversationType?: "standard" | "private" | "background" | "scheduled";
10
10
  source?: string;
11
11
  origin: TitleOrigin;
12
12
  systemHint: string;
13
13
  scheduleJobId?: string;
14
+ groupId?: string;
14
15
  }
15
16
 
16
17
  export function bootstrapConversation(opts: BootstrapConversationOptions) {
@@ -19,6 +20,7 @@ export function bootstrapConversation(opts: BootstrapConversationOptions) {
19
20
  ...(opts.conversationType && { conversationType: opts.conversationType }),
20
21
  ...(opts.source && { source: opts.source }),
21
22
  ...(opts.scheduleJobId && { scheduleJobId: opts.scheduleJobId }),
23
+ ...(opts.groupId && { groupId: opts.groupId }),
22
24
  });
23
25
  queueGenerateConversationTitle({
24
26
  conversationId: conversation.id,