@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,441 @@
1
+ /**
2
+ * Tests for the profiler run store: manifest management, retention sweep,
3
+ * active-run protection, oldest-first pruning, max-run-count pruning,
4
+ * active-run-over-budget signaling, and idempotent rescans.
5
+ */
6
+ import {
7
+ existsSync,
8
+ mkdirSync,
9
+ readFileSync,
10
+ rmSync,
11
+ writeFileSync,
12
+ } from "node:fs";
13
+ import { tmpdir } from "node:os";
14
+ import { join } from "node:path";
15
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
16
+
17
+ import type { ProfilerRunManifest } from "../daemon/profiler-run-store.js";
18
+ import { rescanRuns, runProfilerSweep } from "../daemon/profiler-run-store.js";
19
+
20
+ // ── Test scaffolding ────────────────────────────────────────────────────
21
+
22
+ let testDir: string;
23
+ let runsDir: string;
24
+ let origEnv: Record<string, string | undefined>;
25
+
26
+ /**
27
+ * Create a fake profiler run directory with some payload files.
28
+ */
29
+ function createRun(
30
+ runId: string,
31
+ opts?: {
32
+ sizeBytes?: number;
33
+ manifest?: Partial<ProfilerRunManifest>;
34
+ },
35
+ ): string {
36
+ const dir = join(runsDir, runId);
37
+ mkdirSync(dir, { recursive: true });
38
+
39
+ // Write a payload file of the requested size
40
+ const size = opts?.sizeBytes ?? 1024;
41
+ writeFileSync(join(dir, "profile.cpuprofile"), Buffer.alloc(size));
42
+
43
+ // Optionally write a pre-existing manifest
44
+ if (opts?.manifest) {
45
+ const m: ProfilerRunManifest = {
46
+ runId,
47
+ status: opts.manifest.status ?? "completed",
48
+ createdAt: opts.manifest.createdAt ?? new Date().toISOString(),
49
+ updatedAt: opts.manifest.updatedAt ?? new Date().toISOString(),
50
+ totalBytes: opts.manifest.totalBytes ?? size,
51
+ };
52
+ writeFileSync(join(dir, "manifest.json"), JSON.stringify(m, null, 2));
53
+ }
54
+
55
+ return dir;
56
+ }
57
+
58
+ function readManifestFromDisk(runId: string): ProfilerRunManifest | null {
59
+ const manifestPath = join(runsDir, runId, "manifest.json");
60
+ try {
61
+ return JSON.parse(readFileSync(manifestPath, "utf-8"));
62
+ } catch {
63
+ return null;
64
+ }
65
+ }
66
+
67
+ beforeEach(() => {
68
+ testDir = join(
69
+ tmpdir(),
70
+ `vellum-profiler-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
71
+ );
72
+ runsDir = join(testDir, "data", "profiler", "runs");
73
+ mkdirSync(runsDir, { recursive: true });
74
+
75
+ // Save and override env
76
+ origEnv = {
77
+ VELLUM_WORKSPACE_DIR: process.env.VELLUM_WORKSPACE_DIR,
78
+ VELLUM_PROFILER_RUN_ID: process.env.VELLUM_PROFILER_RUN_ID,
79
+ VELLUM_PROFILER_MAX_BYTES: process.env.VELLUM_PROFILER_MAX_BYTES,
80
+ VELLUM_PROFILER_MAX_RUNS: process.env.VELLUM_PROFILER_MAX_RUNS,
81
+ VELLUM_PROFILER_MIN_FREE_MB: process.env.VELLUM_PROFILER_MIN_FREE_MB,
82
+ };
83
+
84
+ // Point workspace dir to our temp directory
85
+ process.env.VELLUM_WORKSPACE_DIR = testDir;
86
+
87
+ // Clear profiler env vars
88
+ delete process.env.VELLUM_PROFILER_RUN_ID;
89
+ delete process.env.VELLUM_PROFILER_MAX_BYTES;
90
+ delete process.env.VELLUM_PROFILER_MAX_RUNS;
91
+ delete process.env.VELLUM_PROFILER_MIN_FREE_MB;
92
+ });
93
+
94
+ afterEach(() => {
95
+ // Restore env
96
+ for (const [key, value] of Object.entries(origEnv)) {
97
+ if (value === undefined) {
98
+ delete process.env[key];
99
+ } else {
100
+ process.env[key] = value;
101
+ }
102
+ }
103
+
104
+ // Clean up temp directory
105
+ if (existsSync(testDir)) {
106
+ rmSync(testDir, { recursive: true, force: true });
107
+ }
108
+ });
109
+
110
+ // ── Tests ───────────────────────────────────────────────────────────────
111
+
112
+ describe("Profiler run store", () => {
113
+ describe("rescanRuns", () => {
114
+ test("returns empty array when no runs directory exists", () => {
115
+ // Remove the runs directory
116
+ rmSync(runsDir, { recursive: true, force: true });
117
+ const manifests = rescanRuns();
118
+ expect(manifests).toEqual([]);
119
+ });
120
+
121
+ test("returns empty array when runs directory is empty", () => {
122
+ const manifests = rescanRuns();
123
+ expect(manifests).toEqual([]);
124
+ });
125
+
126
+ test("creates manifests for run directories without existing manifests", () => {
127
+ createRun("run-001", { sizeBytes: 2048 });
128
+ createRun("run-002", { sizeBytes: 4096 });
129
+
130
+ const manifests = rescanRuns();
131
+ expect(manifests).toHaveLength(2);
132
+
133
+ const run1 = manifests.find((m) => m.runId === "run-001");
134
+ expect(run1).toBeDefined();
135
+ expect(run1!.status).toBe("completed");
136
+ // totalBytes includes manifest.json that rescan just wrote
137
+ expect(run1!.totalBytes).toBeGreaterThanOrEqual(2048);
138
+
139
+ const run2 = manifests.find((m) => m.runId === "run-002");
140
+ expect(run2).toBeDefined();
141
+ expect(run2!.status).toBe("completed");
142
+ expect(run2!.totalBytes).toBeGreaterThanOrEqual(4096);
143
+ });
144
+
145
+ test("marks the active run correctly", () => {
146
+ process.env.VELLUM_PROFILER_RUN_ID = "active-run";
147
+ createRun("active-run", { sizeBytes: 1024 });
148
+ createRun("old-run", { sizeBytes: 1024 });
149
+
150
+ const manifests = rescanRuns();
151
+ const active = manifests.find((m) => m.runId === "active-run");
152
+ const old = manifests.find((m) => m.runId === "old-run");
153
+
154
+ expect(active!.status).toBe("active");
155
+ expect(old!.status).toBe("completed");
156
+ });
157
+
158
+ test("transitions previously-active run to completed when no longer active", () => {
159
+ // Create a run with an "active" manifest
160
+ createRun("old-active", {
161
+ sizeBytes: 1024,
162
+ manifest: { status: "active", createdAt: "2025-01-01T00:00:00Z" },
163
+ });
164
+
165
+ // No VELLUM_PROFILER_RUN_ID set, so nothing is active
166
+ const manifests = rescanRuns();
167
+ const run = manifests.find((m) => m.runId === "old-active");
168
+
169
+ expect(run!.status).toBe("completed");
170
+
171
+ // Verify it was persisted to disk
172
+ const onDisk = readManifestFromDisk("old-active");
173
+ expect(onDisk!.status).toBe("completed");
174
+ });
175
+
176
+ test("is idempotent — repeated calls after initial scan produce the same result", () => {
177
+ createRun("run-a", { sizeBytes: 1024 });
178
+ process.env.VELLUM_PROFILER_RUN_ID = "run-a";
179
+
180
+ // First call writes the manifest, which changes totalBytes
181
+ rescanRuns();
182
+ // Second and third calls should be stable
183
+ const second = rescanRuns();
184
+ const third = rescanRuns();
185
+
186
+ expect(second).toHaveLength(1);
187
+ expect(third).toHaveLength(1);
188
+ expect(second[0]!.runId).toBe(third[0]!.runId);
189
+ expect(second[0]!.status).toBe(third[0]!.status);
190
+ expect(second[0]!.totalBytes).toBe(third[0]!.totalBytes);
191
+ });
192
+
193
+ test("preserves createdAt from existing manifest", () => {
194
+ const originalCreatedAt = "2024-06-15T12:00:00Z";
195
+ createRun("preserved-run", {
196
+ sizeBytes: 1024,
197
+ manifest: {
198
+ status: "completed",
199
+ createdAt: originalCreatedAt,
200
+ },
201
+ });
202
+
203
+ const manifests = rescanRuns();
204
+ const run = manifests.find((m) => m.runId === "preserved-run");
205
+ expect(run!.createdAt).toBe(originalCreatedAt);
206
+ });
207
+ });
208
+
209
+ describe("runProfilerSweep", () => {
210
+ test("no-ops when no runs exist", () => {
211
+ const result = runProfilerSweep();
212
+ expect(result.prunedCount).toBe(0);
213
+ expect(result.freedBytes).toBe(0);
214
+ expect(result.activeRunOverBudget).toBe(false);
215
+ expect(result.remainingRuns).toBe(0);
216
+ });
217
+
218
+ test("does not prune when under all budgets", () => {
219
+ process.env.VELLUM_PROFILER_MAX_BYTES = "1000000"; // 1 MB
220
+ process.env.VELLUM_PROFILER_MAX_RUNS = "10";
221
+
222
+ createRun("run-1", { sizeBytes: 1024 });
223
+ createRun("run-2", { sizeBytes: 1024 });
224
+
225
+ const result = runProfilerSweep();
226
+ expect(result.prunedCount).toBe(0);
227
+ expect(result.remainingRuns).toBe(2);
228
+
229
+ // Both directories still exist
230
+ expect(existsSync(join(runsDir, "run-1"))).toBe(true);
231
+ expect(existsSync(join(runsDir, "run-2"))).toBe(true);
232
+ });
233
+
234
+ test("prunes oldest completed runs when byte budget exceeded", () => {
235
+ // Set a very small byte budget
236
+ process.env.VELLUM_PROFILER_MAX_BYTES = "3000";
237
+ process.env.VELLUM_PROFILER_MAX_RUNS = "100";
238
+ process.env.VELLUM_PROFILER_MIN_FREE_MB = "0";
239
+
240
+ // Create runs with explicit timestamps for ordering
241
+ createRun("oldest", {
242
+ sizeBytes: 2000,
243
+ manifest: {
244
+ status: "completed",
245
+ createdAt: "2025-01-01T00:00:00Z",
246
+ },
247
+ });
248
+ createRun("middle", {
249
+ sizeBytes: 2000,
250
+ manifest: {
251
+ status: "completed",
252
+ createdAt: "2025-02-01T00:00:00Z",
253
+ },
254
+ });
255
+ createRun("newest", {
256
+ sizeBytes: 2000,
257
+ manifest: {
258
+ status: "completed",
259
+ createdAt: "2025-03-01T00:00:00Z",
260
+ },
261
+ });
262
+
263
+ const result = runProfilerSweep();
264
+
265
+ // Should prune until total bytes fit within 3000.
266
+ // Each run is ~2000 payload + manifest overhead. The sweep recomputes
267
+ // sizes so actual totals include the manifest file. At least 1 run
268
+ // should be pruned (the oldest).
269
+ expect(result.prunedCount).toBeGreaterThanOrEqual(1);
270
+ expect(result.freedBytes).toBeGreaterThan(0);
271
+
272
+ // The oldest should be gone
273
+ expect(existsSync(join(runsDir, "oldest"))).toBe(false);
274
+ });
275
+
276
+ test("prunes oldest completed runs when max-run-count exceeded", () => {
277
+ process.env.VELLUM_PROFILER_MAX_BYTES = "999999999";
278
+ process.env.VELLUM_PROFILER_MAX_RUNS = "2";
279
+ process.env.VELLUM_PROFILER_MIN_FREE_MB = "0";
280
+
281
+ createRun("run-a", {
282
+ sizeBytes: 100,
283
+ manifest: {
284
+ status: "completed",
285
+ createdAt: "2025-01-01T00:00:00Z",
286
+ },
287
+ });
288
+ createRun("run-b", {
289
+ sizeBytes: 100,
290
+ manifest: {
291
+ status: "completed",
292
+ createdAt: "2025-02-01T00:00:00Z",
293
+ },
294
+ });
295
+ createRun("run-c", {
296
+ sizeBytes: 100,
297
+ manifest: {
298
+ status: "completed",
299
+ createdAt: "2025-03-01T00:00:00Z",
300
+ },
301
+ });
302
+ createRun("run-d", {
303
+ sizeBytes: 100,
304
+ manifest: {
305
+ status: "completed",
306
+ createdAt: "2025-04-01T00:00:00Z",
307
+ },
308
+ });
309
+
310
+ const result = runProfilerSweep();
311
+
312
+ // 4 completed runs, max 2: should prune 2 oldest
313
+ expect(result.prunedCount).toBe(2);
314
+ expect(existsSync(join(runsDir, "run-a"))).toBe(false);
315
+ expect(existsSync(join(runsDir, "run-b"))).toBe(false);
316
+ expect(existsSync(join(runsDir, "run-c"))).toBe(true);
317
+ expect(existsSync(join(runsDir, "run-d"))).toBe(true);
318
+ expect(result.remainingRuns).toBe(2);
319
+ });
320
+
321
+ test("never deletes the active run", () => {
322
+ process.env.VELLUM_PROFILER_RUN_ID = "current";
323
+ process.env.VELLUM_PROFILER_MAX_BYTES = "500";
324
+ process.env.VELLUM_PROFILER_MAX_RUNS = "1";
325
+ process.env.VELLUM_PROFILER_MIN_FREE_MB = "0";
326
+
327
+ createRun("current", { sizeBytes: 2000 });
328
+ createRun("old-completed", {
329
+ sizeBytes: 2000,
330
+ manifest: {
331
+ status: "completed",
332
+ createdAt: "2025-01-01T00:00:00Z",
333
+ },
334
+ });
335
+
336
+ const result = runProfilerSweep();
337
+
338
+ // old-completed should be pruned, current should survive
339
+ expect(existsSync(join(runsDir, "current"))).toBe(true);
340
+ expect(existsSync(join(runsDir, "old-completed"))).toBe(false);
341
+ expect(result.prunedCount).toBe(1);
342
+ });
343
+
344
+ test("signals active-run-over-budget when active run exceeds byte budget", () => {
345
+ process.env.VELLUM_PROFILER_RUN_ID = "big-active";
346
+ process.env.VELLUM_PROFILER_MAX_BYTES = "500";
347
+ process.env.VELLUM_PROFILER_MAX_RUNS = "100";
348
+ process.env.VELLUM_PROFILER_MIN_FREE_MB = "0";
349
+
350
+ createRun("big-active", { sizeBytes: 10000 });
351
+
352
+ const result = runProfilerSweep();
353
+
354
+ expect(result.activeRunOverBudget).toBe(true);
355
+ // Active run must still exist
356
+ expect(existsSync(join(runsDir, "big-active"))).toBe(true);
357
+ expect(result.remainingRuns).toBe(1);
358
+ });
359
+
360
+ test("deletes single oversized completed run to recover space", () => {
361
+ process.env.VELLUM_PROFILER_MAX_BYTES = "100";
362
+ process.env.VELLUM_PROFILER_MAX_RUNS = "100";
363
+ process.env.VELLUM_PROFILER_MIN_FREE_MB = "0";
364
+
365
+ createRun("huge-completed", {
366
+ sizeBytes: 50000,
367
+ manifest: {
368
+ status: "completed",
369
+ createdAt: "2025-01-01T00:00:00Z",
370
+ },
371
+ });
372
+
373
+ const result = runProfilerSweep();
374
+
375
+ expect(result.prunedCount).toBe(1);
376
+ expect(result.freedBytes).toBeGreaterThanOrEqual(50000);
377
+ expect(existsSync(join(runsDir, "huge-completed"))).toBe(false);
378
+ });
379
+
380
+ test("creates profiler directories on first sweep if missing", () => {
381
+ // Remove everything
382
+ rmSync(join(testDir, "data", "profiler"), {
383
+ recursive: true,
384
+ force: true,
385
+ });
386
+
387
+ const result = runProfilerSweep();
388
+ expect(result.prunedCount).toBe(0);
389
+ expect(existsSync(runsDir)).toBe(true);
390
+ });
391
+
392
+ test("sweep is idempotent — repeated calls produce consistent state", () => {
393
+ process.env.VELLUM_PROFILER_MAX_BYTES = "999999";
394
+ process.env.VELLUM_PROFILER_MAX_RUNS = "10";
395
+ process.env.VELLUM_PROFILER_MIN_FREE_MB = "0";
396
+
397
+ createRun("stable-1", { sizeBytes: 1024 });
398
+ createRun("stable-2", { sizeBytes: 1024 });
399
+
400
+ const first = runProfilerSweep();
401
+ const second = runProfilerSweep();
402
+
403
+ expect(first.prunedCount).toBe(0);
404
+ expect(second.prunedCount).toBe(0);
405
+ expect(first.remainingRuns).toBe(second.remainingRuns);
406
+ });
407
+
408
+ test("active run is not counted against max completed runs", () => {
409
+ process.env.VELLUM_PROFILER_RUN_ID = "live";
410
+ process.env.VELLUM_PROFILER_MAX_BYTES = "999999";
411
+ process.env.VELLUM_PROFILER_MAX_RUNS = "2";
412
+ process.env.VELLUM_PROFILER_MIN_FREE_MB = "0";
413
+
414
+ createRun("live", { sizeBytes: 100 });
415
+ createRun("done-1", {
416
+ sizeBytes: 100,
417
+ manifest: {
418
+ status: "completed",
419
+ createdAt: "2025-01-01T00:00:00Z",
420
+ },
421
+ });
422
+ createRun("done-2", {
423
+ sizeBytes: 100,
424
+ manifest: {
425
+ status: "completed",
426
+ createdAt: "2025-02-01T00:00:00Z",
427
+ },
428
+ });
429
+
430
+ const result = runProfilerSweep();
431
+
432
+ // 2 completed runs = max, so nothing should be pruned
433
+ expect(result.prunedCount).toBe(0);
434
+ // Active + 2 completed = 3 remaining
435
+ expect(result.remainingRuns).toBe(3);
436
+ expect(existsSync(join(runsDir, "live"))).toBe(true);
437
+ expect(existsSync(join(runsDir, "done-1"))).toBe(true);
438
+ expect(existsSync(join(runsDir, "done-2"))).toBe(true);
439
+ });
440
+ });
441
+ });
@@ -603,6 +603,27 @@ describe("RetryProvider — streaming response handling", () => {
603
603
  expect(receivedSignal).toBe(controller.signal);
604
604
  });
605
605
 
606
+ test("retries overloaded_error with undefined statusCode (mid-stream SSE)", async () => {
607
+ let callCount = 0;
608
+ const inner: Provider = {
609
+ name: "retry-overloaded-undefined",
610
+ async sendMessage() {
611
+ callCount++;
612
+ if (callCount <= 1) {
613
+ throw new ProviderError(
614
+ 'Anthropic API error (undefined): {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}}',
615
+ "anthropic",
616
+ undefined,
617
+ );
618
+ }
619
+ return successResponse();
620
+ },
621
+ };
622
+ const provider = new RetryProvider(inner);
623
+ await provider.sendMessage(MESSAGES);
624
+ expect(callCount).toBe(2);
625
+ });
626
+
606
627
  test("events accumulate across retries (each attempt delivers events independently)", async () => {
607
628
  let callCount = 0;
608
629
  const inner: Provider = {
@@ -189,7 +189,7 @@ describe("createProxyApprovalCallback", () => {
189
189
  expect(prompterSendToClient).not.toHaveBeenCalled();
190
190
  });
191
191
 
192
- test("high-risk with plain allow rule (no allowHighRisk) falls through to prompt", async () => {
192
+ test("ask_missing_credential with allow rule auto-allows (medium risk)", async () => {
193
193
  findHighestPriorityRuleMock.mockReturnValue({
194
194
  id: "rule-hr-1",
195
195
  tool: "network_request",
@@ -198,53 +198,17 @@ describe("createProxyApprovalCallback", () => {
198
198
  decision: "allow" as const,
199
199
  priority: 100,
200
200
  createdAt: Date.now(),
201
- // No allowHighRisk — should NOT auto-allow for high-risk decisions
202
201
  });
203
202
 
204
203
  const ctx = makeContext();
205
204
  const prompterSendToClient = mock(() => {});
206
205
  const prompter = new PermissionPrompter(prompterSendToClient);
207
206
 
208
- const originalPrompt = prompter.prompt.bind(prompter);
209
- prompter.prompt = async (...args) => {
210
- const p = originalPrompt(...args);
211
- await new Promise((r) => setTimeout(r, 10));
212
- const call = (prompterSendToClient.mock.calls as unknown[][])[0];
213
- const msg = call[0] as { requestId: string };
214
- prompter.resolveConfirmation(msg.requestId, "allow");
215
- return p;
216
- };
217
-
218
207
  const callback = createProxyApprovalCallback(prompter, ctx);
219
- // ask_missing_credential is high risk
220
208
  const result = await callback(makeAskMissingCredentialRequest());
221
209
 
222
210
  expect(result).toBe(true);
223
- // Prompter SHOULD have been called — plain allow rule doesn't auto-allow high-risk
224
- expect(prompterSendToClient).toHaveBeenCalled();
225
- });
226
-
227
- test("high-risk with allowHighRisk allow rule auto-allows without prompting", async () => {
228
- findHighestPriorityRuleMock.mockReturnValue({
229
- id: "rule-hr-2",
230
- tool: "network_request",
231
- pattern: "network_request:https://api.fal.ai:443/*",
232
- scope: "/tmp/test-project",
233
- decision: "allow" as const,
234
- priority: 100,
235
- createdAt: Date.now(),
236
- allowHighRisk: true,
237
- });
238
-
239
- const ctx = makeContext();
240
- const prompterSendToClient = mock(() => {});
241
- const prompter = new PermissionPrompter(prompterSendToClient);
242
-
243
- const callback = createProxyApprovalCallback(prompter, ctx);
244
- const result = await callback(makeAskMissingCredentialRequest());
245
-
246
- expect(result).toBe(true);
247
- // Prompter should NOT have been called — allowHighRisk rule auto-allows
211
+ // Plain allow rule auto-allows medium-risk requests
248
212
  expect(prompterSendToClient).not.toHaveBeenCalled();
249
213
  });
250
214
 
@@ -436,7 +400,7 @@ describe("createProxyApprovalCallback", () => {
436
400
  await callback(makeAskUnauthenticatedRequest());
437
401
  });
438
402
 
439
- test("uses high risk level for ask_missing_credential decisions", async () => {
403
+ test("uses medium risk level for ask_missing_credential decisions", async () => {
440
404
  const ctx = makeContext();
441
405
  const prompterSendToClient = mock(() => {});
442
406
  const prompter = new PermissionPrompter(prompterSendToClient);
@@ -447,8 +411,7 @@ describe("createProxyApprovalCallback", () => {
447
411
  await new Promise((r) => setTimeout(r, 10));
448
412
  const call = (prompterSendToClient.mock.calls as unknown[][])[0];
449
413
  const msg = call[0] as { requestId: string; riskLevel: string };
450
- // Missing credential prompts are high risk — the target wants auth
451
- expect(msg.riskLevel).toBe("high");
414
+ expect(msg.riskLevel).toBe("medium");
452
415
  prompter.resolveConfirmation(msg.requestId, "allow");
453
416
  return p;
454
417
  };
@@ -523,40 +486,6 @@ describe("createProxyApprovalCallback", () => {
523
486
  // in contrast to the proxied bash activation path which CANNOT (tested
524
487
  // in tool-executor.test.ts).
525
488
 
526
- test("always_allow_high_risk persists rule with allowHighRisk flag", async () => {
527
- const ctx = makeContext();
528
- const prompterSendToClient = mock(() => {});
529
- const prompter = new PermissionPrompter(prompterSendToClient);
530
-
531
- const originalPrompt = prompter.prompt.bind(prompter);
532
- prompter.prompt = async (...args) => {
533
- const p = originalPrompt(...args);
534
- await new Promise((r) => setTimeout(r, 10));
535
- const call = (prompterSendToClient.mock.calls as unknown[][])[0];
536
- const msg = call[0] as { requestId: string };
537
- prompter.resolveConfirmation(
538
- msg.requestId,
539
- "always_allow_high_risk",
540
- "network_request:https://api.fal.ai:443/*",
541
- "/tmp/test-project",
542
- );
543
- return p;
544
- };
545
-
546
- const callback = createProxyApprovalCallback(prompter, ctx);
547
- const result = await callback(makeAskMissingCredentialRequest());
548
-
549
- expect(result).toBe(true);
550
- expect(addRuleMock).toHaveBeenCalledWith(
551
- "network_request",
552
- "network_request:https://api.fal.ai:443/*",
553
- "/tmp/test-project",
554
- "allow",
555
- 100,
556
- { allowHighRisk: true },
557
- );
558
- });
559
-
560
489
  test("one-time allow does NOT persist any rule", async () => {
561
490
  const ctx = makeContext();
562
491
  const prompterSendToClient = mock(() => {});