@vellumai/assistant 0.5.16 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (592) hide show
  1. package/AGENTS.md +4 -0
  2. package/ARCHITECTURE.md +69 -16
  3. package/Dockerfile +2 -5
  4. package/bun.lock +6 -2
  5. package/docker-entrypoint.sh +32 -1
  6. package/docs/architecture/integrations.md +1 -1
  7. package/docs/architecture/memory.md +21 -24
  8. package/knip.json +2 -1
  9. package/openapi.yaml +1198 -83
  10. package/package.json +5 -1
  11. package/src/__tests__/actor-token-service.test.ts +68 -0
  12. package/src/__tests__/agent-loop.test.ts +0 -32
  13. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  14. package/src/__tests__/anthropic-provider.test.ts +217 -98
  15. package/src/__tests__/app-compiler.test.ts +120 -0
  16. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  17. package/src/__tests__/app-executors.test.ts +47 -1
  18. package/src/__tests__/app-source-watcher.test.ts +159 -0
  19. package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -2
  20. package/src/__tests__/call-conversation-messages.test.ts +2 -6
  21. package/src/__tests__/call-domain.test.ts +2 -6
  22. package/src/__tests__/call-pointer-messages.test.ts +2 -14
  23. package/src/__tests__/call-recovery.test.ts +2 -6
  24. package/src/__tests__/call-routes-http.test.ts +2 -6
  25. package/src/__tests__/call-store.test.ts +2 -6
  26. package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
  27. package/src/__tests__/canonical-guardian-store.test.ts +2 -6
  28. package/src/__tests__/channel-delivery-store.test.ts +2 -6
  29. package/src/__tests__/channel-retry-sweep.test.ts +2 -6
  30. package/src/__tests__/checker.test.ts +63 -9
  31. package/src/__tests__/clawhub.test.ts +54 -24
  32. package/src/__tests__/cli-command-risk-guard.test.ts +14 -0
  33. package/src/__tests__/config-schema.test.ts +6 -1
  34. package/src/__tests__/config-set-platform-guard.test.ts +302 -0
  35. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
  36. package/src/__tests__/contacts-tools.test.ts +31 -0
  37. package/src/__tests__/context-overflow-reducer.test.ts +86 -0
  38. package/src/__tests__/context-token-estimator.test.ts +175 -10
  39. package/src/__tests__/conversation-agent-loop-overflow.test.ts +13 -6
  40. package/src/__tests__/conversation-agent-loop.test.ts +13 -51
  41. package/src/__tests__/conversation-attachments.test.ts +2 -6
  42. package/src/__tests__/conversation-attention-store.test.ts +2 -6
  43. package/src/__tests__/conversation-clear-safety.test.ts +2 -6
  44. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
  45. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
  46. package/src/__tests__/conversation-disk-view.test.ts +2 -6
  47. package/src/__tests__/conversation-error.test.ts +33 -2
  48. package/src/__tests__/conversation-fork-crud.test.ts +2 -6
  49. package/src/__tests__/conversation-history-web-search.test.ts +6 -1
  50. package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
  51. package/src/__tests__/conversation-media-retry.test.ts +91 -0
  52. package/src/__tests__/conversation-runtime-assembly.test.ts +653 -832
  53. package/src/__tests__/conversation-runtime-workspace.test.ts +1 -93
  54. package/src/__tests__/conversation-starter-routes.test.ts +20 -11
  55. package/src/__tests__/conversation-store.test.ts +2 -6
  56. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +17 -4
  57. package/src/__tests__/conversation-usage.test.ts +2 -6
  58. package/src/__tests__/conversation-wipe.test.ts +13 -414
  59. package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -12
  60. package/src/__tests__/conversation-workspace-injection.test.ts +25 -26
  61. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
  62. package/src/__tests__/copy-composer-tc-templates.test.ts +335 -0
  63. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
  64. package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
  65. package/src/__tests__/credential-security-e2e.test.ts +2 -0
  66. package/src/__tests__/date-context.test.ts +76 -210
  67. package/src/__tests__/db-schedule-syntax-migration.test.ts +16 -1
  68. package/src/__tests__/file-list-tool.test.ts +219 -0
  69. package/src/__tests__/first-greeting.test.ts +1 -1
  70. package/src/__tests__/followup-tools.test.ts +2 -6
  71. package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
  72. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
  73. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
  74. package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
  75. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
  76. package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
  77. package/src/__tests__/guardian-action-store.test.ts +2 -6
  78. package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
  79. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
  80. package/src/__tests__/guardian-dispatch.test.ts +2 -6
  81. package/src/__tests__/guardian-grant-minting.test.ts +2 -14
  82. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
  83. package/src/__tests__/guardian-routing-invariants.test.ts +192 -6
  84. package/src/__tests__/guardian-routing-state.test.ts +2 -6
  85. package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
  86. package/src/__tests__/heartbeat-service.test.ts +180 -3
  87. package/src/__tests__/identity-routes.test.ts +328 -0
  88. package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
  89. package/src/__tests__/injection-block.test.ts +178 -0
  90. package/src/__tests__/install-meta.test.ts +506 -0
  91. package/src/__tests__/install-skill-routing.test.ts +293 -0
  92. package/src/__tests__/invite-redemption-service.test.ts +2 -6
  93. package/src/__tests__/invite-routes-http.test.ts +2 -6
  94. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +17 -28
  95. package/src/__tests__/list-messages-attachments.test.ts +2 -6
  96. package/src/__tests__/list-messages-tool-merge.test.ts +300 -0
  97. package/src/__tests__/llm-context-normalization.test.ts +18 -18
  98. package/src/__tests__/llm-context-route-provider.test.ts +103 -6
  99. package/src/__tests__/llm-request-log-turn-query.test.ts +164 -6
  100. package/src/__tests__/llm-usage-store.test.ts +2 -6
  101. package/src/__tests__/log-export-workspace.test.ts +74 -111
  102. package/src/__tests__/managed-store.test.ts +38 -11
  103. package/src/__tests__/mcp-abort-signal.test.ts +5 -0
  104. package/src/__tests__/mcp-client-auth.test.ts +5 -0
  105. package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
  106. package/src/__tests__/memory-recall-log-store.test.ts +134 -6
  107. package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
  108. package/src/__tests__/migration-export-streaming.test.ts +304 -0
  109. package/src/__tests__/migration-import-commit-http.test.ts +11 -10
  110. package/src/__tests__/mock-fetch.ts +87 -0
  111. package/src/__tests__/non-member-access-request.test.ts +2 -6
  112. package/src/__tests__/notification-decision-recipient-context.test.ts +282 -0
  113. package/src/__tests__/notification-guardian-path.test.ts +2 -6
  114. package/src/__tests__/oauth-cli.test.ts +364 -2
  115. package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
  116. package/src/__tests__/onboarding-template-contract.test.ts +62 -14
  117. package/src/__tests__/outlook-attachments.test.ts +301 -0
  118. package/src/__tests__/outlook-automation-tools.test.ts +425 -0
  119. package/src/__tests__/outlook-categories.test.ts +212 -0
  120. package/src/__tests__/outlook-client-automation.test.ts +246 -0
  121. package/src/__tests__/outlook-compose-tools.test.ts +325 -0
  122. package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
  123. package/src/__tests__/outlook-email-watcher.test.ts +322 -0
  124. package/src/__tests__/outlook-follow-up.test.ts +196 -0
  125. package/src/__tests__/outlook-messaging-provider.test.ts +498 -3
  126. package/src/__tests__/outlook-trash.test.ts +77 -0
  127. package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
  128. package/src/__tests__/parser.test.ts +32 -0
  129. package/src/__tests__/permission-checker-host-gate.test.ts +452 -0
  130. package/src/__tests__/permission-controls-v2-flag.test.ts +55 -0
  131. package/src/__tests__/permission-mode-sse.test.ts +418 -0
  132. package/src/__tests__/permission-mode-store.test.ts +277 -0
  133. package/src/__tests__/permission-mode.test.ts +101 -0
  134. package/src/__tests__/platform-bash-auto-approve.test.ts +359 -0
  135. package/src/__tests__/platform-callback-registration.test.ts +4 -4
  136. package/src/__tests__/playbook-execution.test.ts +76 -80
  137. package/src/__tests__/playbook-tools.test.ts +5 -7
  138. package/src/__tests__/profiler-routes.test.ts +502 -0
  139. package/src/__tests__/profiler-run-store.test.ts +441 -0
  140. package/src/__tests__/provider-error-scenarios.test.ts +21 -0
  141. package/src/__tests__/proxy-approval-callback.test.ts +4 -75
  142. package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
  143. package/src/__tests__/registry.test.ts +3 -3
  144. package/src/__tests__/require-fresh-approval.test.ts +64 -2
  145. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
  146. package/src/__tests__/runtime-events-sse.test.ts +2 -6
  147. package/src/__tests__/sandbox-host-parity.test.ts +5 -4
  148. package/src/__tests__/schedule-store.test.ts +2 -6
  149. package/src/__tests__/schedule-tools.test.ts +2 -6
  150. package/src/__tests__/scheduler-recurrence.test.ts +1 -5
  151. package/src/__tests__/scheduler-reuse-conversation.test.ts +368 -0
  152. package/src/__tests__/scoped-approval-grants.test.ts +2 -6
  153. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
  154. package/src/__tests__/scrub-corrupted-image-attachments.test.ts +278 -0
  155. package/src/__tests__/search-skills-unified.test.ts +422 -0
  156. package/src/__tests__/secret-onetime-send.test.ts +2 -0
  157. package/src/__tests__/send-endpoint-busy.test.ts +44 -9
  158. package/src/__tests__/sequence-store.test.ts +2 -6
  159. package/src/__tests__/server-history-render.test.ts +2 -6
  160. package/src/__tests__/set-permission-mode.test.ts +274 -0
  161. package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
  162. package/src/__tests__/skill-feature-flags.test.ts +6 -6
  163. package/src/__tests__/skill-load-feature-flag.test.ts +23 -11
  164. package/src/__tests__/skill-memory.test.ts +2 -741
  165. package/src/__tests__/skills-uninstall.test.ts +2 -2
  166. package/src/__tests__/skills.test.ts +1 -1
  167. package/src/__tests__/slack-inbound-verification.test.ts +2 -6
  168. package/src/__tests__/strip-memory-injections.test.ts +187 -0
  169. package/src/__tests__/subagent-detail.test.ts +84 -0
  170. package/src/__tests__/subagent-disposal.test.ts +308 -0
  171. package/src/__tests__/subagent-manager-notify.test.ts +19 -10
  172. package/src/__tests__/subagent-notify-parent.test.ts +390 -0
  173. package/src/__tests__/subagent-role-registry.test.ts +108 -0
  174. package/src/__tests__/subagent-tool-filtering.test.ts +71 -0
  175. package/src/__tests__/subagent-tools.test.ts +464 -4
  176. package/src/__tests__/system-prompt-ask-mode.test.ts +139 -0
  177. package/src/__tests__/task-compiler.test.ts +2 -6
  178. package/src/__tests__/task-management-tools.test.ts +2 -6
  179. package/src/__tests__/task-memory-cleanup.test.ts +185 -241
  180. package/src/__tests__/task-runner.test.ts +2 -6
  181. package/src/__tests__/task-scheduler.test.ts +2 -6
  182. package/src/__tests__/terminal-tools.test.ts +17 -27
  183. package/src/__tests__/test-preload.ts +7 -0
  184. package/src/__tests__/tool-approval-handler.test.ts +2 -6
  185. package/src/__tests__/tool-executor.test.ts +4 -26
  186. package/src/__tests__/tool-grant-request-escalation.test.ts +2 -6
  187. package/src/__tests__/tool-side-effects-slack-dm.test.ts +277 -0
  188. package/src/__tests__/top-level-renderer.test.ts +10 -13
  189. package/src/__tests__/trust-store.test.ts +1 -1
  190. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +2 -6
  191. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +118 -8
  192. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -6
  193. package/src/__tests__/trusted-contact-verification.test.ts +2 -6
  194. package/src/__tests__/turn-boundary-resolution.test.ts +2 -6
  195. package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -6
  196. package/src/__tests__/usage-routes.test.ts +2 -6
  197. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  198. package/src/__tests__/voice-invite-redemption.test.ts +2 -6
  199. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -6
  200. package/src/__tests__/voice-session-bridge.test.ts +2 -6
  201. package/src/__tests__/volume-security-guard.test.ts +2 -0
  202. package/src/__tests__/workspace-lifecycle.test.ts +29 -1
  203. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -6
  204. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +2 -6
  205. package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
  206. package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +387 -0
  207. package/src/__tests__/workspace-policy.test.ts +1 -1
  208. package/src/agent/attachments.ts +7 -2
  209. package/src/agent/image-optimize.ts +165 -0
  210. package/src/agent/loop.ts +7 -15
  211. package/src/approvals/guardian-request-resolvers.ts +24 -0
  212. package/src/avatar/traits-png-sync.ts +3 -3
  213. package/src/bundler/app-compiler.ts +179 -2
  214. package/src/bundler/package-resolver.ts +3 -5
  215. package/src/cli/__tests__/notifications.test.ts +1 -2
  216. package/src/cli/__tests__/run-assistant-command.ts +29 -0
  217. package/src/cli/commands/__tests__/email-download.test.ts +245 -0
  218. package/src/cli/commands/__tests__/email-list.test.ts +192 -0
  219. package/src/cli/commands/__tests__/email-register.test.ts +186 -0
  220. package/src/cli/commands/__tests__/email-send.test.ts +291 -0
  221. package/src/cli/commands/__tests__/email-status.test.ts +181 -0
  222. package/src/cli/commands/__tests__/email-unregister.test.ts +139 -0
  223. package/src/cli/commands/__tests__/routes.test.ts +562 -0
  224. package/src/cli/commands/avatar.ts +3 -3
  225. package/src/cli/commands/config.ts +26 -13
  226. package/src/cli/commands/conversations.ts +1 -8
  227. package/src/cli/commands/doctor.ts +2 -2
  228. package/src/cli/commands/email.ts +584 -835
  229. package/src/cli/commands/memory.ts +37 -84
  230. package/src/cli/commands/notifications.ts +7 -2
  231. package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
  232. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
  233. package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
  234. package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
  235. package/src/cli/commands/oauth/connect.ts +25 -11
  236. package/src/cli/commands/oauth/mode.ts +7 -0
  237. package/src/cli/commands/oauth/shared.ts +39 -3
  238. package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
  239. package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
  240. package/src/cli/commands/platform/__tests__/status.test.ts +5 -5
  241. package/src/cli/commands/platform/index.ts +16 -16
  242. package/src/cli/commands/routes.ts +396 -0
  243. package/src/cli/commands/skills.ts +218 -36
  244. package/src/cli/commands/trust.ts +2 -2
  245. package/src/cli/lib/daemon-credential-client.ts +2 -3
  246. package/src/cli/program.ts +2 -0
  247. package/src/cli.ts +1 -120
  248. package/src/config/bundled-skills/acp/TOOLS.json +1 -1
  249. package/src/config/bundled-skills/app-builder/SKILL.md +4 -1
  250. package/src/config/bundled-skills/contacts/SKILL.md +0 -1
  251. package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
  252. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
  253. package/src/config/bundled-skills/gmail/SKILL.md +4 -12
  254. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
  255. package/src/config/bundled-skills/messaging/SKILL.md +17 -18
  256. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
  257. package/src/config/bundled-skills/outlook/SKILL.md +189 -0
  258. package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
  259. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
  260. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
  261. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
  262. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
  263. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
  264. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
  265. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
  266. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
  267. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
  268. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
  269. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
  270. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
  271. package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
  272. package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
  273. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
  274. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
  275. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
  276. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
  277. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
  278. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
  279. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
  280. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
  281. package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
  282. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
  283. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
  284. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
  285. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
  286. package/src/config/bundled-skills/schedule/SKILL.md +22 -2
  287. package/src/config/bundled-skills/schedule/TOOLS.json +8 -0
  288. package/src/config/bundled-skills/settings/tools/avatar-get.ts +3 -13
  289. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +2 -4
  290. package/src/config/bundled-skills/settings/tools/avatar-update.ts +5 -2
  291. package/src/config/bundled-skills/slack/SKILL.md +3 -7
  292. package/src/config/bundled-skills/subagent/SKILL.md +43 -3
  293. package/src/config/bundled-skills/subagent/TOOLS.json +29 -4
  294. package/src/config/bundled-tool-registry.ts +56 -4
  295. package/src/config/env-registry.ts +78 -8
  296. package/src/config/feature-flag-registry.json +38 -125
  297. package/src/config/schema.ts +8 -0
  298. package/src/config/schemas/filing.ts +51 -0
  299. package/src/config/schemas/heartbeat.ts +15 -12
  300. package/src/config/schemas/memory-lifecycle.ts +12 -0
  301. package/src/config/schemas/platform.ts +8 -0
  302. package/src/config/schemas/security.ts +14 -0
  303. package/src/config/schemas/timeouts.ts +1 -1
  304. package/src/config/skills.ts +18 -7
  305. package/src/context/token-estimator.ts +25 -18
  306. package/src/context/window-manager.ts +6 -2
  307. package/src/credential-execution/process-manager.ts +3 -1
  308. package/src/daemon/app-source-watcher.ts +93 -0
  309. package/src/daemon/config-watcher.ts +79 -1
  310. package/src/daemon/context-overflow-reducer.ts +46 -2
  311. package/src/daemon/conversation-agent-loop-handlers.ts +143 -82
  312. package/src/daemon/conversation-agent-loop.ts +236 -108
  313. package/src/daemon/conversation-error.ts +31 -8
  314. package/src/daemon/conversation-history.ts +4 -19
  315. package/src/daemon/conversation-lifecycle.ts +36 -9
  316. package/src/daemon/conversation-media-retry.ts +85 -7
  317. package/src/daemon/conversation-notifiers.ts +4 -1
  318. package/src/daemon/conversation-process.ts +13 -7
  319. package/src/daemon/conversation-runtime-assembly.ts +305 -306
  320. package/src/daemon/conversation-tool-setup.ts +44 -14
  321. package/src/daemon/conversation-workspace.ts +1 -2
  322. package/src/daemon/conversation.ts +59 -2
  323. package/src/daemon/daemon-control.ts +8 -2
  324. package/src/daemon/date-context.ts +26 -53
  325. package/src/daemon/first-greeting.ts +1 -1
  326. package/src/daemon/handlers/conversations.ts +4 -7
  327. package/src/daemon/handlers/shared.test.ts +143 -0
  328. package/src/daemon/handlers/shared.ts +85 -17
  329. package/src/daemon/handlers/skills.ts +416 -209
  330. package/src/daemon/lifecycle.ts +212 -131
  331. package/src/daemon/main.ts +5 -1
  332. package/src/daemon/message-types/conversations.ts +29 -7
  333. package/src/daemon/message-types/messages.ts +12 -2
  334. package/src/daemon/message-types/schedules.ts +1 -0
  335. package/src/daemon/message-types/settings.ts +6 -0
  336. package/src/daemon/message-types/skills.ts +97 -36
  337. package/src/daemon/profiler-run-store.ts +557 -0
  338. package/src/daemon/providers-setup.ts +5 -0
  339. package/src/daemon/server.ts +100 -11
  340. package/src/daemon/shutdown-handlers.ts +5 -0
  341. package/src/daemon/tool-side-effects.ts +50 -8
  342. package/src/export/transcript-formatter.ts +148 -0
  343. package/src/filing/filing-service.ts +228 -0
  344. package/src/heartbeat/heartbeat-service.ts +97 -7
  345. package/src/hooks/cli.ts +2 -2
  346. package/src/hooks/runner.ts +15 -38
  347. package/src/inbound/platform-callback-registration.ts +14 -14
  348. package/src/mcp/client.ts +6 -0
  349. package/src/mcp/mcp-oauth-provider.ts +149 -27
  350. package/src/memory/admin.ts +42 -75
  351. package/src/memory/app-store.ts +69 -0
  352. package/src/memory/conversation-bootstrap.ts +3 -1
  353. package/src/memory/conversation-crud.ts +211 -288
  354. package/src/memory/conversation-group-migration.ts +157 -0
  355. package/src/memory/conversation-queries.ts +61 -13
  356. package/src/memory/conversation-title-service.ts +1 -0
  357. package/src/memory/db-init.ts +194 -361
  358. package/src/memory/embed.ts +73 -0
  359. package/src/memory/embedding-backend.ts +8 -14
  360. package/src/memory/embedding-runtime-manager.ts +12 -114
  361. package/src/memory/fingerprint.ts +2 -2
  362. package/src/memory/graph/bootstrap.ts +521 -0
  363. package/src/memory/graph/capability-seed.ts +449 -0
  364. package/src/memory/graph/consolidation.ts +725 -0
  365. package/src/memory/graph/conversation-graph-memory.ts +659 -0
  366. package/src/memory/graph/decay.test.ts +208 -0
  367. package/src/memory/graph/decay.ts +195 -0
  368. package/src/memory/graph/extraction-job.ts +74 -0
  369. package/src/memory/graph/extraction.test.ts +936 -0
  370. package/src/memory/graph/extraction.ts +1297 -0
  371. package/src/memory/graph/graph-memory-state-store.ts +37 -0
  372. package/src/memory/graph/graph-search.ts +280 -0
  373. package/src/memory/graph/image-ref-utils.ts +29 -0
  374. package/src/memory/graph/injection.test.ts +513 -0
  375. package/src/memory/graph/injection.ts +469 -0
  376. package/src/memory/graph/inspect.ts +543 -0
  377. package/src/memory/graph/narrative.ts +267 -0
  378. package/src/memory/graph/pattern-scan.ts +269 -0
  379. package/src/memory/graph/retriever.ts +1111 -0
  380. package/src/memory/graph/scoring.test.ts +548 -0
  381. package/src/memory/graph/scoring.ts +232 -0
  382. package/src/memory/graph/serendipity.ts +65 -0
  383. package/src/memory/graph/store.test.ts +1098 -0
  384. package/src/memory/graph/store.ts +838 -0
  385. package/src/memory/graph/tool-handlers.ts +301 -0
  386. package/src/memory/graph/tools.ts +97 -0
  387. package/src/memory/graph/triggers.test.ts +487 -0
  388. package/src/memory/graph/triggers.ts +223 -0
  389. package/src/memory/graph/types.ts +295 -0
  390. package/src/memory/group-crud.ts +191 -0
  391. package/src/memory/indexer.ts +37 -19
  392. package/src/memory/job-handlers/cleanup.ts +32 -42
  393. package/src/memory/job-handlers/conversation-starters.ts +91 -53
  394. package/src/memory/job-handlers/embedding.ts +5 -31
  395. package/src/memory/job-handlers/index-maintenance.ts +23 -11
  396. package/src/memory/job-handlers/summarization.ts +32 -17
  397. package/src/memory/job-utils.ts +1 -1
  398. package/src/memory/jobs-store.ts +21 -31
  399. package/src/memory/jobs-worker.ts +180 -129
  400. package/src/memory/llm-request-log-store.ts +96 -12
  401. package/src/memory/memory-recall-log-store.ts +49 -5
  402. package/src/memory/message-content.ts +1 -0
  403. package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
  404. package/src/memory/migrations/203-drop-memory-items-tables.ts +55 -0
  405. package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
  406. package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
  407. package/src/memory/migrations/206-memory-graph-node-edits.ts +19 -0
  408. package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +131 -0
  409. package/src/memory/migrations/207-conversation-graph-memory-state.ts +20 -0
  410. package/src/memory/migrations/208-conversations-last-message-at.ts +35 -0
  411. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +85 -0
  412. package/src/memory/migrations/210-schedule-reuse-conversation.ts +13 -0
  413. package/src/memory/migrations/211-memory-recall-logs-query-context.ts +21 -0
  414. package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +19 -0
  415. package/src/memory/migrations/index.ts +12 -0
  416. package/src/memory/migrations/registry.ts +16 -0
  417. package/src/memory/qdrant-client.ts +44 -17
  418. package/src/memory/schema/conversations.ts +14 -0
  419. package/src/memory/schema/index.ts +1 -0
  420. package/src/memory/schema/infrastructure.ts +8 -1
  421. package/src/memory/schema/memory-core.ts +0 -51
  422. package/src/memory/schema/memory-graph.ts +154 -0
  423. package/src/memory/search/semantic.ts +47 -91
  424. package/src/memory/task-memory-cleanup.ts +58 -61
  425. package/src/messaging/providers/outlook/adapter.ts +8 -1
  426. package/src/messaging/providers/outlook/client.ts +299 -0
  427. package/src/messaging/providers/outlook/types.ts +118 -0
  428. package/src/notifications/adapters/macos.ts +1 -0
  429. package/src/notifications/copy-composer.ts +95 -0
  430. package/src/notifications/decision-engine.ts +35 -0
  431. package/src/notifications/signal.ts +16 -0
  432. package/src/oauth/seed-providers.ts +2 -1
  433. package/src/permissions/checker.ts +36 -4
  434. package/src/permissions/defaults.ts +4 -4
  435. package/src/permissions/permission-mode-store.ts +180 -0
  436. package/src/permissions/permission-mode.ts +31 -0
  437. package/src/permissions/workspace-policy.ts +10 -1
  438. package/src/playbooks/playbook-compiler.ts +19 -18
  439. package/src/playbooks/types.ts +4 -3
  440. package/src/prompts/system-prompt.ts +62 -36
  441. package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +100 -0
  442. package/src/prompts/templates/BOOTSTRAP.md +70 -165
  443. package/src/prompts/templates/HEARTBEAT.md +3 -1
  444. package/src/prompts/templates/SOUL.md +25 -4
  445. package/src/prompts/templates/UPDATES.md +8 -0
  446. package/src/providers/anthropic/client.ts +136 -220
  447. package/src/providers/gemini/client.ts +1 -1
  448. package/src/providers/openai/client.ts +1 -1
  449. package/src/providers/registry.ts +1 -1
  450. package/src/providers/retry.ts +19 -3
  451. package/src/runtime/actor-trust-resolver.ts +5 -1
  452. package/src/runtime/auth/route-policy.ts +30 -0
  453. package/src/runtime/guardian-reply-router.ts +5 -1
  454. package/src/runtime/http-server.ts +55 -5
  455. package/src/runtime/http-types.ts +12 -1
  456. package/src/runtime/middleware/auth.ts +20 -0
  457. package/src/runtime/migrations/vbundle-builder.ts +389 -3
  458. package/src/runtime/migrations/vbundle-importer.ts +8 -6
  459. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +378 -0
  460. package/src/runtime/routes/app-management-routes.ts +1 -11
  461. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +26 -0
  462. package/src/runtime/routes/archive-utils.ts +29 -0
  463. package/src/runtime/routes/attachment-routes.test.ts +106 -0
  464. package/src/runtime/routes/attachment-routes.ts +106 -16
  465. package/src/runtime/routes/avatar-routes.ts +2 -9
  466. package/src/runtime/routes/brain-graph-routes.ts +21 -22
  467. package/src/runtime/routes/btw-routes.ts +22 -1
  468. package/src/runtime/routes/conversation-analysis-routes.ts +173 -0
  469. package/src/runtime/routes/conversation-management-routes.ts +3 -14
  470. package/src/runtime/routes/conversation-query-routes.ts +49 -3
  471. package/src/runtime/routes/conversation-routes.ts +264 -44
  472. package/src/runtime/routes/conversation-starter-routes.ts +2 -2
  473. package/src/runtime/routes/debug-routes.ts +1 -1
  474. package/src/runtime/routes/global-search-routes.ts +21 -19
  475. package/src/runtime/routes/group-routes.ts +207 -0
  476. package/src/runtime/routes/guardian-action-routes.ts +21 -10
  477. package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
  478. package/src/runtime/routes/heartbeat-routes.ts +4 -10
  479. package/src/runtime/routes/identity-routes.ts +53 -18
  480. package/src/runtime/routes/inbound-message-handler.ts +19 -0
  481. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
  482. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
  483. package/src/runtime/routes/llm-context-normalization.ts +14 -10
  484. package/src/runtime/routes/log-export-routes.ts +23 -275
  485. package/src/runtime/routes/memory-item-routes.test.ts +170 -247
  486. package/src/runtime/routes/memory-item-routes.ts +341 -388
  487. package/src/runtime/routes/migration-routes.ts +18 -7
  488. package/src/runtime/routes/profiler-routes.ts +350 -0
  489. package/src/runtime/routes/schedule-routes.ts +28 -11
  490. package/src/runtime/routes/settings-routes.ts +95 -8
  491. package/src/runtime/routes/skills-routes.ts +103 -37
  492. package/src/runtime/routes/subagents-routes.ts +28 -7
  493. package/src/runtime/routes/user-route-dispatcher.ts +223 -0
  494. package/src/runtime/routes/user-routes.ts +41 -0
  495. package/src/runtime/routes/work-items-routes.test.ts +2 -6
  496. package/src/runtime/routes/workspace-routes.ts +0 -1
  497. package/src/schedule/schedule-store.ts +30 -0
  498. package/src/schedule/scheduler.ts +52 -18
  499. package/src/security/oauth2.ts +1 -1
  500. package/src/security/secure-keys.ts +4 -8
  501. package/src/shared/provider-env-vars.ts +19 -0
  502. package/src/skills/catalog-cache.ts +5 -0
  503. package/src/skills/catalog-install.ts +25 -16
  504. package/src/skills/clawhub.ts +134 -154
  505. package/src/skills/install-meta.ts +208 -0
  506. package/src/skills/managed-store.ts +29 -18
  507. package/src/skills/skill-memory.ts +12 -229
  508. package/src/skills/skillssh-registry.ts +19 -17
  509. package/src/subagent/index.ts +13 -3
  510. package/src/subagent/manager.ts +308 -29
  511. package/src/subagent/types.ts +68 -0
  512. package/src/tasks/task-runner.ts +7 -5
  513. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
  514. package/src/tools/apps/executors.ts +29 -4
  515. package/src/tools/browser/runtime-check.ts +3 -1
  516. package/src/tools/filesystem/list.ts +93 -0
  517. package/src/tools/memory/register.ts +63 -46
  518. package/src/tools/permission-checker.ts +85 -1
  519. package/src/tools/registry.ts +4 -0
  520. package/src/tools/schedule/create.ts +3 -0
  521. package/src/tools/schedule/list.ts +1 -0
  522. package/src/tools/schedule/update.ts +6 -0
  523. package/src/tools/shared/filesystem/errors.ts +5 -0
  524. package/src/tools/shared/filesystem/file-ops-service.ts +90 -2
  525. package/src/tools/shared/filesystem/image-read.ts +22 -85
  526. package/src/tools/shared/filesystem/types.ts +17 -0
  527. package/src/tools/shared/shell-output.ts +31 -2
  528. package/src/tools/subagent/abort.ts +12 -2
  529. package/src/tools/subagent/message.ts +9 -2
  530. package/src/tools/subagent/notify-parent.ts +79 -0
  531. package/src/tools/subagent/read.ts +29 -8
  532. package/src/tools/subagent/resolve.ts +21 -0
  533. package/src/tools/subagent/spawn.ts +2 -0
  534. package/src/tools/subagent/status.ts +11 -1
  535. package/src/tools/system/avatar-generator.ts +3 -3
  536. package/src/tools/system/register.ts +23 -0
  537. package/src/tools/system/set-permission-mode.ts +103 -0
  538. package/src/tools/terminal/parser.ts +30 -5
  539. package/src/tools/terminal/safe-env.ts +17 -1
  540. package/src/tools/tool-manifest.ts +9 -3
  541. package/src/tools/types.ts +2 -0
  542. package/src/util/browser.ts +25 -10
  543. package/src/util/bun-runtime.ts +172 -0
  544. package/src/util/logger.ts +1 -1
  545. package/src/util/platform.ts +50 -17
  546. package/src/watcher/providers/outlook-calendar.ts +343 -0
  547. package/src/watcher/providers/outlook.ts +198 -0
  548. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +2 -2
  549. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +2 -2
  550. package/src/workspace/migrations/025-remove-oauth-app-setup-skills.ts +76 -0
  551. package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
  552. package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
  553. package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +270 -0
  554. package/src/workspace/migrations/029-seed-pkb.ts +84 -0
  555. package/src/workspace/migrations/registry.ts +10 -0
  556. package/src/workspace/top-level-renderer.ts +5 -9
  557. package/src/__tests__/cli-memory.test.ts +0 -372
  558. package/src/__tests__/clipboard.test.ts +0 -88
  559. package/src/__tests__/context-memory-e2e.test.ts +0 -415
  560. package/src/__tests__/journal-context.test.ts +0 -268
  561. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
  562. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
  563. package/src/__tests__/memory-query-builder.test.ts +0 -59
  564. package/src/__tests__/memory-recall-quality.test.ts +0 -1046
  565. package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
  566. package/src/__tests__/memory-regressions.test.ts +0 -3696
  567. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
  568. package/src/cli/cli-memory.ts +0 -176
  569. package/src/daemon/conversation-memory.ts +0 -207
  570. package/src/memory/conversation-starters-cadence.ts +0 -74
  571. package/src/memory/items-extractor.ts +0 -860
  572. package/src/memory/job-handlers/batch-extraction.ts +0 -753
  573. package/src/memory/job-handlers/extraction.ts +0 -40
  574. package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -355
  575. package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
  576. package/src/memory/journal-memory.ts +0 -224
  577. package/src/memory/query-builder.ts +0 -47
  578. package/src/memory/query-expansion.ts +0 -83
  579. package/src/memory/retriever.test.ts +0 -1592
  580. package/src/memory/retriever.ts +0 -1331
  581. package/src/memory/search/formatting.test.ts +0 -140
  582. package/src/memory/search/formatting.ts +0 -262
  583. package/src/memory/search/mmr.ts +0 -139
  584. package/src/memory/search/ranking.ts +0 -15
  585. package/src/memory/search/staleness.ts +0 -40
  586. package/src/memory/search/tier-classifier.ts +0 -18
  587. package/src/memory/search/types.ts +0 -121
  588. package/src/prompts/journal-context.ts +0 -154
  589. package/src/tools/memory/definitions.ts +0 -69
  590. package/src/tools/memory/handlers.test.ts +0 -562
  591. package/src/tools/memory/handlers.ts +0 -434
  592. package/src/util/clipboard.ts +0 -34
