@vellumai/assistant 0.10.2 → 0.10.3-dev.202606252046.9075fd5

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 (546) hide show
  1. package/bun.lock +20 -0
  2. package/docs/workspace-tools.md +42 -33
  3. package/eslint-rules/cli-no-daemon-internals.js +6 -0
  4. package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +91 -0
  5. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +31 -0
  6. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +44 -0
  7. package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +48 -0
  8. package/node_modules/@vellumai/gateway-client/src/index.ts +14 -0
  9. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +17 -0
  10. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  11. package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +28 -0
  12. package/node_modules/@vellumai/service-contracts/src/channels.ts +41 -0
  13. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  14. package/openapi.yaml +196 -56
  15. package/package.json +4 -1
  16. package/scripts/test.sh +36 -15
  17. package/src/__tests__/actor-token-service.test.ts +36 -14
  18. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +83 -31
  19. package/src/__tests__/agent-loop-override-profile.test.ts +1 -0
  20. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
  21. package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
  22. package/src/__tests__/annotate-activity-metadata.test.ts +2 -0
  23. package/src/__tests__/annotate-risk-options.test.ts +2 -0
  24. package/src/__tests__/approval-cascade.test.ts +2 -0
  25. package/src/__tests__/assistant-attachments.test.ts +42 -0
  26. package/src/__tests__/background-workers-disk-pressure.test.ts +2 -0
  27. package/src/__tests__/btw-routes.test.ts +2 -0
  28. package/src/__tests__/build-persisted-content.test.ts +2 -0
  29. package/src/__tests__/call-controller.test.ts +19 -0
  30. package/src/__tests__/channel-approval-routes.test.ts +21 -26
  31. package/src/__tests__/channel-delivery-store.test.ts +28 -0
  32. package/src/__tests__/channel-guardian.test.ts +164 -78
  33. package/src/__tests__/channel-inbound-disk-pressure.test.ts +11 -19
  34. package/src/__tests__/channel-reply-delivery.test.ts +2 -0
  35. package/src/__tests__/code-search-tool.test.ts +585 -0
  36. package/src/__tests__/compaction-events.test.ts +2 -0
  37. package/src/__tests__/compaction-ledger-store.test.ts +128 -0
  38. package/src/__tests__/compaction.benchmark.test.ts +2 -0
  39. package/src/__tests__/compactor-call-site-logging.test.ts +2 -0
  40. package/src/__tests__/compactor-low-watermark-cut.test.ts +2 -0
  41. package/src/__tests__/compactor-preserved-tail-count.test.ts +2 -0
  42. package/src/__tests__/compactor-summary-call-truncation.test.ts +2 -0
  43. package/src/__tests__/compactor-web-search-strip.test.ts +2 -0
  44. package/src/__tests__/config-loader-backfill.test.ts +123 -10
  45. package/src/__tests__/config-schema.test.ts +1 -0
  46. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +31 -29
  47. package/src/__tests__/consult-deadline.test.ts +60 -0
  48. package/src/__tests__/contact-store-interaction-info.test.ts +156 -0
  49. package/src/__tests__/contact-store-user-file.test.ts +7 -10
  50. package/src/__tests__/contacts-relay-reads.test.ts +19 -24
  51. package/src/__tests__/contacts-write.test.ts +0 -2
  52. package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
  53. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +2 -0
  54. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  55. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
  56. package/src/__tests__/conversation-agent-loop.test.ts +134 -0
  57. package/src/__tests__/conversation-analysis-routes.test.ts +2 -0
  58. package/src/__tests__/conversation-app-control-lifecycle.test.ts +2 -0
  59. package/src/__tests__/conversation-attention-telegram.test.ts +9 -11
  60. package/src/__tests__/conversation-confirmation-signals.test.ts +2 -0
  61. package/src/__tests__/conversation-fork-crud.test.ts +354 -24
  62. package/src/__tests__/conversation-history-web-search.test.ts +2 -0
  63. package/src/__tests__/conversation-load-history-repair.test.ts +2 -0
  64. package/src/__tests__/conversation-load-history-stripped.test.ts +2 -0
  65. package/src/__tests__/conversation-pairing.test.ts +2 -0
  66. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
  67. package/src/__tests__/conversation-process-callsite.test.ts +2 -0
  68. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
  69. package/src/__tests__/conversation-queue.test.ts +91 -0
  70. package/src/__tests__/conversation-routes-guardian-reply.test.ts +14 -0
  71. package/src/__tests__/conversation-routes-slash-commands.test.ts +14 -0
  72. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  73. package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
  74. package/src/__tests__/conversation-speed-override.test.ts +2 -0
  75. package/src/__tests__/conversation-surfaces-task-progress.test.ts +29 -0
  76. package/src/__tests__/conversation-title-service.test.ts +2 -0
  77. package/src/__tests__/conversation-tool-setup-attribution.test.ts +47 -0
  78. package/src/__tests__/conversation-usage.test.ts +2 -0
  79. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -0
  80. package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
  81. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
  82. package/src/__tests__/credential-security-invariants.test.ts +1 -1
  83. package/src/__tests__/db-compaction-events-migration.test.ts +129 -0
  84. package/src/__tests__/db-migration-rollback.test.ts +205 -171
  85. package/src/__tests__/db-test-helpers.ts +5 -4
  86. package/src/__tests__/delete-propagation.test.ts +5 -3
  87. package/src/__tests__/deterministic-verification-control-plane.test.ts +4 -2
  88. package/src/__tests__/disk-pressure-guard.test.ts +41 -0
  89. package/src/__tests__/dm-backfill.test.ts +6 -4
  90. package/src/__tests__/dm-persistence.test.ts +2 -0
  91. package/src/__tests__/emit-signal-routing-intent.test.ts +7 -6
  92. package/src/__tests__/events-dev-bypass-actor.test.ts +7 -1
  93. package/src/__tests__/exploration-drift-hook.test.ts +3 -2
  94. package/src/__tests__/filing-service.test.ts +2 -0
  95. package/src/__tests__/guardian-binding-drift-heal.test.ts +104 -19
  96. package/src/__tests__/guardian-dispatch.test.ts +140 -1
  97. package/src/__tests__/guardian-expiry-notifier.test.ts +282 -0
  98. package/src/__tests__/guardian-outbound-http.test.ts +13 -0
  99. package/src/__tests__/guardian-routing-state.test.ts +6 -10
  100. package/src/__tests__/heartbeat-disk-pressure.test.ts +2 -0
  101. package/src/__tests__/heartbeat-service.test.ts +2 -0
  102. package/src/__tests__/helpers/channel-test-adapter.ts +46 -19
  103. package/src/__tests__/helpers/create-guardian-binding.ts +15 -23
  104. package/src/__tests__/helpers/mock-logger.ts +1 -0
  105. package/src/__tests__/helpers/seed-contact-channel.ts +96 -0
  106. package/src/__tests__/host-app-control-routes.test.ts +24 -30
  107. package/src/__tests__/host-bash-routes.test.ts +31 -41
  108. package/src/__tests__/host-browser-routes.test.ts +26 -32
  109. package/src/__tests__/host-cu-routes-targeted.test.ts +25 -33
  110. package/src/__tests__/host-file-routes-targeted.test.ts +40 -52
  111. package/src/__tests__/host-transfer-routes-targeted.test.ts +31 -43
  112. package/src/__tests__/http-user-message-parity.test.ts +290 -8
  113. package/src/__tests__/inbound-invite-redemption.test.ts +115 -10
  114. package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
  115. package/src/__tests__/invite-redemption-service.test.ts +471 -53
  116. package/src/__tests__/invite-routes-http.test.ts +34 -0
  117. package/src/__tests__/invite-service-ipc.test.ts +65 -2
  118. package/src/__tests__/llm-context-normalization.test.ts +105 -0
  119. package/src/__tests__/llm-request-log-error-payload.test.ts +71 -9
  120. package/src/__tests__/llm-usage-store.test.ts +25 -0
  121. package/src/__tests__/mcp-config-secret-boundary.test.ts +392 -0
  122. package/src/__tests__/mcp-health-check.test.ts +2 -1
  123. package/src/__tests__/media-stream-server-integration.test.ts +127 -0
  124. package/src/__tests__/memory-retrieval-hook.test.ts +2 -0
  125. package/src/__tests__/messaging-send-tool.test.ts +2 -0
  126. package/src/__tests__/migration-import-from-url.test.ts +2 -2
  127. package/src/__tests__/mtime-cache.test.ts +275 -5
  128. package/src/__tests__/native-web-search.test.ts +2 -0
  129. package/src/__tests__/non-member-access-request.test.ts +191 -17
  130. package/src/__tests__/notification-broadcaster.test.ts +4 -0
  131. package/src/__tests__/notification-decision-recipient-context.test.ts +33 -32
  132. package/src/__tests__/notification-deep-link.test.ts +6 -0
  133. package/src/__tests__/notification-guardian-path.test.ts +19 -0
  134. package/src/__tests__/onboarding-persona-write.test.ts +52 -22
  135. package/src/__tests__/openai-provider.test.ts +22 -12
  136. package/src/__tests__/openai-responses-provider.test.ts +12 -2
  137. package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
  138. package/src/__tests__/pending-interactions-resolved-event.test.ts +7 -4
  139. package/src/__tests__/persist-onboarding-artifacts.test.ts +1 -0
  140. package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
  141. package/src/__tests__/persona-resolver.test.ts +75 -45
  142. package/src/__tests__/plugin-bootstrap.test.ts +21 -83
  143. package/src/__tests__/plugin-disabled-state.test.ts +190 -0
  144. package/src/__tests__/plugin-pipeline.test.ts +96 -0
  145. package/src/__tests__/plugin-route-contribution.test.ts +6 -19
  146. package/src/__tests__/plugin-tool-contribution.test.ts +5 -20
  147. package/src/__tests__/plugin-types.test.ts +2 -4
  148. package/src/__tests__/process-message-background-slack.test.ts +2 -0
  149. package/src/__tests__/process-message-display-content.test.ts +2 -0
  150. package/src/__tests__/provider-error-scenarios.test.ts +5 -4
  151. package/src/__tests__/provider-usage-tracking.test.ts +39 -0
  152. package/src/__tests__/reaction-intercept-cold-cache-warm.test.ts +135 -0
  153. package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +158 -0
  154. package/src/__tests__/reaction-persistence.test.ts +51 -4
  155. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +2 -0
  156. package/src/__tests__/registry.test.ts +4 -1
  157. package/src/__tests__/relay-server.test.ts +758 -32
  158. package/src/__tests__/runtime-attachment-metadata.test.ts +9 -12
  159. package/src/__tests__/secret-ingress-http.test.ts +14 -0
  160. package/src/__tests__/send-endpoint-busy.test.ts +30 -8
  161. package/src/__tests__/settings-routes.test.ts +32 -0
  162. package/src/__tests__/skills.test.ts +44 -0
  163. package/src/__tests__/slack-inbound-verification.test.ts +47 -2
  164. package/src/__tests__/sse-actor-principal-guardian-source.test.ts +79 -0
  165. package/src/__tests__/steer-on-enqueue-question.test.ts +181 -0
  166. package/src/__tests__/stt-hints.test.ts +49 -15
  167. package/src/__tests__/subagent-detail.test.ts +27 -0
  168. package/src/__tests__/subagent-disposal.test.ts +65 -0
  169. package/src/__tests__/subagent-fork-prompt-role.test.ts +195 -0
  170. package/src/__tests__/subagent-fork-spawn.test.ts +6 -7
  171. package/src/__tests__/subagent-notify-parent.test.ts +2 -0
  172. package/src/__tests__/subagent-role-registry.test.ts +24 -6
  173. package/src/__tests__/subagent-spawn-and-await.test.ts +546 -0
  174. package/src/__tests__/subagent-spawn-tool-fork.test.ts +2 -0
  175. package/src/__tests__/subagent-tools.test.ts +398 -1
  176. package/src/__tests__/suggestion-routes.test.ts +2 -0
  177. package/src/__tests__/thread-backfill.test.ts +3 -3
  178. package/src/__tests__/title-generate-hook.test.ts +2 -0
  179. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -0
  180. package/src/__tests__/tool-executor.test.ts +16 -11
  181. package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
  182. package/src/__tests__/tool-result-metadata-plumbing.test.ts +2 -0
  183. package/src/__tests__/tool-start-timestamp.test.ts +2 -0
  184. package/src/__tests__/trusted-contact-approval-notifier.test.ts +37 -51
  185. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +12 -12
  186. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -7
  187. package/src/__tests__/trusted-contact-multichannel.test.ts +16 -7
  188. package/src/__tests__/trusted-contact-verification.test.ts +79 -54
  189. package/src/__tests__/twilio-routes.test.ts +96 -0
  190. package/src/__tests__/ui-file-upload-surface.test.ts +86 -0
  191. package/src/__tests__/verification-control-plane-policy.test.ts +2 -0
  192. package/src/__tests__/voice-guardian-cold-cache-warm.test.ts +137 -0
  193. package/src/__tests__/voice-invite-redemption.test.ts +216 -20
  194. package/src/__tests__/web-search-backend-failure.test.ts +2 -0
  195. package/src/__tests__/workspace-migration-102-preserve-heartbeat-enabled-for-existing-workspaces.test.ts +3 -3
  196. package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +208 -0
  197. package/src/__tests__/workspace-migration-112-remove-advisor-callsite-override.test.ts +170 -0
  198. package/src/__tests__/workspace-migration-drop-user-md.test.ts +196 -238
  199. package/src/__tests__/workspace-migration-remove-hooks.test.ts +14 -35
  200. package/src/__tests__/workspace-tool-loader.test.ts +195 -2
  201. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +35 -47
  202. package/src/agent/loop-exclusive-tool.test.ts +154 -0
  203. package/src/agent/loop-native-web-search.test.ts +200 -0
  204. package/src/agent/loop.ts +164 -1
  205. package/src/api/constants/sse-replay.ts +41 -0
  206. package/src/api/events/conversation-notice.ts +26 -0
  207. package/src/api/index.ts +19 -1
  208. package/src/api/responses/llm-request-log-entry.ts +29 -0
  209. package/src/api/responses/subagent-detail.ts +17 -0
  210. package/src/api/surfaces.ts +39 -3
  211. package/src/approvals/guardian-channel-delivery.ts +30 -0
  212. package/src/approvals/guardian-expiry-notifier.ts +148 -0
  213. package/src/approvals/guardian-request-resolvers.ts +17 -15
  214. package/src/calls/__tests__/relay-setup-router.test.ts +267 -17
  215. package/src/calls/call-domain.ts +3 -3
  216. package/src/calls/guardian-dispatch.ts +14 -9
  217. package/src/calls/inbound-trust-reader.ts +24 -2
  218. package/src/calls/media-stream-server.ts +21 -0
  219. package/src/calls/relay-access-wait.ts +6 -6
  220. package/src/calls/relay-server.ts +188 -51
  221. package/src/calls/relay-setup-router.ts +47 -17
  222. package/src/calls/relay-verification.ts +4 -4
  223. package/src/calls/stt-hints.ts +9 -12
  224. package/src/calls/twilio-routes.ts +14 -4
  225. package/src/channels/types.ts +10 -20
  226. package/src/cli/commands/__tests__/cache.test.ts +8 -1
  227. package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -0
  228. package/src/cli/commands/cache.ts +194 -181
  229. package/src/cli/commands/contacts.ts +10 -7
  230. package/src/cli/commands/db/__tests__/repair.test.ts +6 -5
  231. package/src/cli/commands/db/status.ts +37 -1
  232. package/src/cli/commands/mcp.ts +252 -218
  233. package/src/cli/commands/memory/__tests__/worker.test.ts +432 -0
  234. package/src/cli/commands/memory/index.ts +2 -0
  235. package/src/cli/commands/memory/worker.ts +242 -0
  236. package/src/cli/commands/plugins.ts +125 -13
  237. package/src/cli/lib/__tests__/install-from-github.test.ts +102 -0
  238. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +160 -1
  239. package/src/cli/lib/__tests__/publish-plugin.test.ts +404 -0
  240. package/src/cli/lib/list-installed-plugins.ts +179 -1
  241. package/src/cli/lib/publish-plugin.ts +633 -0
  242. package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +143 -0
  243. package/src/config/__tests__/sync-gated-profiles.test.ts +16 -10
  244. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +27 -17
  245. package/src/config/bundled-skills/contacts/tools/contact-search.ts +13 -3
  246. package/src/config/bundled-skills/subagent/SKILL.md +17 -2
  247. package/src/config/bundled-skills/subagent/TOOLS.json +5 -4
  248. package/src/config/call-site-defaults.ts +0 -6
  249. package/src/config/feature-flag-registry.json +5 -13
  250. package/src/config/llm-resolver.ts +0 -3
  251. package/src/config/loader.ts +38 -5
  252. package/src/config/prune-seeded-callsite-defaults.ts +110 -0
  253. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  254. package/src/config/schemas/call-site-catalog.ts +0 -7
  255. package/src/config/schemas/heartbeat.ts +2 -5
  256. package/src/config/schemas/llm.ts +3 -12
  257. package/src/config/schemas/memory-lifecycle.ts +12 -0
  258. package/src/config/schemas/memory-v3.ts +7 -0
  259. package/src/config/schemas/memory.ts +4 -0
  260. package/src/config/schemas/timeouts.ts +8 -0
  261. package/src/config/seed-inference-profiles.ts +30 -34
  262. package/src/config/skills.ts +27 -5
  263. package/src/config/sync-gated-profiles.ts +12 -16
  264. package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +128 -0
  265. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +312 -0
  266. package/src/contacts/__tests__/member-write-relay.test.ts +226 -0
  267. package/src/contacts/contact-store.ts +27 -237
  268. package/src/contacts/contacts-write.ts +18 -55
  269. package/src/contacts/gateway-channel-read.ts +51 -0
  270. package/src/contacts/guardian-delivery-reader.ts +223 -0
  271. package/src/contacts/member-write-relay.ts +183 -0
  272. package/src/contacts/types.ts +3 -15
  273. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +35 -0
  274. package/src/daemon/__tests__/conversation-tool-setup.test.ts +0 -44
  275. package/src/daemon/assistant-attachments.ts +27 -4
  276. package/src/daemon/conversation-agent-loop.ts +28 -0
  277. package/src/daemon/conversation-notices.ts +60 -0
  278. package/src/daemon/conversation-process.ts +35 -16
  279. package/src/daemon/conversation-surfaces.ts +111 -38
  280. package/src/daemon/conversation-tool-setup.ts +71 -30
  281. package/src/daemon/conversation.ts +23 -1
  282. package/src/daemon/disk-pressure-guard.ts +12 -2
  283. package/src/daemon/event-loop-watchdog.ts +28 -1
  284. package/src/daemon/external-plugins-bootstrap.ts +17 -41
  285. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +0 -1
  286. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -2
  287. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +25 -2
  288. package/src/daemon/handlers/__tests__/config-channels.test.ts +220 -0
  289. package/src/daemon/handlers/config-a2a.ts +6 -14
  290. package/src/daemon/handlers/config-channels.ts +67 -26
  291. package/src/daemon/handlers/conversations.ts +77 -0
  292. package/src/daemon/lifecycle.ts +16 -0
  293. package/src/daemon/mcp-reload-service.ts +10 -0
  294. package/src/daemon/memory-v2-startup.test.ts +72 -0
  295. package/src/daemon/memory-v2-startup.ts +87 -19
  296. package/src/daemon/message-types/conversations.ts +2 -0
  297. package/src/daemon/message-types/surfaces.ts +12 -12
  298. package/src/daemon/server.ts +0 -4
  299. package/src/daemon/shutdown-handlers.ts +20 -0
  300. package/src/daemon/tool-setup-types.ts +9 -0
  301. package/src/heartbeat/heartbeat-service.ts +5 -0
  302. package/src/home/relationship-state-writer.ts +5 -0
  303. package/src/hooks/hook-loader.ts +341 -0
  304. package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
  305. package/src/ipc/assistant-server.ts +2 -2
  306. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +1 -0
  307. package/src/mcp/client.ts +15 -1
  308. package/src/mcp/mcp-auth-orchestrator.ts +6 -1
  309. package/src/mcp/mcp-header-store.ts +134 -0
  310. package/src/mcp/mcp-oauth-provider.ts +19 -8
  311. package/src/memory/__tests__/301-create-watchdog-events.test.ts +110 -0
  312. package/src/memory/__tests__/memory-retrospective-job.test.ts +8 -0
  313. package/src/memory/__tests__/prompt-override.test.ts +192 -0
  314. package/src/memory/__tests__/watchdog-events-store.test.ts +161 -0
  315. package/src/memory/compaction-ledger-store.ts +107 -0
  316. package/src/memory/conversation-crud.ts +129 -61
  317. package/src/memory/db-connection.ts +22 -3
  318. package/src/memory/db-init.ts +37 -503
  319. package/src/memory/db-singleton.ts +6 -4
  320. package/src/memory/jobs-worker.ts +104 -0
  321. package/src/memory/llm-request-log-store.ts +26 -1
  322. package/src/memory/llm-usage-store.ts +48 -20
  323. package/src/memory/memory-retrospective-job.ts +14 -8
  324. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +152 -56
  325. package/src/memory/migrations/300-add-processing-started-at.ts +30 -0
  326. package/src/memory/migrations/301-create-watchdog-events.ts +45 -0
  327. package/src/memory/migrations/302-create-compaction-events.ts +107 -0
  328. package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +297 -0
  329. package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
  330. package/src/memory/migrations/run-migrations.ts +106 -10
  331. package/src/memory/migrations/validate-migration-state.ts +105 -67
  332. package/src/memory/prompt-override.ts +129 -0
  333. package/src/memory/schema/contacts.ts +6 -2
  334. package/src/memory/schema/conversations.ts +37 -0
  335. package/src/memory/schema/infrastructure.ts +20 -0
  336. package/src/memory/steps.ts +1294 -0
  337. package/src/memory/v2/__tests__/cli-command-store.test.ts +25 -0
  338. package/src/memory/v2/__tests__/skill-store.test.ts +80 -0
  339. package/src/memory/v2/cli-command-store.ts +75 -38
  340. package/src/memory/v2/prompts/consolidation.ts +13 -82
  341. package/src/memory/v2/prompts/router.ts +21 -93
  342. package/src/memory/v2/skill-store.ts +68 -31
  343. package/src/memory/watchdog-events-store.ts +87 -0
  344. package/src/memory/worker-control.ts +204 -0
  345. package/src/memory/worker-process.ts +89 -0
  346. package/src/messaging/channel-binding-metadata.ts +31 -0
  347. package/src/messaging/provider-types.ts +8 -0
  348. package/src/messaging/providers/slack/binding-metadata.ts +60 -0
  349. package/src/notifications/__tests__/broadcaster.test.ts +8 -8
  350. package/src/notifications/__tests__/connected-channels.test.ts +86 -0
  351. package/src/notifications/__tests__/decision-engine.test.ts +78 -9
  352. package/src/notifications/__tests__/destination-resolver.test.ts +151 -0
  353. package/src/notifications/broadcaster.ts +8 -1
  354. package/src/notifications/decision-engine.ts +15 -7
  355. package/src/notifications/destination-resolver.ts +53 -25
  356. package/src/notifications/emit-signal.ts +34 -15
  357. package/src/onboarding/checkin-event.test.ts +222 -0
  358. package/src/onboarding/checkin-event.ts +321 -0
  359. package/src/onboarding/schedule-checkin.ts +190 -0
  360. package/src/permissions/question-prompter.test.ts +1 -1
  361. package/src/permissions/question-prompter.ts +7 -4
  362. package/src/plugin-api/index.ts +12 -12
  363. package/src/plugin-api/types.ts +12 -14
  364. package/src/plugin-api/vision-support.test.ts +28 -4
  365. package/src/plugin-api/vision-support.ts +66 -31
  366. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +2 -2
  367. package/src/plugins/defaults/empty-response/hooks/stop.ts +2 -2
  368. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +4 -3
  369. package/src/plugins/defaults/history-repair/hooks/post-model-call.ts +2 -2
  370. package/src/plugins/defaults/history-repair/hooks/stop.ts +2 -2
  371. package/src/plugins/defaults/history-repair/hooks/user-prompt-submit.ts +2 -2
  372. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +47 -7
  373. package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +12 -13
  374. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +14 -22
  375. package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +42 -11
  376. package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +2 -2
  377. package/src/plugins/defaults/image-recovery/hooks/stop.ts +2 -2
  378. package/src/plugins/defaults/index.ts +0 -35
  379. package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +2 -2
  380. package/src/plugins/defaults/max-tokens-continue/hooks/stop.ts +2 -2
  381. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +2 -2
  382. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
  383. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +33 -3
  384. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +48 -4
  385. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +4 -8
  386. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +2 -2
  387. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +2 -2
  388. package/src/plugins/defaults/memory-v3-shadow/injector.ts +43 -15
  389. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +11 -2
  390. package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +146 -0
  391. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +77 -13
  392. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +12 -11
  393. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +2 -2
  394. package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +2 -2
  395. package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +2 -2
  396. package/src/plugins/defaults/title-generate/hooks/stop.ts +2 -2
  397. package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +2 -2
  398. package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +2 -2
  399. package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +2 -2
  400. package/src/plugins/disabled-state.ts +31 -0
  401. package/src/plugins/external-plugin-loader.ts +2 -2
  402. package/src/plugins/mtime-cache.ts +186 -330
  403. package/src/plugins/pipeline.ts +111 -13
  404. package/src/plugins/registry.ts +59 -16
  405. package/src/plugins/surface-import.ts +121 -0
  406. package/src/plugins/types.ts +7 -9
  407. package/src/prompts/persona-resolver.ts +43 -11
  408. package/src/providers/anthropic/client.ts +5 -0
  409. package/src/providers/call-site-routing.ts +45 -0
  410. package/src/providers/model-catalog.ts +16 -0
  411. package/src/providers/openai/__tests__/api-error-normalization.test.ts +321 -0
  412. package/src/providers/openai/api-error-normalization.ts +270 -0
  413. package/src/providers/openai/chat-completions-provider.ts +37 -83
  414. package/src/providers/openai/responses-provider.ts +50 -46
  415. package/src/providers/openrouter/client.ts +5 -0
  416. package/src/providers/provider-send-message.ts +10 -0
  417. package/src/providers/ratelimit.ts +10 -0
  418. package/src/providers/registry.ts +1 -1
  419. package/src/providers/retry.ts +10 -0
  420. package/src/providers/types.ts +22 -0
  421. package/src/providers/usage-tracking.ts +10 -0
  422. package/src/runtime/__tests__/channel-verification-service.test.ts +133 -0
  423. package/src/runtime/__tests__/guardian-vellum-migration.test.ts +184 -0
  424. package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +66 -0
  425. package/src/runtime/__tests__/local-principal-trust.test.ts +162 -0
  426. package/src/runtime/__tests__/member-verdict-cache.test.ts +119 -0
  427. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +402 -123
  428. package/src/runtime/access-request-helper.ts +18 -39
  429. package/src/runtime/actor-trust-resolver.ts +46 -19
  430. package/src/runtime/anchored-guardian.test.ts +109 -0
  431. package/src/runtime/anchored-guardian.ts +86 -0
  432. package/src/runtime/assistant-event-hub.ts +1 -1
  433. package/src/runtime/assistant-stream-state.ts +9 -2
  434. package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +99 -0
  435. package/src/runtime/auth/require-bound-guardian.ts +21 -11
  436. package/src/runtime/channel-verification-service.ts +56 -31
  437. package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
  438. package/src/runtime/guardian-vellum-migration.ts +69 -8
  439. package/src/runtime/invite-redemption-service.ts +213 -187
  440. package/src/runtime/local-actor-identity.test.ts +108 -0
  441. package/src/runtime/local-actor-identity.ts +85 -13
  442. package/src/runtime/local-principal-trust.ts +52 -0
  443. package/src/runtime/member-verdict-cache.ts +0 -0
  444. package/src/runtime/pending-interactions.ts +11 -1
  445. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +56 -5
  446. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
  447. package/src/runtime/routes/__tests__/contact-routes.test.ts +305 -0
  448. package/src/runtime/routes/__tests__/global-search-routes.test.ts +92 -0
  449. package/src/runtime/routes/__tests__/http-adapter-actor-header.test.ts +129 -0
  450. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +188 -0
  451. package/src/runtime/routes/browser-routes.ts +1 -1
  452. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +13 -5
  453. package/src/runtime/routes/channel-verification-routes.ts +3 -3
  454. package/src/runtime/routes/contact-routes.ts +48 -57
  455. package/src/runtime/routes/conversation-cli-routes.ts +4 -5
  456. package/src/runtime/routes/conversation-list-routes.ts +4 -7
  457. package/src/runtime/routes/conversation-query-routes.ts +72 -0
  458. package/src/runtime/routes/conversation-routes.ts +84 -85
  459. package/src/runtime/routes/events-routes.ts +2 -2
  460. package/src/runtime/routes/global-search-routes.ts +3 -1
  461. package/src/runtime/routes/guardian-action-routes.ts +4 -5
  462. package/src/runtime/routes/host-app-control-routes.ts +5 -4
  463. package/src/runtime/routes/host-bash-routes.ts +5 -4
  464. package/src/runtime/routes/host-browser-routes.ts +9 -11
  465. package/src/runtime/routes/host-cu-routes.ts +5 -4
  466. package/src/runtime/routes/host-file-routes.ts +5 -4
  467. package/src/runtime/routes/host-transfer-routes.ts +6 -6
  468. package/src/runtime/routes/http-adapter.ts +16 -1
  469. package/src/runtime/routes/identity-routes.ts +3 -2
  470. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  471. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +97 -5
  472. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +61 -59
  473. package/src/runtime/routes/inbound-stages/background-dispatch.ts +13 -5
  474. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
  475. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +21 -8
  476. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -3
  477. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +19 -0
  478. package/src/runtime/routes/index.ts +2 -0
  479. package/src/runtime/routes/llm-context-normalization.ts +83 -0
  480. package/src/runtime/routes/mcp-auth-routes.ts +171 -19
  481. package/src/runtime/routes/migration-rollback-routes.ts +4 -3
  482. package/src/runtime/routes/migration-routes.ts +4 -1
  483. package/src/runtime/routes/onboarding-checkin-routes.ts +86 -0
  484. package/src/runtime/routes/settings-routes.ts +8 -3
  485. package/src/runtime/routes/subagents-routes.ts +5 -0
  486. package/src/runtime/routes/surface-action-routes.ts +42 -56
  487. package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
  488. package/src/runtime/services/conversation-serializer.ts +13 -58
  489. package/src/runtime/tool-grant-request-helper.ts +3 -3
  490. package/src/runtime/trust-verdict-consumer.ts +111 -40
  491. package/src/runtime/verification-outbound-actions.ts +18 -18
  492. package/src/signals/user-message.ts +16 -0
  493. package/src/subagent/__tests__/consult-prompt.test.ts +35 -0
  494. package/src/{plugins/defaults/advisor/__tests__/transcript.test.ts → subagent/__tests__/consult-transcript.test.ts} +47 -10
  495. package/src/{plugins/defaults/advisor/steering.ts → subagent/consult-prompt.ts} +22 -32
  496. package/src/{plugins/defaults/advisor/transcript.ts → subagent/consult-transcript.ts} +18 -8
  497. package/src/subagent/index.ts +1 -1
  498. package/src/subagent/manager.ts +254 -33
  499. package/src/subagent/types.ts +11 -4
  500. package/src/telemetry/types.ts +34 -1
  501. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
  502. package/src/telemetry/usage-telemetry-reporter.ts +87 -3
  503. package/src/tools/ask-question/ask-question-tool.test.ts +29 -0
  504. package/src/tools/ask-question/ask-question-tool.ts +13 -0
  505. package/src/tools/executor.ts +4 -4
  506. package/src/tools/filesystem/search.ts +543 -0
  507. package/src/tools/registry.ts +38 -0
  508. package/src/tools/shared/filesystem/path-policy.ts +12 -5
  509. package/src/tools/subagent/consult-deadline.ts +49 -0
  510. package/src/tools/subagent/spawn.ts +234 -5
  511. package/src/tools/tool-approval-handler.ts +1 -1
  512. package/src/tools/tool-defaults.ts +9 -2
  513. package/src/tools/tool-manifest.ts +3 -0
  514. package/src/tools/types.ts +131 -25
  515. package/src/tools/workspace-tools/loader.ts +348 -244
  516. package/src/util/errors.ts +26 -1
  517. package/src/util/logger.ts +9 -0
  518. package/src/util/platform.ts +19 -0
  519. package/src/util/telemetry-db-path.ts +24 -0
  520. package/src/workflows/library.test.ts +140 -0
  521. package/src/workflows/library.ts +82 -28
  522. package/src/workspace/migrations/017-seed-persona-dirs.ts +3 -34
  523. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +3 -24
  524. package/src/workspace/migrations/031-drop-user-md.ts +232 -148
  525. package/src/workspace/migrations/048-remove-workspace-hooks.ts +14 -66
  526. package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +134 -0
  527. package/src/workspace/migrations/112-remove-advisor-callsite-override.ts +64 -0
  528. package/src/workspace/migrations/registry.ts +4 -0
  529. package/src/__tests__/workspace-tools-watcher-flag.test.ts +0 -70
  530. package/src/daemon/workspace-tools-watcher.ts +0 -328
  531. package/src/memory/migrations/registry.ts +0 -573
  532. package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +0 -56
  533. package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +0 -43
  534. package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +0 -137
  535. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -153
  536. package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +0 -138
  537. package/src/plugins/defaults/advisor/advisor-gate.ts +0 -29
  538. package/src/plugins/defaults/advisor/advisor-state-store.ts +0 -94
  539. package/src/plugins/defaults/advisor/config.ts +0 -21
  540. package/src/plugins/defaults/advisor/consult.ts +0 -93
  541. package/src/plugins/defaults/advisor/hooks/post-model-call.ts +0 -34
  542. package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +0 -30
  543. package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +0 -19
  544. package/src/plugins/defaults/advisor/package.json +0 -14
  545. package/src/plugins/defaults/advisor/tools/advisor.ts +0 -65
  546. package/src/providers/openai/__tests__/api-error-detail.test.ts +0 -120
