@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
@@ -0,0 +1,343 @@
1
+ /**
2
+ * Outlook Calendar watcher provider — uses Microsoft Graph delta queries
3
+ * for efficient change detection.
4
+ *
5
+ * On first poll, performs a delta query to capture the initial @odata.deltaLink
6
+ * as the watermark (start from "now"). Subsequent polls use the deltaLink to
7
+ * detect new/updated events. Falls back to a fresh delta query if the delta
8
+ * token has expired (410 Gone).
9
+ */
10
+
11
+ import { OutlookCalendarApiError } from "../../config/bundled-skills/outlook-calendar/calendar-client.js";
12
+ import type { OutlookCalendarEvent } from "../../config/bundled-skills/outlook-calendar/types.js";
13
+ import type { OAuthConnection } from "../../oauth/connection.js";
14
+ import { resolveOAuthConnection } from "../../oauth/connection-resolver.js";
15
+ import { getLogger } from "../../util/logger.js";
16
+ import type {
17
+ FetchResult,
18
+ WatcherItem,
19
+ WatcherProvider,
20
+ } from "../provider-types.js";
21
+
22
+ const CREDENTIAL_SERVICE = "outlook";
23
+ const log = getLogger("watcher:outlook-calendar");
24
+
25
+ const DELTA_SELECT_FIELDS = [
26
+ "subject",
27
+ "start",
28
+ "end",
29
+ "location",
30
+ "bodyPreview",
31
+ "isAllDay",
32
+ "showAs",
33
+ "organizer",
34
+ "attendees",
35
+ "webLink",
36
+ "createdDateTime",
37
+ "lastModifiedDateTime",
38
+ "isCancelled",
39
+ "type",
40
+ ].join(",");
41
+
42
+ function eventToItem(
43
+ event: OutlookCalendarEvent,
44
+ eventType: string,
45
+ ): WatcherItem {
46
+ const start = event.start?.dateTime ?? "";
47
+ const end = event.end?.dateTime ?? "";
48
+
49
+ // Include lastModifiedDateTime in the dedup key so subsequent edits to the
50
+ // same event aren't silently dropped by the watcher_id + external_id constraint.
51
+ const version = event.lastModifiedDateTime ?? "";
52
+ const externalId = version ? `${event.id}@${version}` : event.id;
53
+
54
+ return {
55
+ externalId,
56
+ eventType,
57
+ summary: `Calendar event: ${event.subject ?? "(no title)"} — ${start}`,
58
+ payload: {
59
+ id: event.id,
60
+ subject: event.subject ?? "",
61
+ start,
62
+ end,
63
+ startTimeZone: event.start?.timeZone ?? "",
64
+ endTimeZone: event.end?.timeZone ?? "",
65
+ location: event.location?.displayName ?? "",
66
+ bodyPreview: event.bodyPreview ?? "",
67
+ isAllDay: event.isAllDay ?? false,
68
+ showAs: event.showAs ?? "busy",
69
+ organizer: event.organizer?.emailAddress?.address ?? "",
70
+ attendees:
71
+ event.attendees?.map((a) => ({
72
+ email: a.emailAddress.address,
73
+ response: a.status?.response,
74
+ })) ?? [],
75
+ webLink: event.webLink ?? "",
76
+ },
77
+ timestamp: event.lastModifiedDateTime
78
+ ? new Date(event.lastModifiedDateTime).getTime()
79
+ : Date.now(),
80
+ };
81
+ }
82
+
83
+ /** Thrown when Microsoft Graph returns 410 Gone (delta token expired). */
84
+ class DeltaSyncExpiredError extends Error {
85
+ constructor(message: string) {
86
+ super(message);
87
+ this.name = "DeltaSyncExpiredError";
88
+ }
89
+ }
90
+
91
+ interface DeltaSyncResult {
92
+ items: OutlookCalendarEvent[];
93
+ deltaLink: string;
94
+ }
95
+
96
+ /**
97
+ * Perform an incremental delta sync using a stored @odata.deltaLink.
98
+ * Follows pagination (@odata.nextLink) until the final page returns
99
+ * @odata.deltaLink. Returns all accumulated events and the new deltaLink.
100
+ */
101
+ async function deltaSync(
102
+ connection: OAuthConnection,
103
+ deltaLink: string,
104
+ ): Promise<DeltaSyncResult> {
105
+ const allItems: OutlookCalendarEvent[] = [];
106
+ let currentUrl = deltaLink;
107
+ let newDeltaLink: string | undefined;
108
+
109
+ do {
110
+ const parsed = new URL(currentUrl);
111
+ const path = parsed.pathname;
112
+ const query: Record<string, string> = {};
113
+ parsed.searchParams.forEach((v, k) => {
114
+ query[k] = v;
115
+ });
116
+
117
+ const resp = await connection.request({
118
+ method: "GET",
119
+ path,
120
+ query: Object.keys(query).length > 0 ? query : undefined,
121
+ });
122
+
123
+ if (resp.status < 200 || resp.status >= 300) {
124
+ const bodyStr =
125
+ typeof resp.body === "string"
126
+ ? resp.body
127
+ : JSON.stringify(resp.body ?? "");
128
+ if (resp.status === 410) {
129
+ throw new DeltaSyncExpiredError(bodyStr);
130
+ }
131
+ throw new OutlookCalendarApiError(
132
+ resp.status,
133
+ "",
134
+ `Microsoft Graph Calendar Delta API ${resp.status}: ${bodyStr}`,
135
+ );
136
+ }
137
+
138
+ const page = resp.body as {
139
+ value?: OutlookCalendarEvent[];
140
+ "@odata.nextLink"?: string;
141
+ "@odata.deltaLink"?: string;
142
+ };
143
+
144
+ if (page.value) {
145
+ allItems.push(...page.value);
146
+ }
147
+
148
+ newDeltaLink = page["@odata.deltaLink"];
149
+ currentUrl = page["@odata.nextLink"] ?? "";
150
+ } while (currentUrl && !newDeltaLink);
151
+
152
+ if (!newDeltaLink) {
153
+ throw new Error(
154
+ "Outlook Calendar delta query completed without returning a deltaLink",
155
+ );
156
+ }
157
+
158
+ return { items: allItems, deltaLink: newDeltaLink };
159
+ }
160
+
161
+ /**
162
+ * Perform the initial delta query to capture the current position.
163
+ * Queries calendarView/delta from now to 30 days out with the selected fields,
164
+ * paginating through all pages until reaching the final @odata.deltaLink.
165
+ */
166
+ async function initialDeltaQuery(
167
+ connection: OAuthConnection,
168
+ ): Promise<DeltaSyncResult> {
169
+ const now = new Date();
170
+ const thirtyDaysOut = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);
171
+
172
+ const allItems: OutlookCalendarEvent[] = [];
173
+ let nextLink: string | undefined;
174
+ let newDeltaLink: string | undefined;
175
+
176
+ // First request — initial delta query with parameters
177
+ const initialQuery: Record<string, string> = {
178
+ startDateTime: now.toISOString(),
179
+ endDateTime: thirtyDaysOut.toISOString(),
180
+ $select: DELTA_SELECT_FIELDS,
181
+ };
182
+
183
+ const firstResp = await connection.request({
184
+ method: "GET",
185
+ path: "/v1.0/me/calendarView/delta",
186
+ query: initialQuery,
187
+ });
188
+
189
+ if (firstResp.status < 200 || firstResp.status >= 300) {
190
+ const bodyStr =
191
+ typeof firstResp.body === "string"
192
+ ? firstResp.body
193
+ : JSON.stringify(firstResp.body ?? "");
194
+ throw new OutlookCalendarApiError(
195
+ firstResp.status,
196
+ "",
197
+ `Microsoft Graph Calendar Delta API ${firstResp.status}: ${bodyStr}`,
198
+ );
199
+ }
200
+
201
+ const firstPage = firstResp.body as {
202
+ value?: OutlookCalendarEvent[];
203
+ "@odata.nextLink"?: string;
204
+ "@odata.deltaLink"?: string;
205
+ };
206
+
207
+ if (firstPage.value) {
208
+ allItems.push(...firstPage.value);
209
+ }
210
+
211
+ newDeltaLink = firstPage["@odata.deltaLink"];
212
+ nextLink = firstPage["@odata.nextLink"];
213
+
214
+ // Follow pagination until we get a deltaLink
215
+ while (nextLink && !newDeltaLink) {
216
+ const parsed = new URL(nextLink);
217
+ const path = parsed.pathname;
218
+ const query: Record<string, string> = {};
219
+ parsed.searchParams.forEach((v, k) => {
220
+ query[k] = v;
221
+ });
222
+
223
+ const resp = await connection.request({
224
+ method: "GET",
225
+ path,
226
+ query: Object.keys(query).length > 0 ? query : undefined,
227
+ });
228
+
229
+ if (resp.status < 200 || resp.status >= 300) {
230
+ const bodyStr =
231
+ typeof resp.body === "string"
232
+ ? resp.body
233
+ : JSON.stringify(resp.body ?? "");
234
+ throw new OutlookCalendarApiError(
235
+ resp.status,
236
+ "",
237
+ `Microsoft Graph Calendar Delta API ${resp.status}: ${bodyStr}`,
238
+ );
239
+ }
240
+
241
+ const page = resp.body as {
242
+ value?: OutlookCalendarEvent[];
243
+ "@odata.nextLink"?: string;
244
+ "@odata.deltaLink"?: string;
245
+ };
246
+
247
+ if (page.value) {
248
+ allItems.push(...page.value);
249
+ }
250
+
251
+ newDeltaLink = page["@odata.deltaLink"];
252
+ nextLink = page["@odata.nextLink"];
253
+ }
254
+
255
+ if (!newDeltaLink) {
256
+ throw new Error(
257
+ "Outlook Calendar initial delta query completed without returning a deltaLink",
258
+ );
259
+ }
260
+
261
+ return { items: allItems, deltaLink: newDeltaLink };
262
+ }
263
+
264
+ export const outlookCalendarProvider: WatcherProvider = {
265
+ id: "outlook-calendar",
266
+ displayName: "Outlook Calendar",
267
+ requiredCredentialService: CREDENTIAL_SERVICE,
268
+
269
+ async getInitialWatermark(credentialService: string): Promise<string> {
270
+ const connection = await resolveOAuthConnection(credentialService);
271
+ const { deltaLink } = await initialDeltaQuery(connection);
272
+ return deltaLink;
273
+ },
274
+
275
+ async fetchNew(
276
+ credentialService: string,
277
+ watermark: string | null,
278
+ _config: Record<string, unknown>,
279
+ _watcherKey: string,
280
+ ): Promise<FetchResult> {
281
+ const connection = await resolveOAuthConnection(credentialService);
282
+
283
+ if (!watermark) {
284
+ // No watermark — get initial position, return no items
285
+ const { deltaLink } = await initialDeltaQuery(connection);
286
+ return { items: [], watermark: deltaLink };
287
+ }
288
+
289
+ try {
290
+ const { items: events, deltaLink: newDeltaLink } = await deltaSync(
291
+ connection,
292
+ watermark,
293
+ );
294
+
295
+ if (events.length === 0) {
296
+ return { items: [], watermark: newDeltaLink };
297
+ }
298
+
299
+ // Filter out cancelled events and convert to watcher items
300
+ const items: WatcherItem[] = [];
301
+ for (const event of events) {
302
+ if (event.isCancelled) continue;
303
+
304
+ const eventType =
305
+ event.createdDateTime === event.lastModifiedDateTime
306
+ ? "new_calendar_event"
307
+ : "updated_calendar_event";
308
+ items.push(eventToItem(event, eventType));
309
+ }
310
+
311
+ log.info(
312
+ { count: items.length, watermark: newDeltaLink },
313
+ "Outlook Calendar: fetched event changes",
314
+ );
315
+
316
+ return { items, watermark: newDeltaLink };
317
+ } catch (err) {
318
+ if (err instanceof DeltaSyncExpiredError) {
319
+ log.warn(
320
+ "Outlook Calendar delta token expired, falling back to fresh query",
321
+ );
322
+ return fallbackFetch(connection);
323
+ }
324
+ throw err;
325
+ }
326
+ },
327
+ };
328
+
329
+ /**
330
+ * Fallback when delta token expires (410 Gone): perform a fresh initial
331
+ * delta query to get current events and a new deltaLink.
332
+ */
333
+ async function fallbackFetch(
334
+ connection: OAuthConnection,
335
+ ): Promise<FetchResult> {
336
+ const { items: events, deltaLink } = await initialDeltaQuery(connection);
337
+
338
+ const items = events
339
+ .filter((event) => !event.isCancelled)
340
+ .map((event) => eventToItem(event, "new_calendar_event"));
341
+
342
+ return { items, watermark: deltaLink };
343
+ }
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Outlook watcher provider — uses Microsoft Graph delta queries for efficient
3
+ * change detection.
4
+ *
5
+ * On first poll, captures the initial deltaLink as the watermark (start from "now").
6
+ * Subsequent polls use the deltaLink to detect new messages.
7
+ * Falls back to listing recent inbox messages if the sync state has expired (410 Gone).
8
+ */
9
+
10
+ import {
11
+ listMessages,
12
+ listMessagesDelta,
13
+ OutlookApiError,
14
+ } from "../../messaging/providers/outlook/client.js";
15
+ import type {
16
+ OutlookDeltaResponse,
17
+ OutlookMessage,
18
+ } from "../../messaging/providers/outlook/types.js";
19
+ import type { OAuthConnection } from "../../oauth/connection.js";
20
+ import { resolveOAuthConnection } from "../../oauth/connection-resolver.js";
21
+ import { getLogger } from "../../util/logger.js";
22
+ import type {
23
+ FetchResult,
24
+ WatcherItem,
25
+ WatcherProvider,
26
+ } from "../provider-types.js";
27
+
28
+ const log = getLogger("watcher:outlook");
29
+
30
+ /** Thrown when Microsoft Graph returns 410 Gone (delta sync state expired). */
31
+ export class DeltaSyncExpiredError extends Error {
32
+ constructor(message: string) {
33
+ super(message);
34
+ this.name = "DeltaSyncExpiredError";
35
+ }
36
+ }
37
+
38
+ function messageToItem(msg: OutlookMessage): WatcherItem {
39
+ const from =
40
+ msg.from?.emailAddress?.name ||
41
+ msg.from?.emailAddress?.address ||
42
+ "Unknown";
43
+ const subject = msg.subject ?? "(no subject)";
44
+
45
+ return {
46
+ externalId: msg.id,
47
+ eventType: "new_email",
48
+ summary: `Email from ${from}: ${subject}`,
49
+ payload: {
50
+ id: msg.id,
51
+ conversationId: msg.conversationId,
52
+ from,
53
+ fromAddress: msg.from?.emailAddress?.address ?? "",
54
+ subject,
55
+ receivedDateTime: msg.receivedDateTime,
56
+ bodyPreview: msg.bodyPreview ?? "",
57
+ isRead: msg.isRead ?? false,
58
+ hasAttachments: msg.hasAttachments ?? false,
59
+ },
60
+ timestamp: msg.receivedDateTime
61
+ ? new Date(msg.receivedDateTime).getTime()
62
+ : Date.now(),
63
+ };
64
+ }
65
+
66
+ /**
67
+ * Fetch all pages of a delta response, following @odata.nextLink until
68
+ * a @odata.deltaLink is returned.
69
+ */
70
+ async function fetchAllDeltaPages(
71
+ connection: OAuthConnection,
72
+ folderId: string,
73
+ deltaLink?: string,
74
+ ): Promise<{ messages: OutlookMessage[]; newDeltaLink: string }> {
75
+ const messages: OutlookMessage[] = [];
76
+
77
+ let resp: OutlookDeltaResponse<OutlookMessage>;
78
+ try {
79
+ resp = await listMessagesDelta(connection, folderId, deltaLink);
80
+ } catch (err) {
81
+ if (err instanceof OutlookApiError && err.status === 410) {
82
+ throw new DeltaSyncExpiredError(err.message);
83
+ }
84
+ throw err;
85
+ }
86
+
87
+ if (resp.value) {
88
+ messages.push(...resp.value);
89
+ }
90
+
91
+ // Follow pagination until we get a deltaLink
92
+ while (resp["@odata.nextLink"] && !resp["@odata.deltaLink"]) {
93
+ try {
94
+ resp = await listMessagesDelta(
95
+ connection,
96
+ folderId,
97
+ resp["@odata.nextLink"],
98
+ );
99
+ } catch (err) {
100
+ if (err instanceof OutlookApiError && err.status === 410) {
101
+ throw new DeltaSyncExpiredError(
102
+ err instanceof Error ? err.message : String(err),
103
+ );
104
+ }
105
+ throw err;
106
+ }
107
+ if (resp.value) {
108
+ messages.push(...resp.value);
109
+ }
110
+ }
111
+
112
+ const newDeltaLink = resp["@odata.deltaLink"];
113
+ if (!newDeltaLink) {
114
+ throw new Error(
115
+ "Outlook delta query completed without returning a deltaLink",
116
+ );
117
+ }
118
+
119
+ return { messages, newDeltaLink };
120
+ }
121
+
122
+ export const outlookProvider: WatcherProvider = {
123
+ id: "outlook",
124
+ displayName: "Outlook",
125
+ requiredCredentialService: "outlook",
126
+
127
+ async getInitialWatermark(credentialService: string): Promise<string> {
128
+ const connection = await resolveOAuthConnection(credentialService);
129
+ const { newDeltaLink } = await fetchAllDeltaPages(connection, "inbox");
130
+ return newDeltaLink;
131
+ },
132
+
133
+ async fetchNew(
134
+ credentialService: string,
135
+ watermark: string | null,
136
+ _config: Record<string, unknown>,
137
+ _watcherKey: string,
138
+ ): Promise<FetchResult> {
139
+ const connection = await resolveOAuthConnection(credentialService);
140
+
141
+ if (!watermark) {
142
+ // No watermark — get initial position, return no items
143
+ const { newDeltaLink } = await fetchAllDeltaPages(connection, "inbox");
144
+ return { items: [], watermark: newDeltaLink };
145
+ }
146
+
147
+ try {
148
+ const { messages, newDeltaLink } = await fetchAllDeltaPages(
149
+ connection,
150
+ "inbox",
151
+ watermark,
152
+ );
153
+
154
+ if (messages.length === 0) {
155
+ return { items: [], watermark: newDeltaLink };
156
+ }
157
+
158
+ const items = messages.map(messageToItem);
159
+ log.info(
160
+ { count: items.length, watermark: newDeltaLink },
161
+ "Outlook: fetched new messages",
162
+ );
163
+
164
+ return { items, watermark: newDeltaLink };
165
+ } catch (err) {
166
+ if (err instanceof DeltaSyncExpiredError) {
167
+ log.warn(
168
+ "Outlook delta sync state expired, falling back to recent inbox messages",
169
+ );
170
+ return fallbackFetch(connection);
171
+ }
172
+ throw err;
173
+ }
174
+ },
175
+ };
176
+
177
+ /**
178
+ * Fallback when sync state expires (410 Gone): list recent inbox messages
179
+ * from the last day, then get a fresh deltaLink.
180
+ */
181
+ async function fallbackFetch(
182
+ connection: OAuthConnection,
183
+ ): Promise<FetchResult> {
184
+ const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
185
+ const resp = await listMessages(connection, {
186
+ folderId: "inbox",
187
+ top: 20,
188
+ filter: `receivedDateTime ge ${oneDayAgo}`,
189
+ orderby: "receivedDateTime desc",
190
+ });
191
+
192
+ const items = (resp.value ?? []).map(messageToItem);
193
+
194
+ // Get a fresh deltaLink for the new watermark
195
+ const { newDeltaLink } = await fetchAllDeltaPages(connection, "inbox");
196
+
197
+ return { items, watermark: newDeltaLink };
198
+ }
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * Previously, dictation-profiles.json, email-guardrails.json, and
5
5
  * active-call-leases.json lived directly under getRootDir() (~/.vellum/).
