@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,274 @@
1
+ /**
2
+ * Tests for the set_permission_mode system tool.
3
+ *
4
+ * Verifies:
5
+ * - Mode transitions via askBeforeActing and hostAccess
6
+ * - Partial updates (only provided fields change)
7
+ * - Idempotent calls (setting same value is safe)
8
+ * - Error when no fields provided
9
+ * - Tool is not registered when permission-controls-v2 flag is off
10
+ * - Tool is registered when permission-controls-v2 flag is on
11
+ */
12
+
13
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
14
+ import { join } from "node:path";
15
+ import {
16
+ afterAll,
17
+ afterEach,
18
+ beforeEach,
19
+ describe,
20
+ expect,
21
+ mock,
22
+ test,
23
+ } from "bun:test";
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // Mocks — declared before imports that depend on platform/logger
27
+ // ---------------------------------------------------------------------------
28
+
29
+ const WORKSPACE_DIR = process.env.VELLUM_WORKSPACE_DIR!;
30
+ const CONFIG_PATH = join(WORKSPACE_DIR, "config.json");
31
+
32
+ function ensureTestDir(): void {
33
+ const dirs = [
34
+ WORKSPACE_DIR,
35
+ join(WORKSPACE_DIR, "data"),
36
+ join(WORKSPACE_DIR, "data", "logs"),
37
+ ];
38
+ for (const dir of dirs) {
39
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
40
+ }
41
+ }
42
+
43
+ function makeLoggerStub(): Record<string, unknown> {
44
+ const stub: Record<string, unknown> = {};
45
+ for (const m of [
46
+ "info",
47
+ "warn",
48
+ "error",
49
+ "debug",
50
+ "trace",
51
+ "fatal",
52
+ "silent",
53
+ "child",
54
+ ]) {
55
+ stub[m] = m === "child" ? () => makeLoggerStub() : () => {};
56
+ }
57
+ return stub;
58
+ }
59
+
60
+ mock.module("../util/logger.js", () => ({
61
+ getLogger: () => makeLoggerStub(),
62
+ }));
63
+
64
+ afterAll(() => {
65
+ mock.restore();
66
+ });
67
+
68
+ import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
69
+ import { invalidateConfigCache } from "../config/loader.js";
70
+ import {
71
+ getMode,
72
+ resetForTesting,
73
+ } from "../permissions/permission-mode-store.js";
74
+ import { __clearRegistryForTesting, getTool } from "../tools/registry.js";
75
+ import { registerSystemTools } from "../tools/system/register.js";
76
+ import { setPermissionModeTool } from "../tools/system/set-permission-mode.js";
77
+ import type { ToolContext } from "../tools/types.js";
78
+
79
+ // ---------------------------------------------------------------------------
80
+ // Helpers
81
+ // ---------------------------------------------------------------------------
82
+
83
+ function writeConfig(obj: unknown): void {
84
+ ensureTestDir();
85
+ writeFileSync(CONFIG_PATH, JSON.stringify(obj, null, 2) + "\n");
86
+ }
87
+
88
+ function makeContext(): ToolContext {
89
+ return {
90
+ workingDir: WORKSPACE_DIR,
91
+ conversationId: "test-conversation",
92
+ trustClass: "guardian",
93
+ };
94
+ }
95
+
96
+ // ---------------------------------------------------------------------------
97
+ // Setup / teardown
98
+ // ---------------------------------------------------------------------------
99
+
100
+ beforeEach(() => {
101
+ ensureTestDir();
102
+ resetForTesting();
103
+ invalidateConfigCache();
104
+ _setOverridesForTesting({});
105
+ __clearRegistryForTesting();
106
+ // Write a minimal config so the store initializes cleanly
107
+ writeConfig({});
108
+ });
109
+
110
+ afterEach(() => {
111
+ resetForTesting();
112
+ invalidateConfigCache();
113
+ _setOverridesForTesting({});
114
+ __clearRegistryForTesting();
115
+ });
116
+
117
+ // ---------------------------------------------------------------------------
118
+ // Tests — tool execution
119
+ // ---------------------------------------------------------------------------
120
+
121
+ describe("set_permission_mode tool", () => {
122
+ describe("mode transitions", () => {
123
+ test("sets askBeforeActing to false", async () => {
124
+ const result = await setPermissionModeTool.execute(
125
+ { askBeforeActing: false },
126
+ makeContext(),
127
+ );
128
+
129
+ expect(result.isError).toBe(false);
130
+ expect(result.content).toContain("askBeforeActing: false");
131
+
132
+ const mode = getMode();
133
+ expect(mode.askBeforeActing).toBe(false);
134
+ });
135
+
136
+ test("sets hostAccess to true", async () => {
137
+ const result = await setPermissionModeTool.execute(
138
+ { hostAccess: true },
139
+ makeContext(),
140
+ );
141
+
142
+ expect(result.isError).toBe(false);
143
+ expect(result.content).toContain("hostAccess: true");
144
+
145
+ const mode = getMode();
146
+ expect(mode.hostAccess).toBe(true);
147
+ });
148
+
149
+ test("sets both fields at once", async () => {
150
+ const result = await setPermissionModeTool.execute(
151
+ { askBeforeActing: false, hostAccess: true },
152
+ makeContext(),
153
+ );
154
+
155
+ expect(result.isError).toBe(false);
156
+ expect(result.content).toContain("askBeforeActing: false");
157
+ expect(result.content).toContain("hostAccess: true");
158
+
159
+ const mode = getMode();
160
+ expect(mode.askBeforeActing).toBe(false);
161
+ expect(mode.hostAccess).toBe(true);
162
+ });
163
+ });
164
+
165
+ describe("partial updates", () => {
166
+ test("only askBeforeActing changes, hostAccess unchanged", async () => {
167
+ await setPermissionModeTool.execute(
168
+ { askBeforeActing: false },
169
+ makeContext(),
170
+ );
171
+
172
+ const mode = getMode();
173
+ expect(mode.askBeforeActing).toBe(false);
174
+ // hostAccess should remain at default (false)
175
+ expect(mode.hostAccess).toBe(false);
176
+ });
177
+
178
+ test("only hostAccess changes, askBeforeActing unchanged", async () => {
179
+ await setPermissionModeTool.execute({ hostAccess: true }, makeContext());
180
+
181
+ const mode = getMode();
182
+ // askBeforeActing should remain at default (true)
183
+ expect(mode.askBeforeActing).toBe(true);
184
+ expect(mode.hostAccess).toBe(true);
185
+ });
186
+ });
187
+
188
+ describe("idempotent calls", () => {
189
+ test("setting askBeforeActing to current value is safe", async () => {
190
+ // Default is true
191
+ const result = await setPermissionModeTool.execute(
192
+ { askBeforeActing: true },
193
+ makeContext(),
194
+ );
195
+
196
+ expect(result.isError).toBe(false);
197
+ expect(getMode().askBeforeActing).toBe(true);
198
+ });
199
+
200
+ test("setting hostAccess to current value is safe", async () => {
201
+ // Default is false
202
+ const result = await setPermissionModeTool.execute(
203
+ { hostAccess: false },
204
+ makeContext(),
205
+ );
206
+
207
+ expect(result.isError).toBe(false);
208
+ expect(getMode().hostAccess).toBe(false);
209
+ });
210
+
211
+ test("repeated calls produce same result", async () => {
212
+ await setPermissionModeTool.execute(
213
+ { askBeforeActing: false, hostAccess: true },
214
+ makeContext(),
215
+ );
216
+ const result = await setPermissionModeTool.execute(
217
+ { askBeforeActing: false, hostAccess: true },
218
+ makeContext(),
219
+ );
220
+
221
+ expect(result.isError).toBe(false);
222
+ const mode = getMode();
223
+ expect(mode.askBeforeActing).toBe(false);
224
+ expect(mode.hostAccess).toBe(true);
225
+ });
226
+ });
227
+
228
+ describe("validation", () => {
229
+ test("returns error when no fields provided", async () => {
230
+ const result = await setPermissionModeTool.execute({}, makeContext());
231
+
232
+ expect(result.isError).toBe(true);
233
+ expect(result.content).toContain("at least one");
234
+ });
235
+ });
236
+
237
+ describe("tool definition", () => {
238
+ test("has correct name", () => {
239
+ expect(setPermissionModeTool.name).toBe("set_permission_mode");
240
+ });
241
+
242
+ test("has correct category", () => {
243
+ expect(setPermissionModeTool.category).toBe("system");
244
+ });
245
+
246
+ test("definition includes both properties", () => {
247
+ const def = setPermissionModeTool.getDefinition();
248
+ const schema = def.input_schema as { properties?: Record<string, unknown> };
249
+ const props = schema.properties as Record<string, unknown>;
250
+ expect(props).toHaveProperty("askBeforeActing");
251
+ expect(props).toHaveProperty("hostAccess");
252
+ });
253
+ });
254
+ });
255
+
256
+ // ---------------------------------------------------------------------------
257
+ // Tests — feature flag gating
258
+ // ---------------------------------------------------------------------------
259
+
260
+ describe("set_permission_mode registration", () => {
261
+ test("tool is NOT registered when permission-controls-v2 flag is off", () => {
262
+ _setOverridesForTesting({ "permission-controls-v2": false });
263
+ registerSystemTools();
264
+
265
+ expect(getTool("set_permission_mode")).toBeUndefined();
266
+ });
267
+
268
+ test("tool IS registered when permission-controls-v2 flag is on", () => {
269
+ _setOverridesForTesting({ "permission-controls-v2": true });
270
+ registerSystemTools();
271
+
272
+ expect(getTool("set_permission_mode")).toBeDefined();
273
+ });
274
+ });
@@ -28,16 +28,16 @@ import { parseFrontmatterFields } from "../skills/frontmatter.js";
28
28
  // Fixtures
