@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
@@ -37,6 +37,7 @@ const GUARDIAN_SENSITIVE_EVENT_PREFIXES = [
37
37
  "guardian.question",
38
38
  "ingress.escalation",
39
39
  "ingress.access_request",
40
+ "guardian.channel_activation",
40
41
  ] as const;
41
42
 
42
43
  export function isGuardianSensitiveEvent(sourceEventName: string): boolean {
@@ -353,6 +353,15 @@ const TEMPLATES: Partial<Record<NotificationSourceEventName, CopyTemplate>> = {
353
353
  };
354
354
  },
355
355
 
356
+ "guardian.channel_activation": (payload) => {
357
+ const code = str(payload.verificationCode, "------");
358
+ const channel = str(payload.sourceChannel, "a channel");
359
+ return {
360
+ title: "Guardian Verification Code",
361
+ body: `Your ${channel} verification code is: ${code}\n\nEnter this code in your ${channel} chat to verify your identity as guardian.`,
362
+ };
363
+ },
364
+
356
365
  "ingress.access_request": (payload) => ({
357
366
  title: "Access Request",
358
367
  body: buildAccessRequestContractText(payload),
@@ -399,6 +408,92 @@ const TEMPLATES: Partial<Record<NotificationSourceEventName, CopyTemplate>> = {
399
408
  };
400
409
  },
401
410
 
411
+ "ingress.trusted_contact.guardian_decision": (payload) => {
412
+ const decision = str(payload.decision, "decided on");
413
+ const sourceChannel =
414
+ typeof payload.sourceChannel === "string"
415
+ ? payload.sourceChannel
416
+ : undefined;
417
+
418
+ const requesterDisplayName =
419
+ typeof payload.requesterDisplayName === "string" &&
420
+ payload.requesterDisplayName.length > 0
421
+ ? payload.requesterDisplayName
422
+ : undefined;
423
+ const requesterExternalUserId =
424
+ typeof payload.requesterExternalUserId === "string" &&
425
+ payload.requesterExternalUserId.length > 0
426
+ ? payload.requesterExternalUserId
427
+ : undefined;
428
+ const requesterLabel = sanitizeIdentityField(
429
+ requesterDisplayName ??
430
+ (sourceChannel === "slack" &&
431
+ requesterExternalUserId &&
432
+ /^U[A-Z0-9]+$/i.test(requesterExternalUserId)
433
+ ? `<@${requesterExternalUserId}>`
434
+ : requesterExternalUserId) ??
435
+ "Someone",
436
+ );
437
+
438
+ const decidedByDisplayName =
439
+ typeof payload.decidedByDisplayName === "string" &&
440
+ payload.decidedByDisplayName.length > 0
441
+ ? payload.decidedByDisplayName
442
+ : undefined;
443
+ const decidedByExternalUserId =
444
+ typeof payload.decidedByExternalUserId === "string" &&
445
+ payload.decidedByExternalUserId.length > 0
446
+ ? payload.decidedByExternalUserId
447
+ : undefined;
448
+ const decidedByLabel = sanitizeIdentityField(
449
+ decidedByDisplayName ??
450
+ (sourceChannel === "slack" &&
451
+ decidedByExternalUserId &&
452
+ /^U[A-Z0-9]+$/i.test(decidedByExternalUserId)
453
+ ? `<@${decidedByExternalUserId}>`
454
+ : decidedByExternalUserId) ??
455
+ "a guardian",
456
+ );
457
+
458
+ const verb = decision === "approved" ? "approved" : "denied";
459
+ return {
460
+ title: "Trusted Contact Decision",
461
+ body: `${requesterLabel}'s access request has been ${verb} by ${decidedByLabel}.`,
462
+ };
463
+ },
464
+
465
+ "ingress.trusted_contact.denied": (payload) => {
466
+ const sourceChannel =
467
+ typeof payload.sourceChannel === "string"
468
+ ? payload.sourceChannel
469
+ : undefined;
470
+
471
+ const requesterDisplayName =
472
+ typeof payload.requesterDisplayName === "string" &&
473
+ payload.requesterDisplayName.length > 0
474
+ ? payload.requesterDisplayName
475
+ : undefined;
476
+ const requesterExternalUserId =
477
+ typeof payload.requesterExternalUserId === "string" &&
478
+ payload.requesterExternalUserId.length > 0
479
+ ? payload.requesterExternalUserId
480
+ : undefined;
481
+ const requesterLabel = sanitizeIdentityField(
482
+ requesterDisplayName ??
483
+ (sourceChannel === "slack" &&
484
+ requesterExternalUserId &&
485
+ /^U[A-Z0-9]+$/i.test(requesterExternalUserId)
486
+ ? `<@${requesterExternalUserId}>`
487
+ : requesterExternalUserId) ??
488
+ "Someone",
489
+ );
490
+
491
+ return {
492
+ title: "Trusted Contact Denied",
493
+ body: `A trusted contact request from ${requesterLabel} has been denied.`,
494
+ };
495
+ },
496
+
402
497
  "ingress.escalation": (payload) => ({
403
498
  title: "Escalation",
404
499
  body:
@@ -13,6 +13,7 @@ import { v4 as uuid } from "uuid";
13
13
 
14
14
  import { getDeliverableChannels } from "../channels/config.js";
15
15
  import { getConfig } from "../config/loader.js";
16
+ import { listGuardianChannels } from "../contacts/contact-store.js";
16
17
  import { resolveGuardianPersona } from "../prompts/persona-resolver.js";
17
18
  import { buildCoreIdentityContext } from "../prompts/system-prompt.js";
18
19
  import {
@@ -73,6 +74,7 @@ function buildSystemPrompt(
73
74
  preferenceContext?: string,
74
75
  candidateContext?: string,
75
76
  identityContext?: string,
77
+ recipientNotes?: string,
76
78
  ): string {
77
79
  const sections: string[] = [
78
80
  `You are a notification routing engine. Given a signal describing an event, decide whether the user should be notified, on which channel(s), and compose the notification copy.`,
@@ -89,6 +91,16 @@ function buildSystemPrompt(
89
91
  );
90
92
  }
91
93
 
94
+ if (recipientNotes) {
95
+ sections.push(
96
+ ``,
97
+ `<recipient-context>`,
98
+ `The following are notes about the notification recipient. Use this context to tailor notification tone, formality, and content to the recipient's preferences.`,
99
+ recipientNotes,
100
+ `</recipient-context>`,
101
+ );
102
+ }
103
+
92
104
  if (identityContext) {
93
105
  sections.push(
94
106
  ``,
@@ -807,11 +819,34 @@ async function classifyWithLLM(
807
819
  const identityContext = rawIdentityContext
808
820
  ? truncate(rawIdentityContext, MAX_IDENTITY_CONTEXT_CHARS, "\n…[truncated]")
809
821
  : undefined;
822
+
823
+ // Resolve guardian contact notes for recipient context. Use the channel-
824
+ // agnostic guardian lookup so notes are available even when the only
825
+ // deliverable channel is "vellum" (which has no contact channel type).
826
+ let recipientNotes: string | undefined;
827
+ try {
828
+ const guardianResult = listGuardianChannels();
829
+ if (guardianResult?.contact.notes) {
830
+ recipientNotes = truncate(
831
+ guardianResult.contact.notes,
832
+ MAX_IDENTITY_CONTEXT_CHARS,
833
+ "\n…[truncated]",
834
+ );
835
+ }
836
+ } catch (err) {
837
+ const errMsg = err instanceof Error ? err.message : String(err);
838
+ log.warn(
839
+ { err: errMsg },
840
+ "Failed to resolve guardian contact notes, proceeding without recipient context",
841
+ );
842
+ }
843
+
810
844
  const systemPrompt = buildSystemPrompt(
811
845
  availableChannels,
812
846
  preferenceContext,
813
847
  candidateContext,
814
848
  identityContext,
849
+ recipientNotes,
815
850
  );
816
851
  const prompt = buildUserPrompt(signal);
817
852
  const tool = buildDecisionTool(availableChannels);
@@ -46,6 +46,11 @@ export const NOTIFICATION_SOURCE_EVENT_NAMES = [
46
46
  id: "guardian.question",
47
47
  description: "Guardian approval question requiring response",
48
48
  },
49
+ {
50
+ id: "guardian.channel_activation",
51
+ description:
52
+ "Guardian channel activation code delivered for /start verification",
53
+ },
49
54
  { id: "ingress.access_request", description: "Non-member requesting access" },
50
55
  {
51
56
  id: "ingress.access_request.callback_handoff",
@@ -155,9 +160,20 @@ export interface AccessRequestContextPayload {
155
160
  messagePreview: string | null;
156
161
  }
157
162
 
163
+ export interface GuardianChannelActivationPayload {
164
+ verificationCode: string;
165
+ sourceChannel: string;
166
+ actorExternalId: string;
167
+ actorDisplayName: string | null;
168
+ actorUsername: string | null;
169
+ sessionId: string;
170
+ expiresAt: number;
171
+ }
172
+
158
173
  export interface NotificationEventContextPayloadMap {
159
174
  "guardian.question": GuardianQuestionPayload;
160
175
  "ingress.access_request": AccessRequestContextPayload;
176
+ "guardian.channel_activation": GuardianChannelActivationPayload;
161
177
  }
162
178
 
163
179
  export type NotificationContextPayload<TEventName extends string = string> =
@@ -90,6 +90,7 @@ const PROVIDER_SEED_DATA: Record<
90
90
  forbiddenScopes: [],
91
91
  },
92
92
  extraParams: { access_type: "offline", prompt: "consent" },
93
+ loopbackPort: 17321,
93
94
  managedServiceConfigKey: "google-oauth",
94
95
  injectionTemplates: [
95
96
  {
@@ -619,6 +620,7 @@ const PROVIDER_SEED_DATA: Record<
619
620
  "Mail.Send",
620
621
  "Calendars.Read",
621
622
  "Calendars.ReadWrite",
623
+ "MailboxSettings.ReadWrite",
622
624
  ],
623
625
  scopePolicy: {
624
626
  allowAdditionalScopes: true,
@@ -640,7 +642,6 @@ const PROVIDER_SEED_DATA: Record<
640
642
  appType: "App registration",
641
643
  identityUrl: "https://graph.microsoft.com/v1.0/me",
642
644
  identityResponsePaths: ["mail", "userPrincipalName"],
643
- featureFlag: "outlook-oauth-integration",
644
645
  },
645
646
 
646
647
  // Manual-token providers: these don't use OAuth2 flows but need provider
@@ -1,6 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { homedir } from "node:os";
3
- import { dirname, resolve } from "node:path";
3
+ import { dirname, join, resolve } from "node:path";
4
4
 
5
5
  import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
6
6
  import { getConfig } from "../config/loader.js";
@@ -19,7 +19,7 @@ import {
19
19
  looksLikePathOnlyInput,
20
20
  } from "../tools/network/url-safety.js";
21
21
  import { getTool } from "../tools/registry.js";
22
- import { getWorkspaceHooksDir } from "../util/platform.js";
22
+ import { getDeprecatedDir, getWorkspaceHooksDir } from "../util/platform.js";
23
23
  import {
24
24
  buildShellAllowlistOptions,
25
25
  buildShellCommandCandidates,
@@ -677,7 +677,7 @@ export async function classifyRisk(
677
677
  }
678
678
  }
679
679
 
680
- const result = await classifyRiskUncached(
680
+ let result = await classifyRiskUncached(
681
681
  toolName,
682
682
  input,
683
683
  workingDir,
@@ -685,6 +685,17 @@ export async function classifyRisk(
685
685
  manifestOverride,
686
686
  );
687
687
 
688
+ // Proxied bash commands route through the credential proxy which handles
689
+ // per-request approval separately. Cap the bash tool's own risk at Medium
690
+ // so trust rules can auto-allow the command execution.
691
+ if (
692
+ toolName === "bash" &&
693
+ input.network_mode === "proxied" &&
694
+ result === RiskLevel.High
695
+ ) {
696
+ result = RiskLevel.Medium;
697
+ }
698
+
688
699
  if (cacheKey) {
689
700
  if (riskCache.size >= RISK_CACHE_MAX) {
690
701
  const oldest = riskCache.keys().next().value;
@@ -703,7 +714,13 @@ async function classifyRiskUncached(
703
714
  preParsed?: ParsedCommand,
704
715
  manifestOverride?: ManifestOverride,
705
716
  ): Promise<RiskLevel> {
706
- if (toolName === "file_read") return RiskLevel.Low;
717
+ if (toolName === "file_read") {
718
+ const filePath = getStringField(input, "path", "file_path");
719
+ if (isActorTokenSigningKeyPath(filePath, workingDir)) {
720
+ return RiskLevel.High;
721
+ }
722
+ return RiskLevel.Low;
723
+ }
707
724
  if (toolName === "file_write" || toolName === "file_edit") {
708
725
  const filePath = getStringField(input, "path", "file_path");
709
726
  if (
@@ -937,6 +954,21 @@ async function classifyRiskUncached(
937
954
  return RiskLevel.Medium;
938
955
  }
939
956
 
957
+ function isActorTokenSigningKeyPath(
958
+ filePath: string | undefined,
959
+ workingDir?: string,
960
+ ): boolean {
961
+ if (!filePath) return false;
962
+ const cwd = workingDir ?? process.cwd();
963
+ const resolvedPath = resolve(cwd, filePath);
964
+ const signingKeyPaths = [
965
+ join(homedir(), ".vellum", "protected", "actor-token-signing-key"),
966
+ join(getDeprecatedDir(), "actor-token-signing-key"),
967
+ resolve(cwd, "deprecated", "actor-token-signing-key"),
968
+ ];
969
+ return signingKeyPaths.includes(resolvedPath);
970
+ }
971
+
940
972
  export async function check(
941
973
  toolName: string,
942
974
  input: Record<string, unknown>,
@@ -287,11 +287,11 @@ export function getDefaultRuleTemplates(): DefaultRuleTemplate[] {
287
287
  }),
288
288
  );
289
289
 
290
- // memory_recall is a read-only tool — always allow without prompting.
290
+ // recall is a read-only tool — always allow without prompting.
291
291
  const memoryRecallRule: DefaultRuleTemplate = {
292
- id: "default:allow-memory_recall-global",
293
- tool: "memory_recall",
294
- pattern: "memory_recall:*",
292
+ id: "default:allow-recall-global",
293
+ tool: "recall",
294
+ pattern: "recall:*",
295
295
  scope: "everywhere",
296
296
  decision: "allow",
297
297
  priority: 100,
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Singleton runtime store for the two-axis permission mode.
3
+ *
4
+ * Reads initial state from the `permissions` section of config.json on
5
+ * initialization and persists mutations back to the config file via the
6
+ * raw-config read/write helpers so env-var–derived keys are never leaked
7
+ * to disk.
8
+ *
9
+ * Downstream consumers (e.g. SSE broadcast) register change listeners
10
+ * via `onModeChanged()`.
11
+ */
12
+
13
+ import {
14
+ invalidateConfigCache,
15
+ loadConfig,
16
+ loadRawConfig,
17
+ saveRawConfig,
18
+ } from "../config/loader.js";
19
+ import { getLogger } from "../util/logger.js";
20
+ import type { PermissionMode } from "./permission-mode.js";
21
+ import { DEFAULT_PERMISSION_MODE } from "./permission-mode.js";
22
+
23
+ const log = getLogger("permission-mode-store");
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // Types
27
+ // ---------------------------------------------------------------------------
28
+
29
+ export type ModeChangeListener = (mode: PermissionMode) => void;
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // Module-level state
33
+ // ---------------------------------------------------------------------------
34
+
35
+ let currentMode: PermissionMode = { ...DEFAULT_PERMISSION_MODE };
36
+ let initialized = false;
37
+ const listeners: ModeChangeListener[] = [];
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Internal helpers
41
+ // ---------------------------------------------------------------------------
42
+
43
+ function notifyListeners(): void {
44
+ const snapshot = { ...currentMode };
45
+ for (const listener of listeners) {
46
+ try {
47
+ listener(snapshot);
48
+ } catch (err) {
49
+ log.error({ err }, "Error in permission mode change listener");
50
+ }
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Persist the current in-memory permission mode to config.json.
56
+ *
57
+ * Uses the raw-config pattern (loadRawConfig → mutate → saveRawConfig) so
58
+ * that env-var–derived fields (API keys, dataDir) are never written to disk.
59
+ */
60
+ function persistToConfig(): void {
61
+ try {
62
+ const raw = loadRawConfig();
63
+
64
+ // Ensure the permissions object exists
65
+ if (
66
+ raw.permissions == null ||
67
+ typeof raw.permissions !== "object" ||
68
+ Array.isArray(raw.permissions)
69
+ ) {
70
+ raw.permissions = {};
71
+ }
72
+
73
+ const permissions = raw.permissions as Record<string, unknown>;
74
+ permissions.askBeforeActing = currentMode.askBeforeActing;
75
+ permissions.hostAccess = currentMode.hostAccess;
76
+
77
+ saveRawConfig(raw);
78
+
79
+ // Invalidate the cached config so the next loadConfig() picks up the
80
+ // persisted values rather than returning stale in-memory state.
81
+ invalidateConfigCache();
82
+ } catch (err) {
83
+ log.error({ err }, "Failed to persist permission mode to config");
84
+ }
85
+ }
86
+
87
+ // ---------------------------------------------------------------------------
88
+ // Public API
89
+ // ---------------------------------------------------------------------------
90
+
91
+ /**
92
+ * Initialize the store from the current config. Safe to call multiple times;
93
+ * subsequent calls are no-ops unless `resetForTesting()` has been called.
94
+ */
95
+ export function initPermissionModeStore(): void {
96
+ if (initialized) return;
97
+
98
+ try {
99
+ const config = loadConfig();
100
+ currentMode = {
101
+ askBeforeActing: config.permissions.askBeforeActing,
102
+ hostAccess: config.permissions.hostAccess,
103
+ };
104
+ } catch (err) {
105
+ log.warn(
106
+ { err },
107
+ "Failed to load permission mode from config; using defaults",
108
+ );
109
+ currentMode = { ...DEFAULT_PERMISSION_MODE };
110
+ }
111
+
112
+ initialized = true;
113
+ }
114
+
115
+ /**
116
+ * Return the current permission mode. Initializes from config on first call
117
+ * if `initPermissionModeStore()` hasn't been called yet.
118
+ */
119
+ export function getMode(): PermissionMode {
120
+ if (!initialized) {
121
+ initPermissionModeStore();
122
+ }
123
+ return { ...currentMode };
124
+ }
125
+
126
+ /**
127
+ * Update the `askBeforeActing` axis. Persists to config.json and notifies
128
+ * change listeners.
129
+ */
130
+ export function setAskBeforeActing(value: boolean): void {
131
+ if (!initialized) {
132
+ initPermissionModeStore();
133
+ }
134
+
135
+ if (currentMode.askBeforeActing === value) return;
136
+
137
+ currentMode.askBeforeActing = value;
138
+ persistToConfig();
139
+ notifyListeners();
140
+ }
141
+
142
+ /**
143
+ * Update the `hostAccess` axis. Persists to config.json and notifies
144
+ * change listeners.
145
+ */
146
+ export function setHostAccess(value: boolean): void {
147
+ if (!initialized) {
148
+ initPermissionModeStore();
149
+ }
150
+
151
+ if (currentMode.hostAccess === value) return;
152
+
153
+ currentMode.hostAccess = value;
154
+ persistToConfig();
155
+ notifyListeners();
156
+ }
157
+
158
+ /**
159
+ * Register a callback that fires whenever the permission mode changes.
160
+ * Returns an unsubscribe function.
161
+ */
162
+ export function onModeChanged(callback: ModeChangeListener): () => void {
163
+ listeners.push(callback);
164
+ return () => {
165
+ const idx = listeners.indexOf(callback);
166
+ if (idx >= 0) {
167
+ listeners.splice(idx, 1);
168
+ }
169
+ };
170
+ }
171
+
172
+ /**
173
+ * Reset the store to uninitialized state. **Test-only** — production code
174
+ * should never call this.
175
+ */
176
+ export function resetForTesting(): void {
177
+ currentMode = { ...DEFAULT_PERMISSION_MODE };
178
+ initialized = false;
179
+ listeners.length = 0;
180
+ }
@@ -0,0 +1,31 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * Two-axis permission model:
5
+ * - `askBeforeActing` — LLM behavior toggle: when true the assistant checks in
6
+ * with the user before taking actions.
7
+ * - `hostAccess` — System-enforced gate: when true the assistant can execute
8
+ * commands on the host machine without prompting.
9
+ */
10
+ export type PermissionMode = {
11
+ askBeforeActing: boolean;
12
+ hostAccess: boolean;
13
+ };
14
+
15
+ export const DEFAULT_PERMISSION_MODE: PermissionMode = {
16
+ askBeforeActing: true,
17
+ hostAccess: false,
18
+ };
19
+
20
+ export const PermissionModeSchema = z.object({
21
+ askBeforeActing: z
22
+ .boolean({ error: "permissionMode.askBeforeActing must be a boolean" })
23
+ .default(true)
24
+ .describe("Whether the assistant should check in before taking actions"),
25
+ hostAccess: z
26
+ .boolean({ error: "permissionMode.hostAccess must be a boolean" })
27
+ .default(false)
28
+ .describe(
29
+ "Whether the assistant can execute commands on the host machine without prompting",
30
+ ),
31
+ });
@@ -74,12 +74,21 @@ const HOST_TOOLS = new Set([
74
74
  "host_file_write",
75
75
  "host_file_edit",
76
76
  "host_bash",
77
+ "computer_use_run_applescript",
77
78
  ]);
78
79
 
80
+ /**
81
+ * Check whether a tool name is a host-level tool that requires the
82
+ * `hostAccess` permission to execute.
83
+ */
84
+ export function isHostTool(toolName: string): boolean {
85
+ return HOST_TOOLS.has(toolName);
86
+ }
87
+
79
88
  /** Safe local-only tools that are always workspace-scoped. */
80
89
  const ALWAYS_SCOPED_TOOLS = new Set([
81
90
  "skill_load",
82
- "memory_recall",
91
+ "recall",
83
92
  "ui_update",
84
93
  "ui_dismiss",
85
94
  ]);
@@ -1,20 +1,20 @@
1
1
  /**
2
- * Compile all active playbook memory items into a triage context block
2
+ * Compile all active playbook graph nodes into a triage context block
3
3
  * that can be injected into the system prompt alongside the contact
4
4
  * graph.
5
5
  */
6
6
 
7
- import { and, desc, eq, isNull } from "drizzle-orm";
7
+ import { and, eq, sql } from "drizzle-orm";
8
8
 
9
9
  import { getDb } from "../memory/db.js";
10
- import { memoryItems } from "../memory/schema.js";
10
+ import { memoryGraphNodes } from "../memory/schema.js";
11
11
  import type { Playbook } from "./types.js";
12
12
  import { parsePlaybookStatement } from "./types.js";
13
13
 
14
14
  export interface CompiledPlaybooks {
15
15
  /** Formatted text block ready for system prompt injection. */
16
16
  text: string;
17
- /** Total number of active playbook items found. */
17
+ /** Total number of active playbook nodes found. */
18
18
  totalCount: number;
19
19
  /** Number of playbooks successfully parsed and included. */
20
20
  includedCount: number;
@@ -26,8 +26,7 @@ export interface CompilePlaybooksOptions {
26
26
 
27
27
  interface PlaybookRow {
28
28
  id: string;
29
- subject: string;
30
- statement: string;
29
+ content: string;
31
30
  }
32
31
 
33
32
  export function compilePlaybooks(
@@ -38,31 +37,33 @@ export function compilePlaybooks(
38
37
 
39
38
  const rows: PlaybookRow[] = db
40
39
  .select({
41
- id: memoryItems.id,
42
- subject: memoryItems.subject,
43
- statement: memoryItems.statement,
40
+ id: memoryGraphNodes.id,
41
+ content: memoryGraphNodes.content,
44
42
  })
45
- .from(memoryItems)
43
+ .from(memoryGraphNodes)
46
44
  .where(
47
45
  and(
48
- eq(memoryItems.kind, "playbook"),
49
- eq(memoryItems.status, "active"),
50
- eq(memoryItems.scopeId, scopeId),
51
- isNull(memoryItems.invalidAt),
46
+ eq(memoryGraphNodes.scopeId, scopeId),
47
+ sql`${memoryGraphNodes.sourceConversations} LIKE '%playbook:%'`,
48
+ sql`${memoryGraphNodes.fidelity} != 'gone'`,
52
49
  ),
53
50
  )
54
- .orderBy(desc(memoryItems.importance))
51
+ .orderBy(sql`${memoryGraphNodes.significance} DESC`)
55
52
  .all();
56
53
 
57
54
  if (rows.length === 0) {
58
55
  return { text: "", totalCount: 0, includedCount: 0 };
59
56
  }
60
57
 
61
- const parsed: Array<{ id: string; subject: string; playbook: Playbook }> = [];
58
+ const parsed: Array<{ id: string; playbook: Playbook }> = [];
62
59
  for (const row of rows) {
63
- const playbook = parsePlaybookStatement(row.statement);
60
+ // Content format: "Playbook: <trigger>\n<json statement>"
61
+ const newlineIdx = row.content.indexOf("\n");
62
+ if (newlineIdx === -1) continue;
63
+ const statement = row.content.slice(newlineIdx + 1);
64
+ const playbook = parsePlaybookStatement(statement);
64
65
  if (playbook) {
65
- parsed.push({ id: row.id, subject: row.subject, playbook });
66
+ parsed.push({ id: row.id, playbook });
66
67
  }
67
68
  }
68
69
 
@@ -2,9 +2,10 @@
2
2
  * Action Playbook — a structured trigger→action rule that tells the
3
3
  * triage engine how to handle incoming messages matching a pattern.
4
4
  *
5
- * Playbooks are stored as memory items with kind='playbook'. The
6
- * structured fields below are serialized into the statement column as
7
- * JSON, while the subject column holds a human-readable label.
5
+ * Playbooks are stored as memory_graph_nodes with
6
+ * sourceConversations containing a "playbook:{nodeId}" entry. The
7
+ * content column holds "Playbook: <trigger>\n<json>" where the JSON
8
+ * encodes the structured fields below.
8
9
  */
9
10
 
10
11
  export interface Playbook {