@vellumai/assistant 0.5.16 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (592) hide show
  1. package/AGENTS.md +4 -0
  2. package/ARCHITECTURE.md +69 -16
  3. package/Dockerfile +2 -5
  4. package/bun.lock +6 -2
  5. package/docker-entrypoint.sh +32 -1
  6. package/docs/architecture/integrations.md +1 -1
  7. package/docs/architecture/memory.md +21 -24
  8. package/knip.json +2 -1
  9. package/openapi.yaml +1198 -83
  10. package/package.json +5 -1
  11. package/src/__tests__/actor-token-service.test.ts +68 -0
  12. package/src/__tests__/agent-loop.test.ts +0 -32
  13. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  14. package/src/__tests__/anthropic-provider.test.ts +217 -98
  15. package/src/__tests__/app-compiler.test.ts +120 -0
  16. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  17. package/src/__tests__/app-executors.test.ts +47 -1
  18. package/src/__tests__/app-source-watcher.test.ts +159 -0
  19. package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -2
  20. package/src/__tests__/call-conversation-messages.test.ts +2 -6
  21. package/src/__tests__/call-domain.test.ts +2 -6
  22. package/src/__tests__/call-pointer-messages.test.ts +2 -14
  23. package/src/__tests__/call-recovery.test.ts +2 -6
  24. package/src/__tests__/call-routes-http.test.ts +2 -6
  25. package/src/__tests__/call-store.test.ts +2 -6
  26. package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
  27. package/src/__tests__/canonical-guardian-store.test.ts +2 -6
  28. package/src/__tests__/channel-delivery-store.test.ts +2 -6
  29. package/src/__tests__/channel-retry-sweep.test.ts +2 -6
  30. package/src/__tests__/checker.test.ts +63 -9
  31. package/src/__tests__/clawhub.test.ts +54 -24
  32. package/src/__tests__/cli-command-risk-guard.test.ts +14 -0
  33. package/src/__tests__/config-schema.test.ts +6 -1
  34. package/src/__tests__/config-set-platform-guard.test.ts +302 -0
  35. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
  36. package/src/__tests__/contacts-tools.test.ts +31 -0
  37. package/src/__tests__/context-overflow-reducer.test.ts +86 -0
  38. package/src/__tests__/context-token-estimator.test.ts +175 -10
  39. package/src/__tests__/conversation-agent-loop-overflow.test.ts +13 -6
  40. package/src/__tests__/conversation-agent-loop.test.ts +13 -51
  41. package/src/__tests__/conversation-attachments.test.ts +2 -6
  42. package/src/__tests__/conversation-attention-store.test.ts +2 -6
  43. package/src/__tests__/conversation-clear-safety.test.ts +2 -6
  44. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
  45. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
  46. package/src/__tests__/conversation-disk-view.test.ts +2 -6
  47. package/src/__tests__/conversation-error.test.ts +33 -2
  48. package/src/__tests__/conversation-fork-crud.test.ts +2 -6
  49. package/src/__tests__/conversation-history-web-search.test.ts +6 -1
  50. package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
  51. package/src/__tests__/conversation-media-retry.test.ts +91 -0
  52. package/src/__tests__/conversation-runtime-assembly.test.ts +653 -832
  53. package/src/__tests__/conversation-runtime-workspace.test.ts +1 -93
  54. package/src/__tests__/conversation-starter-routes.test.ts +20 -11
  55. package/src/__tests__/conversation-store.test.ts +2 -6
  56. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +17 -4
  57. package/src/__tests__/conversation-usage.test.ts +2 -6
  58. package/src/__tests__/conversation-wipe.test.ts +13 -414
  59. package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -12
  60. package/src/__tests__/conversation-workspace-injection.test.ts +25 -26
  61. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
  62. package/src/__tests__/copy-composer-tc-templates.test.ts +335 -0
  63. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
  64. package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
  65. package/src/__tests__/credential-security-e2e.test.ts +2 -0
  66. package/src/__tests__/date-context.test.ts +76 -210
  67. package/src/__tests__/db-schedule-syntax-migration.test.ts +16 -1
  68. package/src/__tests__/file-list-tool.test.ts +219 -0
  69. package/src/__tests__/first-greeting.test.ts +1 -1
  70. package/src/__tests__/followup-tools.test.ts +2 -6
  71. package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
  72. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
  73. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
  74. package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
  75. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
  76. package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
  77. package/src/__tests__/guardian-action-store.test.ts +2 -6
  78. package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
  79. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
  80. package/src/__tests__/guardian-dispatch.test.ts +2 -6
  81. package/src/__tests__/guardian-grant-minting.test.ts +2 -14
  82. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
  83. package/src/__tests__/guardian-routing-invariants.test.ts +192 -6
  84. package/src/__tests__/guardian-routing-state.test.ts +2 -6
  85. package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
  86. package/src/__tests__/heartbeat-service.test.ts +180 -3
  87. package/src/__tests__/identity-routes.test.ts +328 -0
  88. package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
  89. package/src/__tests__/injection-block.test.ts +178 -0
  90. package/src/__tests__/install-meta.test.ts +506 -0
  91. package/src/__tests__/install-skill-routing.test.ts +293 -0
  92. package/src/__tests__/invite-redemption-service.test.ts +2 -6
  93. package/src/__tests__/invite-routes-http.test.ts +2 -6
  94. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +17 -28
  95. package/src/__tests__/list-messages-attachments.test.ts +2 -6
  96. package/src/__tests__/list-messages-tool-merge.test.ts +300 -0
  97. package/src/__tests__/llm-context-normalization.test.ts +18 -18
  98. package/src/__tests__/llm-context-route-provider.test.ts +103 -6
  99. package/src/__tests__/llm-request-log-turn-query.test.ts +164 -6
  100. package/src/__tests__/llm-usage-store.test.ts +2 -6
  101. package/src/__tests__/log-export-workspace.test.ts +74 -111
  102. package/src/__tests__/managed-store.test.ts +38 -11
  103. package/src/__tests__/mcp-abort-signal.test.ts +5 -0
  104. package/src/__tests__/mcp-client-auth.test.ts +5 -0
  105. package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
  106. package/src/__tests__/memory-recall-log-store.test.ts +134 -6
  107. package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
  108. package/src/__tests__/migration-export-streaming.test.ts +304 -0
  109. package/src/__tests__/migration-import-commit-http.test.ts +11 -10
  110. package/src/__tests__/mock-fetch.ts +87 -0
  111. package/src/__tests__/non-member-access-request.test.ts +2 -6
  112. package/src/__tests__/notification-decision-recipient-context.test.ts +282 -0
  113. package/src/__tests__/notification-guardian-path.test.ts +2 -6
  114. package/src/__tests__/oauth-cli.test.ts +364 -2
  115. package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
  116. package/src/__tests__/onboarding-template-contract.test.ts +62 -14
  117. package/src/__tests__/outlook-attachments.test.ts +301 -0
  118. package/src/__tests__/outlook-automation-tools.test.ts +425 -0
  119. package/src/__tests__/outlook-categories.test.ts +212 -0
  120. package/src/__tests__/outlook-client-automation.test.ts +246 -0
  121. package/src/__tests__/outlook-compose-tools.test.ts +325 -0
  122. package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
  123. package/src/__tests__/outlook-email-watcher.test.ts +322 -0
  124. package/src/__tests__/outlook-follow-up.test.ts +196 -0
  125. package/src/__tests__/outlook-messaging-provider.test.ts +498 -3
  126. package/src/__tests__/outlook-trash.test.ts +77 -0
  127. package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
  128. package/src/__tests__/parser.test.ts +32 -0
  129. package/src/__tests__/permission-checker-host-gate.test.ts +452 -0
  130. package/src/__tests__/permission-controls-v2-flag.test.ts +55 -0
  131. package/src/__tests__/permission-mode-sse.test.ts +418 -0
  132. package/src/__tests__/permission-mode-store.test.ts +277 -0
  133. package/src/__tests__/permission-mode.test.ts +101 -0
  134. package/src/__tests__/platform-bash-auto-approve.test.ts +359 -0
  135. package/src/__tests__/platform-callback-registration.test.ts +4 -4
  136. package/src/__tests__/playbook-execution.test.ts +76 -80
  137. package/src/__tests__/playbook-tools.test.ts +5 -7
  138. package/src/__tests__/profiler-routes.test.ts +502 -0
  139. package/src/__tests__/profiler-run-store.test.ts +441 -0
  140. package/src/__tests__/provider-error-scenarios.test.ts +21 -0
  141. package/src/__tests__/proxy-approval-callback.test.ts +4 -75
  142. package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
  143. package/src/__tests__/registry.test.ts +3 -3
  144. package/src/__tests__/require-fresh-approval.test.ts +64 -2
  145. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
  146. package/src/__tests__/runtime-events-sse.test.ts +2 -6
  147. package/src/__tests__/sandbox-host-parity.test.ts +5 -4
  148. package/src/__tests__/schedule-store.test.ts +2 -6
  149. package/src/__tests__/schedule-tools.test.ts +2 -6
  150. package/src/__tests__/scheduler-recurrence.test.ts +1 -5
  151. package/src/__tests__/scheduler-reuse-conversation.test.ts +368 -0
  152. package/src/__tests__/scoped-approval-grants.test.ts +2 -6
  153. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
  154. package/src/__tests__/scrub-corrupted-image-attachments.test.ts +278 -0
  155. package/src/__tests__/search-skills-unified.test.ts +422 -0
  156. package/src/__tests__/secret-onetime-send.test.ts +2 -0
  157. package/src/__tests__/send-endpoint-busy.test.ts +44 -9
  158. package/src/__tests__/sequence-store.test.ts +2 -6
  159. package/src/__tests__/server-history-render.test.ts +2 -6
  160. package/src/__tests__/set-permission-mode.test.ts +274 -0
  161. package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
  162. package/src/__tests__/skill-feature-flags.test.ts +6 -6
  163. package/src/__tests__/skill-load-feature-flag.test.ts +23 -11
  164. package/src/__tests__/skill-memory.test.ts +2 -741
  165. package/src/__tests__/skills-uninstall.test.ts +2 -2
  166. package/src/__tests__/skills.test.ts +1 -1
  167. package/src/__tests__/slack-inbound-verification.test.ts +2 -6
  168. package/src/__tests__/strip-memory-injections.test.ts +187 -0
  169. package/src/__tests__/subagent-detail.test.ts +84 -0
  170. package/src/__tests__/subagent-disposal.test.ts +308 -0
  171. package/src/__tests__/subagent-manager-notify.test.ts +19 -10
  172. package/src/__tests__/subagent-notify-parent.test.ts +390 -0
  173. package/src/__tests__/subagent-role-registry.test.ts +108 -0
  174. package/src/__tests__/subagent-tool-filtering.test.ts +71 -0
  175. package/src/__tests__/subagent-tools.test.ts +464 -4
  176. package/src/__tests__/system-prompt-ask-mode.test.ts +139 -0
  177. package/src/__tests__/task-compiler.test.ts +2 -6
  178. package/src/__tests__/task-management-tools.test.ts +2 -6
  179. package/src/__tests__/task-memory-cleanup.test.ts +185 -241
  180. package/src/__tests__/task-runner.test.ts +2 -6
  181. package/src/__tests__/task-scheduler.test.ts +2 -6
  182. package/src/__tests__/terminal-tools.test.ts +17 -27
  183. package/src/__tests__/test-preload.ts +7 -0
  184. package/src/__tests__/tool-approval-handler.test.ts +2 -6
  185. package/src/__tests__/tool-executor.test.ts +4 -26
  186. package/src/__tests__/tool-grant-request-escalation.test.ts +2 -6
  187. package/src/__tests__/tool-side-effects-slack-dm.test.ts +277 -0
  188. package/src/__tests__/top-level-renderer.test.ts +10 -13
  189. package/src/__tests__/trust-store.test.ts +1 -1
  190. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +2 -6
  191. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +118 -8
  192. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -6
  193. package/src/__tests__/trusted-contact-verification.test.ts +2 -6
  194. package/src/__tests__/turn-boundary-resolution.test.ts +2 -6
  195. package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -6
  196. package/src/__tests__/usage-routes.test.ts +2 -6
  197. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  198. package/src/__tests__/voice-invite-redemption.test.ts +2 -6
  199. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -6
  200. package/src/__tests__/voice-session-bridge.test.ts +2 -6
  201. package/src/__tests__/volume-security-guard.test.ts +2 -0
  202. package/src/__tests__/workspace-lifecycle.test.ts +29 -1
  203. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -6
  204. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +2 -6
  205. package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
  206. package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +387 -0
  207. package/src/__tests__/workspace-policy.test.ts +1 -1
  208. package/src/agent/attachments.ts +7 -2
  209. package/src/agent/image-optimize.ts +165 -0
  210. package/src/agent/loop.ts +7 -15
  211. package/src/approvals/guardian-request-resolvers.ts +24 -0
  212. package/src/avatar/traits-png-sync.ts +3 -3
  213. package/src/bundler/app-compiler.ts +179 -2
  214. package/src/bundler/package-resolver.ts +3 -5
  215. package/src/cli/__tests__/notifications.test.ts +1 -2
  216. package/src/cli/__tests__/run-assistant-command.ts +29 -0
  217. package/src/cli/commands/__tests__/email-download.test.ts +245 -0
  218. package/src/cli/commands/__tests__/email-list.test.ts +192 -0
  219. package/src/cli/commands/__tests__/email-register.test.ts +186 -0
  220. package/src/cli/commands/__tests__/email-send.test.ts +291 -0
  221. package/src/cli/commands/__tests__/email-status.test.ts +181 -0
  222. package/src/cli/commands/__tests__/email-unregister.test.ts +139 -0
  223. package/src/cli/commands/__tests__/routes.test.ts +562 -0
  224. package/src/cli/commands/avatar.ts +3 -3
  225. package/src/cli/commands/config.ts +26 -13
  226. package/src/cli/commands/conversations.ts +1 -8
  227. package/src/cli/commands/doctor.ts +2 -2
  228. package/src/cli/commands/email.ts +584 -835
  229. package/src/cli/commands/memory.ts +37 -84
  230. package/src/cli/commands/notifications.ts +7 -2
  231. package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
  232. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
  233. package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
  234. package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
  235. package/src/cli/commands/oauth/connect.ts +25 -11
  236. package/src/cli/commands/oauth/mode.ts +7 -0
  237. package/src/cli/commands/oauth/shared.ts +39 -3
  238. package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
  239. package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
  240. package/src/cli/commands/platform/__tests__/status.test.ts +5 -5
  241. package/src/cli/commands/platform/index.ts +16 -16
  242. package/src/cli/commands/routes.ts +396 -0
  243. package/src/cli/commands/skills.ts +218 -36
  244. package/src/cli/commands/trust.ts +2 -2
  245. package/src/cli/lib/daemon-credential-client.ts +2 -3
  246. package/src/cli/program.ts +2 -0
  247. package/src/cli.ts +1 -120
  248. package/src/config/bundled-skills/acp/TOOLS.json +1 -1
  249. package/src/config/bundled-skills/app-builder/SKILL.md +4 -1
  250. package/src/config/bundled-skills/contacts/SKILL.md +0 -1
  251. package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
  252. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
  253. package/src/config/bundled-skills/gmail/SKILL.md +4 -12
  254. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
  255. package/src/config/bundled-skills/messaging/SKILL.md +17 -18
  256. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
  257. package/src/config/bundled-skills/outlook/SKILL.md +189 -0
  258. package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
  259. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
  260. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
  261. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
  262. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
  263. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
  264. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
  265. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
  266. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
  267. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
  268. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
  269. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
  270. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
  271. package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
  272. package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
  273. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
  274. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
  275. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
  276. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
  277. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
  278. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
  279. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
  280. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
  281. package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
  282. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
  283. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
  284. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
  285. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
  286. package/src/config/bundled-skills/schedule/SKILL.md +22 -2
  287. package/src/config/bundled-skills/schedule/TOOLS.json +8 -0
  288. package/src/config/bundled-skills/settings/tools/avatar-get.ts +3 -13
  289. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +2 -4
  290. package/src/config/bundled-skills/settings/tools/avatar-update.ts +5 -2
  291. package/src/config/bundled-skills/slack/SKILL.md +3 -7
  292. package/src/config/bundled-skills/subagent/SKILL.md +43 -3
  293. package/src/config/bundled-skills/subagent/TOOLS.json +29 -4
  294. package/src/config/bundled-tool-registry.ts +56 -4
  295. package/src/config/env-registry.ts +78 -8
  296. package/src/config/feature-flag-registry.json +38 -125
  297. package/src/config/schema.ts +8 -0
  298. package/src/config/schemas/filing.ts +51 -0
  299. package/src/config/schemas/heartbeat.ts +15 -12
  300. package/src/config/schemas/memory-lifecycle.ts +12 -0
  301. package/src/config/schemas/platform.ts +8 -0
  302. package/src/config/schemas/security.ts +14 -0
  303. package/src/config/schemas/timeouts.ts +1 -1
  304. package/src/config/skills.ts +18 -7
  305. package/src/context/token-estimator.ts +25 -18
  306. package/src/context/window-manager.ts +6 -2
  307. package/src/credential-execution/process-manager.ts +3 -1
  308. package/src/daemon/app-source-watcher.ts +93 -0
  309. package/src/daemon/config-watcher.ts +79 -1
  310. package/src/daemon/context-overflow-reducer.ts +46 -2
  311. package/src/daemon/conversation-agent-loop-handlers.ts +143 -82
  312. package/src/daemon/conversation-agent-loop.ts +236 -108
  313. package/src/daemon/conversation-error.ts +31 -8
  314. package/src/daemon/conversation-history.ts +4 -19
  315. package/src/daemon/conversation-lifecycle.ts +36 -9
  316. package/src/daemon/conversation-media-retry.ts +85 -7
  317. package/src/daemon/conversation-notifiers.ts +4 -1
  318. package/src/daemon/conversation-process.ts +13 -7
  319. package/src/daemon/conversation-runtime-assembly.ts +305 -306
  320. package/src/daemon/conversation-tool-setup.ts +44 -14
  321. package/src/daemon/conversation-workspace.ts +1 -2
  322. package/src/daemon/conversation.ts +59 -2
  323. package/src/daemon/daemon-control.ts +8 -2
  324. package/src/daemon/date-context.ts +26 -53
  325. package/src/daemon/first-greeting.ts +1 -1
  326. package/src/daemon/handlers/conversations.ts +4 -7
  327. package/src/daemon/handlers/shared.test.ts +143 -0
  328. package/src/daemon/handlers/shared.ts +85 -17
  329. package/src/daemon/handlers/skills.ts +416 -209
  330. package/src/daemon/lifecycle.ts +212 -131
  331. package/src/daemon/main.ts +5 -1
  332. package/src/daemon/message-types/conversations.ts +29 -7
  333. package/src/daemon/message-types/messages.ts +12 -2
  334. package/src/daemon/message-types/schedules.ts +1 -0
  335. package/src/daemon/message-types/settings.ts +6 -0
  336. package/src/daemon/message-types/skills.ts +97 -36
  337. package/src/daemon/profiler-run-store.ts +557 -0
  338. package/src/daemon/providers-setup.ts +5 -0
  339. package/src/daemon/server.ts +100 -11
  340. package/src/daemon/shutdown-handlers.ts +5 -0
  341. package/src/daemon/tool-side-effects.ts +50 -8
  342. package/src/export/transcript-formatter.ts +148 -0
  343. package/src/filing/filing-service.ts +228 -0
  344. package/src/heartbeat/heartbeat-service.ts +97 -7
  345. package/src/hooks/cli.ts +2 -2
  346. package/src/hooks/runner.ts +15 -38
  347. package/src/inbound/platform-callback-registration.ts +14 -14
  348. package/src/mcp/client.ts +6 -0
  349. package/src/mcp/mcp-oauth-provider.ts +149 -27
  350. package/src/memory/admin.ts +42 -75
  351. package/src/memory/app-store.ts +69 -0
  352. package/src/memory/conversation-bootstrap.ts +3 -1
  353. package/src/memory/conversation-crud.ts +211 -288
  354. package/src/memory/conversation-group-migration.ts +157 -0
  355. package/src/memory/conversation-queries.ts +61 -13
  356. package/src/memory/conversation-title-service.ts +1 -0
  357. package/src/memory/db-init.ts +194 -361
  358. package/src/memory/embed.ts +73 -0
  359. package/src/memory/embedding-backend.ts +8 -14
  360. package/src/memory/embedding-runtime-manager.ts +12 -114
  361. package/src/memory/fingerprint.ts +2 -2
  362. package/src/memory/graph/bootstrap.ts +521 -0
  363. package/src/memory/graph/capability-seed.ts +449 -0
  364. package/src/memory/graph/consolidation.ts +725 -0
  365. package/src/memory/graph/conversation-graph-memory.ts +659 -0
  366. package/src/memory/graph/decay.test.ts +208 -0
  367. package/src/memory/graph/decay.ts +195 -0
  368. package/src/memory/graph/extraction-job.ts +74 -0
  369. package/src/memory/graph/extraction.test.ts +936 -0
  370. package/src/memory/graph/extraction.ts +1297 -0
  371. package/src/memory/graph/graph-memory-state-store.ts +37 -0
  372. package/src/memory/graph/graph-search.ts +280 -0
  373. package/src/memory/graph/image-ref-utils.ts +29 -0
  374. package/src/memory/graph/injection.test.ts +513 -0
  375. package/src/memory/graph/injection.ts +469 -0
  376. package/src/memory/graph/inspect.ts +543 -0
  377. package/src/memory/graph/narrative.ts +267 -0
  378. package/src/memory/graph/pattern-scan.ts +269 -0
  379. package/src/memory/graph/retriever.ts +1111 -0
  380. package/src/memory/graph/scoring.test.ts +548 -0
  381. package/src/memory/graph/scoring.ts +232 -0
  382. package/src/memory/graph/serendipity.ts +65 -0
  383. package/src/memory/graph/store.test.ts +1098 -0
  384. package/src/memory/graph/store.ts +838 -0
  385. package/src/memory/graph/tool-handlers.ts +301 -0
  386. package/src/memory/graph/tools.ts +97 -0
  387. package/src/memory/graph/triggers.test.ts +487 -0
  388. package/src/memory/graph/triggers.ts +223 -0
  389. package/src/memory/graph/types.ts +295 -0
  390. package/src/memory/group-crud.ts +191 -0
  391. package/src/memory/indexer.ts +37 -19
  392. package/src/memory/job-handlers/cleanup.ts +32 -42
  393. package/src/memory/job-handlers/conversation-starters.ts +91 -53
  394. package/src/memory/job-handlers/embedding.ts +5 -31
  395. package/src/memory/job-handlers/index-maintenance.ts +23 -11
  396. package/src/memory/job-handlers/summarization.ts +32 -17
  397. package/src/memory/job-utils.ts +1 -1
  398. package/src/memory/jobs-store.ts +21 -31
  399. package/src/memory/jobs-worker.ts +180 -129
  400. package/src/memory/llm-request-log-store.ts +96 -12
  401. package/src/memory/memory-recall-log-store.ts +49 -5
  402. package/src/memory/message-content.ts +1 -0
  403. package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
  404. package/src/memory/migrations/203-drop-memory-items-tables.ts +55 -0
  405. package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
  406. package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
  407. package/src/memory/migrations/206-memory-graph-node-edits.ts +19 -0
  408. package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +131 -0
  409. package/src/memory/migrations/207-conversation-graph-memory-state.ts +20 -0
  410. package/src/memory/migrations/208-conversations-last-message-at.ts +35 -0
  411. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +85 -0
  412. package/src/memory/migrations/210-schedule-reuse-conversation.ts +13 -0
  413. package/src/memory/migrations/211-memory-recall-logs-query-context.ts +21 -0
  414. package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +19 -0
  415. package/src/memory/migrations/index.ts +12 -0
  416. package/src/memory/migrations/registry.ts +16 -0
  417. package/src/memory/qdrant-client.ts +44 -17
  418. package/src/memory/schema/conversations.ts +14 -0
  419. package/src/memory/schema/index.ts +1 -0
  420. package/src/memory/schema/infrastructure.ts +8 -1
  421. package/src/memory/schema/memory-core.ts +0 -51
  422. package/src/memory/schema/memory-graph.ts +154 -0
  423. package/src/memory/search/semantic.ts +47 -91
  424. package/src/memory/task-memory-cleanup.ts +58 -61
  425. package/src/messaging/providers/outlook/adapter.ts +8 -1
  426. package/src/messaging/providers/outlook/client.ts +299 -0
  427. package/src/messaging/providers/outlook/types.ts +118 -0
  428. package/src/notifications/adapters/macos.ts +1 -0
  429. package/src/notifications/copy-composer.ts +95 -0
  430. package/src/notifications/decision-engine.ts +35 -0
  431. package/src/notifications/signal.ts +16 -0
  432. package/src/oauth/seed-providers.ts +2 -1
  433. package/src/permissions/checker.ts +36 -4
  434. package/src/permissions/defaults.ts +4 -4
  435. package/src/permissions/permission-mode-store.ts +180 -0
  436. package/src/permissions/permission-mode.ts +31 -0
  437. package/src/permissions/workspace-policy.ts +10 -1
  438. package/src/playbooks/playbook-compiler.ts +19 -18
  439. package/src/playbooks/types.ts +4 -3
  440. package/src/prompts/system-prompt.ts +62 -36
  441. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +100 -0
  442. package/src/prompts/templates/BOOTSTRAP.md +70 -165
  443. package/src/prompts/templates/HEARTBEAT.md +3 -1
  444. package/src/prompts/templates/SOUL.md +25 -4
  445. package/src/prompts/templates/UPDATES.md +8 -0
  446. package/src/providers/anthropic/client.ts +136 -220
  447. package/src/providers/gemini/client.ts +1 -1
  448. package/src/providers/openai/client.ts +1 -1
  449. package/src/providers/registry.ts +1 -1
  450. package/src/providers/retry.ts +19 -3
  451. package/src/runtime/actor-trust-resolver.ts +5 -1
  452. package/src/runtime/auth/route-policy.ts +30 -0
  453. package/src/runtime/guardian-reply-router.ts +5 -1
  454. package/src/runtime/http-server.ts +55 -5
  455. package/src/runtime/http-types.ts +12 -1
  456. package/src/runtime/middleware/auth.ts +20 -0
  457. package/src/runtime/migrations/vbundle-builder.ts +389 -3
  458. package/src/runtime/migrations/vbundle-importer.ts +8 -6
  459. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +378 -0
  460. package/src/runtime/routes/app-management-routes.ts +1 -11
  461. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +26 -0
  462. package/src/runtime/routes/archive-utils.ts +29 -0
  463. package/src/runtime/routes/attachment-routes.test.ts +106 -0
  464. package/src/runtime/routes/attachment-routes.ts +106 -16
  465. package/src/runtime/routes/avatar-routes.ts +2 -9
  466. package/src/runtime/routes/brain-graph-routes.ts +21 -22
  467. package/src/runtime/routes/btw-routes.ts +22 -1
  468. package/src/runtime/routes/conversation-analysis-routes.ts +173 -0
  469. package/src/runtime/routes/conversation-management-routes.ts +3 -14
  470. package/src/runtime/routes/conversation-query-routes.ts +49 -3
  471. package/src/runtime/routes/conversation-routes.ts +264 -44
  472. package/src/runtime/routes/conversation-starter-routes.ts +2 -2
  473. package/src/runtime/routes/debug-routes.ts +1 -1
  474. package/src/runtime/routes/global-search-routes.ts +21 -19
  475. package/src/runtime/routes/group-routes.ts +207 -0
  476. package/src/runtime/routes/guardian-action-routes.ts +21 -10
  477. package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
  478. package/src/runtime/routes/heartbeat-routes.ts +4 -10
  479. package/src/runtime/routes/identity-routes.ts +53 -18
  480. package/src/runtime/routes/inbound-message-handler.ts +19 -0
  481. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
  482. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
  483. package/src/runtime/routes/llm-context-normalization.ts +14 -10
  484. package/src/runtime/routes/log-export-routes.ts +23 -275
  485. package/src/runtime/routes/memory-item-routes.test.ts +170 -247
  486. package/src/runtime/routes/memory-item-routes.ts +341 -388
  487. package/src/runtime/routes/migration-routes.ts +18 -7
  488. package/src/runtime/routes/profiler-routes.ts +350 -0
  489. package/src/runtime/routes/schedule-routes.ts +28 -11
  490. package/src/runtime/routes/settings-routes.ts +95 -8
  491. package/src/runtime/routes/skills-routes.ts +103 -37
  492. package/src/runtime/routes/subagents-routes.ts +28 -7
  493. package/src/runtime/routes/user-route-dispatcher.ts +223 -0
  494. package/src/runtime/routes/user-routes.ts +41 -0
  495. package/src/runtime/routes/work-items-routes.test.ts +2 -6
  496. package/src/runtime/routes/workspace-routes.ts +0 -1
  497. package/src/schedule/schedule-store.ts +30 -0
  498. package/src/schedule/scheduler.ts +52 -18
  499. package/src/security/oauth2.ts +1 -1
  500. package/src/security/secure-keys.ts +4 -8
  501. package/src/shared/provider-env-vars.ts +19 -0
  502. package/src/skills/catalog-cache.ts +5 -0
  503. package/src/skills/catalog-install.ts +25 -16
  504. package/src/skills/clawhub.ts +134 -154
  505. package/src/skills/install-meta.ts +208 -0
  506. package/src/skills/managed-store.ts +29 -18
  507. package/src/skills/skill-memory.ts +12 -229
  508. package/src/skills/skillssh-registry.ts +19 -17
  509. package/src/subagent/index.ts +13 -3
  510. package/src/subagent/manager.ts +308 -29
  511. package/src/subagent/types.ts +68 -0
  512. package/src/tasks/task-runner.ts +7 -5
  513. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
  514. package/src/tools/apps/executors.ts +29 -4
  515. package/src/tools/browser/runtime-check.ts +3 -1
  516. package/src/tools/filesystem/list.ts +93 -0
  517. package/src/tools/memory/register.ts +63 -46
  518. package/src/tools/permission-checker.ts +85 -1
  519. package/src/tools/registry.ts +4 -0
  520. package/src/tools/schedule/create.ts +3 -0
  521. package/src/tools/schedule/list.ts +1 -0
  522. package/src/tools/schedule/update.ts +6 -0
  523. package/src/tools/shared/filesystem/errors.ts +5 -0
  524. package/src/tools/shared/filesystem/file-ops-service.ts +90 -2
  525. package/src/tools/shared/filesystem/image-read.ts +22 -85
  526. package/src/tools/shared/filesystem/types.ts +17 -0
  527. package/src/tools/shared/shell-output.ts +31 -2
  528. package/src/tools/subagent/abort.ts +12 -2
  529. package/src/tools/subagent/message.ts +9 -2
  530. package/src/tools/subagent/notify-parent.ts +79 -0
  531. package/src/tools/subagent/read.ts +29 -8
  532. package/src/tools/subagent/resolve.ts +21 -0
  533. package/src/tools/subagent/spawn.ts +2 -0
  534. package/src/tools/subagent/status.ts +11 -1
  535. package/src/tools/system/avatar-generator.ts +3 -3
  536. package/src/tools/system/register.ts +23 -0
  537. package/src/tools/system/set-permission-mode.ts +103 -0
  538. package/src/tools/terminal/parser.ts +30 -5
  539. package/src/tools/terminal/safe-env.ts +17 -1
  540. package/src/tools/tool-manifest.ts +9 -3
  541. package/src/tools/types.ts +2 -0
  542. package/src/util/browser.ts +25 -10
  543. package/src/util/bun-runtime.ts +172 -0
  544. package/src/util/logger.ts +1 -1
  545. package/src/util/platform.ts +50 -17
  546. package/src/watcher/providers/outlook-calendar.ts +343 -0
  547. package/src/watcher/providers/outlook.ts +198 -0
  548. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +2 -2
  549. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +2 -2
  550. package/src/workspace/migrations/025-remove-oauth-app-setup-skills.ts +76 -0
  551. package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
  552. package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
  553. package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +270 -0
  554. package/src/workspace/migrations/029-seed-pkb.ts +84 -0
  555. package/src/workspace/migrations/registry.ts +10 -0
  556. package/src/workspace/top-level-renderer.ts +5 -9
  557. package/src/__tests__/cli-memory.test.ts +0 -372
  558. package/src/__tests__/clipboard.test.ts +0 -88
  559. package/src/__tests__/context-memory-e2e.test.ts +0 -415
  560. package/src/__tests__/journal-context.test.ts +0 -268
  561. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
  562. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
  563. package/src/__tests__/memory-query-builder.test.ts +0 -59
  564. package/src/__tests__/memory-recall-quality.test.ts +0 -1046
  565. package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
  566. package/src/__tests__/memory-regressions.test.ts +0 -3696
  567. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
  568. package/src/cli/cli-memory.ts +0 -176
  569. package/src/daemon/conversation-memory.ts +0 -207
  570. package/src/memory/conversation-starters-cadence.ts +0 -74
  571. package/src/memory/items-extractor.ts +0 -860
  572. package/src/memory/job-handlers/batch-extraction.ts +0 -753
  573. package/src/memory/job-handlers/extraction.ts +0 -40
  574. package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -355
  575. package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
  576. package/src/memory/journal-memory.ts +0 -224
  577. package/src/memory/query-builder.ts +0 -47
  578. package/src/memory/query-expansion.ts +0 -83
  579. package/src/memory/retriever.test.ts +0 -1592
  580. package/src/memory/retriever.ts +0 -1331
  581. package/src/memory/search/formatting.test.ts +0 -140
  582. package/src/memory/search/formatting.ts +0 -262
  583. package/src/memory/search/mmr.ts +0 -139
  584. package/src/memory/search/ranking.ts +0 -15
  585. package/src/memory/search/staleness.ts +0 -40
  586. package/src/memory/search/tier-classifier.ts +0 -18
  587. package/src/memory/search/types.ts +0 -121
  588. package/src/prompts/journal-context.ts +0 -154
  589. package/src/tools/memory/definitions.ts +0 -69
  590. package/src/tools/memory/handlers.test.ts +0 -562
  591. package/src/tools/memory/handlers.ts +0 -434
  592. package/src/util/clipboard.ts +0 -34