29
29
  // ---------------------------------------------------------------------------
30
30
 
31
- /** A SKILL.md with `feature-flag: contacts` declared in its vellum metadata. */
31
+ /** A SKILL.md with `feature-flag: email-channel` declared in its vellum metadata. */
32
32
  const SKILL_MD_WITH_FLAG = `---
33
- name: "Contacts"
34
- description: "View and manage contacts"
33
+ name: "Email Setup"
34
+ description: "Set up email integration"
35
35
  metadata:
36
36
  vellum:
37
- feature-flag: contacts
37
+ feature-flag: email-channel
38
38
  ---
39
39
 
40
- Instructions for the contacts skill.
40
+ Instructions for the email setup skill.
41
41
  `;
42
42
 
43
43
  /** A SKILL.md with no feature-flag field at all. */
@@ -128,16 +128,16 @@ describe("frontmatter feature-flag integration", () => {
128
128
  expect(metadataObj).toBeTruthy();
129
129
 
130
130
  const vellum = metadataObj.vellum as Record<string, unknown>;
131
- expect(vellum["feature-flag"]).toBe("contacts");
131
+ expect(vellum["feature-flag"]).toBe("email-channel");
132
132
  });
133
133
 
134
134
  test("skillFlagKey returns correct key for parsed skill", () => {
135
- const skill = buildSkillSummary("contacts", SKILL_MD_WITH_FLAG);
135
+ const skill = buildSkillSummary("email-setup", SKILL_MD_WITH_FLAG);
136
136
  expect(skill).not.toBeNull();
137
- expect(skill!.featureFlag).toBe("contacts");
137
+ expect(skill!.featureFlag).toBe("email-channel");
138
138
 
139
139
  const key = skillFlagKey(skill!);
140
- expect(key).toBe("contacts");
140
+ expect(key).toBe("email-channel");
141
141
  });