@@ -0,0 +1,208 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import {
3
+ existsSync,
4
+ mkdirSync,
5
+ readdirSync,
6
+ readFileSync,
7
+ renameSync,
8
+ statSync,
9
+ writeFileSync,
10
+ } from "node:fs";
11
+ import { dirname, join } from "node:path";
12
+
13
+ // ─── SkillInstallMeta type ──────────────────────────────────────────────────
14
+
15
+ export interface SkillInstallMeta {
16
+ origin: "vellum" | "clawhub" | "skillssh" | "custom";
17
+ installedAt: string; // ISO 8601
18
+ installedBy?: string; // actorPrincipalId from auth context (identifies who initiated the install)
19
+ backfilledBy?: string; // set by migration that backfilled this file (e.g. "migration-026")
20
+ version?: string; // semver if known
21
+ slug?: string; // registry slug
22
+ sourceRepo?: string; // GitHub repo (e.g. "vercel-labs/agent-skills")
23
+ contentHash?: string; // SHA-256 content hash (v2:hex format)
24
+ }
25
+
26
+ // ─── Atomic write helper ────────────────────────────────────────────────────
27
+
28
+ function atomicWriteFile(filePath: string, content: string): void {
29
+ const dir = dirname(filePath);
30
+ mkdirSync(dir, { recursive: true });
31
+ const tmpPath = join(dir, `.tmp-${randomUUID()}`);
32
+ writeFileSync(tmpPath, content, "utf-8");
33
+ renameSync(tmpPath, filePath);
34
+ }
35
+
36
+ // ─── Write install-meta.json ────────────────────────────────────────────────
37
+
38
+ const INSTALL_META_FILENAME = "install-meta.json";
39
+ const LEGACY_VERSION_FILENAME = "version.json";
40
+
41
+ /**
42
+ * Atomically write `install-meta.json` inside the skill directory.
43
+ */
44
+ export function writeInstallMeta(
45
+ skillDir: string,
46
+ meta: SkillInstallMeta,
47
+ ): void {
48
+ const filePath = join(skillDir, INSTALL_META_FILENAME);
49
+ atomicWriteFile(filePath, JSON.stringify(meta, null, 2) + "\n");
50
+ }
51
+
52
+ // ─── Read install-meta.json (with legacy fallback) ──────────────────────────
53
+
54
+ /**
55
+ * Reads `install-meta.json` from the skill directory. If not found, falls
56
+ * back to reading legacy `version.json` and inferring the origin:
57
+ *
58
+ * - Has `origin: "skills.sh"` -> `origin: "skillssh"`, copies `source` as
59
+ * `sourceRepo` and `skillSlug` as `slug`.
60
+ * - Has `version` but no `origin` field -> `origin: "vellum"`.
61
+ * - Otherwise -> `origin: "custom"`.
62
+ *
63
+ * Legacy files never have `installedBy`, so it will be `undefined` for
64
+ * backfilled skills.
65
+ *
66
+ * If neither file exists, returns `null`.
67
+ */
68
+ export function readInstallMeta(skillDir: string): SkillInstallMeta | null {
69
+ // Try install-meta.json first
70
+ const metaPath = join(skillDir, INSTALL_META_FILENAME);
71
+ if (existsSync(metaPath)) {
72
+ try {
73
+ return JSON.parse(readFileSync(metaPath, "utf-8")) as SkillInstallMeta;
74
+ } catch {
75
+ // Malformed install-meta.json (partial write, manual edit, etc.) —
76
+ // fall through to the legacy version.json path so we don't lose
77
+ // provenance info when a valid legacy file exists.
78
+ }
79
+ }
80
+
81
+ // Fall back to legacy version.json
82
+ const legacyPath = join(skillDir, LEGACY_VERSION_FILENAME);
83
+ if (!existsSync(legacyPath)) {
84
+ return null;
85
+ }
86
+
87
+ try {
88
+ const raw = JSON.parse(readFileSync(legacyPath, "utf-8")) as Record<
89
+ string,
90
+ unknown
91
+ >;
92
+ return inferFromLegacyVersionJson(raw);
93
+ } catch {
94
+ return null;
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Infer a SkillInstallMeta from a legacy version.json object.
100
+ */
101
+ function inferFromLegacyVersionJson(
102
+ raw: Record<string, unknown>,
103
+ ): SkillInstallMeta {
104
+ // skills.sh origin: has `origin: "skills.sh"`
105
+ if (raw.origin === "skills.sh") {
106
+ return {
107
+ origin: "skillssh",
108
+ installedAt:
109
+ typeof raw.installedAt === "string"
110
+ ? raw.installedAt
111
+ : new Date().toISOString(),
112
+ sourceRepo: typeof raw.source === "string" ? raw.source : undefined,
113
+ slug: typeof raw.skillSlug === "string" ? raw.skillSlug : undefined,
114
+ };
115
+ }
116
+
117
+ // Vellum (first-party catalog) origin: has `version` but no `origin` field
118
+ if (typeof raw.version === "string" && !("origin" in raw)) {
119
+ return {
120
+ origin: "vellum",
121
+ installedAt:
122
+ typeof raw.installedAt === "string"
123
+ ? raw.installedAt
124
+ : new Date().toISOString(),
125
+ version: raw.version,
126
+ };
127
+ }
128
+
129
+ // Unknown format -> custom
130
+ return {
131
+ origin: "custom",
132
+ installedAt:
133
+ typeof raw.installedAt === "string"
134
+ ? raw.installedAt
135
+ : new Date().toISOString(),
136
+ };
137
+ }
138
+
139
+ // ─── Content hash computation ───────────────────────────────────────────────
140
+
141
+ /**
142
+ * Metadata files excluded from content hashing. These are written by the
143
+ * installer and must not contribute to the content hash — otherwise the hash
144
+ * stored inside `install-meta.json` would change after writing the file.
145
+ */
146
+ const METADATA_FILENAMES = new Set([
147
+ INSTALL_META_FILENAME, // install-meta.json
148
+ LEGACY_VERSION_FILENAME, // version.json
149
+ ]);
150
+
151
+ /**
152
+ * Collect all file contents in a directory tree, sorted by relative path
153
+ * for determinism. Metadata files (`install-meta.json`, `version.json`) at
154
+ * the root level are excluded so the content hash covers only actual skill
155
+ * content.
156
+ */
157
+ export function collectFileContents(
158
+ dir: string,
159
+ prefix = "",
160
+ ): Array<{ relPath: string; content: Buffer }> {
161
+ const results: Array<{ relPath: string; content: Buffer }> = [];
162
+ if (!existsSync(dir)) return results;
163
+
164
+ const entries = readdirSync(dir, { withFileTypes: true });
165
+ for (const entry of entries) {
166
+ // Exclude metadata files at the root level (prefix === "").
167
+ // Only exclude actual files — a directory with a metadata name should
168
+ // still be traversed so nested content contributes to the hash.
169
+ if (!prefix && entry.isFile() && METADATA_FILENAMES.has(entry.name))
170
+ continue;
171
+
172
+ const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
173
+ const fullPath = join(dir, entry.name);
174
+ if (entry.isDirectory()) {
175
+ results.push(...collectFileContents(fullPath, relPath));
176
+ } else if (entry.isFile()) {
177
+ results.push({ relPath, content: readFileSync(fullPath) });
178
+ }
179
+ }
180
+ return results.sort((a, b) => a.relPath.localeCompare(b.relPath));
181
+ }
182
+
183
+ /**
184
+ * Compute a SHA-256 hash over all files in a skill directory.
185
+ * Returns format: "v2:sha256hex" (version prefix added to support hash format
186
+ * evolution).
187
+ *
188
+ * This is the content hash used by the integrity manifest (trust-on-first-use).
189
+ * It differs from `computeSkillVersionHash` in `version-hash.ts`, which uses a
190
+ * different hashing strategy (v1: prefix) for version identity.
191
+ */
192
+ export function computeSkillHash(skillDir: string): string | null {
193
+ if (!existsSync(skillDir) || !statSync(skillDir).isDirectory()) return null;
194
+
195
+ const files = collectFileContents(skillDir);
196
+ if (files.length === 0) return null;
197
+
198
+ const hasher = new Bun.CryptoHasher("sha256");
199
+ for (const file of files) {
200
+ // Length-prefix each segment to prevent boundary ambiguity collisions
201
+ const pathBuf = Buffer.from(file.relPath, "utf-8");
202
+ hasher.update(`${pathBuf.length}:`);
203
+ hasher.update(pathBuf);
204
+ hasher.update(`${file.content.length}:`);
205
+ hasher.update(file.content);
206
+ }
207
+ return `v2:${hasher.digest("hex")}`;
208
+ }
@@ -11,9 +11,10 @@ import { dirname, join } from "node:path";
11
11
 
12
12
  import { stringify as stringifyYaml } from "yaml";
13
13
 
14
+ import { deleteSkillCapabilityNode } from "../memory/graph/capability-seed.js";
14
15
  import { getLogger } from "../util/logger.js";
15
16
  import { getWorkspaceSkillsDir } from "../util/platform.js";
16
- import { deleteSkillCapabilityMemory } from "./skill-memory.js";
17
+ import { writeInstallMeta } from "./install-meta.js";
17
18
 
18
19
  const log = getLogger("managed-store");
19
20
 
@@ -165,15 +166,20 @@ function getVersionMetaPath(id: string): string {
165
166
  return join(getManagedSkillDir(id), "version.json");
166
167
  }
167
168
 
168
- function writeVersionMeta(id: string, version: string): void {
169
- const meta: SkillVersionMeta = {
170
- version,
171
- installedAt: new Date().toISOString(),
172
- };
173
- atomicWriteFile(getVersionMetaPath(id), JSON.stringify(meta, null, 2) + "\n");
174
- }
175
-
176
169
  export function readSkillVersion(id: string): string | null {
170
+ // Try install-meta.json first (new format)
171
+ const installMetaPath = join(getManagedSkillDir(id), "install-meta.json");
172
+ if (existsSync(installMetaPath)) {
173
+ try {
174
+ const raw = readFileSync(installMetaPath, "utf-8");
175
+ const meta = JSON.parse(raw) as { version?: string };
176
+ if (meta.version) return meta.version;
177
+ } catch {
178
+ // Fall through to legacy path
179
+ }
180
+ }
181
+
182
+ // Fall back to legacy version.json
177
183
  const metaPath = getVersionMetaPath(id);
178
184
  if (!existsSync(metaPath)) return null;
179
185
  try {
@@ -197,6 +203,7 @@ interface CreateManagedSkillParams {
197
203
  addToIndex?: boolean;
198
204
  includes?: string[];
199
205
  version?: string;
206
+ contactId?: string;
200
207
  }
201
208
 
202
209
  interface CreateManagedSkillResult {
@@ -259,14 +266,18 @@ export function createManagedSkill(
259
266
  mkdirSync(skillDir, { recursive: true });
260
267
  atomicWriteFile(skillFilePath, content);
261
268
 
262
- if (params.version) {
263
- writeVersionMeta(params.id, params.version);
264
- } else {
265
- // Remove stale version metadata when overwriting without a version
266
- const metaPath = getVersionMetaPath(params.id);
267
- if (existsSync(metaPath)) {
268
- rmSync(metaPath);
269
- }
269
+ // Write install metadata
270
+ writeInstallMeta(skillDir, {
271
+ origin: "custom",
272
+ installedAt: new Date().toISOString(),
273
+ ...(params.version ? { version: params.version } : {}),
274
+ ...(params.contactId ? { installedBy: params.contactId } : {}),
275
+ });
276
+
277
+ // Clean up legacy version.json if present (superseded by install-meta.json)
278
+ const metaPath = getVersionMetaPath(params.id);
279
+ if (existsSync(metaPath)) {
280
+ rmSync(metaPath);
270
281
  }
271
282
 
272
283
  log.info(
@@ -308,7 +319,7 @@ export function deleteManagedSkill(
308
319
  }
309
320
 
310
321
  rmSync(skillDir, { recursive: true });
311
- deleteSkillCapabilityMemory(id);
322
+ deleteSkillCapabilityNode(id);
312
323
  log.info({ id, path: skillDir }, "Deleted managed skill");
313
324
 
314
325
  let indexUpdated = false;
@@ -1,16 +1,5 @@
1
- import { and, eq } from "drizzle-orm";
2
- import { v4 as uuid } from "uuid";
3
-
4
- import { getConfig } from "../config/loader.js";
5
- import { resolveSkillStates } from "../config/skill-state.js";
6
- import { loadSkillCatalog, type SkillSummary } from "../config/skills.js";
7
- import { getDb } from "../memory/db.js";
8
- import { computeMemoryFingerprint } from "../memory/fingerprint.js";
9
- import { enqueueMemoryJob } from "../memory/jobs-store.js";
10
- import { memoryItems } from "../memory/schema.js";
11
- import { getLogger } from "../util/logger.js";
12
-
13
- const log = getLogger("skill-memory");
1
+ import type { SkillSummary } from "../config/skills.js";
2
+ import type { CatalogSkill } from "./catalog-install.js";
14
3
 
15
4
  /**
16
5
  * Generic input for building capability statements.
@@ -40,222 +29,16 @@ export function fromSkillSummary(entry: SkillSummary): SkillCapabilityInput {
40
29
  }
41
30
 
42
31
  /**
43
- * Build a semantically rich capability statement from a skill capability input.
44
- * Truncated to 500 chars max (matching the limit used by memory item extraction).
45
- */
46
- export function buildCapabilityStatement(input: SkillCapabilityInput): string {
47
- const { displayName, activationHints, avoidWhen } = input;
48
-
49
- let statement = `The "${displayName}" skill (${input.id}) is available. ${input.description}.`;
50
- if (activationHints && activationHints.length > 0) {
51
- statement += ` Use when: ${activationHints.join("; ")}.`;
52
- }
53
- if (avoidWhen && avoidWhen.length > 0) {
54
- statement += ` Avoid when: ${avoidWhen.join("; ")}.`;
55
- }
56
-
57
- // Truncate to 500 chars max
58
- if (statement.length > 500) {
59
- statement = statement.slice(0, 500);
60
- }
61
-
62
- return statement;
63
- }
64
-
65
- /**
66
- * Upsert a capability memory item for a skill.
67
- * Best-effort: errors are logged but never thrown.
68
- */
69
- export function upsertSkillCapabilityMemory(
70
- skillId: string,
71
- input: SkillCapabilityInput,
72
- ): void {
73
- try {
74
- const db = getDb();
75
- const subject = `skill:${skillId}`;
76
- const statement = buildCapabilityStatement(input);
77
- const kind = "capability";
78
- const scopeId = "default";
79
- const confidence = 1.0;
80
- const importance = 0.7;
81
- const fingerprint = computeMemoryFingerprint(
82
- scopeId,
83
- kind,
84
- subject,
85
- statement,
86
- );
87
- const now = Date.now();
88
-
89
- const existing = db
90
- .select()
91
- .from(memoryItems)
92
- .where(
93
- and(
94
- eq(memoryItems.kind, kind),
95
- eq(memoryItems.subject, subject),
96
- eq(memoryItems.scopeId, scopeId),
97
- ),
98
- )
99
- .get();
100
-
101
- if (existing) {
102
- if (
103
- existing.status === "active" &&
104
- existing.fingerprint === fingerprint
105
- ) {
106
- // Same content — just touch lastSeenAt
107
- db.update(memoryItems)
108
- .set({ lastSeenAt: now })
109
- .where(eq(memoryItems.id, existing.id))
110
- .run();
111
- return;
112
- }
113
-
114
- if (existing.status === "active") {
115
- // Content changed — update statement and fingerprint
116
- db.update(memoryItems)
117
- .set({
118
- statement,
119
- fingerprint,
120
- lastSeenAt: now,
121
- })
122
- .where(eq(memoryItems.id, existing.id))
123
- .run();
124
- enqueueMemoryJob("embed_item", { itemId: existing.id });
125
- return;
126
- }
127
-
128
- // status === "deleted" or other — reactivate
129
- db.update(memoryItems)
130
- .set({
131
- status: "active",
132
- statement,
133
- fingerprint,
134
- lastSeenAt: now,
135
- firstSeenAt: now,
136
- })
137
- .where(eq(memoryItems.id, existing.id))
138
- .run();
139
- enqueueMemoryJob("embed_item", { itemId: existing.id });
140
- return;
141
- }
142
-
143
- // No existing — insert new row
144
- const id = uuid();
145
- db.insert(memoryItems)
146
- .values({
147
- id,
148
- kind,
149
- subject,
150
- statement,
151
- status: "active",
152
- confidence,
153
- importance,
154
- fingerprint,
155
- sourceType: "extraction",
156
- scopeId,
157
- firstSeenAt: now,
158
- lastSeenAt: now,
159
- })
160
- .run();
161
- enqueueMemoryJob("embed_item", { itemId: id });
162
- } catch (err) {
163
- log.warn({ err, skillId }, "Failed to upsert skill capability memory");
164
- }
165
- }
166
-
167
- /**
168
- * Soft-delete the capability memory item for a skill.
169
- * Best-effort: errors are logged but never thrown.
32
+ * Convert a CatalogSkill to a SkillCapabilityInput.
33
+ * CatalogSkill stores display-name and hints inside nested metadata.
170
34
  */
171
- export function deleteSkillCapabilityMemory(skillId: string): void {
172
- try {
173
- const db = getDb();
174
- const subject = `skill:${skillId}`;
175
- const now = Date.now();
176
-
177
- const existing = db
178
- .select()
179
- .from(memoryItems)
180
- .where(
181
- and(
182
- eq(memoryItems.kind, "capability"),
183
- eq(memoryItems.subject, subject),
184
- eq(memoryItems.scopeId, "default"),
185
- ),
186
- )
187
- .get();
188
-
189
- if (existing && existing.status !== "deleted") {
190
- db.update(memoryItems)
191
- .set({ status: "deleted", lastSeenAt: now })
192
- .where(eq(memoryItems.id, existing.id))
193
- .run();
194
- }
195
- } catch (err) {
196
- log.warn({ err, skillId }, "Failed to delete skill capability memory");
197
- }
35
+ export function fromCatalogSkill(entry: CatalogSkill): SkillCapabilityInput {
36
+ return {
37
+ id: entry.id,
38
+ displayName: entry.metadata?.vellum?.["display-name"] ?? entry.name,
39
+ description: entry.description,
40
+ activationHints: entry.metadata?.vellum?.["activation-hints"],
41
+ avoidWhen: entry.metadata?.vellum?.["avoid-when"],
42
+ };
198
43
  }
199
44
 
200
- /**
201
- * Seed capability memory items for all enabled skills (bundled, managed, workspace, extra).
202
- * Prunes stale entries whose skills are no longer in the enabled set.
203
- * Best-effort: errors are logged but never thrown.
204
- */
205
- export function seedCatalogSkillMemories(): void {
206
- try {
207
- const catalog = loadSkillCatalog();
208
- const config = getConfig();
209
- const resolved = resolveSkillStates(catalog, config);
210
- const enabled = resolved.filter((r) => r.state === "enabled");
211
-
212
- const catalogIds = new Set<string>();
213
- for (const { summary } of enabled) {
214
- catalogIds.add(summary.id);
215
- const input = fromSkillSummary(summary);
216
-
217
- // Enrich mcp-setup description with configured server names
218
- if (summary.id === "mcp-setup") {
219
- const servers = config.mcp?.servers;
220
- if (servers) {
221
- const names = Object.keys(servers).filter(
222
- (name) => servers[name]?.enabled !== false,
223
- );
224
- if (names.length > 0) {
225
- input.description += ` Configured: ${names.join(", ")}`;
226
- }
227
- }
228
- }
229
-
230
- upsertSkillCapabilityMemory(summary.id, input);
231
- }
232
-
233
- // Prune stale capability memories for skills no longer in the enabled set
234
- const db = getDb();
235
- const allCapabilities = db
236
- .select()
237
- .from(memoryItems)
238
- .where(
239
- and(
240
- eq(memoryItems.kind, "capability"),
241
- eq(memoryItems.scopeId, "default"),
242
- eq(memoryItems.status, "active"),
243
- ),
244
- )
245
- .all();
246
-
247
- const now = Date.now();
248
- for (const item of allCapabilities) {
249
- if (!item.subject.startsWith("skill:")) continue;
250
- const itemSkillId = item.subject.replace("skill:", "");
251
- if (!catalogIds.has(itemSkillId)) {
252
- db.update(memoryItems)
253
- .set({ status: "deleted", lastSeenAt: now })
254
- .where(eq(memoryItems.id, item.id))
255
- .run();
256
- }
257
- }
258
- } catch (err) {
259
- log.warn({ err }, "Failed to seed catalog skill memories");
260
- }
261
- }
@@ -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
  }
@@ -1,6 +1,16 @@
1
- export { SubagentManager } from "./manager.js";
2
- export type { SubagentConfig, SubagentState, SubagentStatus } from "./types.js";
3
- export { SUBAGENT_LIMITS, TERMINAL_STATUSES } from "./types.js";
1
+ export { mergeSkillIds, SubagentManager } from "./manager.js";
2
+ export type {
3
+ SubagentConfig,
4
+ SubagentRole,
5
+ SubagentRoleConfig,
6
+ SubagentState,
7
+ SubagentStatus,
8
+ } from "./types.js";
9
+ export {
10
+ SUBAGENT_LIMITS,
11
+ SUBAGENT_ROLE_REGISTRY,
12
+ TERMINAL_STATUSES,
13
+ } from "./types.js";
4
14
 
5
15
  import { SubagentManager } from "./manager.js";
6
16