@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
@@ -1,4 +1,4 @@
1
- import { beforeEach, describe, expect, mock, test } from "bun:test";
1
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
2
2
 
3
3
  import { Command } from "commander";
4
4
 
@@ -88,6 +88,10 @@ let mockGetCredentialMetadata: (
88
88
  service: string,
89
89
  field: string,
90
90
  ) => Record<string, unknown> | undefined = () => undefined;
91
+ let mockPlatformClientCreate: () => Promise<Record<
92
+ string,
93
+ unknown
94
+ > | null> = async () => null;
91
95
 
92
96
  // ---------------------------------------------------------------------------
93
97
  // Mock token-manager
@@ -236,10 +240,43 @@ mock.module("../oauth/connection-resolver.js", () => ({
236
240
 
237
241
  mock.module("../platform/client.js", () => ({
238
242
  VellumPlatformClient: {
239
- create: async () => null,
243
+ create: () => mockPlatformClientCreate(),
240
244
  },
241
245
  }));
242
246
 
247
+ // ---------------------------------------------------------------------------
248
+ // Mock config/loader (needed by isManagedMode in shared.ts)
249
+ // ---------------------------------------------------------------------------
250
+
251
+ let mockGetConfig: () => Record<string, unknown> = () => ({
252
+ services: {},
253
+ });
254
+
255
+ mock.module("../config/loader.js", () => ({
256
+ getConfig: () => mockGetConfig(),
257
+ loadConfig: () => mockGetConfig(),
258
+ saveConfig: () => {},
259
+ invalidateConfigCache: () => {},
260
+ loadRawConfig: () => ({}),
261
+ saveRawConfig: () => {},
262
+ applyNestedDefaults: (c: unknown) => c,
263
+ deepMergeMissing: (a: unknown) => a,
264
+ deepMergeOverwrite: (a: unknown) => a,
265
+ mergeDefaultWorkspaceConfig: () => {},
266
+ getNestedValue: () => undefined,
267
+ setNestedValue: () => {},
268
+ API_KEY_PROVIDERS: [
269
+ "anthropic",
270
+ "openai",
271
+ "gemini",
272
+ "ollama",
273
+ "fireworks",
274
+ "openrouter",
275
+ "brave",
276
+ "perplexity",
277
+ ],
278
+ }));
279
+
243
280
  mock.module("../util/logger.js", () => ({
244
281
  getLogger: () => ({
245
282
  info: () => {},
@@ -260,6 +297,8 @@ mock.module("../util/logger.js", () => ({
260
297
  // ---------------------------------------------------------------------------
261
298
 
262
299
  const { registerOAuthCommand } = await import("../cli/commands/oauth/index.js");
300
+ const { requirePlatformClient, requirePlatformConnection } =
301
+ await import("../cli/commands/oauth/shared.js");
263
302
 
264
303
  // ---------------------------------------------------------------------------
265
304
  // Test helper
@@ -951,3 +990,326 @@ describe("assistant oauth ping <provider-key>", () => {
951
990
  expect(parsed.error).toContain("No access token");
952
991
  });
953
992
  });
993
+
994
+ // ---------------------------------------------------------------------------
995
+ // oauth connect — managed mode 401/403 error messages
996
+ // ---------------------------------------------------------------------------
997
+
998
+ describe("assistant oauth connect managed mode — platform 401/403 errors", () => {
999
+ /**
1000
+ * Helper: create a mock platform client whose `fetch` always returns the
1001
+ * given status code and body text.
1002
+ */
1003
+ function makeMockPlatformClient(status: number, body = "") {
1004
+ return {
1005
+ platformAssistantId: "asst-test-123",
1006
+ fetch: async () =>
1007
+ new Response(body, { status, statusText: `HTTP ${status}` }),
1008
+ };
1009
+ }
1010
+
1011
+ beforeEach(() => {
1012
+ mockWithValidToken = async (_service, cb) => cb("mock-access-token-xyz");
1013
+ mockOrchestrateOAuthConnect = async () => ({
1014
+ success: true,
1015
+ deferred: false,
1016
+ grantedScopes: [],
1017
+ });
1018
+ mockGetAppByProviderAndClientId = () => undefined;
1019
+ mockGetMostRecentAppByProvider = () => undefined;
1020
+ mockGetSecureKey = () => undefined;
1021
+ mockGetCredentialMetadata = () => undefined;
1022
+
1023
+ // Set up managed mode: provider has managedServiceConfigKey, config
1024
+ // returns the matching service with mode "managed".
1025
+ mockGetProvider = () => ({
1026
+ providerKey: "google",
1027
+ authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
1028
+ tokenUrl: "https://oauth2.googleapis.com/token",
1029
+ defaultScopes: "[]",
1030
+ scopePolicy: "{}",
1031
+ extraParams: null,
1032
+ managedServiceConfigKey: "google-oauth",
1033
+ createdAt: Date.now(),
1034
+ updatedAt: Date.now(),
1035
+ });
1036
+ mockGetConfig = () => ({
1037
+ services: {
1038
+ "google-oauth": { mode: "managed" },
1039
+ },
1040
+ });
1041
+ });
1042
+
1043
+ afterEach(() => {
1044
+ mockPlatformClientCreate = async () => null;
1045
+ mockGetConfig = () => ({ services: {} });
1046
+ });
1047
+
1048
+ test("401 response includes 'vellum platform connect' suggestion", async () => {
1049
+ mockPlatformClientCreate = async () =>
1050
+ makeMockPlatformClient(401, "Unauthorized");
1051
+ const { exitCode, stdout } = await runCli([
1052
+ "connect",
1053
+ "google",
1054
+ "--no-browser",
1055
+ "--json",
1056
+ ]);
1057
+ expect(exitCode).toBe(1);
1058
+ const parsed = JSON.parse(stdout);
1059
+ expect(parsed.ok).toBe(false);
1060
+ expect(parsed.error).toContain("Platform returned HTTP 401");
1061
+ expect(parsed.error).toContain("Unauthorized");
1062
+ expect(parsed.error).toContain("vellum platform connect");
1063
+ });
1064
+
1065
+ test("403 response includes 'vellum platform connect' suggestion", async () => {
1066
+ mockPlatformClientCreate = async () =>
1067
+ makeMockPlatformClient(403, "Forbidden");
1068
+ const { exitCode, stdout } = await runCli([
1069
+ "connect",
1070
+ "google",
1071
+ "--no-browser",
1072
+ "--json",
1073
+ ]);
1074
+ expect(exitCode).toBe(1);
1075
+ const parsed = JSON.parse(stdout);
1076
+ expect(parsed.ok).toBe(false);
1077
+ expect(parsed.error).toContain("Platform returned HTTP 403");
1078
+ expect(parsed.error).toContain("Forbidden");
1079
+ expect(parsed.error).toContain("vellum platform connect");
1080
+ });
1081
+
1082
+ test("500 response does NOT include 'vellum platform connect' suggestion", async () => {
1083
+ mockPlatformClientCreate = async () =>
1084
+ makeMockPlatformClient(500, "Internal Server Error");
1085
+ const { exitCode, stdout } = await runCli([
1086
+ "connect",
1087
+ "google",
1088
+ "--no-browser",
1089
+ "--json",
1090
+ ]);
1091
+ expect(exitCode).toBe(1);
1092
+ const parsed = JSON.parse(stdout);
1093
+ expect(parsed.ok).toBe(false);
1094
+ expect(parsed.error).toContain("Platform returned HTTP 500");
1095
+ expect(parsed.error).not.toContain("vellum platform connect");
1096
+ });
1097
+ });
1098
+
1099
+ // ---------------------------------------------------------------------------
1100
+ // requirePlatformClient — improved error messages
1101
+ // ---------------------------------------------------------------------------
1102
+
1103
+ describe("requirePlatformClient", () => {
1104
+ test("returns error mentioning 'vellum platform connect' when not connected", async () => {
1105
+ mockPlatformClientCreate = async () => null;
1106
+ const stdoutChunks: string[] = [];
1107
+ const originalWrite = process.stdout.write.bind(process.stdout);
1108
+ process.stdout.write = ((chunk: unknown) => {
1109
+ stdoutChunks.push(typeof chunk === "string" ? chunk : String(chunk));
1110
+ return true;
1111
+ }) as typeof process.stdout.write;
1112
+ process.exitCode = 0;
1113
+
1114
+ try {
1115
+ const cmd = new Command();
1116
+ cmd.option("--json");
1117
+ cmd.parse(["node", "test", "--json"]);
1118
+ const result = await requirePlatformClient(cmd);
1119
+ expect(result).toBeNull();
1120
+ expect(process.exitCode).toBe(1);
1121
+ const output = stdoutChunks.join("");
1122
+ const parsed = JSON.parse(output);
1123
+ expect(parsed.ok).toBe(false);
1124
+ expect(parsed.error).toContain("vellum platform connect");
1125
+ expect(parsed.error).toContain("Not connected");
1126
+ } finally {
1127
+ process.stdout.write = originalWrite;
1128
+ process.exitCode = 0;
1129
+ }
1130
+ });
1131
+
1132
+ test("returns distinct error when connected but missing assistant ID", async () => {
1133
+ mockPlatformClientCreate = async () => ({
1134
+ platformAssistantId: "",
1135
+ fetch: async () => new Response(),
1136
+ });
1137
+ const stdoutChunks: string[] = [];
1138
+ const originalWrite = process.stdout.write.bind(process.stdout);
1139
+ process.stdout.write = ((chunk: unknown) => {
1140
+ stdoutChunks.push(typeof chunk === "string" ? chunk : String(chunk));
1141
+ return true;
1142
+ }) as typeof process.stdout.write;
1143
+ process.exitCode = 0;
1144
+
1145
+ try {
1146
+ const cmd = new Command();
1147
+ cmd.option("--json");
1148
+ cmd.parse(["node", "test", "--json"]);
1149
+ const result = await requirePlatformClient(cmd);
1150
+ expect(result).toBeNull();
1151
+ expect(process.exitCode).toBe(1);
1152
+ const output = stdoutChunks.join("");
1153
+ const parsed = JSON.parse(output);
1154
+ expect(parsed.ok).toBe(false);
1155
+ expect(parsed.error).toContain("no assistant ID is configured");
1156
+ expect(parsed.error).toContain("registered on the platform");
1157
+ } finally {
1158
+ process.stdout.write = originalWrite;
1159
+ process.exitCode = 0;
1160
+ }
1161
+ });
1162
+
1163
+ test("returns client when connected with assistant ID", async () => {
1164
+ mockPlatformClientCreate = async () => ({
1165
+ platformAssistantId: "asst-123",
1166
+ fetch: async () => new Response(),
1167
+ });
1168
+ process.exitCode = 0;
1169
+
1170
+ const cmd = new Command();
1171
+ cmd.option("--json");
1172
+ cmd.parse(["node", "test", "--json"]);
1173
+ const result = await requirePlatformClient(cmd);
1174
+ expect(result).not.toBeNull();
1175
+ expect(result!.platformAssistantId).toBe("asst-123");
1176
+ expect(process.exitCode).toBe(0);
1177
+ });
1178
+ });
1179
+
1180
+ // ---------------------------------------------------------------------------
1181
+ // requirePlatformConnection
1182
+ // ---------------------------------------------------------------------------
1183
+
1184
+ describe("requirePlatformConnection", () => {
1185
+ test("returns false and writes error when not connected", async () => {
1186
+ mockPlatformClientCreate = async () => null;
1187
+ const stdoutChunks: string[] = [];
1188
+ const originalWrite = process.stdout.write.bind(process.stdout);
1189
+ process.stdout.write = ((chunk: unknown) => {
1190
+ stdoutChunks.push(typeof chunk === "string" ? chunk : String(chunk));
1191
+ return true;
1192
+ }) as typeof process.stdout.write;
1193
+ process.exitCode = 0;
1194
+
1195
+ try {
1196
+ const cmd = new Command();
1197
+ cmd.option("--json");
1198
+ cmd.parse(["node", "test", "--json"]);
1199
+ const result = await requirePlatformConnection(cmd);
1200
+ expect(result).toBe(false);
1201
+ expect(process.exitCode).toBe(1);
1202
+ const output = stdoutChunks.join("");
1203
+ const parsed = JSON.parse(output);
1204
+ expect(parsed.ok).toBe(false);
1205
+ expect(parsed.error).toContain("vellum platform connect");
1206
+ expect(parsed.error).toContain("Not connected");
1207
+ } finally {
1208
+ process.stdout.write = originalWrite;
1209
+ process.exitCode = 0;
1210
+ }
1211
+ });
1212
+
1213
+ test("returns true when client can be created (even without assistant ID)", async () => {
1214
+ mockPlatformClientCreate = async () => ({
1215
+ platformAssistantId: "",
1216
+ fetch: async () => new Response(),
1217
+ });
1218
+ process.exitCode = 0;
1219
+
1220
+ const cmd = new Command();
1221
+ cmd.option("--json");
1222
+ cmd.parse(["node", "test", "--json"]);
1223
+ const result = await requirePlatformConnection(cmd);
1224
+ expect(result).toBe(true);
1225
+ expect(process.exitCode).toBe(0);
1226
+ });
1227
+
1228
+ test("returns true when client can be created with assistant ID", async () => {
1229
+ mockPlatformClientCreate = async () => ({
1230
+ platformAssistantId: "asst-456",
1231
+ fetch: async () => new Response(),
1232
+ });
1233
+ process.exitCode = 0;
1234
+
1235
+ const cmd = new Command();
1236
+ cmd.option("--json");
1237
+ cmd.parse(["node", "test", "--json"]);
1238
+ const result = await requirePlatformConnection(cmd);
1239
+ expect(result).toBe(true);
1240
+ expect(process.exitCode).toBe(0);
1241
+ });
1242
+ });
1243
+
1244
+ // ---------------------------------------------------------------------------
1245
+ // oauth mode — platform connection guard
1246
+ // ---------------------------------------------------------------------------
1247
+
1248
+ describe("assistant oauth mode", () => {
1249
+ beforeEach(() => {
1250
+ mockWithValidToken = async (_service, cb) => cb("mock-access-token-xyz");
1251
+ mockGetProvider = () => ({
1252
+ providerKey: "google",
1253
+ authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
1254
+ tokenUrl: "https://oauth2.googleapis.com/token",
1255
+ defaultScopes: "[]",
1256
+ scopePolicy: "{}",
1257
+ extraParams: null,
1258
+ managedServiceConfigKey: "google-oauth",
1259
+ createdAt: Date.now(),
1260
+ updatedAt: Date.now(),
1261
+ });
1262
+ mockGetConfig = () => ({
1263
+ services: {
1264
+ "google-oauth": { mode: "your-own" },
1265
+ },
1266
+ });
1267
+ });
1268
+
1269
+ afterEach(() => {
1270
+ mockPlatformClientCreate = async () => null;
1271
+ mockGetConfig = () => ({ services: {} });
1272
+ mockGetProvider = () => undefined;
1273
+ });
1274
+
1275
+ test("oauth mode <provider> --set managed fails when not connected to platform", async () => {
1276
+ mockPlatformClientCreate = async () => null;
1277
+ const { exitCode, stdout } = await runCli([
1278
+ "mode",
1279
+ "google",
1280
+ "--set",
1281
+ "managed",
1282
+ "--json",
1283
+ ]);
1284
+ expect(exitCode).toBe(1);
1285
+ const parsed = JSON.parse(stdout);
1286
+ expect(parsed.ok).toBe(false);
1287
+ expect(parsed.error).toContain("vellum platform connect");
1288
+ });
1289
+
1290
+ test("oauth mode <provider> --set your-own succeeds without platform connection", async () => {
1291
+ mockPlatformClientCreate = async () => null;
1292
+ const { exitCode, stdout } = await runCli([
1293
+ "mode",
1294
+ "google",
1295
+ "--set",
1296
+ "your-own",
1297
+ "--json",
1298
+ ]);
1299
+ // Setting to "your-own" doesn't need platform — it's a local-only operation
1300
+ expect(exitCode).toBe(0);
1301
+ const parsed = JSON.parse(stdout);
1302
+ expect(parsed.ok).toBe(true);
1303
+ expect(parsed.mode).toBe("your-own");
1304
+ });
1305
+
1306
+ test("oauth mode <provider> (read) succeeds without platform connection", async () => {
1307
+ mockPlatformClientCreate = async () => null;
1308
+ const { exitCode, stdout } = await runCli(["mode", "google", "--json"]);
1309
+ expect(exitCode).toBe(0);
1310
+ const parsed = JSON.parse(stdout);
1311
+ expect(parsed.ok).toBe(true);
1312
+ expect(parsed.provider).toBe("google");
1313
+ expect(parsed.mode).toBe("your-own");
1314
+ });
1315
+ });
@@ -383,17 +383,22 @@ describe("OAuth2 gateway transport", () => {
383
383
  describe("loopback transport flow", () => {
384
384
  test("success: starts server, receives callback, exchanges for tokens", async () => {
385
385
  let capturedAuthUrl = "";
386
+ let urlReady!: () => void;
387
+ const urlReadyPromise = new Promise<void>((r) => {
388
+ urlReady = r;
389
+ });
386
390
  const flowPromise = startOAuth2Flow(
387
391
  BASE_OAUTH_CONFIG,
388
392
  {
389
393
  openUrl: (url) => {
390
394
  capturedAuthUrl = url;
395
+ urlReady();
391
396
  },
392
397
  },
393
398
  { callbackTransport: "loopback" },
394
399
  );
395
400
 
396
- await new Promise((r) => setTimeout(r, 50));
401
+ await urlReadyPromise;
397
402
 
398
403
  expect(capturedAuthUrl).toContain("redirect_uri=");
399
404
  expect(capturedAuthUrl).toMatch(/localhost|127\.0\.0\.1/);
@@ -418,17 +423,22 @@ describe("OAuth2 gateway transport", () => {
418
423
 
419
424
  test("error: OAuth provider returns error parameter", async () => {
420
425
  let capturedAuthUrl = "";
426
+ let urlReady!: () => void;
427
+ const urlReadyPromise = new Promise<void>((r) => {
428
+ urlReady = r;
429
+ });
421
430
  const flowPromise = startOAuth2Flow(
422
431
  BASE_OAUTH_CONFIG,
423
432
  {
424
433
  openUrl: (url) => {
425
434
  capturedAuthUrl = url;
435
+ urlReady();
426
436
  },
427
437
  },
428
438
  { callbackTransport: "loopback" },
429
439
  );
430
440
 
431
- await new Promise((r) => setTimeout(r, 50));
441
+ await urlReadyPromise;
432
442
 
433
443
  const authUrl = new URL(capturedAuthUrl);
434
444
  const redirectUri = authUrl.searchParams.get("redirect_uri")!;
@@ -446,17 +456,22 @@ describe("OAuth2 gateway transport", () => {
446
456
 
447
457
  test("rejects callback with wrong state parameter", async () => {
448
458
  let capturedAuthUrl = "";
459
+ let urlReady!: () => void;
460
+ const urlReadyPromise = new Promise<void>((r) => {
461
+ urlReady = r;
462
+ });
449
463
  const flowPromise = startOAuth2Flow(
450
464
  BASE_OAUTH_CONFIG,
451
465
  {
452
466
  openUrl: (url) => {
453
467
  capturedAuthUrl = url;
468
+ urlReady();
454
469
  },
455
470
  },
456
471
  { callbackTransport: "loopback" },
457
472
  );
458
473
 
459
- await new Promise((r) => setTimeout(r, 50));
474
+ await urlReadyPromise;
460
475
 
461
476
  const authUrl = new URL(capturedAuthUrl);
462
477
  const redirectUri = authUrl.searchParams.get("redirect_uri")!;
@@ -4,6 +4,10 @@ import { describe, expect, test } from "bun:test";
4
4
 
5
5
  const templatesDir = join(import.meta.dirname, "..", "prompts", "templates");
6
6
  const bootstrap = readFileSync(join(templatesDir, "BOOTSTRAP.md"), "utf-8");
7
+ const bootstrapRef = readFileSync(
8
+ join(templatesDir, "BOOTSTRAP-REFERENCE.md"),
9
+ "utf-8",
10
+ );
7
11
  const identity = readFileSync(join(templatesDir, "IDENTITY.md"), "utf-8");
8
12
  const user = readFileSync(join(templatesDir, "USER.md"), "utf-8");
9
13
 
@@ -17,28 +21,32 @@ describe("onboarding template contracts", () => {
17
21
  const lower = bootstrap.toLowerCase();
18
22
  expect(lower).toContain("your name");
19
23
  expect(lower).toContain("personality");
20
- expect(lower).toContain("avatar");
21
24
  });
22
25
 
23
- test("infers personality organically instead of asking directly", () => {
26
+ test("leads with personality-first emotional arc", () => {
24
27
  const lower = bootstrap.toLowerCase();
25
28
  expect(lower).toContain("personality");
26
- expect(lower).toContain("emerge");
27
29
  expect(lower).toContain("vibe");
30
+ // Personality arc should come before usefulness arc
31
+ const personalityIdx = lower.indexOf("oh, this has personality");
32
+ const usefulIdx = lower.indexOf("oh, this is useful");
33
+ expect(personalityIdx).toBeGreaterThan(-1);
34
+ expect(usefulIdx).toBeGreaterThan(-1);
35
+ expect(personalityIdx).toBeLessThan(usefulIdx);
28
36
  });
29
37
 
30
38
  test("contains name selection with change-later instruction", () => {
31
39
  const lower = bootstrap.toLowerCase();
32
- expect(lower).toContain("what do you want to call me");
40
+ expect(lower).toContain("what they want to call you");
33
41
  expect(lower).toContain("change it later");
34
42
  });
35
43
 
36
- test("asks about user after assistant identity", () => {
37
- const nameIdx = bootstrap.indexOf("Your name");
38
- const theirNameIdx = bootstrap.indexOf("Their name");
44
+ test("name exchange happens before personality quiz", () => {
45
+ const nameIdx = bootstrap.indexOf("Step 1: Name Exchange");
46
+ const quizIdx = bootstrap.indexOf("Step 2: Personality Quiz");
39
47
  expect(nameIdx).toBeGreaterThan(-1);
40
- expect(theirNameIdx).toBeGreaterThan(-1);
41
- expect(nameIdx).toBeLessThan(theirNameIdx);
48
+ expect(quizIdx).toBeGreaterThan(-1);
49
+ expect(nameIdx).toBeLessThan(quizIdx);
42
50
  });
43
51
 
44
52
  test("gathers user context: work role, hobbies, daily tools", () => {
@@ -48,18 +56,16 @@ describe("onboarding template contracts", () => {
48
56
  expect(lower).toContain("tools");
49
57
  });
50
58
 
51
- test("shows exactly 2 suggestions via ui_show card with relay_prompt actions", () => {
59
+ test("references ui_show payloads from BOOTSTRAP-REFERENCE.md", () => {
52
60
  expect(bootstrap).toContain("ui_show");
53
- expect(bootstrap).toContain("exactly 2");
54
- expect(bootstrap).toContain("relay_prompt");
61
+ expect(bootstrap).toContain("BOOTSTRAP-REFERENCE.md");
55
62
  });
56
63
 
57
- test("contains wrapping-up criteria with required conditions", () => {
64
+ test("contains wrapping-up criteria with deletion instructions", () => {
58
65
  const lower = bootstrap.toLowerCase();
59
66
  expect(lower).toContain("wrapping up");
60
67
  expect(lower).toContain("delete");
61
68
  expect(lower).toContain("bootstrap.md");
62
- expect(lower).toContain("two suggestions");
63
69
  });
64
70
 
65
71
  test("contains refusal policy", () => {
@@ -83,6 +89,48 @@ describe("onboarding template contracts", () => {
83
89
  expect(bootstrap).toContain("SOUL.md");
84
90
  expect(bootstrap).toContain("file_edit");
85
91
  });
92
+
93
+ test("includes budget constraint", () => {
94
+ expect(bootstrap).toContain("$5");
95
+ });
96
+
97
+ test("includes new colleague framing", () => {
98
+ expect(bootstrap).toContain("new colleague");
99
+ });
100
+
101
+ test("instructs checking Connected Services for email task variant", () => {
102
+ expect(bootstrap).toContain("Connected Services");
103
+ expect(bootstrap).toContain("Connect my email");
104
+ expect(bootstrap).toContain("Check my email");
105
+ });
106
+
107
+ test("includes daily briefing and channel suggestions in getting set up", () => {
108
+ const lower = bootstrap.toLowerCase();
109
+ expect(lower).toContain("daily briefing");
110
+ expect(lower).toContain("slack");
111
+ expect(lower).toContain("telegram");
112
+ });
113
+ });
114
+
115
+ describe("BOOTSTRAP-REFERENCE.md", () => {
116
+ test("contains personality form with 4 dropdowns", () => {
117
+ expect(bootstrapRef).toContain('surface_type: "form"');
118
+ expect(bootstrapRef).toContain("communication_style");
119
+ expect(bootstrapRef).toContain("task_style");
120
+ expect(bootstrapRef).toContain("humor");
121
+ expect(bootstrapRef).toContain("depth");
122
+ });
123
+
124
+ test("contains email-not-connected task card variant", () => {
125
+ expect(bootstrapRef).toContain("Email Not Connected");
126
+ expect(bootstrapRef).toContain("Connect my email");
127
+ expect(bootstrapRef).toContain("relay_prompt");
128
+ });
129
+
130
+ test("contains email-already-connected task card variant", () => {
131
+ expect(bootstrapRef).toContain("Email Already Connected");
132
+ expect(bootstrapRef).toContain("Check my email");
133
+ });
86
134
  });
87
135
 
88
136
  describe("IDENTITY.md", () => {