@@ -29,7 +29,11 @@ import {
29
29
  PluginAlreadyInstalledError,
30
30
  PluginNotFoundError,
31
31
  } from "../lib/install-from-github.js";
32
- import { listInstalledPlugins } from "../lib/list-installed-plugins.js";
32
+ import {
33
+ type AllPluginInfo,
34
+ listAllPlugins,
35
+ listInstalledPlugins,
36
+ } from "../lib/list-installed-plugins.js";
33
37
  import type { FingerprintComparison } from "../lib/plugin-fingerprint.js";
34
38
  import {
35
39
  DEFAULT_PIN_HISTORY_LIMIT,
@@ -38,6 +42,7 @@ import {
38
42
  PluginPinHistoryError,
39
43
  resolvePinToMarketplaceCommit,
40
44
  } from "../lib/plugin-pin-history.js";
45
+ import { runPublish } from "../lib/publish-plugin.js";
41
46
  import { registerCommand } from "../lib/register-command.js";
42
47
  import {
43
48
  InvalidSearchPatternError,
@@ -85,6 +90,8 @@ Examples:
85
90
  $ assistant plugins install example --pin <sha> --force
86
91
  $ assistant plugins list
87
92
  $ assistant plugins list --json
93
+ $ assistant plugins list --all
94
+ $ assistant plugins list --all --json
88
95
  $ assistant plugins inspect example
89
96
  $ assistant plugins inspect example --json
90
97
  $ assistant plugins diff example
@@ -155,7 +162,6 @@ Examples:
155
162
  console.log(
156
163
  `Installed plugin "${result.name}" (${result.fileCount} file${result.fileCount === 1 ? "" : "s"})${pinned} → ${result.target}`,
157
164
  );
158
- console.log("Restart the assistant to pick up the new plugin.");
159
165
  } catch (err) {
160
166
  if (err instanceof PluginAlreadyInstalledError) {
161
167
  console.error(`${err.message}\nPass --force to overwrite.`);
@@ -239,9 +245,58 @@ Examples:
239
245
 
240
246
  plugins
241
247
  .command("list")
242
- .description("List plugins installed under <workspaceDir>/plugins/")
248
+ .description("List plugins installed in your workspace.")
243
249
  .option("--json", "Emit machine-readable JSON instead of a table")
244
- .action((opts: { json?: boolean }) => {
250
+ .option(
251
+ "--all",
252
+ "Include first-party default plugins and disabled plugins in the listing",
253
+ )
254
+ .action((opts: { json?: boolean; all?: boolean }) => {
255
+ if (opts.all) {
256
+ const all = listAllPlugins();
257
+
258
+ if (opts.json) {
259
+ process.stdout.write(JSON.stringify(all, null, 2) + "\n");
260
+ return;
261
+ }
262
+
263
+ if (all.length === 0) {
264
+ console.log("No plugins found.");
265
+ return;
266
+ }
267
+
268
+ const rows = all.map((p) => ({
269
+ name: p.name,
270
+ version: p.packageJson?.version ?? "—",
271
+ source: p.source,
272
+ status: formatAllPluginStatus(p),
273
+ }));
274
+ const nameW = Math.max(4, ...rows.map((r) => r.name.length));
275
+ const versionW = Math.max(7, ...rows.map((r) => r.version.length));
276
+ const sourceW = Math.max(6, ...rows.map((r) => r.source.length));
277
+ const pad = (s: string, w: number) => s + " ".repeat(w - s.length);
278
+ console.log(
279
+ `${pad("NAME", nameW)} ${pad("VERSION", versionW)} ${pad("SOURCE", sourceW)} STATUS`,
280
+ );
281
+ for (const r of rows) {
282
+ console.log(
283
+ `${pad(r.name, nameW)} ${pad(r.version, versionW)} ${pad(r.source, sourceW)} ${r.status}`,
284
+ );
285
+ }
286
+
287
+ const userCount = all.filter((p) => p.source === "user").length;
288
+ const defaultCount = all.length - userCount;
289
+ const disabledCount = all.filter((p) => p.disabled).length;
290
+ console.log("");
291
+ console.log(
292
+ `${all.length} plugin${all.length === 1 ? "" : "s"} ` +
293
+ `(${userCount} user, ${defaultCount} default` +
294
+ (disabledCount > 0 ? `, ${disabledCount} disabled` : "") +
295
+ `).`,
296
+ );
297
+ return;
298
+ }
299
+
245
300
  const installed = listInstalledPlugins();
246
301
 
247
302
  if (opts.json) {
@@ -451,6 +506,56 @@ Examples:
451
506
  }
452
507
  });
453
508
 
509
+ plugins
510
+ .command("publish")
511
+ .description(
512
+ "Validate and submit the plugin in the current directory to the Vellum marketplace catalog",
513
+ )
514
+ .option(
515
+ "--print",
516
+ "Print the entry JSON without submitting to the platform",
517
+ )
518
+ .option(
519
+ "--path <dir>",
520
+ "Validate a plugin at the given path instead of CWD",
521
+ )
522
+ .option("--force", "Skip the confirmation prompt")
523
+ .option("--json", "Emit machine-readable JSON instead of human output")
524
+ .option(
525
+ "--category <cat>",
526
+ "Set the category, skipping the interactive prompt",
527
+ )
528
+ .addHelpText(
529
+ "after",
530
+ `
531
+
532
+ Validates the plugin in the current directory (or --path), resolves the
533
+ git commit SHA and GitHub remote, and submits the entry to the Vellum
534
+ platform API. The platform creates a pull request against
535
+ vellum-ai/vellum-assistant adding the plugin to the marketplace catalog.
536
+
537
+ Requires a connected Vellum platform account (run \`assistant platform connect\`).
538
+ Use --print to validate and print the entry without submitting.
539
+
540
+ Examples:
541
+ $ assistant plugins publish
542
+ $ assistant plugins publish --print
543
+ $ assistant plugins publish --path ./my-plugin --category productivity
544
+ $ assistant plugins publish --json`,
545
+ )
546
+ .action(
547
+ async (opts: {
548
+ print?: boolean;
549
+ path?: string;
550
+ force?: boolean;
551
+ json?: boolean;
552
+ category?: string;
553
+ }) => {
554
+ const ok = await runPublish(opts, { confirmPrompt });
555
+ if (!ok) process.exitCode = 1;
556
+ },
557
+ );
558
+
454
559
  plugins
455
560
  .command("uninstall <name>")
456
561
  .description("Remove a plugin from <workspaceDir>/plugins/<name>/")
@@ -480,7 +585,6 @@ Examples:
480
585
  console.log(
481
586
  `Uninstalled plugin "${result.name}" from ${result.target}`,
482
587
  );
483
- console.log("Restart the assistant to drop the plugin.");
484
588
  } catch (err) {
485
589
  if (err instanceof InvalidPluginNameError) {
486
590
  console.error(err.message);
@@ -501,15 +605,13 @@ Examples:
501
605
  plugins
502
606
  .command("disable <name>")
503
607
  .description(
504
- "Disable a plugin by creating a .disabled sentinel file. Works for both user-installed and default plugins. Restart the assistant for the change to take effect.",
608
+ "Disable a plugin by creating a .disabled sentinel file. Works for both user-installed and default plugins. Takes effect immediately in a running assistant.",
505
609
  )
506
610
  .action((name: string) => {
507
611
  try {
508
612
  const result = disablePlugin(name);
509
613
  log.info({ name: result.name }, "plugin disabled");
510
- console.log(
511
- `Disabled plugin "${result.name}". Restart the assistant for the change to take effect.`,
512
- );
614
+ console.log(`Disabled plugin "${result.name}".`);
513
615
  } catch (err) {
514
616
  if (
515
617
  err instanceof PluginAlreadyInStateException ||
@@ -529,15 +631,13 @@ Examples:
529
631
  plugins
530
632
  .command("enable <name>")
531
633
  .description(
532
- "Re-enable a disabled plugin by removing the .disabled sentinel file. Restart the assistant for the change to take effect.",
634
+ "Re-enable a disabled plugin by removing the .disabled sentinel file. Takes effect immediately.",
533
635
  )
534
636
  .action((name: string) => {
535
637
  try {
536
638
  const result = enablePlugin(name);
537
639
  log.info({ name: result.name }, "plugin enabled");
538
- console.log(
539
- `Enabled plugin "${result.name}". Restart the assistant for the change to take effect.`,
540
- );
640
+ console.log(`Enabled plugin "${result.name}".`);
541
641
  } catch (err) {
542
642
  if (
543
643
  err instanceof PluginAlreadyInStateException ||
@@ -757,6 +857,18 @@ function formatTimestamp(iso: string | null): string {
757
857
  return new Date(ms).toISOString().slice(0, 19);
758
858
  }
759
859
 
860
+ /**
861
+ * Build a human-readable status string for a plugin in the `--all` listing.
862
+ * Combines disabled state with any structural issues.
863
+ */
864
+ function formatAllPluginStatus(p: AllPluginInfo): string {
865
+ const parts: string[] = [];
866
+ if (p.disabled) parts.push("disabled");
867
+ if (p.issues.length > 0) parts.push(p.issues.join("; "));
868
+ if (parts.length === 0) parts.push("enabled");
869
+ return parts.join(", ");
870
+ }
871
+
760
872
  /** Human-readable status line for an inspection result. The from/to revisions
761
873
  * now live in the installed/remote blocks, so the status itself is just words. */
762
874
  function statusLine(status: PluginInspection["status"]): string {
@@ -436,6 +436,108 @@ describe("installPlugin — marketplace resolution", () => {
436
436
  expect(meta.contentHash).toMatch(/^v2:[0-9a-f]{64}$/);
437
437
  });
438
438
 
439
+ test("installs a plugin rooted at a sub-path, copying only that subtree", async () => {
440
+ // GIVEN a marketplace entry whose source pins a directory *within* a repo
441
+ // (a monorepo that ships several plugins) rather than the repo root.
442
+ const NESTED_SHA = "0f".repeat(20);
443
+ const NESTED_MANIFEST = {
444
+ name: "vellum-assistant",
445
+ plugins: [
446
+ {
447
+ name: "nested-plugin",
448
+ source: {
449
+ source: "github",
450
+ repo: "example-org/monorepo",
451
+ path: "packages/my-plugin",
452
+ ref: NESTED_SHA,
453
+ },
454
+ description: "A plugin that lives in a monorepo sub-directory.",
455
+ },
456
+ ],
457
+ };
458
+ const fetch = makeContentsFetch({ tree: {}, manifest: NESTED_MANIFEST });
459
+ // The clone carries files both at the repo root and under the pinned
460
+ // sub-path; only the sub-path subtree should be materialized.
461
+ const runGit = fakeGitRunner({
462
+ tree: {
463
+ "package.json": '{"name":"monorepo-root"}',
464
+ "README.md": "# monorepo root",
465
+ "packages/my-plugin/package.json": '{"name":"nested-plugin"}',
466
+ "packages/my-plugin/README.md": "# nested plugin",
467
+ "packages/my-plugin/hooks/init.ts": "export default async () => {};",
468
+ "packages/other-plugin/package.json": '{"name":"other"}',
469
+ },
470
+ commit: NESTED_SHA,
471
+ });
472
+
473
+ // WHEN we install by name
474
+ const result = await installPlugin(
475
+ { name: "nested-plugin", ref: "main" },
476
+ { fetch, runGit, workspacePluginsDir: pluginsDir },
477
+ );
478
+
479
+ // THEN only the sub-path subtree lands, rooted at <pluginsDir>/nested-plugin
480
+ const target = join(pluginsDir, "nested-plugin");
481
+ expect(result.target).toBe(target);
482
+ expect(readFileSync(join(target, "package.json"), "utf-8")).toBe(
483
+ '{"name":"nested-plugin"}',
484
+ );
485
+ expect(existsSync(join(target, "README.md"))).toBe(true);
486
+ expect(existsSync(join(target, "hooks", "init.ts"))).toBe(true);
487
+ // AND the repo-root and sibling-package files are NOT copied in — the
488
+ // install is scoped to the pinned directory.
489
+ expect(result.fileCount).toBe(3);
490
+ expect(readFileSync(join(target, "package.json"), "utf-8")).not.toContain(
491
+ "monorepo-root",
492
+ );
493
+ expect(existsSync(join(target, "packages"))).toBe(false);
494
+
495
+ // AND provenance records the sub-path so an upgrade/diff re-resolves the
496
+ // same directory rather than the repo root.
497
+ const meta = readInstallMeta(target);
498
+ expect(meta?.source.owner).toBe("example-org");
499
+ expect(meta?.source.repo).toBe("monorepo");
500
+ expect(meta?.source.path).toBe("packages/my-plugin");
501
+ expect(meta?.source.ref).toBe(NESTED_SHA);
502
+ });
503
+
504
+ test("a sub-path that does not exist in the clone surfaces a clean not-found", async () => {
505
+ // GIVEN an entry pinning a directory the cloned ref doesn't contain
506
+ const MISSING_SHA = "1a".repeat(20);
507
+ const MISSING_PATH_MANIFEST = {
508
+ name: "vellum-assistant",
509
+ plugins: [
510
+ {
511
+ name: "nested-plugin",
512
+ source: {
513
+ source: "github",
514
+ repo: "example-org/monorepo",
515
+ path: "packages/does-not-exist",
516
+ ref: MISSING_SHA,
517
+ },
518
+ },
519
+ ],
520
+ };
521
+ const fetch = makeContentsFetch({
522
+ tree: {},
523
+ manifest: MISSING_PATH_MANIFEST,
524
+ });
525
+ const runGit = fakeGitRunner({
526
+ tree: { "package.json": '{"name":"monorepo-root"}' },
527
+ commit: MISSING_SHA,
528
+ });
529
+
530
+ // WHEN we install
531
+ // THEN the absent sub-path yields a hard not-found and nothing is staged
532
+ await expect(
533
+ installPlugin(
534
+ { name: "nested-plugin", ref: "main" },
535
+ { fetch, runGit, workspacePluginsDir: pluginsDir },
536
+ ),
537
+ ).rejects.toBeInstanceOf(PluginNotFoundError);
538
+ expect(readdirSync(pluginsDir)).toEqual([]);
539
+ });
540
+
439
541
  test("refuses to install when the checked-out commit differs from the pinned SHA", async () => {
440
542
  // GIVEN a clone whose resolved HEAD does not match the manifest's pinned
441
543
  // commit SHA — i.e. the upstream object served something unexpected
@@ -17,7 +17,7 @@ import { tmpdir } from "node:os";
17
17
  import { join } from "node:path";
18
18
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
19
19
 
20
- import { listInstalledPlugins } from "../list-installed-plugins.js";
20
+ import { listAllPlugins, listInstalledPlugins } from "../list-installed-plugins.js";
21
21
 
22
22
  let pluginsDir: string;
23
23
 
@@ -152,3 +152,162 @@ describe("listInstalledPlugins", () => {
152
152
  expect(result.map((p) => p.name)).toEqual(["valid"]);
153
153
  });
154
154
  });
155
+
156
+ describe("listAllPlugins", () => {
157
+ test("includes default plugins with source=default", () => {
158
+ const result = listAllPlugins({ workspacePluginsDir: pluginsDir });
159
+ const defaults = result.filter((p) => p.source === "default");
160
+ // All 14 default plugins should be present.
161
+ expect(defaults.length).toBe(14);
162
+ // Names should all start with "default-".
163
+ expect(defaults.every((p) => p.name.startsWith("default-"))).toBe(true);
164
+ // None should be disabled by default in a fresh temp dir.
165
+ expect(defaults.every((p) => !p.disabled)).toBe(true);
166
+ });
167
+
168
+ test("includes user plugins with source=user", () => {
169
+ mkdirSync(join(pluginsDir, "my-plugin"));
170
+ writeFileSync(
171
+ join(pluginsDir, "my-plugin", "package.json"),
172
+ JSON.stringify({ name: "my-plugin", version: "1.0.0" }),
173
+ );
174
+
175
+ const result = listAllPlugins({ workspacePluginsDir: pluginsDir });
176
+ const user = result.filter((p) => p.source === "user");
177
+ expect(user).toHaveLength(1);
178
+ expect(user[0]!.name).toBe("my-plugin");
179
+ expect(user[0]!.disabled).toBe(false);
180
+ });
181
+
182
+ test("user plugins appear before default plugins", () => {
183
+ mkdirSync(join(pluginsDir, "zzz-user"));
184
+ writeFileSync(
185
+ join(pluginsDir, "zzz-user", "package.json"),
186
+ JSON.stringify({ name: "zzz-user", version: "1.0.0" }),
187
+ );
188
+
189
+ const result = listAllPlugins({ workspacePluginsDir: pluginsDir });
190
+ const firstDefaultIdx = result.findIndex((p) => p.source === "default");
191
+ const lastUserIdx = result
192
+ .map((p, i) => (p.source === "user" ? i : -1))
193
+ .filter((i) => i >= 0)
194
+ .pop();
195
+
196
+ expect(lastUserIdx).toBeDefined();
197
+ expect(firstDefaultIdx).toBeGreaterThan(lastUserIdx!);
198
+ });
199
+
200
+ test("detects disabled state for user plugins", () => {
201
+ mkdirSync(join(pluginsDir, "my-plugin"));
202
+ writeFileSync(
203
+ join(pluginsDir, "my-plugin", "package.json"),
204
+ JSON.stringify({ name: "my-plugin", version: "1.0.0" }),
205
+ );
206
+ writeFileSync(join(pluginsDir, "my-plugin", ".disabled"), "");
207
+
208
+ const result = listAllPlugins({ workspacePluginsDir: pluginsDir });
209
+ const entry = result.find((p) => p.name === "my-plugin");
210
+ expect(entry).toBeDefined();
211
+ expect(entry!.disabled).toBe(true);
212
+ });
213
+
214
+ test("detects disabled state for default plugins via stub directory", () => {
215
+ mkdirSync(join(pluginsDir, "default-compaction"), { recursive: true });
216
+ writeFileSync(join(pluginsDir, "default-compaction", ".disabled"), "");
217
+
218
+ const result = listAllPlugins({ workspacePluginsDir: pluginsDir });
219
+ const compaction = result.find((p) => p.name === "default-compaction");
220
+ expect(compaction).toBeDefined();
221
+ expect(compaction!.disabled).toBe(true);
222
+ });
223
+
224
+ test("default stub directory is excluded from user listing", () => {
225
+ mkdirSync(join(pluginsDir, "default-compaction"), { recursive: true });
226
+ writeFileSync(join(pluginsDir, "default-compaction", ".disabled"), "");
227
+
228
+ const result = listAllPlugins({ workspacePluginsDir: pluginsDir });
229
+ // Should appear exactly once, as a default entry (not a user entry).
230
+ const compactionEntries = result.filter((p) => p.name === "default-compaction");
231
+ expect(compactionEntries).toHaveLength(1);
232
+ expect(compactionEntries[0]!.source).toBe("default");
233
+ });
234
+
235
+ test("sort order: enabled user, disabled user, enabled default, disabled default", () => {
236
+ // User plugins
237
+ mkdirSync(join(pluginsDir, "aaa-enabled"));
238
+ writeFileSync(
239
+ join(pluginsDir, "aaa-enabled", "package.json"),
240
+ JSON.stringify({ name: "aaa-enabled", version: "1.0.0" }),
241
+ );
242
+ mkdirSync(join(pluginsDir, "bbb-disabled"));
243
+ writeFileSync(
244
+ join(pluginsDir, "bbb-disabled", "package.json"),
245
+ JSON.stringify({ name: "bbb-disabled", version: "1.0.0" }),
246
+ );
247
+ writeFileSync(join(pluginsDir, "bbb-disabled", ".disabled"), "");
248
+
249
+ // Disable one default plugin
250
+ mkdirSync(join(pluginsDir, "default-compaction"), { recursive: true });
251
+ writeFileSync(join(pluginsDir, "default-compaction", ".disabled"), "");
252
+
253
+ const result = listAllPlugins({ workspacePluginsDir: pluginsDir });
254
+
255
+ const enabledUserIdx = result.findIndex(
256
+ (p) => p.source === "user" && !p.disabled,
257
+ );
258
+ const disabledUserIdx = result.findIndex(
259
+ (p) => p.source === "user" && p.disabled,
260
+ );
261
+ const enabledDefaultIdx = result.findIndex(
262
+ (p) => p.source === "default" && !p.disabled,
263
+ );
264
+ const disabledDefaultIdx = result.findIndex(
265
+ (p) => p.source === "default" && p.disabled,
266
+ );
267
+
268
+ // All groups present.
269
+ expect(enabledUserIdx).toBeGreaterThanOrEqual(0);
270
+ expect(disabledUserIdx).toBeGreaterThan(enabledUserIdx);
271
+ expect(enabledDefaultIdx).toBeGreaterThan(disabledUserIdx);
272
+ expect(disabledDefaultIdx).toBeGreaterThan(enabledDefaultIdx);
273
+ });
274
+
275
+ test("user plugins sorted by install date within each group", () => {
276
+ // Create two user plugins with different install dates.
277
+ // First plugin (older).
278
+ mkdirSync(join(pluginsDir, "older-plugin"));
279
+ writeFileSync(
280
+ join(pluginsDir, "older-plugin", "package.json"),
281
+ JSON.stringify({ name: "older-plugin", version: "1.0.0" }),
282
+ );
283
+ writeFileSync(
284
+ join(pluginsDir, "older-plugin", "install-meta.json"),
285
+ JSON.stringify({ installedAt: "2025-01-01T00:00:00.000Z" }),
286
+ );
287
+
288
+ // Second plugin (newer).
289
+ mkdirSync(join(pluginsDir, "newer-plugin"));
290
+ writeFileSync(
291
+ join(pluginsDir, "newer-plugin", "package.json"),
292
+ JSON.stringify({ name: "newer-plugin", version: "1.0.0" }),
293
+ );
294
+ writeFileSync(
295
+ join(pluginsDir, "newer-plugin", "install-meta.json"),
296
+ JSON.stringify({ installedAt: "2025-06-01T00:00:00.000Z" }),
297
+ );
298
+
299
+ const result = listAllPlugins({ workspacePluginsDir: pluginsDir });
300
+ const userPlugins = result.filter((p) => p.source === "user");
301
+ expect(userPlugins).toHaveLength(2);
302
+ // Older plugin should come first (install date ascending).
303
+ expect(userPlugins[0]!.name).toBe("older-plugin");
304
+ expect(userPlugins[1]!.name).toBe("newer-plugin");
305
+ });
306
+
307
+ test("default plugins have version from their manifest", () => {
308
+ const result = listAllPlugins({ workspacePluginsDir: pluginsDir });
309
+ const compaction = result.find((p) => p.name === "default-compaction");
310
+ expect(compaction).toBeDefined();
311
+ expect(compaction!.packageJson?.version).toBeTruthy();
312
+ });
313
+ });