@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,325 @@
1
+ /**
2
+ * Workspace migration 026: Backfill install-meta.json for existing skills
3
+ *
4
+ * Scans ~/.vellum/workspace/skills/ for installed skill directories and writes
5
+ * an install-meta.json for each skill that lacks one, inferring the origin
6
+ * from legacy version.json and .integrity.json files.
7
+ *
8
+ * Idempotent: safe to re-run after interruption at any point.
9
+ */
10
+
11
+ import { randomUUID } from "node:crypto";
12
+ import {
13
+ existsSync,
14
+ mkdirSync,
15
+ readdirSync,
16
+ readFileSync,
17
+ renameSync,
18
+ statSync,
19
+ unlinkSync,
20
+ writeFileSync,
21
+ } from "node:fs";
22
+ import { dirname, join } from "node:path";
23
+
24
+ import type { WorkspaceMigration } from "./types.js";
25
+
26
+ // ---------------------------------------------------------------------------
27
+ // Constants
28
+ // ---------------------------------------------------------------------------
29
+
30
+ const INSTALL_META_FILENAME = "install-meta.json";
31
+ const VERSION_JSON_FILENAME = "version.json";
32
+ const INTEGRITY_JSON_FILENAME = ".integrity.json";
33
+ const SKILL_MD_FILENAME = "SKILL.md";
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // Inlined helpers (self-contained per migrations/AGENTS.md)
37
+ // ---------------------------------------------------------------------------
38
+
39
+ interface SkillInstallMeta {
40
+ origin: "vellum" | "clawhub" | "skillssh" | "custom";
41
+ installedAt: string;
42
+ installedBy?: string;
43
+ backfilledBy?: string;
44
+ version?: string;
45
+ slug?: string;
46
+ sourceRepo?: string;
47
+ contentHash?: string;
48
+ }
49
+
50
+ /**
51
+ * Atomically write a file: write to a temp file, then rename.
52
+ */
53
+ function atomicWriteFile(filePath: string, content: string): void {
54
+ const dir = dirname(filePath);
55
+ mkdirSync(dir, { recursive: true });
56
+ const tmpPath = join(dir, `.tmp-${randomUUID()}`);
57
+ writeFileSync(tmpPath, content, "utf-8");
58
+ renameSync(tmpPath, filePath);
59
+ }
60
+
61
+ /**
62
+ * Write install-meta.json into a skill directory.
63
+ */
64
+ function writeInstallMeta(skillDir: string, meta: SkillInstallMeta): void {
65
+ const filePath = join(skillDir, INSTALL_META_FILENAME);
66
+ atomicWriteFile(filePath, JSON.stringify(meta, null, 2) + "\n");
67
+ }
68
+
69
+ /**
70
+ * Metadata files excluded from content hashing.
71
+ */
72
+ const METADATA_FILENAMES = new Set([
73
+ INSTALL_META_FILENAME,
74
+ VERSION_JSON_FILENAME,
75
+ ]);
76
+
77
+ /**
78
+ * Collect all file contents in a directory tree, sorted by relative path.
79
+ * Metadata files at root level are excluded.
80
+ */
81
+ function collectFileContents(
82
+ dir: string,
83
+ prefix = "",
84
+ ): Array<{ relPath: string; content: Buffer }> {
85
+ const results: Array<{ relPath: string; content: Buffer }> = [];
86
+ if (!existsSync(dir)) return results;
87
+
88
+ const entries = readdirSync(dir, { withFileTypes: true });
89
+ for (const entry of entries) {
90
+ if (!prefix && METADATA_FILENAMES.has(entry.name)) continue;
91
+
92
+ const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
93
+ const fullPath = join(dir, entry.name);
94
+ if (entry.isDirectory()) {
95
+ results.push(...collectFileContents(fullPath, relPath));
96
+ } else if (entry.isFile()) {
97
+ results.push({ relPath, content: readFileSync(fullPath) });
98
+ }
99
+ }
100
+ return results.sort((a, b) => a.relPath.localeCompare(b.relPath));
101
+ }
102
+
103
+ /**
104
+ * Compute SHA-256 content hash over all non-metadata files in a skill dir.
105
+ * Returns format: "v2:sha256hex".
106
+ */
107
+ function computeSkillHash(skillDir: string): string | null {
108
+ if (!existsSync(skillDir) || !statSync(skillDir).isDirectory()) return null;
109
+
110
+ const files = collectFileContents(skillDir);
111
+ if (files.length === 0) return null;
112
+
113
+ const hasher = new Bun.CryptoHasher("sha256");
114
+ for (const file of files) {
115
+ const pathBuf = Buffer.from(file.relPath, "utf-8");
116
+ hasher.update(`${pathBuf.length}:`);
117
+ hasher.update(pathBuf);
118
+ hasher.update(`${file.content.length}:`);
119
+ hasher.update(file.content);
120
+ }
121
+ return `v2:${hasher.digest("hex")}`;
122
+ }
123
+
124
+ // ---------------------------------------------------------------------------
125
+ // Integrity manifest helpers
126
+ // ---------------------------------------------------------------------------
127
+
128
+ interface IntegrityRecord {
129
+ sha256: string;
130
+ installedAt: string;
131
+ }
132
+
133
+ type IntegrityManifest = Record<string, IntegrityRecord>;
134
+
135
+ function loadIntegrityManifest(skillsDir: string): IntegrityManifest {
136
+ const path = join(skillsDir, INTEGRITY_JSON_FILENAME);
137
+ if (!existsSync(path)) return {};
138
+ try {
139
+ return JSON.parse(readFileSync(path, "utf-8")) as IntegrityManifest;
140
+ } catch {
141
+ return {};
142
+ }
143
+ }
144
+
145
+ // ---------------------------------------------------------------------------
146
+ // Origin inference
147
+ // ---------------------------------------------------------------------------
148
+
149
+ /**
150
+ * Infer SkillInstallMeta for a skill directory that has no install-meta.json.
151
+ *
152
+ * Decision tree:
153
+ * 1. version.json with `origin: "skills.sh"` -> skillssh
154
+ * 2. version.json with `version` but no `origin` field:
155
+ * - Has entry in .integrity.json -> clawhub
156
+ * - Otherwise -> vellum
157
+ * 3. version.json exists but doesn't match above -> custom
158
+ * 4. No version.json:
159
+ * - Has entry in .integrity.json -> clawhub
160
+ * - Otherwise -> custom
161
+ */
162
+ function inferInstallMeta(
163
+ skillDir: string,
164
+ skillId: string,
165
+ integrityManifest: IntegrityManifest,
166
+ ): SkillInstallMeta {
167
+ const versionJsonPath = join(skillDir, VERSION_JSON_FILENAME);
168
+ const hasIntegrityEntry = skillId in integrityManifest;
169
+
170
+ if (existsSync(versionJsonPath)) {
171
+ let raw: Record<string, unknown>;
172
+ try {
173
+ raw = JSON.parse(readFileSync(versionJsonPath, "utf-8")) as Record<
174
+ string,
175
+ unknown
176
+ >;
177
+ } catch {
178
+ // Malformed version.json — treat as if it doesn't exist
179
+ return buildFallbackMeta(skillDir, skillId, hasIntegrityEntry);
180
+ }
181
+
182
+ // Case 1: skills.sh origin
183
+ if (raw.origin === "skills.sh") {
184
+ return {
185
+ origin: "skillssh",
186
+ installedAt:
187
+ typeof raw.installedAt === "string"
188
+ ? raw.installedAt
189
+ : getDirectoryMtime(skillDir),
190
+ sourceRepo: typeof raw.source === "string" ? raw.source : undefined,
191
+ slug: typeof raw.skillSlug === "string" ? raw.skillSlug : undefined,
192
+ contentHash: computeSkillHash(skillDir) ?? undefined,
193
+ };
194
+ }
195
+
196
+ // Case 2: has version but no origin field
197
+ if (typeof raw.version === "string" && !("origin" in raw)) {
198
+ return {
199
+ origin: hasIntegrityEntry ? "clawhub" : "vellum",
200
+ installedAt:
201
+ typeof raw.installedAt === "string"
202
+ ? raw.installedAt
203
+ : getDirectoryMtime(skillDir),
204
+ version: raw.version,
205
+ contentHash: computeSkillHash(skillDir) ?? undefined,
206
+ };
207
+ }
208
+
209
+ // Case 3: version.json exists but doesn't match known patterns
210
+ return {
211
+ origin: "custom",
212
+ installedAt:
213
+ typeof raw.installedAt === "string"
214
+ ? raw.installedAt
215
+ : getDirectoryMtime(skillDir),
216
+ contentHash: computeSkillHash(skillDir) ?? undefined,
217
+ };
218
+ }
219
+
220
+ // Case 4: no version.json
221
+ return buildFallbackMeta(skillDir, skillId, hasIntegrityEntry);
222
+ }
223
+
224
+ function buildFallbackMeta(
225
+ skillDir: string,
226
+ _skillId: string,
227
+ hasIntegrityEntry: boolean,
228
+ ): SkillInstallMeta {
229
+ return {
230
+ origin: hasIntegrityEntry ? "clawhub" : "custom",
231
+ installedAt: getDirectoryMtime(skillDir),
232
+ contentHash: computeSkillHash(skillDir) ?? undefined,
233
+ };
234
+ }
235
+
236
+ /**
237
+ * Get directory mtime as ISO 8601 string. Falls back to current time.
238
+ */
239
+ function getDirectoryMtime(dir: string): string {
240
+ try {
241
+ return statSync(dir).mtime.toISOString();
242
+ } catch {
243
+ return new Date().toISOString();
244
+ }
245
+ }
246
+
247
+ // ---------------------------------------------------------------------------
248
+ // Migration
249
+ // ---------------------------------------------------------------------------
250
+
251
+ export const backfillInstallMetaMigration: WorkspaceMigration = {
252
+ id: "026-backfill-install-meta",
253
+ description:
254
+ "Backfill install-meta.json with origin field for existing skill directories",
255
+
256
+ run(workspaceDir: string): void {
257
+ const skillsDir = join(workspaceDir, "skills");
258
+ if (!existsSync(skillsDir)) return;
259
+
260
+ // Load the integrity manifest once — shared across all skills
261
+ const integrityManifest = loadIntegrityManifest(skillsDir);
262
+
263
+ // Enumerate skill directories (each subdirectory containing a SKILL.md)
264
+ let dirNames: string[];
265
+ try {
266
+ dirNames = readdirSync(skillsDir, { withFileTypes: true })
267
+ .filter((entry) => entry.isDirectory())
268
+ .map((entry) => entry.name);
269
+ } catch {
270
+ return;
271
+ }
272
+
273
+ for (const name of dirNames) {
274
+ const skillDir = join(skillsDir, name);
275
+ const skillMdPath = join(skillDir, SKILL_MD_FILENAME);
276
+ const installMetaPath = join(skillDir, INSTALL_META_FILENAME);
277
+
278
+ // Only process directories that contain SKILL.md
279
+ if (!existsSync(skillMdPath)) continue;
280
+
281
+ // Skip if install-meta.json already exists (idempotency)
282
+ if (existsSync(installMetaPath)) continue;
283
+
284
+ const meta = inferInstallMeta(skillDir, name, integrityManifest);
285
+
286
+ // Mark as backfilled so down() can safely identify and remove only
287
+ // migration-created files without touching CLI-installed ones.
288
+ writeInstallMeta(skillDir, { ...meta, backfilledBy: "migration-026" });
289
+ }
290
+ },
291
+
292
+ down(workspaceDir: string): void {
293
+ const skillsDir = join(workspaceDir, "skills");
294
+ if (!existsSync(skillsDir)) return;
295
+
296
+ let dirNames: string[];
297
+ try {
298
+ dirNames = readdirSync(skillsDir, { withFileTypes: true })
299
+ .filter((entry) => entry.isDirectory())
300
+ .map((entry) => entry.name);
301
+ } catch {
302
+ return;
303
+ }
304
+
305
+ for (const name of dirNames) {
306
+ const installMetaPath = join(skillsDir, name, INSTALL_META_FILENAME);
307
+ if (existsSync(installMetaPath)) {
308
+ try {
309
+ const meta = JSON.parse(
310
+ readFileSync(installMetaPath, "utf-8"),
311
+ ) as SkillInstallMeta;
312
+
313
+ // Only remove install-meta.json that were backfilled by this migration.
314
+ // Files written by the normal install flow (CLI, daemon, etc.) won't
315
+ // have backfilledBy set and are safely preserved on rollback.
316
+ if (meta.backfilledBy === "migration-026") {
317
+ unlinkSync(installMetaPath);
318
+ }
319
+ } catch {
320
+ // Malformed file — skip
321
+ }
322
+ }
323
+ }
324
+ },
325
+ };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Workspace migration 027: Remove orphaned optimized-images cache directory.
3
+ *
4
+ * The optimized image cache was moved from `workspace/cache/optimized-images/`
5
+ * to `os.tmpdir()/vellum-optimized-images/`. This migration cleans up the old
6
+ * directory and removes the parent `cache/` directory if it is now empty.
7
+ *
8
+ * Idempotent: safe to re-run after interruption at any point.
9
+ */
10
+
11
+ import { existsSync, readdirSync, rmdirSync, rmSync } from "node:fs";
12
+ import { join } from "node:path";
13
+
14
+ import type { WorkspaceMigration } from "./types.js";
15
+
16
+ export const removeOrphanedOptimizedImagesCacheMigration: WorkspaceMigration = {
17
+ id: "027-remove-orphaned-optimized-images-cache",
18
+ description:
19
+ "Remove orphaned cache/optimized-images/ directory after cache moved to tmpdir",
20
+
21
+ run(workspaceDir: string): void {
22
+ const cacheDir = join(workspaceDir, "cache");
23
+ const optimizedImagesDir = join(cacheDir, "optimized-images");
24
+
25
+ if (existsSync(optimizedImagesDir)) {
26
+ rmSync(optimizedImagesDir, { recursive: true, force: true });
27
+ }
28
+
29
+ // Remove the parent cache/ directory if it is now empty
30
+ if (existsSync(cacheDir)) {
31
+ const remaining = readdirSync(cacheDir);
32
+ if (remaining.length === 0) {
33
+ rmdirSync(cacheDir);
34
+ }
35
+ }
36
+ },
37
+
38
+ down(_workspaceDir: string): void {
39
+ // The old cache directory contained ephemeral cached data that does not
40
+ // need to be restored. The cache will be rebuilt in tmpdir on next use.
41
+ },
42
+ };
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Workspace migration 028: Recover conversations from disk-view directories.
3
+ *
4
+ * If the SQLite database was recreated empty but the disk-view directories
5
+ * under `workspace/conversations/` still exist, this migration reads each
6
+ * conversation's `meta.json` and `messages.jsonl` and re-inserts the rows
7
+ * into the database.
8
+ *
9
+ * Idempotent: conversations already present in the DB are skipped.
10
+ * Malformed files are skipped with warnings — they do not crash the migration.
11
+ */
12
+
13
+ import { randomUUID } from "node:crypto";
14
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
15
+ import { join } from "node:path";
16
+
17
+ import { eq } from "drizzle-orm";
18
+
19
+ import { getDb } from "../../memory/db.js";
20
+ import { conversations, messages } from "../../memory/schema/conversations.js";
21
+ import { getLogger } from "../../util/logger.js";
22
+ import type { WorkspaceMigration } from "./types.js";
23
+
24
+ const log = getLogger("workspace-migrations");
25
+
26
+ interface DiskMeta {
27
+ id: string;
28
+ title?: string;
29
+ type?: string;
30
+ channel?: string;
31
+ createdAt?: string;
32
+ updatedAt?: string;
33
+ }
34
+
35
+ interface DiskToolCall {
36
+ name?: string;
37
+ input?: unknown;
38
+ }
39
+
40
+ interface DiskToolResult {
41
+ content?: unknown;
42
+ }
43
+
44
+ interface DiskMessageRecord {
45
+ role: string;
46
+ ts?: string;
47
+ content?: string;
48
+ toolCalls?: DiskToolCall[];
49
+ toolResults?: DiskToolResult[];
50
+ attachments?: unknown[];
51
+ }
52
+
53
+ function parseEpochMs(isoString: string | undefined): number | null {
54
+ if (!isoString) return null;
55
+ const ms = new Date(isoString).getTime();
56
+ return Number.isNaN(ms) ? null : ms;
57
+ }
58
+
59
+ function buildContentBlocks(record: DiskMessageRecord): unknown[] {
60
+ const blocks: unknown[] = [];
61
+
62
+ if (record.content) {
63
+ blocks.push({ type: "text", text: record.content });
64
+ }
65
+
66
+ if (Array.isArray(record.toolCalls)) {
67
+ for (const tc of record.toolCalls) {
68
+ blocks.push({
69
+ type: "tool_use",
70
+ id: randomUUID(),
71
+ name: tc.name ?? "unknown",
72
+ input: tc.input ?? {},
73
+ });
74
+ }
75
+ }
76
+
77
+ if (Array.isArray(record.toolResults)) {
78
+ for (const tr of record.toolResults) {
79
+ blocks.push({
80
+ type: "tool_result",
81
+ tool_use_id: "",
82
+ content:
83
+ typeof tr.content === "string"
84
+ ? tr.content
85
+ : JSON.stringify(tr.content),
86
+ });
87
+ }
88
+ }
89
+
90
+ // content column is NOT NULL — ensure at least one block
91
+ if (blocks.length === 0) {
92
+ blocks.push({ type: "text", text: "" });
93
+ }
94
+
95
+ return blocks;
96
+ }
97
+
98
+ export const recoverConversationsFromDiskViewMigration: WorkspaceMigration = {
99
+ id: "028-recover-conversations-from-disk-view",
100
+ description:
101
+ "Recover conversations from disk-view directories into the database",
102
+
103
+ run(workspaceDir: string): void {
104
+ const conversationsDir = join(workspaceDir, "conversations");
105
+ if (!existsSync(conversationsDir)) return;
106
+
107
+ const db = getDb();
108
+
109
+ let entries: string[];
110
+ try {
111
+ entries = readdirSync(conversationsDir);
112
+ } catch (err) {
113
+ log.warn(`Failed to read conversations directory: ${err}`);
114
+ return;
115
+ }
116
+
117
+ let recovered = 0;
118
+ let skipped = 0;
119
+ let errors = 0;
120
+
121
+ for (const entry of entries) {
122
+ const dirPath = join(conversationsDir, entry);
123
+
124
+ // Skip non-directories
125
+ try {
126
+ if (!statSync(dirPath).isDirectory()) {
127
+ continue;
128
+ }
129
+ } catch {
130
+ continue;
131
+ }
132
+
133
+ // Read and parse meta.json
134
+ const metaPath = join(dirPath, "meta.json");
135
+ if (!existsSync(metaPath)) {
136
+ log.warn(
137
+ `Skipping ${entry}: missing meta.json`,
138
+ );
139
+ skipped++;
140
+ continue;
141
+ }
142
+
143
+ let meta: DiskMeta;
144
+ try {
145
+ meta = JSON.parse(readFileSync(metaPath, "utf-8")) as DiskMeta;
146
+ } catch (err) {
147
+ log.warn(
148
+ `Skipping ${entry}: malformed meta.json: ${err}`,
149
+ );
150
+ skipped++;
151
+ continue;
152
+ }
153
+
154
+ if (!meta.id) {
155
+ log.warn(
156
+ `Skipping ${entry}: meta.json missing id`,
157
+ );
158
+ skipped++;
159
+ continue;
160
+ }
161
+
162
+ // Check if conversation already exists in DB (idempotency)
163
+ const existing = db
164
+ .select()
165
+ .from(conversations)
166
+ .where(eq(conversations.id, meta.id))
167
+ .get();
168
+
169
+ if (existing) {
170
+ skipped++;
171
+ continue;
172
+ }
173
+
174
+ // Parse messages.jsonl
175
+ const messagesPath = join(dirPath, "messages.jsonl");
176
+ const messageRecords: DiskMessageRecord[] = [];
177
+
178
+ if (existsSync(messagesPath)) {
179
+ try {
180
+ const raw = readFileSync(messagesPath, "utf-8");
181
+ for (const line of raw.split("\n")) {
182
+ const trimmed = line.trim();
183
+ if (!trimmed) continue;
184
+ try {
185
+ messageRecords.push(
186
+ JSON.parse(trimmed) as DiskMessageRecord,
187
+ );
188
+ } catch {
189
+ log.warn(
190
+ `Skipping malformed JSONL line in ${entry}/messages.jsonl`,
191
+ );
192
+ }
193
+ }
194
+ } catch (err) {
195
+ log.warn(
196
+ `Failed to read messages.jsonl for ${entry}: ${err}`,
197
+ );
198
+ }
199
+ }
200
+
201
+ // Compute timestamps
202
+ const createdAt = parseEpochMs(meta.createdAt) ?? Date.now();
203
+ const updatedAt = parseEpochMs(meta.updatedAt) ?? createdAt;
204
+
205
+ // Insert conversation + messages in a transaction
206
+ try {
207
+ db.transaction((tx) => {
208
+ tx.insert(conversations)
209
+ .values({
210
+ id: meta.id,
211
+ title: meta.title ?? null,
212
+ createdAt,
213
+ updatedAt,
214
+ conversationType: meta.type ?? "standard",
215
+ originChannel: meta.channel ?? null,
216
+ source: "user",
217
+ memoryScopeId: "default",
218
+ isAutoTitle: 1,
219
+ totalInputTokens: 0,
220
+ totalOutputTokens: 0,
221
+ totalEstimatedCost: 0,
222
+ contextSummary: null,
223
+ contextCompactedMessageCount: 0,
224
+ contextCompactedAt: null,
225
+ originInterface: null,
226
+ forkParentConversationId: null,
227
+ forkParentMessageId: null,
228
+ scheduleJobId: null,
229
+ })
230
+ .run();
231
+
232
+ for (const record of messageRecords) {
233
+ const contentBlocks = buildContentBlocks(record);
234
+ const msgCreatedAt =
235
+ parseEpochMs(record.ts) ?? createdAt;
236
+
237
+ tx.insert(messages)
238
+ .values({
239
+ id: randomUUID(),
240
+ conversationId: meta.id,
241
+ role: record.role,
242
+ content: JSON.stringify(contentBlocks),
243
+ createdAt: msgCreatedAt,
244
+ metadata: null,
245
+ })
246
+ .run();
247
+ }
248
+ });
249
+
250
+ recovered++;
251
+ } catch (err) {
252
+ log.warn(
253
+ `Failed to insert conversation ${meta.id} (${entry}): ${err}`,
254
+ );
255
+ errors++;
256
+ }
257
+ }
258
+
259
+ if (recovered > 0 || errors > 0) {
260
+ log.info(
261
+ `Recover conversations from disk-view: recovered=${recovered}, skipped=${skipped}, errors=${errors}`,
262
+ );
263
+ }
264
+ },
265
+
266
+ // No-op: deleting recovered conversation data from the database would cause
267
+ // data loss — the disk-view files are the only remaining copy after the
268
+ // original DB was lost.
269
+ down(_workspaceDir: string): void {},
270
+ };