@@ -1,4 +1,4 @@
1
- import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
1
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
2
2
 
3
3
  mock.module("../util/logger.js", () => ({
4
4
  getLogger: () =>
@@ -7,7 +7,7 @@ mock.module("../util/logger.js", () => ({
7
7
  }),
8
8
  }));
9
9
 
10
- import { getDb, initializeDb, resetDb } from "../memory/db.js";
10
+ import { getDb, initializeDb } from "../memory/db.js";
11
11
  import {
12
12
  getUsageDayBuckets,
13
13
  getUsageGroupBreakdown,
@@ -21,10 +21,6 @@ import type { PricingResult, UsageEventInput } from "../usage/types.js";
21
21
  // Initialize db once before all tests
22
22
  initializeDb();
23
23
 
24
- afterAll(() => {
25
- resetDb();
26
- });
27
-
28
24
  function makeInput(overrides?: Partial<UsageEventInput>): UsageEventInput {
29
25
  return {
30
26
  provider: "anthropic",
@@ -5,8 +5,6 @@
5
5
  * - audit-data.json with tool invocation records
6
6
  * - daemon-logs/ with log file contents
7
7
  * - config-snapshot.json with sanitized config
8
- * - workspace/ with text files, SQL dumps for .db files, and proper
9
- * filtering (excluded directories, binary files, symlinks).
10
8
  */
11
9
 
12
10
  import { spawnSync } from "node:child_process";
@@ -16,16 +14,14 @@ import {
16
14
  readdirSync,
17
15
  readFileSync,
18
16
  rmSync,
19
- symlinkSync,
20
17
  writeFileSync,
21
18
  } from "node:fs";
22
19
  import { tmpdir } from "node:os";
23
20
  import { join } from "node:path";
24
- import { afterAll, describe, expect, mock, test } from "bun:test";
21
+ import { describe, expect, mock, test } from "bun:test";
25
22
 
26
23
  // Set up temp directories before mocking
27
- const testDir = process.env.VELLUM_WORKSPACE_DIR!;
28
- const testWorkspaceDir = testDir;
24
+ const testWorkspaceDir = process.env.VELLUM_WORKSPACE_DIR!;
29
25
  mkdirSync(testWorkspaceDir, { recursive: true });
30
26
 
31
27
  mock.module("../util/logger.js", () => ({
@@ -40,15 +36,11 @@ mock.module("../util/secure-keys.js", () => ({
40
36
  getSecureKeyAsync: async () => undefined,
41
37
  }));
42
38
 
43
- import { initializeDb, resetDb } from "../memory/db.js";
39
+ import { initializeDb } from "../memory/db.js";
44
40
  import { logExportRouteDefinitions } from "../runtime/routes/log-export-routes.js";
45
41
 
46
42
  initializeDb();
47
43
 
48
- afterAll(() => {
49
- resetDb();
50
- });
51
-
52
44
  // ---------------------------------------------------------------------------
53
45
  // Helpers
54
46
  // ---------------------------------------------------------------------------
@@ -56,11 +48,13 @@ afterAll(() => {
56
48
  const routes = logExportRouteDefinitions();
57
49
  const exportRoute = routes.find((r) => r.endpoint === "export")!;
58
50
 
59
- async function callExport(): Promise<Response> {
51
+ async function callExport(
52
+ body: Record<string, unknown> = {},
53
+ ): Promise<Response> {
60
54
  const req = new Request("http://localhost/v1/export", {
61
55
  method: "POST",
62
56
  headers: { "Content-Type": "application/json" },
63
- body: JSON.stringify({}),
57
+ body: JSON.stringify(body),
64
58
  });
65
59
  const url = new URL(req.url);
66
60
  return exportRoute.handler({
@@ -89,73 +83,37 @@ async function extractArchive(res: Response): Promise<string> {
89
83
  return extractDir;
90
84
  }
91
85
 
92
- /** Recursively lists all files under a directory as relative paths. */
93
- function listFiles(dir: string, base = dir): string[] {
94
- const result: string[] = [];
95
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
96
- const full = join(dir, entry.name);
97
- if (entry.isDirectory()) {
98
- result.push(...listFiles(full, base));
99
- } else {
100
- result.push(full.slice(base.length + 1));
101
- }
102
- }
103
- return result;
104
- }
105
-
106
86
  // ---------------------------------------------------------------------------
107
- // Seed workspace files
87
+ // Seed test data
108
88
  // ---------------------------------------------------------------------------
109
89
 
110
- // Text filesshould be included
111
- writeFileSync(join(testWorkspaceDir, "IDENTITY.md"), "# My Identity\nHello");
112
- mkdirSync(join(testWorkspaceDir, "notes"), { recursive: true });
113
- writeFileSync(join(testWorkspaceDir, "notes", "daily.txt"), "Some daily notes");
114
-
115
- // SQLite DB file — should be dumped as .sql
116
- mkdirSync(join(testWorkspaceDir, "data", "db"), { recursive: true });
117
- // Create a real sqlite db with a table
118
- import { Database } from "bun:sqlite";
119
- const wsDbPath = join(testWorkspaceDir, "data", "db", "assistant.db");
120
- const wsDb = new Database(wsDbPath);
121
- wsDb.run("CREATE TABLE test_table (id INTEGER PRIMARY KEY, name TEXT)");
122
- wsDb.run("INSERT INTO test_table (name) VALUES ('hello')");
123
- wsDb.close();
124
-
125
- // Excluded directory: embedding-models/
126
- mkdirSync(join(testWorkspaceDir, "embedding-models"), { recursive: true });
90
+ // config.json at workspace root needed for config-snapshot test
127
91
  writeFileSync(
128
- join(testWorkspaceDir, "embedding-models", "model.bin"),
129
- "large binary model data",
92
+ join(testWorkspaceDir, "config.json"),
93
+ JSON.stringify({ provider: "anthropic" }),
130
94
  );
131
95
 
132
- // Excluded directory: data/qdrant/
133
- mkdirSync(join(testWorkspaceDir, "data", "qdrant"), { recursive: true });
96
+ // Daemon log files — used for date filtering tests
97
+ const logsDir = join(testWorkspaceDir, "data", "logs");
98
+ mkdirSync(logsDir, { recursive: true });
134
99
  writeFileSync(
135
- join(testWorkspaceDir, "data", "qdrant", "index.bin"),
136
- "vector index data",
100
+ join(logsDir, "assistant-2025-01-10.log"),
101
+ "log entry from Jan 10\n",
137
102
  );
138
-
139
- // Binary file — should be skipped
140
103
  writeFileSync(
141
- join(testWorkspaceDir, "binary-file.dat"),
142
- Buffer.from([0x48, 0x65, 0x6c, 0x00, 0x6f]), // contains null byte
104
+ join(logsDir, "assistant-2025-01-15.log"),
105
+ "log entry from Jan 15\n",
143
106
  );
144
-
145
- // config.json at workspace root — should be skipped (already in configSnapshot)
146
107
  writeFileSync(
147
- join(testWorkspaceDir, "config.json"),
148
- JSON.stringify({ provider: "anthropic" }),
108
+ join(logsDir, "assistant-2025-01-20.log"),
109
+ "log entry from Jan 20\n",
149
110
  );
150
-
151
- // Symlink pointing outside workspace — should be skipped
152
- const outsideFile = join(testDir, "outside-secret.txt");
153
- writeFileSync(outsideFile, "sensitive data outside workspace");
154
- try {
155
- symlinkSync(outsideFile, join(testWorkspaceDir, "sneaky-link.txt"));
156
- } catch {
157
- // Symlink creation may fail on some platforms; tests will still pass
158
- }
111
+ writeFileSync(
112
+ join(logsDir, "assistant-2025-01-25.log"),
113
+ "log entry from Jan 25\n",
114
+ );
115
+ // Non-dated log file — should always be included regardless of time filter
116
+ writeFileSync(join(logsDir, "vellum.log"), "non-dated log content\n");
159
117
 
160
118
  // ---------------------------------------------------------------------------
161
119
  // Tests
@@ -189,90 +147,95 @@ describe("POST /v1/export — tar.gz archive", () => {
189
147
  }
190
148
  });
191
149
 
192
- test("archive contains workspace text files", async () => {
150
+ test("archive contains config-snapshot.json when config exists", async () => {
193
151
  const res = await callExport();
194
152
  const dir = await extractArchive(res);
195
153
  try {
196
- const identity = readFileSync(
197
- join(dir, "workspace", "IDENTITY.md"),
198
- "utf-8",
199
- );
200
- expect(identity).toBe("# My Identity\nHello");
201
-
202
- const daily = readFileSync(
203
- join(dir, "workspace", "notes", "daily.txt"),
154
+ const configContent = readFileSync(
155
+ join(dir, "config-snapshot.json"),
204
156
  "utf-8",
205
157
  );
206
- expect(daily).toBe("Some daily notes");
158
+ const parsed = JSON.parse(configContent);
159
+ expect(parsed.provider).toBe("anthropic");
207
160
  } finally {
208
161
  rmSync(dir, { recursive: true, force: true });
209
162
  }
210
163
  });
164
+ });
211
165
 
212
- test("archive contains SQLite DB dumps as .sql files", async () => {
213
- const res = await callExport();
166
+ describe("POST /v1/export daemon log date filtering", () => {
167
+ test("excludes log files before startTime", async () => {
168
+ // startTime = Jan 14 — should exclude assistant-2025-01-10.log
169
+ const startTime = new Date("2025-01-14T00:00:00.000Z").getTime();
170
+ const res = await callExport({ startTime });
214
171
  const dir = await extractArchive(res);
215
172
  try {
216
- const sqlContent = readFileSync(
217
- join(dir, "workspace", "data", "db", "assistant.db.sql"),
218
- "utf-8",
219
- );
220
- expect(sqlContent).toContain("CREATE TABLE");
221
- expect(sqlContent).toContain("test_table");
173
+ const logFiles = readdirSync(join(dir, "daemon-logs"));
174
+ expect(logFiles).not.toContain("assistant-2025-01-10.log");
175
+ expect(logFiles).toContain("assistant-2025-01-15.log");
176
+ expect(logFiles).toContain("assistant-2025-01-20.log");
177
+ expect(logFiles).toContain("assistant-2025-01-25.log");
222
178
  } finally {
223
179
  rmSync(dir, { recursive: true, force: true });
224
180
  }
225
181
  });
226
182
 
227
- test("archive excludes embedding-models/ and data/qdrant/", async () => {
228
- const res = await callExport();
183
+ test("excludes log files after endTime", async () => {
184
+ // endTime = Jan 22 — should exclude assistant-2025-01-25.log
185
+ const endTime = new Date("2025-01-22T00:00:00.000Z").getTime();
186
+ const res = await callExport({ endTime });
229
187
  const dir = await extractArchive(res);
230
188
  try {
231
- const files = listFiles(join(dir, "workspace"));
232
- const embeddingFiles = files.filter((f) =>
233
- f.startsWith("embedding-models/"),
234
- );
235
- const qdrantFiles = files.filter((f) => f.startsWith("data/qdrant/"));
236
- expect(embeddingFiles).toHaveLength(0);
237
- expect(qdrantFiles).toHaveLength(0);
189
+ const logFiles = readdirSync(join(dir, "daemon-logs"));
190
+ expect(logFiles).toContain("assistant-2025-01-10.log");
191
+ expect(logFiles).toContain("assistant-2025-01-15.log");
192
+ expect(logFiles).toContain("assistant-2025-01-20.log");
193
+ expect(logFiles).not.toContain("assistant-2025-01-25.log");
238
194
  } finally {
239
195
  rmSync(dir, { recursive: true, force: true });
240
196
  }
241
197
  });
242
198
 
243
- test("archive excludes binary files and config.json at workspace root", async () => {
244
- const res = await callExport();
199
+ test("filters log files by both startTime and endTime", async () => {
200
+ // startTime = Jan 14, endTime = Jan 22 — should only include Jan 15 and Jan 20
201
+ const startTime = new Date("2025-01-14T00:00:00.000Z").getTime();
202
+ const endTime = new Date("2025-01-22T00:00:00.000Z").getTime();
203
+ const res = await callExport({ startTime, endTime });
245
204
  const dir = await extractArchive(res);
246
205
  try {
247
- const files = listFiles(join(dir, "workspace"));
248
- expect(files).not.toContain("binary-file.dat");
249
- expect(files).not.toContain("config.json");
206
+ const logFiles = readdirSync(join(dir, "daemon-logs"));
207
+ expect(logFiles).not.toContain("assistant-2025-01-10.log");
208
+ expect(logFiles).toContain("assistant-2025-01-15.log");
209
+ expect(logFiles).toContain("assistant-2025-01-20.log");
210
+ expect(logFiles).not.toContain("assistant-2025-01-25.log");
250
211
  } finally {
251
212
  rmSync(dir, { recursive: true, force: true });
252
213
  }
253
214
  });
254
215
 
255
- test("archive excludes symlinks", async () => {
256
- const res = await callExport();
216
+ test("always includes non-dated log files regardless of time filter", async () => {
217
+ const startTime = new Date("2025-01-14T00:00:00.000Z").getTime();
218
+ const endTime = new Date("2025-01-22T00:00:00.000Z").getTime();
219
+ const res = await callExport({ startTime, endTime });
257
220
  const dir = await extractArchive(res);
258
221
  try {
259
- const files = listFiles(join(dir, "workspace"));
260
- expect(files).not.toContain("sneaky-link.txt");
222
+ const logFiles = readdirSync(join(dir, "daemon-logs"));
223
+ expect(logFiles).toContain("vellum.log");
261
224
  } finally {
262
225
  rmSync(dir, { recursive: true, force: true });
263
226
  }
264
227
  });
265
228
 
266
- test("archive contains config-snapshot.json when config exists", async () => {
229
+ test("includes all log files when no time filter is specified", async () => {
267
230
  const res = await callExport();
268
231
  const dir = await extractArchive(res);
269
232
  try {
270
- const configContent = readFileSync(
271
- join(dir, "config-snapshot.json"),
272
- "utf-8",
273
- );
274
- const parsed = JSON.parse(configContent);
275
- expect(parsed.provider).toBe("anthropic");
233
+ const logFiles = readdirSync(join(dir, "daemon-logs"));
234
+ expect(logFiles).toContain("assistant-2025-01-10.log");
235
+ expect(logFiles).toContain("assistant-2025-01-15.log");
236
+ expect(logFiles).toContain("assistant-2025-01-20.log");
237
+ expect(logFiles).toContain("assistant-2025-01-25.log");
238
+ expect(logFiles).toContain("vellum.log");
276
239
  } finally {
277
240
  rmSync(dir, { recursive: true, force: true });
278
241
  }
@@ -496,9 +496,9 @@ describe("atomic write safety", () => {
496
496
  });
497
497
 
498
498
  const skillDir = join(TEST_DIR, "skills", "atomic-overwrite");
499
- const files = readdirSync(skillDir);
500
- // Only SKILL.md should exist — no .tmp-* leftover files
501
- expect(files).toEqual(["SKILL.md"]);
499
+ const files = readdirSync(skillDir).sort();
500
+ // SKILL.md and install-meta.json should exist — no .tmp-* leftover files
501
+ expect(files).toEqual(["SKILL.md", "install-meta.json"]);
502
502
 
503
503
  const content = readFileSync(join(skillDir, "SKILL.md"), "utf-8");
504
504
  expect(content).toContain('name: "V2"');
@@ -649,7 +649,7 @@ describe("version metadata", () => {
649
649
  expect(readSkillVersion("no-version")).toBeNull();
650
650
  });
651
651
 
652
- test("createManagedSkill writes version.json when version is provided", () => {
652
+ test("createManagedSkill writes install-meta.json when version is provided", () => {
653
653
  createManagedSkill({
654
654
  id: "versioned",
655
655
  name: "Versioned",
@@ -662,7 +662,7 @@ describe("version metadata", () => {
662
662
  expect(version).toBe("v1:abc123");
663
663
  });
664
664
 
665
- test("version.json contains valid JSON with version and installedAt", () => {
665
+ test("install-meta.json contains valid JSON with origin, version, and installedAt", () => {
666
666
  createManagedSkill({
667
667
  id: "version-meta",
668
668
  name: "Meta",
@@ -671,16 +671,43 @@ describe("version metadata", () => {
671
671
  version: "v1:deadbeef",
672
672
  });
673
673
 
674
- const metaPath = join(TEST_DIR, "skills", "version-meta", "version.json");
674
+ const metaPath = join(
675
+ TEST_DIR,
676
+ "skills",
677
+ "version-meta",
678
+ "install-meta.json",
679
+ );
675
680
  expect(existsSync(metaPath)).toBe(true);
676
681
  const meta = JSON.parse(readFileSync(metaPath, "utf-8"));
682
+ expect(meta.origin).toBe("custom");
677
683
  expect(meta.version).toBe("v1:deadbeef");
678
684
  expect(typeof meta.installedAt).toBe("string");
679
685
  // installedAt should be a valid ISO date
680
686
  expect(new Date(meta.installedAt).toISOString()).toBe(meta.installedAt);
681
687
  });
682
688
 
683
- test("overwrite updates version.json", () => {
689
+ test("install-meta.json includes installedBy when contactId is provided", () => {
690
+ createManagedSkill({
691
+ id: "with-contact",
692
+ name: "With Contact",
693
+ description: "Has contactId",
694
+ bodyMarkdown: "Body.",
695
+ contactId: "contact-uuid-456",
696
+ });
697
+
698
+ const metaPath = join(
699
+ TEST_DIR,
700
+ "skills",
701
+ "with-contact",
702
+ "install-meta.json",
703
+ );
704
+ expect(existsSync(metaPath)).toBe(true);
705
+ const meta = JSON.parse(readFileSync(metaPath, "utf-8"));
706
+ expect(meta.origin).toBe("custom");
707
+ expect(meta.installedBy).toBe("contact-uuid-456");
708
+ });
709
+
710
+ test("overwrite updates install-meta.json", () => {
684
711
  createManagedSkill({
685
712
  id: "update-version",
686
713
  name: "V1",
@@ -701,21 +728,21 @@ describe("version metadata", () => {
701
728
  expect(readSkillVersion("update-version")).toBe("v1:second");
702
729
  });
703
730
 
704
- test("readSkillVersion returns null for corrupted version.json", () => {
731
+ test("readSkillVersion returns null for corrupted install-meta.json", () => {
705
732
  createManagedSkill({
706
733
  id: "corrupt-version",
707
734
  name: "Corrupt",
708
- description: "Will corrupt version file",
735
+ description: "Will corrupt meta file",
709
736
  bodyMarkdown: "Body.",
710
737
  version: "v1:valid",
711
738
  });
712
739
 
713
- // Corrupt the version.json
740
+ // Corrupt the install-meta.json
714
741
  const metaPath = join(
715
742
  TEST_DIR,
716
743
  "skills",
717
744
  "corrupt-version",
718
- "version.json",
745
+ "install-meta.json",
719
746
  );
720
747
  writeFileSync(metaPath, "{invalid json!!!", "utf-8");
721
748
 
@@ -7,6 +7,11 @@ mock.module("../security/secure-keys.js", () => ({
7
7
  deleteSecureKeyAsync: jest.fn().mockResolvedValue("deleted"),
8
8
  }));
9
9
 
10
+ // Mock platform-callback-registration (imported by client.ts)
11
+ mock.module("../inbound/platform-callback-registration.js", () => ({
12
+ shouldUsePlatformCallbacks: jest.fn().mockReturnValue(false),
13
+ }));
14
+
10
15
  const { McpClient } = await import("../mcp/client.js");
11
16
  const { McpServerManager } = await import("../mcp/manager.js");
12
17
  const { createMcpTool } = await import("../tools/mcp/mcp-tool-factory.js");
@@ -7,6 +7,11 @@ mock.module("../security/secure-keys.js", () => ({
7
7
  deleteSecureKeyAsync: jest.fn().mockResolvedValue("deleted"),
8
8
  }));
9
9
 
10
+ // Mock platform-callback-registration (imported by client.ts)
11
+ mock.module("../inbound/platform-callback-registration.js", () => ({
12
+ shouldUsePlatformCallbacks: jest.fn().mockReturnValue(false),
13
+ }));
14
+
10
15
  const { McpClient } = await import("../mcp/client.js");
11
16
 
12
17
  /**
@@ -34,15 +34,9 @@ mock.module("../memory/jobs-store.js", () => ({
34
34
  deferMemoryJob: () => "deferred",
35
35
  failMemoryJob: () => {},
36
36
  failStalledJobs: () => 0,
37
- enqueueCleanupStaleSupersededItemsJob: () => null,
38
37
  enqueuePruneOldConversationsJob: () => null,
39
38
  }));
40
39
 
41
- // Mock db.js (rawRun used in sweepStaleItems)
42
- mock.module("../memory/db.js", () => ({
43
- rawRun: () => 0,
44
- }));
45
-
46
40
  import {
47
41
  POLL_INTERVAL_MAX_MS,
48
42
  POLL_INTERVAL_MIN_MS,
@@ -90,7 +84,7 @@ describe("memory jobs worker adaptive poll interval", () => {
90
84
  timeoutDelays.push(delay);
91
85
  pendingCallbacks.push(fn);
92
86
  }
93
- return 999 as unknown as ReturnType<typeof setTimeout>;
87
+ return (999 as unknown) as ReturnType<typeof setTimeout>;
94
88
  }) as typeof setTimeout;
95
89
  globalThis.clearTimeout = (() => {}) as typeof clearTimeout;
96
90
 
@@ -129,7 +123,7 @@ describe("memory jobs worker adaptive poll interval", () => {
129
123
 
130
124
  // Should eventually reach the cap
131
125
  expect(timeoutDelays[timeoutDelays.length - 1]).toBe(
132
- POLL_INTERVAL_MAX_MS,
126
+ POLL_INTERVAL_MAX_MS
133
127
  );
134
128
  } finally {
135
129
  globalThis.setTimeout = originalSetTimeout;
@@ -1,4 +1,4 @@
1
- import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
1
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
2
2
 
3
3
  mock.module("../util/logger.js", () => ({
4
4
  getLogger: () =>
@@ -18,10 +18,11 @@ mock.module("../config/loader.js", () => ({
18
18
  }),
19
19
  }));
20
20
 
21
- import { getDb, initializeDb, resetDb } from "../memory/db.js";
21
+ import { getDb, initializeDb } from "../memory/db.js";
22
22
  import {
23
23
  backfillMemoryRecallLogMessageId,
24
24
  getMemoryRecallLogByMessageIds,
25
+ normalizeTopCandidates,
25
26
  recordMemoryRecallLog,
26
27
  } from "../memory/memory-recall-log-store.js";
27
28
  import { memoryRecallLogs } from "../memory/schema.js";
@@ -33,10 +34,6 @@ function resetTables(): void {
33
34
  db.delete(memoryRecallLogs).run();
34
35
  }
35
36
 
36
- afterAll(() => {
37
- resetDb();
38
- });
39
-
40
37
  describe("memory-recall-log-store", () => {
41
38
  beforeEach(() => {
42
39
  resetTables();
@@ -65,6 +62,7 @@ describe("memory-recall-log-store", () => {
65
62
  topCandidatesJson: [{ id: "c1", score: 0.9 }],
66
63
  injectedText: "some memory context",
67
64
  reason: "user query matched memories",
65
+ queryContext: "what is the weather like",
68
66
  });
69
67
 
70
68
  backfillMemoryRecallLogMessageId(conversationId, messageId);
@@ -88,6 +86,34 @@ describe("memory-recall-log-store", () => {
88
86
  expect(result!.topCandidates).toEqual([{ id: "c1", score: 0.9 }]);
89
87
  expect(result!.injectedText).toBe("some memory context");
90
88
  expect(result!.reason).toBe("user query matched memories");
89
+ expect(result!.queryContext).toBe("what is the weather like");
90
+ });
91
+
92
+ test("queryContext defaults to null when omitted", () => {
93
+ const conversationId = "conv-no-query-ctx";
94
+ const messageId = "msg-no-query-ctx";
95
+
96
+ recordMemoryRecallLog({
97
+ conversationId,
98
+ enabled: true,
99
+ degraded: false,
100
+ semanticHits: 1,
101
+ mergedCount: 1,
102
+ selectedCount: 1,
103
+ tier1Count: 1,
104
+ tier2Count: 0,
105
+ hybridSearchLatencyMs: 50,
106
+ sparseVectorUsed: false,
107
+ injectedTokens: 100,
108
+ latencyMs: 80,
109
+ topCandidatesJson: [],
110
+ });
111
+
112
+ backfillMemoryRecallLogMessageId(conversationId, messageId);
113
+
114
+ const result = getMemoryRecallLogByMessageIds([messageId]);
115
+ expect(result).not.toBeNull();
116
+ expect(result!.queryContext).toBeNull();
91
117
  });
92
118
 
93
119
  test("returns null when no log exists for a messageId", () => {
@@ -152,4 +178,106 @@ describe("memory-recall-log-store", () => {
152
178
  expect(secondLog).not.toBeNull();
153
179
  expect(secondLog!.degraded).toBe(true);
154
180
  });
181
+
182
+ test("normalizes SSE-event format candidates to inspector format on read", () => {
183
+ const conversationId = "conv-normalize-sse";
184
+ const messageId = "msg-normalize-sse";
185
+
186
+ // Store candidates in SSE-event format (key/finalScore/semantic/recency/kind)
187
+ recordMemoryRecallLog({
188
+ conversationId,
189
+ enabled: true,
190
+ degraded: false,
191
+ semanticHits: 2,
192
+ mergedCount: 1,
193
+ selectedCount: 1,
194
+ tier1Count: 1,
195
+ tier2Count: 0,
196
+ hybridSearchLatencyMs: 100,
197
+ sparseVectorUsed: false,
198
+ injectedTokens: 200,
199
+ latencyMs: 120,
200
+ topCandidatesJson: [
201
+ {
202
+ key: "node-abc",
203
+ finalScore: 0.85,
204
+ semantic: 0.9,
205
+ recency: 0.1,
206
+ kind: "episode",
207
+ type: "episodic",
208
+ },
209
+ ],
210
+ });
211
+
212
+ backfillMemoryRecallLogMessageId(conversationId, messageId);
213
+
214
+ const result = getMemoryRecallLogByMessageIds([messageId]);
215
+ expect(result).not.toBeNull();
216
+ const candidates = result!.topCandidates as Array<Record<string, unknown>>;
217
+ expect(candidates).toHaveLength(1);
218
+ expect(candidates[0]).toEqual({
219
+ nodeId: "node-abc",
220
+ score: 0.85,
221
+ semanticSimilarity: 0.9,
222
+ recencyBoost: 0.1,
223
+ type: "episodic",
224
+ });
225
+ // kind should be stripped
226
+ expect(candidates[0]).not.toHaveProperty("kind");
227
+ // Old field names should not be present
228
+ expect(candidates[0]).not.toHaveProperty("key");
229
+ expect(candidates[0]).not.toHaveProperty("finalScore");
230
+ expect(candidates[0]).not.toHaveProperty("semantic");
231
+ expect(candidates[0]).not.toHaveProperty("recency");
232
+ });
233
+
234
+ test("passes through candidates already in inspector format unchanged", () => {
235
+ const conversationId = "conv-normalize-inspector";
236
+ const messageId = "msg-normalize-inspector";
237
+
238
+ // Store candidates already in inspector format (nodeId/score/semanticSimilarity/recencyBoost)
239
+ recordMemoryRecallLog({
240
+ conversationId,
241
+ enabled: true,
242
+ degraded: false,
243
+ semanticHits: 1,
244
+ mergedCount: 1,
245
+ selectedCount: 1,
246
+ tier1Count: 1,
247
+ tier2Count: 0,
248
+ hybridSearchLatencyMs: 80,
249
+ sparseVectorUsed: false,
250
+ injectedTokens: 100,
251
+ latencyMs: 90,
252
+ topCandidatesJson: [
253
+ {
254
+ nodeId: "node-xyz",
255
+ score: 0.92,
256
+ semanticSimilarity: 0.88,
257
+ recencyBoost: 0.05,
258
+ type: "semantic",
259
+ },
260
+ ],
261
+ });
262
+
263
+ backfillMemoryRecallLogMessageId(conversationId, messageId);
264
+
265
+ const result = getMemoryRecallLogByMessageIds([messageId]);
266
+ expect(result).not.toBeNull();
267
+ const candidates = result!.topCandidates as Array<Record<string, unknown>>;
268
+ expect(candidates).toHaveLength(1);
269
+ expect(candidates[0]).toEqual({
270
+ nodeId: "node-xyz",
271
+ score: 0.92,
272
+ semanticSimilarity: 0.88,
273
+ recencyBoost: 0.05,
274
+ type: "semantic",
275
+ });
276
+ });
277
+
278
+ test("normalizeTopCandidates handles non-array input", () => {
279
+ expect(normalizeTopCandidates(null)).toBeNull();
280
+ expect(normalizeTopCandidates("not-an-array")).toBe("not-an-array");
281
+ expect(normalizeTopCandidates(42)).toBe(42);
282
+ });
155
283
  });