@vellumai/assistant 0.5.15 → 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 (503) hide show
  1. package/ARCHITECTURE.md +3 -3
  2. package/Dockerfile +0 -3
  3. package/docs/architecture/integrations.md +15 -14
  4. package/knip.json +4 -1
  5. package/openapi.yaml +670 -122
  6. package/package.json +1 -1
  7. package/src/__tests__/actor-token-service.test.ts +68 -0
  8. package/src/__tests__/agent-loop.test.ts +0 -32
  9. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  10. package/src/__tests__/anthropic-provider.test.ts +57 -3
  11. package/src/__tests__/app-compiler.test.ts +120 -0
  12. package/src/__tests__/assistant-feature-flags-integration.test.ts +5 -377
  13. package/src/__tests__/call-conversation-messages.test.ts +2 -6
  14. package/src/__tests__/call-domain.test.ts +2 -6
  15. package/src/__tests__/call-pointer-messages.test.ts +2 -14
  16. package/src/__tests__/call-recovery.test.ts +2 -6
  17. package/src/__tests__/call-routes-http.test.ts +2 -6
  18. package/src/__tests__/call-store.test.ts +2 -6
  19. package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
  20. package/src/__tests__/canonical-guardian-store.test.ts +2 -6
  21. package/src/__tests__/ces-rpc-credential-backend.test.ts +4 -1
  22. package/src/__tests__/channel-delivery-store.test.ts +2 -6
  23. package/src/__tests__/channel-retry-sweep.test.ts +2 -6
  24. package/src/__tests__/checker.test.ts +84 -3
  25. package/src/__tests__/clawhub.test.ts +54 -24
  26. package/src/__tests__/cli-command-risk-guard.test.ts +108 -6
  27. package/src/__tests__/cli-memory.test.ts +377 -0
  28. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +12 -2
  29. package/src/__tests__/config-schema.test.ts +1 -3
  30. package/src/__tests__/config-set-platform-guard.test.ts +302 -0
  31. package/src/__tests__/config-watcher-feature-flags.test.ts +211 -0
  32. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
  33. package/src/__tests__/contacts-tools.test.ts +31 -0
  34. package/src/__tests__/context-overflow-reducer.test.ts +86 -0
  35. package/src/__tests__/context-token-estimator.test.ts +175 -10
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +9 -0
  37. package/src/__tests__/conversation-agent-loop.test.ts +9 -0
  38. package/src/__tests__/conversation-attachments.test.ts +2 -6
  39. package/src/__tests__/conversation-attention-store.test.ts +2 -6
  40. package/src/__tests__/conversation-clear-safety.test.ts +2 -6
  41. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
  42. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
  43. package/src/__tests__/conversation-disk-view.test.ts +2 -6
  44. package/src/__tests__/conversation-error.test.ts +33 -2
  45. package/src/__tests__/conversation-fork-crud.test.ts +2 -6
  46. package/src/__tests__/conversation-history-web-search.test.ts +5 -0
  47. package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
  48. package/src/__tests__/conversation-media-retry.test.ts +91 -0
  49. package/src/__tests__/conversation-runtime-assembly.test.ts +7 -4
  50. package/src/__tests__/conversation-slash-commands.test.ts +2 -6
  51. package/src/__tests__/conversation-starter-routes.test.ts +20 -11
  52. package/src/__tests__/conversation-store.test.ts +2 -6
  53. package/src/__tests__/conversation-usage.test.ts +3 -6
  54. package/src/__tests__/conversation-wipe.test.ts +11 -408
  55. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
  56. package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
  57. package/src/__tests__/credential-security-e2e.test.ts +6 -1
  58. package/src/__tests__/docker-signing-key-bootstrap.test.ts +7 -73
  59. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -7
  60. package/src/__tests__/followup-tools.test.ts +2 -6
  61. package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
  62. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
  63. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
  64. package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
  65. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
  66. package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
  67. package/src/__tests__/guardian-action-store.test.ts +2 -6
  68. package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
  69. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
  70. package/src/__tests__/guardian-dispatch.test.ts +2 -6
  71. package/src/__tests__/guardian-grant-minting.test.ts +2 -14
  72. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
  73. package/src/__tests__/guardian-routing-invariants.test.ts +343 -6
  74. package/src/__tests__/guardian-routing-state.test.ts +2 -6
  75. package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
  76. package/src/__tests__/heartbeat-service.test.ts +1 -3
  77. package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
  78. package/src/__tests__/injection-block.test.ts +154 -0
  79. package/src/__tests__/install-meta.test.ts +506 -0
  80. package/src/__tests__/install-skill-routing.test.ts +292 -0
  81. package/src/__tests__/intent-routing.test.ts +6 -18
  82. package/src/__tests__/invite-redemption-service.test.ts +2 -6
  83. package/src/__tests__/invite-routes-http.test.ts +2 -6
  84. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -14
  85. package/src/__tests__/list-messages-attachments.test.ts +2 -6
  86. package/src/__tests__/llm-context-route-provider.test.ts +2 -6
  87. package/src/__tests__/llm-request-log-turn-query.test.ts +2 -6
  88. package/src/__tests__/llm-usage-store.test.ts +2 -6
  89. package/src/__tests__/log-export-workspace.test.ts +4 -34
  90. package/src/__tests__/managed-skill-lifecycle.test.ts +7 -37
  91. package/src/__tests__/managed-store.test.ts +40 -21
  92. package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
  93. package/src/__tests__/memory-recall-log-store.test.ts +2 -6
  94. package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
  95. package/src/__tests__/messaging-send-tool.test.ts +6 -6
  96. package/src/__tests__/migration-cross-version-compatibility.test.ts +1 -29
  97. package/src/__tests__/migration-export-http.test.ts +3 -34
  98. package/src/__tests__/migration-import-commit-http.test.ts +1 -29
  99. package/src/__tests__/migration-import-preflight-http.test.ts +3 -34
  100. package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +2 -1
  101. package/src/__tests__/non-member-access-request.test.ts +2 -6
  102. package/src/__tests__/notification-guardian-path.test.ts +2 -6
  103. package/src/__tests__/oauth-apps-routes.test.ts +120 -10
  104. package/src/__tests__/oauth-cli.test.ts +364 -2
  105. package/src/__tests__/oauth-connect-orchestrator.test.ts +709 -0
  106. package/src/__tests__/oauth-provider-serializer.test.ts +2 -1
  107. package/src/__tests__/oauth-provider-visibility.test.ts +149 -0
  108. package/src/__tests__/oauth-providers-routes.test.ts +5 -2
  109. package/src/__tests__/oauth-store.test.ts +0 -5
  110. package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
  111. package/src/__tests__/outlook-attachments.test.ts +301 -0
  112. package/src/__tests__/outlook-automation-tools.test.ts +425 -0
  113. package/src/__tests__/outlook-categories.test.ts +212 -0
  114. package/src/__tests__/outlook-client-automation.test.ts +246 -0
  115. package/src/__tests__/outlook-compose-tools.test.ts +325 -0
  116. package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
  117. package/src/__tests__/outlook-email-watcher.test.ts +322 -0
  118. package/src/__tests__/outlook-follow-up.test.ts +196 -0
  119. package/src/__tests__/outlook-messaging-provider.test.ts +1071 -0
  120. package/src/__tests__/outlook-trash.test.ts +77 -0
  121. package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
  122. package/src/__tests__/path-policy.test.ts +2 -17
  123. package/src/__tests__/permission-types.test.ts +0 -1
  124. package/src/__tests__/platform-callback-registration.test.ts +7 -11
  125. package/src/__tests__/playbook-execution.test.ts +76 -80
  126. package/src/__tests__/playbook-tools.test.ts +5 -7
  127. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  128. package/src/__tests__/provider-error-scenarios.test.ts +21 -2
  129. package/src/__tests__/qdrant-manager.test.ts +68 -21
  130. package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
  131. package/src/__tests__/registry.test.ts +2 -2
  132. package/src/__tests__/require-fresh-approval.test.ts +64 -3
  133. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
  134. package/src/__tests__/runtime-events-sse.test.ts +2 -6
  135. package/src/__tests__/sandbox-diagnostics.test.ts +20 -29
  136. package/src/__tests__/scaffold-managed-skill-tool.test.ts +2 -10
  137. package/src/__tests__/schedule-store.test.ts +2 -6
  138. package/src/__tests__/schedule-tools.test.ts +2 -6
  139. package/src/__tests__/scheduler-recurrence.test.ts +1 -5
  140. package/src/__tests__/scoped-approval-grants.test.ts +2 -6
  141. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
  142. package/src/__tests__/search-skills-unified.test.ts +421 -0
  143. package/src/__tests__/secret-allowlist.test.ts +20 -35
  144. package/src/__tests__/secret-onetime-send.test.ts +2 -0
  145. package/src/__tests__/send-endpoint-busy.test.ts +2 -6
  146. package/src/__tests__/sequence-store.test.ts +2 -6
  147. package/src/__tests__/server-history-render.test.ts +2 -6
  148. package/src/__tests__/shell-credential-ref.test.ts +0 -5
  149. package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
  150. package/src/__tests__/skill-feature-flags.test.ts +6 -6
  151. package/src/__tests__/skill-load-feature-flag.test.ts +13 -54
  152. package/src/__tests__/skill-load-inline-command.test.ts +3 -65
  153. package/src/__tests__/skill-load-inline-includes.test.ts +3 -65
  154. package/src/__tests__/skill-load-tool.test.ts +3 -67
  155. package/src/__tests__/skill-memory.test.ts +480 -195
  156. package/src/__tests__/skills-uninstall.test.ts +2 -2
  157. package/src/__tests__/skills.test.ts +23 -50
  158. package/src/__tests__/slack-channel-config.test.ts +2 -21
  159. package/src/__tests__/slack-inbound-verification.test.ts +2 -6
  160. package/src/__tests__/starter-bundle.test.ts +2 -8
  161. package/src/__tests__/stt-hints.test.ts +7 -2
  162. package/src/__tests__/system-prompt.test.ts +25 -45
  163. package/src/__tests__/task-compiler.test.ts +2 -27
  164. package/src/__tests__/task-management-tools.test.ts +2 -27
  165. package/src/__tests__/task-memory-cleanup.test.ts +173 -250
  166. package/src/__tests__/task-runner.test.ts +2 -27
  167. package/src/__tests__/task-scheduler.test.ts +2 -27
  168. package/src/__tests__/terminal-tools.test.ts +1 -17
  169. package/src/__tests__/test-preload.ts +3 -0
  170. package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +0 -79
  171. package/src/__tests__/tool-approval-handler.test.ts +4 -27
  172. package/src/__tests__/tool-execution-abort-cleanup.test.ts +2 -11
  173. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -25
  174. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  175. package/src/__tests__/tool-executor.test.ts +0 -1
  176. package/src/__tests__/tool-grant-request-escalation.test.ts +4 -27
  177. package/src/__tests__/tool-preview-lifecycle.test.ts +0 -20
  178. package/src/__tests__/tool-side-effects-slack-dm.test.ts +276 -0
  179. package/src/__tests__/trust-store.test.ts +10 -42
  180. package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -30
  181. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +3 -27
  182. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -28
  183. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -28
  184. package/src/__tests__/trusted-contact-verification.test.ts +2 -28
  185. package/src/__tests__/turn-boundary-resolution.test.ts +2 -34
  186. package/src/__tests__/twilio-provider.test.ts +0 -16
  187. package/src/__tests__/twilio-routes-twiml.test.ts +7 -12
  188. package/src/__tests__/twilio-routes.test.ts +0 -24
  189. package/src/__tests__/update-bulletin.test.ts +17 -89
  190. package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -26
  191. package/src/__tests__/usage-routes.test.ts +2 -27
  192. package/src/__tests__/user-reference.test.ts +1 -5
  193. package/src/__tests__/vbundle-pax-and-symlink.test.ts +4 -34
  194. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +2 -53
  195. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  196. package/src/__tests__/voice-invite-redemption.test.ts +2 -27
  197. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -30
  198. package/src/__tests__/voice-session-bridge.test.ts +2 -27
  199. package/src/__tests__/volume-security-guard.test.ts +2 -0
  200. package/src/__tests__/workspace-lifecycle.test.ts +29 -1
  201. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +4 -29
  202. package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +2 -2
  203. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +4 -29
  204. package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
  205. package/src/__tests__/workspace-migration-down-functions.test.ts +0 -6
  206. package/src/__tests__/workspace-policy.test.ts +1 -1
  207. package/src/acp/client-handler.ts +1 -2
  208. package/src/agent/attachments.ts +7 -2
  209. package/src/agent/image-optimize.ts +165 -0
  210. package/src/agent/loop.ts +1 -15
  211. package/src/bundler/app-compiler.ts +179 -2
  212. package/src/bundler/package-resolver.ts +3 -5
  213. package/src/cli/__tests__/notifications.test.ts +1 -24
  214. package/src/cli/cli-memory.ts +179 -0
  215. package/src/cli/commands/avatar.ts +3 -3
  216. package/src/cli/commands/config.ts +26 -13
  217. package/src/cli/commands/doctor.ts +2 -2
  218. package/src/cli/commands/memory.ts +41 -55
  219. package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
  220. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
  221. package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
  222. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
  223. package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
  224. package/src/cli/commands/oauth/connect.ts +26 -6
  225. package/src/cli/commands/oauth/mode.ts +7 -0
  226. package/src/cli/commands/oauth/providers.ts +49 -42
  227. package/src/cli/commands/oauth/shared.ts +39 -3
  228. package/src/cli/commands/platform/__tests__/connect.test.ts +3 -49
  229. package/src/cli/commands/platform/__tests__/disconnect.test.ts +3 -49
  230. package/src/cli/commands/platform/__tests__/status.test.ts +5 -55
  231. package/src/cli/commands/platform/index.ts +16 -16
  232. package/src/cli/commands/skills.ts +88 -16
  233. package/src/cli/commands/trust.ts +2 -2
  234. package/src/cli/lib/daemon-credential-client.ts +2 -3
  235. package/src/config/bundled-skills/acp/TOOLS.json +1 -1
  236. package/src/config/bundled-skills/computer-use/TOOLS.json +7 -7
  237. package/src/config/bundled-skills/contacts/SKILL.md +0 -1
  238. package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
  239. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
  240. package/src/config/bundled-skills/gmail/SKILL.md +2 -10
  241. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
  242. package/src/config/bundled-skills/messaging/SKILL.md +26 -19
  243. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
  244. package/src/config/bundled-skills/outlook/SKILL.md +189 -0
  245. package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
  246. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
  247. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
  248. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
  249. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
  250. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
  251. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
  252. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
  253. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
  254. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
  255. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
  256. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
  257. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
  258. package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
  259. package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
  260. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
  261. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
  262. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
  263. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
  264. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
  265. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
  266. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
  267. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
  268. package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
  269. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
  270. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
  271. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
  272. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
  273. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  274. package/src/config/bundled-skills/slack/SKILL.md +1 -7
  275. package/src/config/bundled-tool-registry.ts +56 -4
  276. package/src/config/env-registry.ts +15 -8
  277. package/src/config/feature-flag-registry.json +29 -116
  278. package/src/config/loader.ts +4 -0
  279. package/src/config/schemas/platform.ts +8 -0
  280. package/src/config/schemas/security.ts +0 -6
  281. package/src/config/schemas/services.ts +8 -0
  282. package/src/config/schemas/timeouts.ts +1 -1
  283. package/src/config/skills.ts +18 -7
  284. package/src/context/token-estimator.ts +25 -18
  285. package/src/context/window-manager.ts +32 -9
  286. package/src/credential-execution/approval-bridge.ts +0 -1
  287. package/src/credential-execution/process-manager.ts +3 -1
  288. package/src/daemon/config-watcher.ts +51 -0
  289. package/src/daemon/context-overflow-reducer.ts +46 -2
  290. package/src/daemon/conversation-agent-loop-handlers.ts +123 -82
  291. package/src/daemon/conversation-agent-loop.ts +99 -63
  292. package/src/daemon/conversation-error.ts +31 -8
  293. package/src/daemon/conversation-lifecycle.ts +33 -0
  294. package/src/daemon/conversation-media-retry.ts +85 -7
  295. package/src/daemon/conversation-notifiers.ts +4 -1
  296. package/src/daemon/conversation-process.ts +1 -0
  297. package/src/daemon/conversation-runtime-assembly.ts +5 -0
  298. package/src/daemon/conversation-usage.ts +1 -0
  299. package/src/daemon/conversation.ts +41 -2
  300. package/src/daemon/daemon-control.ts +8 -2
  301. package/src/daemon/handlers/shared.ts +22 -12
  302. package/src/daemon/handlers/skills.ts +423 -201
  303. package/src/daemon/lifecycle.ts +52 -4
  304. package/src/daemon/main.ts +5 -1
  305. package/src/daemon/message-types/conversations.ts +5 -1
  306. package/src/daemon/message-types/messages.ts +3 -1
  307. package/src/daemon/message-types/skills.ts +97 -36
  308. package/src/daemon/providers-setup.ts +7 -0
  309. package/src/daemon/server.ts +35 -22
  310. package/src/daemon/tool-side-effects.ts +27 -5
  311. package/src/events/domain-events.ts +1 -2
  312. package/src/heartbeat/heartbeat-service.ts +1 -0
  313. package/src/hooks/cli.ts +2 -2
  314. package/src/hooks/runner.ts +15 -38
  315. package/src/inbound/platform-callback-registration.ts +14 -14
  316. package/src/memory/admin.ts +11 -45
  317. package/src/memory/conversation-bootstrap.ts +2 -0
  318. package/src/memory/conversation-crud.ts +242 -348
  319. package/src/memory/conversation-group-migration.ts +157 -0
  320. package/src/memory/conversation-queries.ts +4 -2
  321. package/src/memory/db-init.ts +39 -3
  322. package/src/memory/embed.ts +73 -0
  323. package/src/memory/embedding-backend.ts +8 -14
  324. package/src/memory/embedding-runtime-manager.ts +12 -114
  325. package/src/memory/fingerprint.ts +2 -2
  326. package/src/memory/graph/bootstrap.ts +512 -0
  327. package/src/memory/graph/capability-seed.ts +297 -0
  328. package/src/memory/graph/consolidation.ts +691 -0
  329. package/src/memory/graph/conversation-graph-memory.ts +630 -0
  330. package/src/memory/graph/decay.test.ts +208 -0
  331. package/src/memory/graph/decay.ts +195 -0
  332. package/src/memory/graph/extraction-job.ts +69 -0
  333. package/src/memory/graph/extraction.test.ts +936 -0
  334. package/src/memory/graph/extraction.ts +1254 -0
  335. package/src/memory/graph/graph-search.ts +266 -0
  336. package/src/memory/graph/image-ref-utils.ts +29 -0
  337. package/src/memory/graph/injection.test.ts +513 -0
  338. package/src/memory/graph/injection.ts +439 -0
  339. package/src/memory/graph/inspect.ts +534 -0
  340. package/src/memory/graph/narrative.ts +267 -0
  341. package/src/memory/graph/pattern-scan.ts +269 -0
  342. package/src/memory/graph/retriever.ts +1008 -0
  343. package/src/memory/graph/scoring.test.ts +548 -0
  344. package/src/memory/graph/scoring.ts +232 -0
  345. package/src/memory/graph/serendipity.ts +65 -0
  346. package/src/memory/graph/store.test.ts +1050 -0
  347. package/src/memory/graph/store.ts +699 -0
  348. package/src/memory/graph/tool-handlers.ts +426 -0
  349. package/src/memory/graph/tools.ts +141 -0
  350. package/src/memory/graph/triggers.test.ts +487 -0
  351. package/src/memory/graph/triggers.ts +223 -0
  352. package/src/memory/graph/types.ts +271 -0
  353. package/src/memory/group-crud.ts +191 -0
  354. package/src/memory/indexer.ts +37 -19
  355. package/src/memory/job-handlers/cleanup.ts +0 -53
  356. package/src/memory/job-handlers/conversation-starters.ts +91 -53
  357. package/src/memory/job-handlers/embedding.test.ts +3 -27
  358. package/src/memory/job-handlers/embedding.ts +5 -31
  359. package/src/memory/job-handlers/index-maintenance.ts +23 -11
  360. package/src/memory/job-handlers/summarization.ts +32 -17
  361. package/src/memory/job-utils.ts +1 -1
  362. package/src/memory/jobs-store.ts +50 -70
  363. package/src/memory/jobs-worker.ts +147 -112
  364. package/src/memory/llm-usage-store.ts +35 -2
  365. package/src/memory/message-content.ts +1 -0
  366. package/src/memory/migrations/201-oauth-providers-feature-flag.ts +11 -0
  367. package/src/memory/migrations/202-drop-callback-transport-column.ts +13 -0
  368. package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
  369. package/src/memory/migrations/203-drop-memory-items-tables.ts +23 -0
  370. package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
  371. package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
  372. package/src/memory/migrations/index.ts +6 -0
  373. package/src/memory/migrations/registry.ts +8 -0
  374. package/src/memory/qdrant-client.ts +44 -17
  375. package/src/memory/qdrant-manager.ts +26 -5
  376. package/src/memory/schema/index.ts +1 -0
  377. package/src/memory/schema/memory-graph.ts +139 -0
  378. package/src/memory/schema/oauth.ts +1 -1
  379. package/src/memory/search/semantic.ts +47 -91
  380. package/src/memory/slack-thread-store.ts +17 -0
  381. package/src/memory/task-memory-cleanup.ts +28 -50
  382. package/src/messaging/providers/outlook/adapter.ts +200 -0
  383. package/src/messaging/providers/outlook/client.ts +610 -0
  384. package/src/messaging/providers/outlook/types.ts +201 -0
  385. package/src/notifications/adapters/macos.ts +1 -0
  386. package/src/notifications/adapters/slack.ts +1 -1
  387. package/src/notifications/copy-composer.ts +9 -0
  388. package/src/notifications/signal.ts +16 -0
  389. package/src/oauth/__tests__/identity-verifier.test.ts +1 -1
  390. package/src/oauth/connect-orchestrator.ts +10 -3
  391. package/src/oauth/oauth-store.ts +10 -11
  392. package/src/oauth/provider-serializer.ts +3 -0
  393. package/src/oauth/provider-visibility.ts +16 -0
  394. package/src/oauth/seed-providers.ts +50 -17
  395. package/src/permissions/checker.ts +62 -9
  396. package/src/permissions/defaults.ts +4 -4
  397. package/src/permissions/types.ts +2 -4
  398. package/src/permissions/workspace-policy.ts +1 -1
  399. package/src/playbooks/playbook-compiler.ts +19 -18
  400. package/src/playbooks/types.ts +4 -3
  401. package/src/prompts/system-prompt.ts +6 -93
  402. package/src/prompts/templates/UPDATES.md +6 -0
  403. package/src/providers/anthropic/client.ts +47 -19
  404. package/src/providers/gemini/client.ts +1 -1
  405. package/src/providers/openai/client.ts +1 -1
  406. package/src/providers/registry.ts +1 -1
  407. package/src/providers/retry.ts +19 -3
  408. package/src/runtime/actor-trust-resolver.ts +5 -1
  409. package/src/runtime/auth/__tests__/credential-service.test.ts +1 -27
  410. package/src/runtime/auth/__tests__/token-service.test.ts +1 -25
  411. package/src/runtime/auth/route-policy.ts +7 -4
  412. package/src/runtime/guardian-reply-router.ts +10 -2
  413. package/src/runtime/http-server.ts +23 -3
  414. package/src/runtime/middleware/auth.ts +20 -0
  415. package/src/runtime/routes/attachment-routes.test.ts +106 -0
  416. package/src/runtime/routes/attachment-routes.ts +106 -16
  417. package/src/runtime/routes/brain-graph-routes.ts +21 -22
  418. package/src/runtime/routes/btw-routes.ts +8 -0
  419. package/src/runtime/routes/conversation-management-routes.ts +2 -0
  420. package/src/runtime/routes/conversation-query-routes.ts +2 -58
  421. package/src/runtime/routes/conversation-starter-routes.ts +2 -2
  422. package/src/runtime/routes/debug-routes.ts +1 -1
  423. package/src/runtime/routes/global-search-routes.ts +21 -19
  424. package/src/runtime/routes/group-routes.ts +207 -0
  425. package/src/runtime/routes/guardian-action-routes.ts +21 -10
  426. package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
  427. package/src/runtime/routes/inbound-message-handler.ts +19 -0
  428. package/src/runtime/routes/inbound-stages/background-dispatch.ts +43 -2
  429. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
  430. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
  431. package/src/runtime/routes/memory-item-routes.test.ts +2 -31
  432. package/src/runtime/routes/memory-item-routes.ts +385 -341
  433. package/src/runtime/routes/oauth-apps.ts +18 -1
  434. package/src/runtime/routes/oauth-providers.ts +13 -1
  435. package/src/runtime/routes/schedule-routes.ts +2 -0
  436. package/src/runtime/routes/settings-routes.ts +1 -0
  437. package/src/runtime/routes/skills-routes.ts +103 -37
  438. package/src/runtime/routes/usage-routes.ts +19 -2
  439. package/src/runtime/routes/work-items-routes.test.ts +2 -27
  440. package/src/runtime/routes/workspace-routes.test.ts +3 -27
  441. package/src/schedule/scheduler.ts +8 -1
  442. package/src/security/oauth2.ts +1 -1
  443. package/src/security/secret-allowlist.ts +4 -4
  444. package/src/security/secure-keys.ts +4 -8
  445. package/src/shared/provider-env-vars.ts +19 -0
  446. package/src/skills/catalog-cache.ts +5 -0
  447. package/src/skills/catalog-install.ts +15 -14
  448. package/src/skills/clawhub.ts +134 -154
  449. package/src/skills/install-meta.ts +208 -0
  450. package/src/skills/managed-store.ts +27 -16
  451. package/src/skills/skill-memory.ts +210 -96
  452. package/src/skills/skillssh-registry.ts +19 -17
  453. package/src/tasks/task-runner.ts +3 -1
  454. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
  455. package/src/tools/browser/runtime-check.ts +3 -1
  456. package/src/tools/memory/register.ts +63 -46
  457. package/src/tools/permission-checker.ts +7 -19
  458. package/src/tools/shared/filesystem/image-read.ts +22 -85
  459. package/src/tools/skills/skill-script-runner.ts +1 -1
  460. package/src/tools/terminal/safe-env.ts +1 -0
  461. package/src/tools/tool-manifest.ts +3 -3
  462. package/src/util/browser.ts +25 -10
  463. package/src/util/bun-runtime.ts +172 -0
  464. package/src/util/device-id.ts +3 -65
  465. package/src/watcher/providers/outlook-calendar.ts +343 -0
  466. package/src/watcher/providers/outlook.ts +198 -0
  467. package/src/workspace/git-service.ts +27 -6
  468. package/src/workspace/migrations/025-remove-oauth-app-setup-skills.ts +76 -0
  469. package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
  470. package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
  471. package/src/workspace/migrations/registry.ts +6 -0
  472. package/src/__tests__/context-memory-e2e.test.ts +0 -415
  473. package/src/__tests__/journal-context.test.ts +0 -268
  474. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
  475. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
  476. package/src/__tests__/memory-query-builder.test.ts +0 -59
  477. package/src/__tests__/memory-recall-quality.test.ts +0 -1046
  478. package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
  479. package/src/__tests__/memory-regressions.test.ts +0 -3696
  480. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
  481. package/src/daemon/conversation-memory.ts +0 -207
  482. package/src/memory/conversation-starters-cadence.ts +0 -74
  483. package/src/memory/items-extractor.ts +0 -860
  484. package/src/memory/job-handlers/batch-extraction.ts +0 -741
  485. package/src/memory/job-handlers/extraction.ts +0 -40
  486. package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -383
  487. package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
  488. package/src/memory/journal-memory.ts +0 -224
  489. package/src/memory/query-builder.ts +0 -47
  490. package/src/memory/query-expansion.ts +0 -83
  491. package/src/memory/retriever.test.ts +0 -1590
  492. package/src/memory/retriever.ts +0 -1323
  493. package/src/memory/search/formatting.test.ts +0 -140
  494. package/src/memory/search/formatting.ts +0 -262
  495. package/src/memory/search/mmr.ts +0 -136
  496. package/src/memory/search/ranking.ts +0 -15
  497. package/src/memory/search/staleness.ts +0 -40
  498. package/src/memory/search/tier-classifier.ts +0 -18
  499. package/src/memory/search/types.ts +0 -121
  500. package/src/prompts/journal-context.ts +0 -156
  501. package/src/tools/memory/definitions.ts +0 -69
  502. package/src/tools/memory/handlers.test.ts +0 -590
  503. package/src/tools/memory/handlers.ts +0 -434