6
- * This migration moves them into the workspace directory so they are
7
- * included in diagnostic exports and follow the workspace convention.
6
+ * This migration moves them into the workspace directory so they follow
7
+ * the workspace convention for organizational consistency.
8
8
  */
9
9
 
10
10
  import { existsSync, renameSync, unlinkSync } from "node:fs";
@@ -40,8 +40,8 @@ function getRootDir(): string {
40
40
  const FILE_MOVES: Array<{ name: string; subdir?: string }> = [
41
41
  { name: "daemon-stderr.log", subdir: "logs" },
42
42
  { name: "daemon-startup.lock" },
43
- // .env stays at root — it contains secrets (API keys) and the entire
44
- // workspace directory is included in diagnostic log exports.
43
+ // .env stays at root — it contains secrets (API keys) and should not
44
+ // be in the sandbox working directory.
45
45
  { name: "embed-worker.pid" },
46
46
  ];
47
47
 
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Workspace migration 025: Remove standalone OAuth app setup skill directories
3
+ * and their SKILLS.md entries from user workspaces.
4
+ *
5
+ * These skills have been consolidated into vellum-oauth-integrations and are
6
+ * no longer shipped as standalone skills.
7
+ *
8
+ * Idempotent: safe to re-run after interruption at any point.
9
+ */
10
+
11
+ import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
12
+ import { join } from "node:path";
13
+
14
+ import type { WorkspaceMigration } from "./types.js";
15
+
16
+ // ---------------------------------------------------------------------------
17
+ // Skills to remove
18
+ // ---------------------------------------------------------------------------
19
+
20
+ const DELETED_SKILLS = [
21
+ "airtable-oauth-app-setup",
22
+ "asana-oauth-app-setup",
23
+ "discord-oauth-app-setup",
24
+ "dropbox-oauth-app-setup",
25
+ "figma-oauth-app-setup",
26
+ "github-oauth-app-setup",
27
+ "google-oauth-app-setup",
28
+ "hubspot-oauth-app-setup",
29
+ "linear-oauth-app-setup",
30
+ "notion-oauth-app-setup",
31
+ "spotify-oauth-app-setup",
32
+ "todoist-oauth-app-setup",
33
+ "twitter-oauth-app-setup",
34
+ ];
35
+
36
+ // ---------------------------------------------------------------------------
37
+ // Migration
38
+ // ---------------------------------------------------------------------------
39
+
40
+ export const removeOauthAppSetupSkillsMigration: WorkspaceMigration = {
41
+ id: "025-remove-oauth-app-setup-skills",
42
+ description:
43
+ "Remove standalone OAuth app setup skill directories consolidated into vellum-oauth-integrations",
44
+
45
+ run(workspaceDir: string): void {
46
+ const skillsDir = join(workspaceDir, "skills");
47
+ if (!existsSync(skillsDir)) return;
48
+
49
+ // 1. Remove skill directories
50
+ for (const name of DELETED_SKILLS) {
51
+ const dir = join(skillsDir, name);
52
+ if (existsSync(dir)) {
53
+ rmSync(dir, { recursive: true, force: true });
54
+ }
55
+ }
56
+
57
+ // 2. Update SKILLS.md to remove entries referencing deleted skills
58
+ const indexPath = join(skillsDir, "SKILLS.md");
59
+ if (existsSync(indexPath)) {
60
+ let content = readFileSync(indexPath, "utf-8");
61
+ for (const name of DELETED_SKILLS) {
62
+ content = content.replace(
63
+ new RegExp(`^[\\t ]*-\\s*${name}\\s*\\n?`, "gm"),
64
+ "",
65
+ );
66
+ }
67
+ writeFileSync(indexPath, content, "utf-8");
68
+ }
69
+ },
70
+
71
+ down(_workspaceDir: string): void {
72
+ // Deleted skills cannot be restored since they have been removed from the
73
+ // repo. Users would need to reinstall the `vellum-oauth-integrations`
74
+ // skill to regain the consolidated OAuth setup functionality.
75
+ },
76
+ };