142
142
 
143
143
  test("skillFlagKey returns undefined for skill without feature-flag", () => {
@@ -149,27 +149,26 @@ describe("frontmatter feature-flag integration", () => {
149
149
  expect(key).toBeUndefined();
150
150
  });
151
151
 
152
- test("resolveSkillStates includes skill with featureFlag when flag defaults to ON", () => {
153
- const skill = buildSkillSummary("contacts", SKILL_MD_WITH_FLAG)!;
154
- // "contacts" is in the registry with defaultEnabled: true
152
+ test("resolveSkillStates includes skill with featureFlag when flag is ON", () => {
153
+ _setOverridesForTesting({
154
+ "email-channel": true,
155
+ });
156
+ const skill = buildSkillSummary("email-setup", SKILL_MD_WITH_FLAG)!;
155
157
  const config = makeConfig();
156
158
 
157
159
  const resolved = resolveSkillStates([skill], config);
158
- // Flag defaults to true → skill passes through
159
160
  expect(resolved.length).toBe(1);
160
- expect(resolved[0].summary.id).toBe("contacts");
161
+ expect(resolved[0].summary.id).toBe("email-setup");
161
162
  });
162
163
 
163
- test("resolveSkillStates includes skill with featureFlag when flag is ON", () => {
164
- _setOverridesForTesting({
165
- contacts: true,
166
- });
167
- const skill = buildSkillSummary("contacts", SKILL_MD_WITH_FLAG)!;
164
+ test("resolveSkillStates excludes skill with featureFlag when flag defaults to OFF", () => {
165
+ const skill = buildSkillSummary("email-setup", SKILL_MD_WITH_FLAG)!;
166
+ // "email-channel" is in the registry with defaultEnabled: false
168
167
  const config = makeConfig();
169
168
 
170
169
  const resolved = resolveSkillStates([skill], config);
171
- expect(resolved.length).toBe(1);
172
- expect(resolved[0].summary.id).toBe("contacts");
170
+ // Flag defaults to false → skill is filtered out
171
+ expect(resolved.length).toBe(0);
173
172
  });
174
173
 
175
174
  test("resolveSkillStates never gates skill without featureFlag", () => {
@@ -192,26 +191,34 @@ describe("frontmatter feature-flag integration", () => {
192
191
  const metadataObj = parsed!.fields.metadata as Record<string, unknown>;
193
192
  const vellum = metadataObj.vellum as Record<string, unknown>;
194
193
  const flagId = vellum["feature-flag"];
195
- expect(flagId).toBe("contacts");
194
+ expect(flagId).toBe("email-channel");
196
195
 
197
196
  // Step 2: Build SkillSummary (as the catalog loader would)
198
- const skill = buildSkillSummary("contacts", SKILL_MD_WITH_FLAG)!;
199
- expect(skill.featureFlag).toBe("contacts");
197
+ const skill = buildSkillSummary("email-setup", SKILL_MD_WITH_FLAG)!;
198
+ expect(skill.featureFlag).toBe("email-channel");
200
199
 
201
200
  // Step 3: Derive the flag key
202
201
  const key = skillFlagKey(skill);
203
- expect(key).toBe("contacts");
202
+ expect(key).toBe("email-channel");
204
203
 
205
- // Step 4: Check flag state — "contacts" has defaultEnabled: true in registry
204
+ // Step 4: Check flag state — "email-channel" has defaultEnabled: false in registry
206
205
  const configDefault = makeConfig();
207
- expect(isAssistantFeatureFlagEnabled(key!, configDefault)).toBe(true);
206
+ expect(isAssistantFeatureFlagEnabled(key!, configDefault)).toBe(false);
208
207
 
209
- // Step 5: resolveSkillStates includes it by default
208
+ // Step 5: resolveSkillStates excludes it by default (flag is off)
210
209
  const resolvedDefault = resolveSkillStates([skill], configDefault);
211
- expect(resolvedDefault.length).toBe(1);
212
- expect(resolvedDefault[0].summary.id).toBe("contacts");
210
+ expect(resolvedDefault.length).toBe(0);
211
+
212
+ // Step 6: With override enabled, skill passes through
213
+ _setOverridesForTesting({ [key!]: true });
214
+ const configOn = makeConfig();
215
+ expect(isAssistantFeatureFlagEnabled(key!, configOn)).toBe(true);
216
+
217
+ const resolvedOn = resolveSkillStates([skill], configOn);
218
+ expect(resolvedOn.length).toBe(1);
219
+ expect(resolvedOn[0].summary.id).toBe("email-setup");
213
220
 
214
- // Step 6: With override disabled, skill is filtered out
221
+ // Step 7: With override disabled, skill is filtered out
215
222
  _setOverridesForTesting({ [key!]: false });
216
223
  const configOff = makeConfig();
217
224
  expect(isAssistantFeatureFlagEnabled(key!, configOff)).toBe(false);
@@ -16,9 +16,9 @@ afterEach(() => {
16
16
  _setOverridesForTesting({});
17
17
  });
18
18
 
19
- const DECLARED_FLAG_ID = "contacts";
19
+ const DECLARED_FLAG_ID = "sounds";
20
20
  const DECLARED_FLAG_KEY = DECLARED_FLAG_ID;
21
- const DECLARED_SKILL_ID = "contacts";
21
+ const DECLARED_SKILL_ID = "sounds";
22
22
  const APP_BUILDER_MULTIFILE_FLAG_KEY = "app-builder-multifile";
23
23
  // ---------------------------------------------------------------------------
24
24
  // Helpers
@@ -144,7 +144,7 @@ describe("isAssistantFeatureFlagEnabled", () => {
144
144
 
145
145
  test("falls back to registry default when no override", () => {
146
146
  const config = makeConfig();
147
- // contacts defaults to true in the registry
147
+ // sounds defaults to true in the registry
148
148
  expect(isAssistantFeatureFlagEnabled(DECLARED_FLAG_KEY, config)).toBe(true);
149
149
  });
150
150
 
@@ -214,7 +214,7 @@ describe("resolveSkillStates with feature flags", () => {
214
214
  const config = makeConfig();
215
215
 
216
216
  const resolved = resolveSkillStates(catalog, config);
217
- // contacts registry default is true, so it passes through
217
+ // sounds registry default is true, so it passes through
218
218
  expect(resolved.length).toBe(1);
219
219
  expect(resolved[0].summary.id).toBe(DECLARED_SKILL_ID);
220
220
  });
@@ -272,7 +272,7 @@ describe("resolveSkillStates with feature flags", () => {
272
272
  const resolved = resolveSkillStates(catalog, config);
273
273
  const ids = resolved.map((r) => r.summary.id);
274
274
 
275
- // contacts and deploy explicitly false; browser explicitly true
275
+ // sounds and deploy explicitly false; browser explicitly true
276
276
  expect(ids).toEqual(["browser"]);
277
277
  });
278
278
  });
@@ -283,7 +283,7 @@ describe("resolveSkillStates with feature flags", () => {
283
283
 
284
284
  describe("resolveSkillStates with frontmatter featureFlag", () => {
285
285
  test("skill with featureFlag (defaultEnabled: true) is included when no config override", () => {
286
- // contacts has defaultEnabled: true in the registry
286
+ // sounds has defaultEnabled: true in the registry
287
287
  const catalog = [makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID)];
288
288
  const config = makeConfig();
289
289
 
@@ -12,8 +12,8 @@ const TEST_DIR = process.env.VELLUM_WORKSPACE_DIR!;
12
12
 
13
13
  let currentConfig: Record<string, unknown> = {};
14
14
 
15
- const DECLARED_SKILL_ID = "contacts";
16
- const DECLARED_FLAG_KEY = "contacts";
15
+ const DECLARED_SKILL_ID = "sounds";
16
+ const DECLARED_FLAG_KEY = "sounds";
17
17
 
18
18
  const noopLogger = new Proxy({} as Record<string, unknown>, {
19
19
  get: (_target, prop) => (prop === "child" ? () => noopLogger : () => {}),
@@ -39,6 +39,18 @@ mock.module("../config/loader.js", () => ({
39
39
  invalidateConfigCache: () => {},
40
40
  getNestedValue: () => undefined,
41
41
  setNestedValue: () => {},
42
+ deepMergeOverwrite: (a: unknown) => a,
43
+ mergeDefaultWorkspaceConfig: () => {},
44
+ API_KEY_PROVIDERS: [
45
+ "anthropic",
46
+ "openai",
47
+ "gemini",
48
+ "ollama",
49
+ "fireworks",
50
+ "openrouter",
51
+ "brave",
52
+ "perplexity",
53
+ ],
42
54
  }));
43
55
 
44
56
  await import("../tools/skills/load.js");
@@ -86,8 +98,8 @@ describe("skill_load feature flag enforcement", () => {
86
98
  test("returns deterministic error for flag OFF skill", async () => {
87
99
  writeSkill(
88
100
  DECLARED_SKILL_ID,
89
- "Contacts",
90
- "Toggle contacts behavior",
101
+ "Sounds",
102
+ "Toggle sounds behavior",
91
103
  "Use the feature.",
92
104
  );
93
105
  writeFileSync(
@@ -107,8 +119,8 @@ describe("skill_load feature flag enforcement", () => {
107
119
  test("loads skill normally when flag is ON", async () => {
108
120
  writeSkill(
109
121
  DECLARED_SKILL_ID,
110
- "Contacts",
111
- "Toggle contacts behavior",
122
+ "Sounds",
123
+ "Toggle sounds behavior",
112
124
  "Use the feature.",
113
125
  );
114
126
  writeFileSync(
@@ -121,14 +133,14 @@ describe("skill_load feature flag enforcement", () => {
121
133
  const result = await executeSkillLoad({ skill: DECLARED_SKILL_ID });
122
134
 
123
135
  expect(result.isError).toBe(false);
124
- expect(result.content).toContain("Skill: Contacts");
136
+ expect(result.content).toContain("Skill: Sounds");
125
137
  });
126
138
 
127
139
  test("loads skill when flag key is absent (registry defaults to enabled)", async () => {
128
140
  writeSkill(
129
141
  DECLARED_SKILL_ID,
130
- "Contacts",
131
- "Toggle contacts behavior",
142
+ "Sounds",
143
+ "Toggle sounds behavior",
132
144
  "Use the feature.",
133
145
  );
134
146
  writeFileSync(
@@ -140,8 +152,8 @@ describe("skill_load feature flag enforcement", () => {
140
152
 
141
153
  const result = await executeSkillLoad({ skill: DECLARED_SKILL_ID });
142
154
 
143
- // contacts is declared in the registry with defaultEnabled: true
155
+ // sounds is declared in the registry with defaultEnabled: true
144
156
  expect(result.isError).toBe(false);
145
- expect(result.content).toContain("Skill: Contacts");
157
+ expect(result.content).toContain("Skill: Sounds");
146
158
  });
147
159
  });