@@ -1,29 +1,80 @@
1
- import { and, eq } from "drizzle-orm";
1
+ import { and, eq, sql } from "drizzle-orm";
2
2
  import { v4 as uuid } from "uuid";
3
3
 
4
4
  import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
5
5
  import { getConfig } from "../config/loader.js";
6
+ import { resolveSkillStates } from "../config/skill-state.js";
7
+ import { loadSkillCatalog, type SkillSummary } from "../config/skills.js";
6
8
  import { getDb } from "../memory/db.js";
7
- import { computeMemoryFingerprint } from "../memory/fingerprint.js";
8
9
  import { enqueueMemoryJob } from "../memory/jobs-store.js";
9
- import { memoryItems } from "../memory/schema.js";
10
+ import { memoryGraphNodes } from "../memory/schema.js";
10
11
  import { getLogger } from "../util/logger.js";
11
- import { type CatalogSkill, resolveCatalog } from "./catalog-install.js";
12
+ import { getCachedCatalogSync } from "./catalog-cache.js";
13
+ import type { CatalogSkill } from "./catalog-install.js";
12
14
 
13
15
  const log = getLogger("skill-memory");
14
16
 
17
+ /** Escape SQL LIKE wildcards so they match literally.
18
+ * Uses backslash as the escape character — callers must pair with ESCAPE '\\'. */
19
+ function escapeLike(s: string): string {
20
+ return s.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
21
+ }
22
+
23
+ /**
24
+ * Generic input for building capability statements.
25
+ * Decoupled from CatalogSkill so other skill sources (e.g. bundled skills) can
26
+ * produce capability memories without being shoehorned into the catalog type.
27
+ */
28
+ export interface SkillCapabilityInput {
29
+ id: string;
30
+ displayName: string;
31
+ description: string;
32
+ activationHints?: string[];
33
+ avoidWhen?: string[];
34
+ }
35
+
36
+ /**
37
+ * Convert a SkillSummary to a SkillCapabilityInput.
38
+ * SkillSummary already has flat properties, so this is a straightforward mapping.
39
+ */
40
+ export function fromSkillSummary(entry: SkillSummary): SkillCapabilityInput {
41
+ return {
42
+ id: entry.id,
43
+ displayName: entry.displayName,
44
+ description: entry.description,
45
+ activationHints: entry.activationHints,
46
+ avoidWhen: entry.avoidWhen,
47
+ };
48
+ }
49
+
15
50
  /**
16
- * Build a semantically rich capability statement from a catalog skill entry.
51
+ * Convert a CatalogSkill to a SkillCapabilityInput.
52
+ * CatalogSkill stores display-name and hints inside nested metadata.
53
+ */
54
+ export function fromCatalogSkill(entry: CatalogSkill): SkillCapabilityInput {
55
+ return {
56
+ id: entry.id,
57
+ displayName: entry.metadata?.vellum?.["display-name"] ?? entry.name,
58
+ description: entry.description,
59
+ activationHints: entry.metadata?.vellum?.["activation-hints"],
60
+ avoidWhen: entry.metadata?.vellum?.["avoid-when"],
61
+ };
62
+ }
63
+
64
+ /**
65
+ * Build a semantically rich capability statement from a skill capability input.
17
66
  * Truncated to 500 chars max (matching the limit used by memory item extraction).
18
67
  */
