@vellumai/assistant 0.5.16 → 0.6.0

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 (407) hide show
  1. package/ARCHITECTURE.md +1 -1
  2. package/Dockerfile +0 -3
  3. package/knip.json +2 -1
  4. package/openapi.yaml +660 -80
  5. package/package.json +1 -1
  6. package/src/__tests__/actor-token-service.test.ts +68 -0
  7. package/src/__tests__/agent-loop.test.ts +0 -32
  8. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  9. package/src/__tests__/anthropic-provider.test.ts +57 -3
  10. package/src/__tests__/app-compiler.test.ts +120 -0
  11. package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -2
  12. package/src/__tests__/call-conversation-messages.test.ts +2 -6
  13. package/src/__tests__/call-domain.test.ts +2 -6
  14. package/src/__tests__/call-pointer-messages.test.ts +2 -14
  15. package/src/__tests__/call-recovery.test.ts +2 -6
  16. package/src/__tests__/call-routes-http.test.ts +2 -6
  17. package/src/__tests__/call-store.test.ts +2 -6
  18. package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
  19. package/src/__tests__/canonical-guardian-store.test.ts +2 -6
  20. package/src/__tests__/channel-delivery-store.test.ts +2 -6
  21. package/src/__tests__/channel-retry-sweep.test.ts +2 -6
  22. package/src/__tests__/checker.test.ts +25 -3
  23. package/src/__tests__/clawhub.test.ts +54 -24
  24. package/src/__tests__/cli-command-risk-guard.test.ts +14 -0
  25. package/src/__tests__/cli-memory.test.ts +74 -69
  26. package/src/__tests__/config-schema.test.ts +1 -1
  27. package/src/__tests__/config-set-platform-guard.test.ts +302 -0
  28. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
  29. package/src/__tests__/contacts-tools.test.ts +31 -0
  30. package/src/__tests__/context-overflow-reducer.test.ts +86 -0
  31. package/src/__tests__/context-token-estimator.test.ts +175 -10
  32. package/src/__tests__/conversation-agent-loop-overflow.test.ts +9 -0
  33. package/src/__tests__/conversation-agent-loop.test.ts +9 -0
  34. package/src/__tests__/conversation-attachments.test.ts +2 -6
  35. package/src/__tests__/conversation-attention-store.test.ts +2 -6
  36. package/src/__tests__/conversation-clear-safety.test.ts +2 -6
  37. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
  38. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
  39. package/src/__tests__/conversation-disk-view.test.ts +2 -6
  40. package/src/__tests__/conversation-error.test.ts +33 -2
  41. package/src/__tests__/conversation-fork-crud.test.ts +2 -6
  42. package/src/__tests__/conversation-history-web-search.test.ts +5 -0
  43. package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
  44. package/src/__tests__/conversation-media-retry.test.ts +91 -0
  45. package/src/__tests__/conversation-starter-routes.test.ts +20 -11
  46. package/src/__tests__/conversation-store.test.ts +2 -6
  47. package/src/__tests__/conversation-usage.test.ts +2 -6
  48. package/src/__tests__/conversation-wipe.test.ts +11 -408
  49. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
  50. package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
  51. package/src/__tests__/credential-security-e2e.test.ts +2 -0
  52. package/src/__tests__/followup-tools.test.ts +2 -6
  53. package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
  54. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
  55. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
  56. package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
  57. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
  58. package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
  59. package/src/__tests__/guardian-action-store.test.ts +2 -6
  60. package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
  61. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
  62. package/src/__tests__/guardian-dispatch.test.ts +2 -6
  63. package/src/__tests__/guardian-grant-minting.test.ts +2 -14
  64. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
  65. package/src/__tests__/guardian-routing-invariants.test.ts +192 -6
  66. package/src/__tests__/guardian-routing-state.test.ts +2 -6
  67. package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
  68. package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
  69. package/src/__tests__/injection-block.test.ts +154 -0
  70. package/src/__tests__/install-meta.test.ts +506 -0
  71. package/src/__tests__/install-skill-routing.test.ts +292 -0
  72. package/src/__tests__/invite-redemption-service.test.ts +2 -6
  73. package/src/__tests__/invite-routes-http.test.ts +2 -6
  74. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -14
  75. package/src/__tests__/list-messages-attachments.test.ts +2 -6
  76. package/src/__tests__/llm-context-route-provider.test.ts +2 -6
  77. package/src/__tests__/llm-request-log-turn-query.test.ts +2 -6
  78. package/src/__tests__/llm-usage-store.test.ts +2 -6
  79. package/src/__tests__/log-export-workspace.test.ts +2 -6
  80. package/src/__tests__/managed-store.test.ts +38 -11
  81. package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
  82. package/src/__tests__/memory-recall-log-store.test.ts +2 -6
  83. package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
  84. package/src/__tests__/non-member-access-request.test.ts +2 -6
  85. package/src/__tests__/notification-guardian-path.test.ts +2 -6
  86. package/src/__tests__/oauth-cli.test.ts +364 -2
  87. package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
  88. package/src/__tests__/outlook-attachments.test.ts +301 -0
  89. package/src/__tests__/outlook-automation-tools.test.ts +425 -0
  90. package/src/__tests__/outlook-categories.test.ts +212 -0
  91. package/src/__tests__/outlook-client-automation.test.ts +246 -0
  92. package/src/__tests__/outlook-compose-tools.test.ts +325 -0
  93. package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
  94. package/src/__tests__/outlook-email-watcher.test.ts +322 -0
  95. package/src/__tests__/outlook-follow-up.test.ts +196 -0
  96. package/src/__tests__/outlook-messaging-provider.test.ts +498 -3
  97. package/src/__tests__/outlook-trash.test.ts +77 -0
  98. package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
  99. package/src/__tests__/platform-callback-registration.test.ts +4 -4
  100. package/src/__tests__/playbook-execution.test.ts +76 -80
  101. package/src/__tests__/playbook-tools.test.ts +5 -7
  102. package/src/__tests__/provider-error-scenarios.test.ts +21 -0
  103. package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
  104. package/src/__tests__/registry.test.ts +2 -2
  105. package/src/__tests__/require-fresh-approval.test.ts +64 -2
  106. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
  107. package/src/__tests__/runtime-events-sse.test.ts +2 -6
  108. package/src/__tests__/schedule-store.test.ts +2 -6
  109. package/src/__tests__/schedule-tools.test.ts +2 -6
  110. package/src/__tests__/scheduler-recurrence.test.ts +1 -5
  111. package/src/__tests__/scoped-approval-grants.test.ts +2 -6
  112. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
  113. package/src/__tests__/search-skills-unified.test.ts +421 -0
  114. package/src/__tests__/secret-onetime-send.test.ts +2 -0
  115. package/src/__tests__/send-endpoint-busy.test.ts +2 -6
  116. package/src/__tests__/sequence-store.test.ts +2 -6
  117. package/src/__tests__/server-history-render.test.ts +2 -6
  118. package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
  119. package/src/__tests__/skill-feature-flags.test.ts +6 -6
  120. package/src/__tests__/skill-load-feature-flag.test.ts +11 -11
  121. package/src/__tests__/skill-memory.test.ts +140 -98
  122. package/src/__tests__/skills-uninstall.test.ts +2 -2
  123. package/src/__tests__/skills.test.ts +1 -1
  124. package/src/__tests__/slack-inbound-verification.test.ts +2 -6
  125. package/src/__tests__/task-compiler.test.ts +2 -6
  126. package/src/__tests__/task-management-tools.test.ts +2 -6
  127. package/src/__tests__/task-memory-cleanup.test.ts +173 -229
  128. package/src/__tests__/task-runner.test.ts +2 -6
  129. package/src/__tests__/task-scheduler.test.ts +2 -6
  130. package/src/__tests__/test-preload.ts +3 -0
  131. package/src/__tests__/tool-approval-handler.test.ts +2 -6
  132. package/src/__tests__/tool-grant-request-escalation.test.ts +2 -6
  133. package/src/__tests__/tool-side-effects-slack-dm.test.ts +276 -0
  134. package/src/__tests__/trust-store.test.ts +1 -1
  135. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +2 -6
  136. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -6
  137. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -6
  138. package/src/__tests__/trusted-contact-verification.test.ts +2 -6
  139. package/src/__tests__/turn-boundary-resolution.test.ts +2 -6
  140. package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -6
  141. package/src/__tests__/usage-routes.test.ts +2 -6
  142. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  143. package/src/__tests__/voice-invite-redemption.test.ts +2 -6
  144. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -6
  145. package/src/__tests__/voice-session-bridge.test.ts +2 -6
  146. package/src/__tests__/volume-security-guard.test.ts +2 -0
  147. package/src/__tests__/workspace-lifecycle.test.ts +29 -1
  148. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -6
  149. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +2 -6
  150. package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
  151. package/src/__tests__/workspace-policy.test.ts +1 -1
  152. package/src/agent/attachments.ts +7 -2
  153. package/src/agent/image-optimize.ts +165 -0
  154. package/src/agent/loop.ts +1 -15
  155. package/src/bundler/app-compiler.ts +179 -2
  156. package/src/bundler/package-resolver.ts +3 -5
  157. package/src/cli/__tests__/notifications.test.ts +1 -2
  158. package/src/cli/cli-memory.ts +67 -64
  159. package/src/cli/commands/avatar.ts +3 -3
  160. package/src/cli/commands/config.ts +26 -13
  161. package/src/cli/commands/doctor.ts +2 -2
  162. package/src/cli/commands/memory.ts +41 -55
  163. package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
  164. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
  165. package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
  166. package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
  167. package/src/cli/commands/oauth/connect.ts +11 -6
  168. package/src/cli/commands/oauth/mode.ts +7 -0
  169. package/src/cli/commands/oauth/shared.ts +39 -3
  170. package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
  171. package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
  172. package/src/cli/commands/platform/__tests__/status.test.ts +5 -5
  173. package/src/cli/commands/platform/index.ts +16 -16
  174. package/src/cli/commands/skills.ts +88 -16
  175. package/src/cli/commands/trust.ts +2 -2
  176. package/src/cli/lib/daemon-credential-client.ts +2 -3
  177. package/src/config/bundled-skills/acp/TOOLS.json +1 -1
  178. package/src/config/bundled-skills/contacts/SKILL.md +0 -1
  179. package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
  180. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
  181. package/src/config/bundled-skills/gmail/SKILL.md +2 -10
  182. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
  183. package/src/config/bundled-skills/messaging/SKILL.md +10 -18
  184. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
  185. package/src/config/bundled-skills/outlook/SKILL.md +189 -0
  186. package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
  187. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
  188. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
  189. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
  190. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
  191. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
  192. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
  193. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
  194. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
  195. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
  196. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
  197. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
  198. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
  199. package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
  200. package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
  201. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
  202. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
  203. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
  204. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
  205. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
  206. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
  207. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
  208. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
  209. package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
  210. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
  211. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
  212. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
  213. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
  214. package/src/config/bundled-skills/slack/SKILL.md +1 -7
  215. package/src/config/bundled-tool-registry.ts +56 -4
  216. package/src/config/env-registry.ts +15 -8
  217. package/src/config/feature-flag-registry.json +21 -124
  218. package/src/config/schemas/platform.ts +8 -0
  219. package/src/config/schemas/timeouts.ts +1 -1
  220. package/src/config/skills.ts +18 -7
  221. package/src/context/token-estimator.ts +25 -18
  222. package/src/context/window-manager.ts +6 -2
  223. package/src/credential-execution/process-manager.ts +3 -1
  224. package/src/daemon/context-overflow-reducer.ts +46 -2
  225. package/src/daemon/conversation-agent-loop-handlers.ts +123 -82
  226. package/src/daemon/conversation-agent-loop.ts +96 -61
  227. package/src/daemon/conversation-error.ts +31 -8
  228. package/src/daemon/conversation-lifecycle.ts +33 -0
  229. package/src/daemon/conversation-media-retry.ts +85 -7
  230. package/src/daemon/conversation-notifiers.ts +4 -1
  231. package/src/daemon/conversation-runtime-assembly.ts +5 -0
  232. package/src/daemon/conversation.ts +41 -2
  233. package/src/daemon/daemon-control.ts +8 -2
  234. package/src/daemon/handlers/shared.ts +22 -12
  235. package/src/daemon/handlers/skills.ts +416 -202
  236. package/src/daemon/lifecycle.ts +40 -1
  237. package/src/daemon/main.ts +5 -1
  238. package/src/daemon/message-types/conversations.ts +4 -1
  239. package/src/daemon/message-types/messages.ts +3 -1
  240. package/src/daemon/message-types/skills.ts +97 -36
  241. package/src/daemon/providers-setup.ts +5 -0
  242. package/src/daemon/server.ts +11 -2
  243. package/src/daemon/tool-side-effects.ts +27 -5
  244. package/src/heartbeat/heartbeat-service.ts +1 -0
  245. package/src/hooks/cli.ts +2 -2
  246. package/src/hooks/runner.ts +15 -38
  247. package/src/inbound/platform-callback-registration.ts +14 -14
  248. package/src/memory/admin.ts +11 -45
  249. package/src/memory/conversation-bootstrap.ts +2 -0
  250. package/src/memory/conversation-crud.ts +242 -348
  251. package/src/memory/conversation-group-migration.ts +157 -0
  252. package/src/memory/conversation-queries.ts +4 -2
  253. package/src/memory/db-init.ts +30 -3
  254. package/src/memory/embed.ts +73 -0
  255. package/src/memory/embedding-backend.ts +8 -14
  256. package/src/memory/embedding-runtime-manager.ts +12 -114
  257. package/src/memory/fingerprint.ts +2 -2
  258. package/src/memory/graph/bootstrap.ts +512 -0
  259. package/src/memory/graph/capability-seed.ts +297 -0
  260. package/src/memory/graph/consolidation.ts +691 -0
  261. package/src/memory/graph/conversation-graph-memory.ts +630 -0
  262. package/src/memory/graph/decay.test.ts +208 -0
  263. package/src/memory/graph/decay.ts +195 -0
  264. package/src/memory/graph/extraction-job.ts +69 -0
  265. package/src/memory/graph/extraction.test.ts +936 -0
  266. package/src/memory/graph/extraction.ts +1254 -0
  267. package/src/memory/graph/graph-search.ts +266 -0
  268. package/src/memory/graph/image-ref-utils.ts +29 -0
  269. package/src/memory/graph/injection.test.ts +513 -0
  270. package/src/memory/graph/injection.ts +439 -0
  271. package/src/memory/graph/inspect.ts +534 -0
  272. package/src/memory/graph/narrative.ts +267 -0
  273. package/src/memory/graph/pattern-scan.ts +269 -0
  274. package/src/memory/graph/retriever.ts +1008 -0
  275. package/src/memory/graph/scoring.test.ts +548 -0
  276. package/src/memory/graph/scoring.ts +232 -0
  277. package/src/memory/graph/serendipity.ts +65 -0
  278. package/src/memory/graph/store.test.ts +1050 -0
  279. package/src/memory/graph/store.ts +699 -0
  280. package/src/memory/graph/tool-handlers.ts +426 -0
  281. package/src/memory/graph/tools.ts +141 -0
  282. package/src/memory/graph/triggers.test.ts +487 -0
  283. package/src/memory/graph/triggers.ts +223 -0
  284. package/src/memory/graph/types.ts +271 -0
  285. package/src/memory/group-crud.ts +191 -0
  286. package/src/memory/indexer.ts +37 -19
  287. package/src/memory/job-handlers/cleanup.ts +0 -53
  288. package/src/memory/job-handlers/conversation-starters.ts +91 -53
  289. package/src/memory/job-handlers/embedding.ts +5 -31
  290. package/src/memory/job-handlers/index-maintenance.ts +23 -11
  291. package/src/memory/job-handlers/summarization.ts +32 -17
  292. package/src/memory/job-utils.ts +1 -1
  293. package/src/memory/jobs-store.ts +50 -70
  294. package/src/memory/jobs-worker.ts +147 -112
  295. package/src/memory/message-content.ts +1 -0
  296. package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
  297. package/src/memory/migrations/203-drop-memory-items-tables.ts +23 -0
  298. package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
  299. package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
  300. package/src/memory/migrations/index.ts +4 -0
  301. package/src/memory/migrations/registry.ts +8 -0
  302. package/src/memory/qdrant-client.ts +44 -17
  303. package/src/memory/schema/index.ts +1 -0
  304. package/src/memory/schema/memory-graph.ts +139 -0
  305. package/src/memory/search/semantic.ts +47 -91
  306. package/src/memory/task-memory-cleanup.ts +28 -50
  307. package/src/messaging/providers/outlook/adapter.ts +8 -1
  308. package/src/messaging/providers/outlook/client.ts +299 -0
  309. package/src/messaging/providers/outlook/types.ts +118 -0
  310. package/src/notifications/adapters/macos.ts +1 -0
  311. package/src/notifications/copy-composer.ts +9 -0
  312. package/src/notifications/signal.ts +16 -0
  313. package/src/oauth/seed-providers.ts +2 -1
  314. package/src/permissions/checker.ts +24 -3
  315. package/src/permissions/defaults.ts +4 -4
  316. package/src/permissions/workspace-policy.ts +1 -1
  317. package/src/playbooks/playbook-compiler.ts +19 -18
  318. package/src/playbooks/types.ts +4 -3
  319. package/src/prompts/system-prompt.ts +3 -29
  320. package/src/providers/anthropic/client.ts +47 -19
  321. package/src/providers/gemini/client.ts +1 -1
  322. package/src/providers/openai/client.ts +1 -1
  323. package/src/providers/registry.ts +1 -1
  324. package/src/providers/retry.ts +19 -3
  325. package/src/runtime/actor-trust-resolver.ts +5 -1
  326. package/src/runtime/auth/route-policy.ts +7 -0
  327. package/src/runtime/guardian-reply-router.ts +5 -1
  328. package/src/runtime/http-server.ts +23 -3
  329. package/src/runtime/middleware/auth.ts +20 -0
  330. package/src/runtime/routes/attachment-routes.test.ts +106 -0
  331. package/src/runtime/routes/attachment-routes.ts +106 -16
  332. package/src/runtime/routes/brain-graph-routes.ts +21 -22
  333. package/src/runtime/routes/btw-routes.ts +8 -0
  334. package/src/runtime/routes/conversation-management-routes.ts +2 -0
  335. package/src/runtime/routes/conversation-starter-routes.ts +2 -2
  336. package/src/runtime/routes/debug-routes.ts +1 -1
  337. package/src/runtime/routes/global-search-routes.ts +21 -19
  338. package/src/runtime/routes/group-routes.ts +207 -0
  339. package/src/runtime/routes/guardian-action-routes.ts +21 -10
  340. package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
  341. package/src/runtime/routes/inbound-message-handler.ts +19 -0
  342. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
  343. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
  344. package/src/runtime/routes/memory-item-routes.test.ts +2 -14
  345. package/src/runtime/routes/memory-item-routes.ts +341 -388
  346. package/src/runtime/routes/schedule-routes.ts +2 -0
  347. package/src/runtime/routes/skills-routes.ts +103 -37
  348. package/src/runtime/routes/work-items-routes.test.ts +2 -6
  349. package/src/schedule/scheduler.ts +8 -1
  350. package/src/security/oauth2.ts +1 -1
  351. package/src/security/secure-keys.ts +4 -8
  352. package/src/shared/provider-env-vars.ts +19 -0
  353. package/src/skills/catalog-cache.ts +5 -0
  354. package/src/skills/catalog-install.ts +15 -14
  355. package/src/skills/clawhub.ts +134 -154
  356. package/src/skills/install-meta.ts +208 -0
  357. package/src/skills/managed-store.ts +27 -16
  358. package/src/skills/skill-memory.ts +152 -77
  359. package/src/skills/skillssh-registry.ts +19 -17
  360. package/src/tasks/task-runner.ts +3 -1
  361. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
  362. package/src/tools/browser/runtime-check.ts +3 -1
  363. package/src/tools/memory/register.ts +63 -46
  364. package/src/tools/permission-checker.ts +7 -1
  365. package/src/tools/shared/filesystem/image-read.ts +22 -85
  366. package/src/tools/terminal/safe-env.ts +1 -0
  367. package/src/tools/tool-manifest.ts +3 -3
  368. package/src/util/browser.ts +25 -10
  369. package/src/util/bun-runtime.ts +172 -0
  370. package/src/watcher/providers/outlook-calendar.ts +343 -0
  371. package/src/watcher/providers/outlook.ts +198 -0
  372. package/src/workspace/migrations/025-remove-oauth-app-setup-skills.ts +76 -0
  373. package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
  374. package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
  375. package/src/workspace/migrations/registry.ts +6 -0
  376. package/src/__tests__/context-memory-e2e.test.ts +0 -415
  377. package/src/__tests__/journal-context.test.ts +0 -268
  378. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
  379. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
  380. package/src/__tests__/memory-query-builder.test.ts +0 -59
  381. package/src/__tests__/memory-recall-quality.test.ts +0 -1046
  382. package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
  383. package/src/__tests__/memory-regressions.test.ts +0 -3696
  384. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
  385. package/src/daemon/conversation-memory.ts +0 -207
  386. package/src/memory/conversation-starters-cadence.ts +0 -74
  387. package/src/memory/items-extractor.ts +0 -860
  388. package/src/memory/job-handlers/batch-extraction.ts +0 -753
  389. package/src/memory/job-handlers/extraction.ts +0 -40
  390. package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -355
  391. package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
  392. package/src/memory/journal-memory.ts +0 -224
  393. package/src/memory/query-builder.ts +0 -47
  394. package/src/memory/query-expansion.ts +0 -83
  395. package/src/memory/retriever.test.ts +0 -1592
  396. package/src/memory/retriever.ts +0 -1331
  397. package/src/memory/search/formatting.test.ts +0 -140
  398. package/src/memory/search/formatting.ts +0 -262
  399. package/src/memory/search/mmr.ts +0 -139
  400. package/src/memory/search/ranking.ts +0 -15
  401. package/src/memory/search/staleness.ts +0 -40
  402. package/src/memory/search/tier-classifier.ts +0 -18
  403. package/src/memory/search/types.ts +0 -121
  404. package/src/prompts/journal-context.ts +0 -154
  405. package/src/tools/memory/definitions.ts +0 -69
  406. package/src/tools/memory/handlers.test.ts +0 -562
  407. package/src/tools/memory/handlers.ts +0 -434