19
- export function buildCapabilityStatement(entry: CatalogSkill): string {
20
- const displayName = entry.metadata?.vellum?.["display-name"] ?? entry.name;
21
- const activationHints = entry.metadata?.vellum?.["activation-hints"];
68
+ export function buildCapabilityStatement(input: SkillCapabilityInput): string {
69
+ const { displayName, activationHints, avoidWhen } = input;
22
70
 
23
- let statement = `The "${displayName}" skill (${entry.id}) is available. ${entry.description}.`;
71
+ let statement = `The "${displayName}" skill (${input.id}) is available. ${input.description}.`;
24
72
  if (activationHints && activationHints.length > 0) {
25
73
  statement += ` Use when: ${activationHints.join("; ")}.`;
26
74
  }
75
+ if (avoidWhen && avoidWhen.length > 0) {
76
+ statement += ` Avoid when: ${avoidWhen.join("; ")}.`;
77
+ }
27
78
 
28
79
  // Truncate to 500 chars max
29
80
  if (statement.length > 500) {
@@ -33,134 +84,140 @@ export function buildCapabilityStatement(entry: CatalogSkill): string {
33
84
  return statement;
34
85
  }
35
86
 
87
+ /** Default emotional charge for capability graph nodes. */
88
+ const DEFAULT_EMOTIONAL_CHARGE = JSON.stringify({
89
+ valence: 0,
90
+ intensity: 0.1,
91
+ decayCurve: "linear",
92
+ decayRate: 0.05,
93
+ originalIntensity: 0.1,
94
+ });
95
+
36
96
  /**
37
- * Upsert a capability memory item for a catalog skill.
97
+ * Upsert a capability memory graph node for a skill.
38
98
  * Best-effort: errors are logged but never thrown.
39
99
  */
40
100
  export function upsertSkillCapabilityMemory(
41
101
  skillId: string,
42
- entry: CatalogSkill,
102
+ input: SkillCapabilityInput,
43
103
  ): void {
44
104
  try {
45
105
  const db = getDb();
46
- const subject = `skill:${skillId}`;
47
- const statement = buildCapabilityStatement(entry);
48
- const kind = "capability";
106
+ const statement = buildCapabilityStatement(input);
107
+ const content = `skill:${skillId}\n${statement}`;
49
108
  const scopeId = "default";
50
- const confidence = 1.0;
51
- const importance = 0.7;
52
- const fingerprint = computeMemoryFingerprint(
53
- scopeId,
54
- kind,
55
- subject,
56
- statement,
57
- );
58
109
  const now = Date.now();
59
110
 
60
111
  const existing = db
61
112
  .select()
62
- .from(memoryItems)
113
+ .from(memoryGraphNodes)
63
114
  .where(
64
115
  and(
65
- eq(memoryItems.kind, kind),
66
- eq(memoryItems.subject, subject),
67
- eq(memoryItems.scopeId, scopeId),
116
+ eq(memoryGraphNodes.type, "procedural"),
117
+ sql`${memoryGraphNodes.content} LIKE ${'skill:' + escapeLike(skillId) + '\n%'} ESCAPE '\\'`,
118
+ eq(memoryGraphNodes.scopeId, scopeId),
68
119
  ),
69
120
  )
70
121
  .get();
71
122
 
72
123
  if (existing) {
73
124
  if (
74
- existing.status === "active" &&
75
- existing.fingerprint === fingerprint
125
+ existing.content === content &&
126
+ existing.fidelity !== "gone"
76
127
  ) {
77
- // Same content — just touch lastSeenAt
78
- db.update(memoryItems)
79
- .set({ lastSeenAt: now })
80
- .where(eq(memoryItems.id, existing.id))
128
+ // Same content — just touch lastAccessed
129
+ db.update(memoryGraphNodes)
130
+ .set({ lastAccessed: now })
131
+ .where(eq(memoryGraphNodes.id, existing.id))
81
132
  .run();
82
133
  return;
83
134
  }
84
135
 
85
- if (existing.status === "active") {
86
- // Content changed — update statement and fingerprint
87
- db.update(memoryItems)
136
+ if (existing.fidelity !== "gone") {
137
+ // Content changed — update content
138
+ db.update(memoryGraphNodes)
88
139
  .set({
89
- statement,
90
- fingerprint,
91
- lastSeenAt: now,
140
+ content,
141
+ lastAccessed: now,
92
142
  })
93
- .where(eq(memoryItems.id, existing.id))
143
+ .where(eq(memoryGraphNodes.id, existing.id))
94
144
  .run();
95
- enqueueMemoryJob("embed_item", { itemId: existing.id });
145
+ enqueueMemoryJob("embed_graph_node", { nodeId: existing.id });
96
146
  return;
97
147
  }
98
148
 
99
- // status === "deleted" or other — reactivate
100
- db.update(memoryItems)
149
+ // fidelity === "gone" — reactivate
150
+ db.update(memoryGraphNodes)
101
151
  .set({
102
- status: "active",
103
- statement,
104
- fingerprint,
105
- lastSeenAt: now,
106
- firstSeenAt: now,
152
+ fidelity: "vivid",
153
+ content,
154
+ created: now,
155
+ lastAccessed: now,
107
156
  })
108
- .where(eq(memoryItems.id, existing.id))
157
+ .where(eq(memoryGraphNodes.id, existing.id))
109
158
  .run();
110
- enqueueMemoryJob("embed_item", { itemId: existing.id });
159
+ enqueueMemoryJob("embed_graph_node", { nodeId: existing.id });
160
+ log.info({ skillId, nodeId: existing.id }, "Reactivated skill capability memory");
111
161
  return;
112
162
  }
113
163
 
114
- // No existing — insert new row
164
+ // No existing — insert new graph node
115
165
  const id = uuid();
116
- db.insert(memoryItems)
166
+ db.insert(memoryGraphNodes)
117
167
  .values({
118
168
  id,
119
- kind,
120
- subject,
121
- statement,
122
- status: "active",
123
- confidence,
124
- importance,
125
- fingerprint,
126
- sourceType: "extraction",
169
+ content,
170
+ type: "procedural",
171
+ created: now,
172
+ lastAccessed: now,
173
+ lastConsolidated: now,
174
+ emotionalCharge: DEFAULT_EMOTIONAL_CHARGE,
175
+ fidelity: "vivid",
176
+ confidence: 1.0,
177
+ significance: 0.7,
178
+ stability: 14,
179
+ reinforcementCount: 0,
180
+ lastReinforced: now,
181
+ sourceConversations: JSON.stringify([]),
182
+ sourceType: "inferred",
183
+ narrativeRole: null,
184
+ partOfStory: null,
127
185
  scopeId,
128
- firstSeenAt: now,
129
- lastSeenAt: now,
130
186
  })
131
187
  .run();
132
- enqueueMemoryJob("embed_item", { itemId: id });
188
+ enqueueMemoryJob("embed_graph_node", { nodeId: id });
189
+ log.info({ skillId, nodeId: id }, "Created skill capability memory");
133
190
  } catch (err) {
134
191
  log.warn({ err, skillId }, "Failed to upsert skill capability memory");
135
192
  }
136
193
  }
137
194
 
138
195
  /**
139
- * Soft-delete the capability memory item for a skill.
196
+ * Soft-delete the capability memory graph node for a skill.
140
197
  * Best-effort: errors are logged but never thrown.
141
198
  */
142
199
  export function deleteSkillCapabilityMemory(skillId: string): void {
143
200
  try {
144
201
  const db = getDb();
145
- const subject = `skill:${skillId}`;
146
202
  const now = Date.now();
147
203
 
148
204
  const existing = db
149
205
  .select()
150
- .from(memoryItems)
206
+ .from(memoryGraphNodes)
151
207
  .where(
152
208
  and(
153
- eq(memoryItems.kind, "capability"),
154
- eq(memoryItems.subject, subject),
155
- eq(memoryItems.scopeId, "default"),
209
+ eq(memoryGraphNodes.type, "procedural"),
210
+ sql`${memoryGraphNodes.content} LIKE ${'skill:' + escapeLike(skillId) + '\n%'} ESCAPE '\\'`,
211
+ eq(memoryGraphNodes.scopeId, "default"),
212
+ sql`${memoryGraphNodes.fidelity} != 'gone'`,
156
213
  ),
157
214
  )
158
215
  .get();
159
216
 
160
- if (existing && existing.status !== "deleted") {
161
- db.update(memoryItems)
162
- .set({ status: "deleted", lastSeenAt: now })
163
- .where(eq(memoryItems.id, existing.id))
217
+ if (existing) {
218
+ db.update(memoryGraphNodes)
219
+ .set({ fidelity: "gone", lastAccessed: now })
220
+ .where(eq(memoryGraphNodes.id, existing.id))
164
221
  .run();
165
222
  }
166
223
  } catch (err) {
@@ -169,54 +226,111 @@ export function deleteSkillCapabilityMemory(skillId: string): void {
169
226
  }
170
227
 
171
228
  /**
172
- * Seed capability memory items for all catalog skills.
173
- * Prunes stale entries whose skills are no longer in the catalog.
229
+ * Seed capability memory graph nodes for all enabled skills (bundled, managed, workspace, extra).
230
+ * Prunes stale entries whose skills are no longer in the enabled set.
174
231
  * Best-effort: errors are logged but never thrown.
175
232
  */
176
- export async function seedCatalogSkillMemories(): Promise<void> {
233
+ export function seedCatalogSkillMemories(): void {
177
234
  try {
178
- const catalog = await resolveCatalog();
235
+ const catalog = loadSkillCatalog();
179
236
  const config = getConfig();
237
+ const resolved = resolveSkillStates(catalog, config);
238
+ const enabled = resolved.filter((r) => r.state === "enabled");
239
+
180
240
  const catalogIds = new Set<string>();
241
+ for (const { summary } of enabled) {
242
+ catalogIds.add(summary.id);
243
+ const input = fromSkillSummary(summary);
181
244
 
182
- for (const entry of catalog) {
183
- // Skip skills whose feature flag is disabled
184
- const flagId = entry.metadata?.vellum?.["feature-flag"];
185
- if (flagId) {
186
- if (!isAssistantFeatureFlagEnabled(flagId, config)) {
187
- continue;
245
+ // Enrich mcp-setup description with configured server names
246
+ if (summary.id === "mcp-setup") {
247
+ const servers = config.mcp?.servers;
248
+ if (servers) {
249
+ const names = Object.keys(servers).filter(
250
+ (name) => servers[name]?.enabled !== false,
251
+ );
252
+ if (names.length > 0) {
253
+ input.description += ` Configured: ${names.join(", ")}`;
254
+ }
188
255
  }
189
256
  }
190
257
 
191
- catalogIds.add(entry.id);
192
- upsertSkillCapabilityMemory(entry.id, entry);
258
+ upsertSkillCapabilityMemory(summary.id, input);
193
259
  }
194
260
 
195
- // Prune stale capability memories for skills no longer in catalog
261
+ // Prune stale capability memories for skills no longer in the enabled set
262
+ // and not available in the remote/local catalog.
196
263
  const db = getDb();
197
264
  const allCapabilities = db
198
265
  .select()
199
- .from(memoryItems)
266
+ .from(memoryGraphNodes)
200
267
  .where(
201
268
  and(
202
- eq(memoryItems.kind, "capability"),
203
- eq(memoryItems.scopeId, "default"),
204
- eq(memoryItems.status, "active"),
269
+ eq(memoryGraphNodes.type, "procedural"),
270
+ eq(memoryGraphNodes.scopeId, "default"),
271
+ sql`${memoryGraphNodes.fidelity} != 'gone'`,
205
272
  ),
206
273
  )
207
274
  .all();
208
275
 
276
+ const allLocalSkillIds = new Set(catalog.map((s) => s.id));
277
+ const cachedCatalog = getCachedCatalogSync();
278
+ const cachedCatalogIds = new Set(cachedCatalog.map((s) => s.id));
279
+
209
280
  const now = Date.now();
210
281
  for (const item of allCapabilities) {
211
- const itemSkillId = item.subject.replace("skill:", "");
212
- if (!catalogIds.has(itemSkillId)) {
213
- db.update(memoryItems)
214
- .set({ status: "deleted", lastSeenAt: now })
215
- .where(eq(memoryItems.id, item.id))
216
- .run();
217
- }
282
+ if (!item.content.startsWith("skill:")) continue;
283
+ const itemSkillId = item.content.split("\n")[0].replace("skill:", "");
284
+
285
+ // Keep enabled skills
286
+ if (catalogIds.has(itemSkillId)) continue;
287
+
288
+ // Keep uninstalled catalog skills that are still in the remote catalog
289
+ if (cachedCatalogIds.has(itemSkillId)) continue;
290
+
291
+ // If the catalog cache is empty (cold start, before async fetch),
292
+ // we can't tell whether an unknown skill is a stale entry or
293
+ // a valid uninstalled catalog skill. Only prune skills we can
294
+ // positively identify as local-but-disabled.
295
+ if (cachedCatalogIds.size === 0 && !allLocalSkillIds.has(itemSkillId)) continue;
296
+
297
+ log.info({ skillId: itemSkillId, nodeId: item.id, catalogSize: catalogIds.size, cacheSize: cachedCatalogIds.size }, "Pruning stale skill capability memory");
298
+ db.update(memoryGraphNodes)
299
+ .set({ fidelity: "gone", lastAccessed: now })
300
+ .where(eq(memoryGraphNodes.id, item.id))
301
+ .run();
218
302
  }
219
303
  } catch (err) {
220
304
  log.warn({ err }, "Failed to seed catalog skill memories");
221
305
  }
222
306
  }
307
+
308
+ /**
309
+ * Seed capability memories for catalog skills that are not yet installed.
310
+ * This makes uninstalled skills discoverable via memory injection so the LLM
311
+ * can auto-install them via skill_load when relevant.
312
+ * Best-effort: errors are logged but never thrown.
313
+ */
314
+ export async function seedUninstalledCatalogSkillMemories(): Promise<void> {
315
+ try {
316
+ const { getCatalog } = await import("./catalog-cache.js");
317
+ const fullCatalog = await getCatalog();
318
+ if (fullCatalog.length === 0) return;
319
+
320
+ const installedCatalog = loadSkillCatalog();
321
+ const installedIds = new Set(installedCatalog.map((s) => s.id));
322
+
323
+ const config = getConfig();
324
+ for (const entry of fullCatalog) {
325
+ if (installedIds.has(entry.id)) continue;
326
+
327
+ const flagKey = entry.metadata?.vellum?.["feature-flag"];
328
+ if (flagKey && !isAssistantFeatureFlagEnabled(flagKey, config)) continue;
329
+
330
+ const input = fromCatalogSkill(entry);
331
+ upsertSkillCapabilityMemory(entry.id, input);
332
+ }
333
+ } catch (err) {
334
+ log.warn({ err }, "Failed to seed uninstalled catalog skill memories");
335
+ }
336
+ }
@@ -5,6 +5,7 @@ import { dirname, join, resolve, sep } from "node:path";
5
5
 
6
6
  import { getWorkspaceSkillsDir } from "../util/platform.js";
7
7
  import { upsertSkillsIndex } from "./catalog-install.js";
8
+ import { computeSkillHash, writeInstallMeta } from "./install-meta.js";
8
9
 
9
10
  // ─── Types ───────────────────────────────────────────────────────────────────
10
11
 
@@ -434,9 +435,12 @@ export function validateSkillSlug(slug: string): void {
434
435
  * 1. Validates the skill slug for path safety
435
436
  * 2. Fetches all files from `skills/<skillSlug>/` in the source repo
436
437
  * 3. Writes them to `<workspace>/skills/<skillSlug>/` with path traversal protection
437
- * 4. Writes `version.json` with origin metadata
438
- * 5. Runs `bun install` if a `package.json` is present
439
- * 6. Registers the skill in SKILLS.md only after all steps succeed
438
+ * 4. Writes `install-meta.json` with origin metadata
439
+ * 5. Installs npm dependencies (if package.json exists)
440
+ * 6. Updates SKILLS.md index
441
+ *
442
+ * Auto-enable and memory seeding are handled by the caller (e.g.
443
+ * `postInstallSkill()` in the daemon, or left to the user for CLI installs).
440
444
  */
441
445
  export async function installExternalSkill(
442
446
  owner: string,
@@ -444,6 +448,7 @@ export async function installExternalSkill(
444
448
  skillSlug: string,
445
449
  overwrite: boolean,
446
450
  ref?: string,
451
+ contactId?: string,
447
452
  ): Promise<void> {
448
453
  // Validate slug before using in filesystem paths
449
454
  validateSkillSlug(skillSlug);
@@ -480,20 +485,19 @@ export async function installExternalSkill(
480
485
  writeFileSync(destPath, content, "utf-8");
481
486
  }
482
487
 
483
- // Write origin metadata
484
- const meta = {
485
- origin: "skills.sh",
486
- source: `${owner}/${repo}`,
487
- skillSlug,
488
+ // Write install metadata
489
+ writeInstallMeta(skillDir, {
490
+ origin: "skillssh",
491
+ slug: skillSlug,
492
+ sourceRepo: `${owner}/${repo}`,
488
493
  installedAt: new Date().toISOString(),
489
- };
490
- writeFileSync(
491
- join(skillDir, "version.json"),
492
- JSON.stringify(meta, null, 2) + "\n",
493
- "utf-8",
494
- );
494
+ ...(contactId ? { installedBy: contactId } : {}),
495
+ contentHash: computeSkillHash(skillDir) ?? undefined,
496
+ });
495
497
 
496
- // Install npm dependencies if the skill ships a package.json
498
+ // Post-install: install dependencies first, then index the skill.
499
+ // Running bun install before upsertSkillsIndex ensures we don't index a
500
+ // skill whose dependencies failed to install.
497
501
  if (existsSync(join(skillDir, "package.json"))) {
498
502
  const bunPath = `${homedir()}/.bun/bin`;
499
503
  execSync("bun install", {
@@ -502,7 +506,5 @@ export async function installExternalSkill(
502
506
  env: { ...process.env, PATH: `${bunPath}:${process.env.PATH}` },
503
507
  });
504
508
  }
505
-
506
- // Register in SKILLS.md only after files are written and deps installed
507
509
  upsertSkillsIndex(skillSlug);
508
510
  }
@@ -64,8 +64,10 @@ export async function runTask(
64
64
  // Scheduled section; non-schedule tasks use "background" to stay out of
65
65
  // the main conversation list.
66
66
  conversationType: opts.source === "schedule" ? undefined : "background",
67
- source: opts.source,
67
+ source: opts.source === "schedule" ? "schedule" : "task",
68
68
  scheduleJobId: opts.scheduleJobId,
69
+ groupId:
70
+ opts.source === "schedule" ? "system:scheduled" : "system:background",
69
71
  origin: "task",
70
72
  systemHint: `Task: ${task.title}`,
71
73
  });
@@ -504,17 +504,15 @@ describe("UsageTelemetryReporter", () => {
504
504
  // No HTTP call should have been made
505
505
  expect(mockFetch).not.toHaveBeenCalled();
506
506
 
507
- // All 6 watermarks should have been advanced (3 timestamps + 3 IDs)
508
- expect(mockSetMemoryCheckpoint).toHaveBeenCalledTimes(6);
507
+ // All 3 timestamp watermarks should have been advanced (IDs left untouched
508
+ // so the compound-cursor branch stays active)
509
+ expect(mockSetMemoryCheckpoint).toHaveBeenCalledTimes(3);
509
510
 
510
511
  const calls = mockSetMemoryCheckpoint.mock.calls;
511
512
  const keys = calls.map((c) => c[0]);
512
513
  expect(keys).toContain("telemetry:usage:last_reported_at");
513
- expect(keys).toContain("telemetry:usage:last_reported_id");
514
514
  expect(keys).toContain("telemetry:turns:last_reported_at");
515
- expect(keys).toContain("telemetry:turns:last_reported_id");
516
515
  expect(keys).toContain("telemetry:lifecycle:last_reported_at");
517
- expect(keys).toContain("telemetry:lifecycle:last_reported_id");
518
516
  });
519
517
 
520
518
  test("events sent normally after re-enabling collectUsageData", async () => {
@@ -1,6 +1,7 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
 
4
+ import { ensureBun } from "../../util/bun-runtime.js";
4
5
  import { getExternalDir } from "../../util/platform.js";
5
6
 
6
7
  export interface BrowserRuntimeStatus {
@@ -83,7 +84,8 @@ export async function importPlaywright(): Promise<typeof import("playwright")> {
83
84
  if (!existsSync(join(externalDir, "package.json"))) {
84
85
  writeFileSync(join(externalDir, "package.json"), '{"private":true}\n');
85
86
  }
86
- const proc = Bun.spawn(["bun", "add", "playwright"], {
87
+ const bunPath = await ensureBun();
88
+ const proc = Bun.spawn([bunPath, "add", "playwright"], {
87
89
  cwd: externalDir,
88
90
  stdout: "pipe",
89
91
  stderr: "pipe",