@@ -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: () =>
@@ -15,22 +15,17 @@ import {
15
15
  getMessages,
16
16
  wipeConversation,
17
17
  } from "../memory/conversation-crud.js";
18
- import { getDb, initializeDb, resetDb } from "../memory/db.js";
18
+ import { getDb, initializeDb } from "../memory/db.js";
19
19
  import { enqueueMemoryJob } from "../memory/jobs-store.js";
20
20
 
21
21
  // Initialize db once before all tests
22
22
  initializeDb();
23
23
 
24
- afterAll(() => {
25
- resetDb();
26
- });
27
-
28
24
  describe("wipeConversation", () => {
29
25
  beforeEach(() => {
30
26
  const db = getDb();
31
- db.run(`DELETE FROM memory_item_sources`);
27
+ db.run(`DELETE FROM memory_graph_nodes`);
32
28
  db.run(`DELETE FROM memory_segments`);
33
- db.run(`DELETE FROM memory_items`);
34
29
  db.run(`DELETE FROM memory_summaries`);
35
30
  db.run(`DELETE FROM memory_embeddings`);
36
31
  db.run(`DELETE FROM memory_jobs`);
@@ -52,237 +47,6 @@ describe("wipeConversation", () => {
52
47
  expect(getMessages(conv.id)).toEqual([]);
53
48
  });
54
49
 
55
- test("restores explicitly superseded memory items", async () => {
56
- const convA = createConversation("conversation A");
57
- const msgA = await addMessage(convA.id, "user", "I like blue");
58
-
59
- const convB = createConversation("conversation B");
60
- const msgB = await addMessage(convB.id, "user", "I like red");
61
-
62
- const db = getDb();
63
- const now = Date.now();
64
-
65
- // Insert itemA: active preference about color
66
- db.run(
67
- `INSERT INTO memory_items (id, status, kind, subject, statement, confidence, fingerprint, scope_id, first_seen_at, last_seen_at)
68
- VALUES ('itemA', 'active', 'preference', 'color', 'likes blue', 0.8, 'fp-a', 'default', ${now}, ${now})`,
69
- );
70
-
71
- // Insert itemB: active preference about color, supersedes itemA
72
- db.run(
73
- `INSERT INTO memory_items (id, status, kind, subject, statement, confidence, fingerprint, scope_id, supersedes, first_seen_at, last_seen_at)
74
- VALUES ('itemB', 'active', 'preference', 'color', 'likes red', 0.9, 'fp-b', 'default', 'itemA', ${now}, ${now})`,
75
- );
76
-
77
- // Mark itemA as superseded by itemB
78
- db.run(
79
- `UPDATE memory_items SET status = 'superseded', superseded_by = 'itemB' WHERE id = 'itemA'`,
80
- );
81
-
82
- // Link itemA to convA's message, itemB to convB's message
83
- db.run(
84
- `INSERT INTO memory_item_sources (memory_item_id, message_id, created_at) VALUES ('itemA', '${msgA.id}', ${now})`,
85
- );
86
- db.run(
87
- `INSERT INTO memory_item_sources (memory_item_id, message_id, created_at) VALUES ('itemB', '${msgB.id}', ${now})`,
88
- );
89
-
90
- const result = wipeConversation(convB.id);
91
-
92
- // itemA should be restored to active with superseded_by cleared
93
- const raw = (
94
- getDb() as unknown as {
95
- $client: import("bun:sqlite").Database;
96
- }
97
- ).$client;
98
- const itemARow = raw
99
- .query(
100
- "SELECT status, superseded_by FROM memory_items WHERE id = 'itemA'",
101
- )
102
- .get() as { status: string; superseded_by: string | null } | null;
103
- expect(itemARow).not.toBeNull();
104
- expect(itemARow!.status).toBe("active");
105
- expect(itemARow!.superseded_by).toBeNull();
106
-
107
- // itemB should no longer exist (orphaned and deleted by deleteConversation)
108
- const itemBRow = (
109
- getDb() as unknown as {
110
- $client: import("bun:sqlite").Database;
111
- }
112
- ).$client
113
- .query("SELECT * FROM memory_items WHERE id = 'itemB'")
114
- .get();
115
- expect(itemBRow).toBeNull();
116
-
117
- expect(result.unsupersededItemIds).toContain("itemA");
118
- });
119
-
120
- test("does not restore superseded items when superseding item has other sources", async () => {
121
- const convA = createConversation("conversation A");
122
- const msgA = await addMessage(convA.id, "user", "I like red in A");
123
-
124
- const convB = createConversation("conversation B");
125
- const msgB = await addMessage(convB.id, "user", "I like red in B");
126
-
127
- const db = getDb();
128
- const now = Date.now();
129
-
130
- // Insert itemOld (will be superseded)
131
- db.run(
132
- `INSERT INTO memory_items (id, status, kind, subject, statement, confidence, fingerprint, scope_id, first_seen_at, last_seen_at)
133
- VALUES ('itemOld', 'active', 'preference', 'color', 'likes blue', 0.8, 'fp-old', 'default', ${now}, ${now})`,
134
- );
135
-
136
- // Insert itemNew (supersedes itemOld)
137
- db.run(
138
- `INSERT INTO memory_items (id, status, kind, subject, statement, confidence, fingerprint, scope_id, supersedes, first_seen_at, last_seen_at)
139
- VALUES ('itemNew', 'active', 'preference', 'color', 'likes red', 0.9, 'fp-new', 'default', 'itemOld', ${now}, ${now})`,
140
- );
141
-
142
- // Mark itemOld as superseded
143
- db.run(
144
- `UPDATE memory_items SET status = 'superseded', superseded_by = 'itemNew' WHERE id = 'itemOld'`,
145
- );
146
-
147
- // Link itemNew to BOTH conversations
148
- db.run(
149
- `INSERT INTO memory_item_sources (memory_item_id, message_id, created_at) VALUES ('itemNew', '${msgA.id}', ${now})`,
150
- );
151
- db.run(
152
- `INSERT INTO memory_item_sources (memory_item_id, message_id, created_at) VALUES ('itemNew', '${msgB.id}', ${now})`,
153
- );
154
-
155
- wipeConversation(convA.id);
156
-
157
- const raw = (
158
- getDb() as unknown as {
159
- $client: import("bun:sqlite").Database;
160
- }
161
- ).$client;
162
-
163
- // itemOld should still be superseded because itemNew has another source (convB)
164
- const itemOldRow = raw
165
- .query("SELECT status FROM memory_items WHERE id = 'itemOld'")
166
- .get() as { status: string } | null;
167
- expect(itemOldRow).not.toBeNull();
168
- expect(itemOldRow!.status).toBe("superseded");
169
-
170
- // itemNew should still exist (has source from convB)
171
- const itemNewRow = raw
172
- .query("SELECT * FROM memory_items WHERE id = 'itemNew'")
173
- .get();
174
- expect(itemNewRow).not.toBeNull();
175
- });
176
-
177
- test("restores orphaned subject-match superseded items", async () => {
178
- const convB = createConversation("conversation B");
179
- const msgB = await addMessage(convB.id, "user", "I use vim");
180
-
181
- const db = getDb();
182
- const now = Date.now();
183
-
184
- // Insert itemOld: superseded with no superseded_by link
185
- db.run(
186
- `INSERT INTO memory_items (id, status, kind, subject, statement, confidence, fingerprint, scope_id, first_seen_at, last_seen_at)
187
- VALUES ('itemOld', 'superseded', 'preference', 'editor', 'uses emacs', 0.7, 'fp-old', 'default', ${now}, ${now})`,
188
- );
189
-
190
- // Insert itemNew: active, same kind/subject/scope_id
191
- db.run(
192
- `INSERT INTO memory_items (id, status, kind, subject, statement, confidence, fingerprint, scope_id, first_seen_at, last_seen_at)
193
- VALUES ('itemNew', 'active', 'preference', 'editor', 'uses vim', 0.9, 'fp-new', 'default', ${now}, ${now})`,
194
- );
195
-
196
- // Link itemNew to convB's message
197
- db.run(
198
- `INSERT INTO memory_item_sources (memory_item_id, message_id, created_at) VALUES ('itemNew', '${msgB.id}', ${now})`,
199
- );
200
-
201
- wipeConversation(convB.id);
202
-
203
- const raw = (
204
- getDb() as unknown as {
205
- $client: import("bun:sqlite").Database;
206
- }
207
- ).$client;
208
-
209
- // itemOld should now be active (restored as orphaned subject-match superseded item)
210
- const itemOldRow = raw
211
- .query("SELECT status FROM memory_items WHERE id = 'itemOld'")
212
- .get() as { status: string } | null;
213
- expect(itemOldRow).not.toBeNull();
214
- expect(itemOldRow!.status).toBe("active");
215
- });
216
-
217
- test("does not restore superseded items from unrelated conversations", async () => {
218
- // convA has an item that superseded an older item — convA was previously
219
- // deleted via regular deleteConversation, leaving the old item superseded
220
- // with superseded_by = NULL. When we later wipe convB, Step F should NOT
221
- // restore that unrelated item.
222
- const convA = createConversation("conversation A");
223
- const _msgA = await addMessage(convA.id, "user", "I use dark theme");
224
-
225
- const convB = createConversation("conversation B");
226
- const msgB = await addMessage(convB.id, "user", "I use vim");
227
-
228
- const db = getDb();
229
- const now = Date.now();
230
-
231
- // unrelatedOld: superseded item from an old conversation (e.g. "uses light theme")
232
- // Its superseder was deleted in a prior deleteConversation, leaving
233
- // superseded_by = NULL.
234
- db.run(
235
- `INSERT INTO memory_items (id, status, kind, subject, statement, confidence, fingerprint, scope_id, first_seen_at, last_seen_at)
236
- VALUES ('unrelatedOld', 'superseded', 'preference', 'theme', 'uses light theme', 0.7, 'fp-unrelated', 'default', ${now}, ${now})`,
237
- );
238
-
239
- // convA's active item that superseded unrelatedOld — we simulate the
240
- // case where convA was already deleted, leaving unrelatedOld with
241
- // superseded_by = NULL and no active replacement.
242
- // (We don't actually insert the superseder — just leave unrelatedOld
243
- // as a superseded item with no superseded_by and no active match.)
244
-
245
- // convB's items — itemOld is superseded by itemNew (subject: editor)
246
- db.run(
247
- `INSERT INTO memory_items (id, status, kind, subject, statement, confidence, fingerprint, scope_id, first_seen_at, last_seen_at)
248
- VALUES ('editorOld', 'superseded', 'preference', 'editor', 'uses emacs', 0.7, 'fp-editor-old', 'default', ${now}, ${now})`,
249
- );
250
- db.run(
251
- `INSERT INTO memory_items (id, status, kind, subject, statement, confidence, fingerprint, scope_id, first_seen_at, last_seen_at)
252
- VALUES ('editorNew', 'active', 'preference', 'editor', 'uses vim', 0.9, 'fp-editor-new', 'default', ${now}, ${now})`,
253
- );
254
- db.run(
255
- `INSERT INTO memory_item_sources (memory_item_id, message_id, created_at) VALUES ('editorNew', '${msgB.id}', ${now})`,
256
- );
257
-
258
- const result = wipeConversation(convB.id);
259
-
260
- const raw = (
261
- getDb() as unknown as {
262
- $client: import("bun:sqlite").Database;
263
- }
264
- ).$client;
265
-
266
- // editorOld SHOULD be restored (its kind+subject matches an orphaned item from convB)
267
- const editorOldRow = raw
268
- .query("SELECT status FROM memory_items WHERE id = 'editorOld'")
269
- .get() as { status: string } | null;
270
- expect(editorOldRow).not.toBeNull();
271
- expect(editorOldRow!.status).toBe("active");
272
-
273
- // unrelatedOld should NOT be restored — it was superseded by a different
274
- // conversation's item (theme, not editor) and has nothing to do with convB
275
- const unrelatedOldRow = raw
276
- .query("SELECT status FROM memory_items WHERE id = 'unrelatedOld'")
277
- .get() as { status: string } | null;
278
- expect(unrelatedOldRow).not.toBeNull();
279
- expect(unrelatedOldRow!.status).toBe("superseded");
280
-
281
- // Only editorOld should be in the unsuperseded list, not unrelatedOld
282
- expect(result.unsupersededItemIds).toContain("editorOld");
283
- expect(result.unsupersededItemIds).not.toContain("unrelatedOld");
284
- });
285
-
286
50
  test("deletes conversation summaries", async () => {
287
51
  const conv = createConversation("test");
288
52
  await addMessage(conv.id, "user", "hello");
@@ -378,52 +142,14 @@ describe("wipeConversation", () => {
378
142
  expect(result.deletedSummaryIds).toEqual([]);
379
143
  expect(result.cancelledJobCount).toBe(0);
380
144
  });
381
-
382
- test("does not affect other conversations", async () => {
383
- const convA = createConversation("conversation A");
384
- await addMessage(convA.id, "user", "message in A");
385
-
386
- const convB = createConversation("conversation B");
387
- const msgB = await addMessage(convB.id, "user", "message in B");
388
-
389
- const db = getDb();
390
- const now = Date.now();
391
-
392
- // Insert a memory item sourced from convB's message
393
- db.run(
394
- `INSERT INTO memory_items (id, status, kind, subject, statement, confidence, fingerprint, scope_id, first_seen_at, last_seen_at)
395
- VALUES ('itemB', 'active', 'fact', 'test', 'test fact', 0.8, 'fp-b', 'default', ${now}, ${now})`,
396
- );
397
- db.run(
398
- `INSERT INTO memory_item_sources (memory_item_id, message_id, created_at) VALUES ('itemB', '${msgB.id}', ${now})`,
399
- );
400
-
401
- wipeConversation(convA.id);
402
-
403
- // convB should still exist
404
- expect(getConversation(convB.id)).not.toBeNull();
405
- expect(getMessages(convB.id)).toHaveLength(1);
406
-
407
- // convB's memory item should still exist
408
- const raw = (
409
- getDb() as unknown as {
410
- $client: import("bun:sqlite").Database;
411
- }
412
- ).$client;
413
- const itemBRow = raw
414
- .query("SELECT * FROM memory_items WHERE id = 'itemB'")
415
- .get();
416
- expect(itemBRow).not.toBeNull();
417
- });
418
145
  });
419
146
 
420
147
  describe("deleteConversation — private scope cleanup", () => {
421
148
  beforeEach(() => {
422
149
  const db = getDb();
423
150
  db.run(`DELETE FROM conversation_starters`);
424
- db.run(`DELETE FROM memory_item_sources`);
151
+ db.run(`DELETE FROM memory_graph_nodes`);
425
152
  db.run(`DELETE FROM memory_segments`);
426
- db.run(`DELETE FROM memory_items`);
427
153
  db.run(`DELETE FROM memory_summaries`);
428
154
  db.run(`DELETE FROM memory_embeddings`);
429
155
  db.run(`DELETE FROM memory_jobs`);
@@ -433,37 +159,6 @@ describe("deleteConversation — private scope cleanup", () => {
433
159
  db.run(`DELETE FROM conversations`);
434
160
  });
435
161
 
436
- test("sourceless items cleaned up", () => {
437
- const conv = createConversation({ conversationType: "private" });
438
- const scopeId = conv.memoryScopeId;
439
- const now = Date.now();
440
-
441
- const raw = (
442
- getDb() as unknown as {
443
- $client: import("bun:sqlite").Database;
444
- }
445
- ).$client;
446
-
447
- // Insert a memory item with matching scopeId but no memory_item_sources
448
- raw
449
- .query(
450
- `INSERT INTO memory_items (id, status, kind, subject, statement, confidence, fingerprint, scope_id, first_seen_at, last_seen_at)
451
- VALUES ('priv-item-1', 'active', 'fact', 'test', 'test fact', 0.8, 'fp-priv-1', ?, ?, ?)`,
452
- )
453
- .run(scopeId, now, now);
454
-
455
- const result = deleteConversation(conv.id);
456
-
457
- // Item should be gone
458
- const itemRow = raw
459
- .query("SELECT * FROM memory_items WHERE id = 'priv-item-1'")
460
- .get();
461
- expect(itemRow).toBeNull();
462
-
463
- // Its ID should be in orphanedItemIds
464
- expect(result.orphanedItemIds).toContain("priv-item-1");
465
- });
466
-
467
162
  test("summaries cleaned up", () => {
468
163
  const conv = createConversation({ conversationType: "private" });
469
164
  const scopeId = conv.memoryScopeId;
@@ -496,71 +191,15 @@ describe("deleteConversation — private scope cleanup", () => {
496
191
  });
497
192
 
498
193
  test("standard conversations unaffected", async () => {
499
- const conv = createConversation("standard test");
500
- const now = Date.now();
194
+ // Create a standard conversation and a private one
195
+ const standardConv = createConversation("standard test");
196
+ const privateConv = createConversation({ conversationType: "private" });
501
197
 
502
- const raw = (
503
- getDb() as unknown as {
504
- $client: import("bun:sqlite").Database;
505
- }
506
- ).$client;
198
+ // Delete the private conversation
199
+ deleteConversation(privateConv.id);
507
200
 
508
- // Insert items with scopeId = "default"
509
- raw
510
- .query(
511
- `INSERT INTO memory_items (id, status, kind, subject, statement, confidence, fingerprint, scope_id, first_seen_at, last_seen_at)
512
- VALUES ('default-item-1', 'active', 'fact', 'test', 'test fact', 0.8, 'fp-default', 'default', ?, ?)`,
513
- )
514
- .run(now, now);
515
-
516
- deleteConversation(conv.id);
517
-
518
- // Default-scope items should still exist
519
- const itemRow = raw
520
- .query("SELECT * FROM memory_items WHERE id = 'default-item-1'")
521
- .get();
522
- expect(itemRow).not.toBeNull();
523
- });
524
-
525
- test("embeddings cleaned up", () => {
526
- const conv = createConversation({ conversationType: "private" });
527
- const scopeId = conv.memoryScopeId;
528
- const now = Date.now();
529
-
530
- const raw = (
531
- getDb() as unknown as {
532
- $client: import("bun:sqlite").Database;
533
- }
534
- ).$client;
535
-
536
- // Insert a memory item with matching scopeId
537
- raw
538
- .query(
539
- `INSERT INTO memory_items (id, status, kind, subject, statement, confidence, fingerprint, scope_id, first_seen_at, last_seen_at)
540
- VALUES ('priv-item-emb', 'active', 'fact', 'test', 'test fact', 0.8, 'fp-priv-emb', ?, ?, ?)`,
541
- )
542
- .run(scopeId, now, now);
543
-
544
- // Insert a corresponding embedding
545
- raw
546
- .query(
547
- `INSERT INTO memory_embeddings (id, target_type, target_id, provider, model, dimensions, created_at, updated_at)
548
- VALUES ('emb-priv-item', 'item', 'priv-item-emb', 'test', 'test', 384, ?, ?)`,
549
- )
550
- .run(now, now);
551
-
552
- deleteConversation(conv.id);
553
-
554
- // Both item and embedding should be deleted
555
- const itemRow = raw
556
- .query("SELECT * FROM memory_items WHERE id = 'priv-item-emb'")
557
- .get();
558
- expect(itemRow).toBeNull();
559
-
560
- const embeddingRow = raw
561
- .query("SELECT * FROM memory_embeddings WHERE id = 'emb-priv-item'")
562
- .get();
563
- expect(embeddingRow).toBeNull();
201
+ // Standard conversation should still exist
202
+ expect(getConversation(standardConv.id)).not.toBeNull();
564
203
  });
565
204
 
566
205
  test("conversationStarters cleaned up", () => {
@@ -604,40 +243,4 @@ describe("deleteConversation — private scope cleanup", () => {
604
243
  .get();
605
244
  expect(defaultStarterRow).not.toBeNull();
606
245
  });
607
-
608
- test("no duplicate IDs", async () => {
609
- const conv = createConversation({ conversationType: "private" });
610
- const scopeId = conv.memoryScopeId;
611
- const msg = await addMessage(conv.id, "user", "hello");
612
- const now = Date.now();
613
-
614
- const raw = (
615
- getDb() as unknown as {
616
- $client: import("bun:sqlite").Database;
617
- }
618
- ).$client;
619
-
620
- // Insert a memory item with the private scopeId AND a source linking to the message
621
- raw
622
- .query(
623
- `INSERT INTO memory_items (id, status, kind, subject, statement, confidence, fingerprint, scope_id, first_seen_at, last_seen_at)
624
- VALUES ('priv-item-dup', 'active', 'fact', 'test', 'test fact', 0.8, 'fp-priv-dup', ?, ?, ?)`,
625
- )
626
- .run(scopeId, now, now);
627
-
628
- raw
629
- .query(
630
- `INSERT INTO memory_item_sources (memory_item_id, message_id, created_at) VALUES ('priv-item-dup', ?, ?)`,
631
- )
632
- .run(msg.id, now);
633
-
634
- const result = deleteConversation(conv.id);
635
-
636
- // The item ID should appear exactly once in orphanedItemIds (caught by
637
- // source-based cleanup, not double-counted by scope sweep).
638
- const count = result.orphanedItemIds.filter(
639
- (id) => id === "priv-item-dup",
640
- ).length;
641
- expect(count).toBe(1);
642
- });
643
246
  });
@@ -180,7 +180,7 @@ describe("CES flags do not affect unrelated flags", () => {
180
180
  expect(isAssistantFeatureFlagEnabled("browser", config)).toBe(true);
181
181
  });
182
182
 
183
- test("enabling all CES flags does not change contacts flag (defaultEnabled: true)", () => {
183
+ test("enabling all CES flags does not change sounds flag (defaultEnabled: true)", () => {
184
184
  const overrides: Record<string, boolean> = {};
185
185
  for (const key of ALL_CES_FLAG_KEYS) {
186
186
  overrides[key] = true;
@@ -188,7 +188,7 @@ describe("CES flags do not affect unrelated flags", () => {
188
188
  _setOverridesForTesting(overrides);
189
189
  const config = makeConfig();
190
190
 
191
- // contacts defaults to true in the registry and should stay true
192
- expect(isAssistantFeatureFlagEnabled("contacts", config)).toBe(true);
191
+ // sounds defaults to true in the registry and should stay true
192
+ expect(isAssistantFeatureFlagEnabled("sounds", config)).toBe(true);
193
193
  });
194
194
  });
@@ -33,8 +33,8 @@ describe("trust class categorization for CES lockdown", () => {
33
33
  expect(isUntrustedTrustClass("unknown")).toBe(true);
34
34
  });
35
35
 
36
- test("undefined is not untrusted", () => {
37
- expect(isUntrustedTrustClass(undefined)).toBe(false);
36
+ test("undefined is untrusted", () => {
37
+ expect(isUntrustedTrustClass(undefined)).toBe(true);
38
38
  });
39
39
  });
40
40
 
@@ -70,6 +70,8 @@ mock.module("../security/secure-keys.js", () => {
70
70
  accounts: [...storedKeys.keys()],
71
71
  unreachable: false,
72
72
  }),
73
+ getProviderKeyAsync: async () => undefined,
74
+ getMaskedProviderKey: async () => null,
73
75
  };
74
76
  });
75
77
 
@@ -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: () =>
@@ -16,7 +16,7 @@ mock.module("../config/loader.js", () => ({
16
16
 
17
17
  import type { Database } from "bun:sqlite";
18
18
 
19
- import { getDb, initializeDb, resetDb } from "../memory/db.js";
19
+ import { getDb, initializeDb } from "../memory/db.js";
20
20
  import { executeFollowupCreate } from "../tools/followups/followup_create.js";
21
21
  import { executeFollowupList } from "../tools/followups/followup_list.js";
22
22
  import { executeFollowupResolve } from "../tools/followups/followup_resolve.js";
@@ -24,10 +24,6 @@ import type { ToolContext } from "../tools/types.js";
24
24
 
25
25
  initializeDb();
26
26
 
27
- afterAll(() => {
28
- resetDb();
29
- });
30
-
31
27
  function getRawDb(): Database {
32
28
  return (getDb() as unknown as { $client: Database }).$client;
33
29
  }