@vellumai/assistant 0.11.4 → 0.11.5-staging.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 (358) hide show
  1. package/AGENTS.md +2 -2
  2. package/ARCHITECTURE.md +29 -4
  3. package/README.md +1 -1
  4. package/docs/architecture/memory.md +17 -5
  5. package/docs/architecture/security.md +96 -152
  6. package/docs/guardian-request-flow.md +13 -2
  7. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  8. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  9. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  10. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  11. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  12. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  13. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  14. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  15. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
  16. package/node_modules/@vellumai/gateway-client/src/http-delivery.ts +7 -14
  17. package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
  18. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +29 -31
  19. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  20. package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  21. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  22. package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  23. package/openapi.yaml +193 -3
  24. package/package.json +1 -1
  25. package/src/__tests__/anthropic-provider.test.ts +10 -3
  26. package/src/__tests__/approval-interception-trust-gates.test.ts +40 -0
  27. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  28. package/src/__tests__/channel-approval-routes.test.ts +4 -0
  29. package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -6
  30. package/src/__tests__/channel-reply-delivery.test.ts +26 -13
  31. package/src/__tests__/checker.test.ts +20 -314
  32. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
  33. package/src/__tests__/client-os-metadata-persistence.test.ts +16 -0
  34. package/src/__tests__/compactor-retained-image-validation.test.ts +142 -0
  35. package/src/__tests__/container-cpu-sampler.test.ts +153 -0
  36. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
  37. package/src/__tests__/conversation-attachments.test.ts +0 -1
  38. package/src/__tests__/conversation-error.test.ts +17 -0
  39. package/src/__tests__/conversation-lifecycle.test.ts +20 -26
  40. package/src/__tests__/conversation-pairing.test.ts +186 -0
  41. package/src/__tests__/conversation-runtime-assembly.test.ts +21 -2
  42. package/src/__tests__/credential-broker-server-use.test.ts +24 -5
  43. package/src/__tests__/credential-routes.test.ts +22 -3
  44. package/src/__tests__/credential-security-invariants.test.ts +2 -1
  45. package/src/__tests__/daemon-credential-client.test.ts +88 -0
  46. package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
  47. package/src/__tests__/dm-backfill.test.ts +63 -0
  48. package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
  49. package/src/__tests__/edit-propagation.test.ts +107 -4
  50. package/src/__tests__/events-client-registration.test.ts +28 -0
  51. package/src/__tests__/file-write-tool.test.ts +4 -2
  52. package/src/__tests__/guardian-prompt-notice-privacy.test.ts +133 -0
  53. package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +143 -97
  54. package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
  55. package/src/__tests__/host-proxy-interface.test.ts +11 -1
  56. package/src/__tests__/host-shell-tool.test.ts +23 -4
  57. package/src/__tests__/image-conversion.test.ts +143 -1
  58. package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
  59. package/src/__tests__/input-repairs.test.ts +207 -0
  60. package/src/__tests__/live-workspace-guard.test.ts +75 -0
  61. package/src/__tests__/mcp-abort-signal.test.ts +1 -1
  62. package/src/__tests__/mcp-client-auth.test.ts +1 -1
  63. package/src/__tests__/mcp-tool-annotations-risk.test.ts +1 -1
  64. package/src/__tests__/media-resolve-image-validation.test.ts +310 -0
  65. package/src/__tests__/mtime-cache.test.ts +2 -0
  66. package/src/__tests__/notification-vellum-adapter.test.ts +124 -1
  67. package/src/__tests__/openai-provider.test.ts +22 -0
  68. package/src/__tests__/personal-memory-auth-bypass.test.ts +22 -6
  69. package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
  70. package/src/__tests__/platform.test.ts +16 -1
  71. package/src/__tests__/plugin-api-resolve-credential.test.ts +22 -13
  72. package/src/__tests__/plugin-api-shim.test.ts +5 -0
  73. package/src/__tests__/plugin-api-store-credential.test.ts +268 -0
  74. package/src/__tests__/plugin-config-data-migration.test.ts +8 -1
  75. package/src/__tests__/plugin-disabled-state.test.ts +2 -0
  76. package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
  77. package/src/__tests__/plugin-execution-context.test.ts +73 -0
  78. package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -1
  79. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +0 -1
  80. package/src/__tests__/reaction-persistence.test.ts +200 -7
  81. package/src/__tests__/require-fresh-approval.test.ts +0 -4
  82. package/src/__tests__/resource-pressure-guard.test.ts +428 -0
  83. package/src/__tests__/resource-pressure-routes.test.ts +113 -0
  84. package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
  85. package/src/__tests__/run-conversation-turn-persistence.test.ts +27 -1
  86. package/src/__tests__/secret-routes-platform-proxy.test.ts +7 -0
  87. package/src/__tests__/skill-tool-factory.test.ts +161 -0
  88. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  89. package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
  90. package/src/__tests__/tool-executor.test.ts +63 -38
  91. package/src/__tests__/tool-policy.test.ts +97 -1
  92. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +7 -4
  93. package/src/__tests__/user-plugin-loader.test.ts +2 -0
  94. package/src/__tests__/validate-input.test.ts +243 -7
  95. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  96. package/src/acp/__tests__/acp-claude-oauth.test.ts +97 -29
  97. package/src/acp/__tests__/prepare-agent-env.test.ts +376 -153
  98. package/src/acp/acp-claude-oauth.ts +38 -21
  99. package/src/acp/prepare-agent-env.ts +146 -55
  100. package/src/agent/loop-tool-dedup.test.ts +161 -0
  101. package/src/agent/loop.ts +68 -22
  102. package/src/api/constants/app-tools.ts +34 -0
  103. package/src/api/events/resource-pressure-status-changed.ts +53 -0
  104. package/src/api/index.ts +19 -0
  105. package/src/api/responses/resource-pressure-status.ts +25 -0
  106. package/src/approvals/guardian-channel-delivery.ts +70 -6
  107. package/src/approvals/guardian-request-resolvers.ts +32 -66
  108. package/src/channels/__tests__/message-audience.test.ts +49 -0
  109. package/src/channels/__tests__/types.test.ts +17 -3
  110. package/src/channels/message-audience.ts +40 -0
  111. package/src/channels/types.ts +16 -12
  112. package/src/cli/__tests__/catalog-search-help.test.ts +50 -0
  113. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +31 -0
  114. package/src/cli/commands/__tests__/conversations-search.test.ts +289 -0
  115. package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -0
  116. package/src/cli/commands/__tests__/inference-providers.test.ts +68 -0
  117. package/src/cli/commands/__tests__/keys.test.ts +89 -8
  118. package/src/cli/commands/__tests__/plugins.test.ts +57 -1
  119. package/src/cli/commands/channel-verification-sessions.help.ts +11 -9
  120. package/src/cli/commands/channel-verification-sessions.ts +11 -21
  121. package/src/cli/commands/conversations.help.ts +34 -0
  122. package/src/cli/commands/conversations.ts +125 -0
  123. package/src/cli/commands/inference-providers.ts +9 -4
  124. package/src/cli/commands/inference.help.ts +9 -4
  125. package/src/cli/commands/keys.help.ts +13 -1
  126. package/src/cli/commands/keys.ts +26 -15
  127. package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
  128. package/src/cli/commands/memory/index.help.ts +41 -27
  129. package/src/cli/commands/memory/index.ts +2 -0
  130. package/src/cli/commands/memory/memory-v2.ts +58 -54
  131. package/src/cli/commands/memory/memory-validate.ts +18 -0
  132. package/src/cli/commands/monitoring.ts +1 -0
  133. package/src/cli/commands/plugins.help.ts +28 -31
  134. package/src/cli/commands/plugins.ts +10 -0
  135. package/src/cli/commands/skills.help.ts +13 -16
  136. package/src/cli/commands/trust.ts +3 -14
  137. package/src/cli/lib/__tests__/install-from-github.test.ts +38 -0
  138. package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +34 -0
  139. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +32 -1
  140. package/src/cli/lib/__tests__/toggle-plugin.test.ts +2 -1
  141. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +64 -0
  142. package/src/cli/lib/bundled-marketplace.json +13 -0
  143. package/src/cli/lib/daemon-credential-client.ts +25 -3
  144. package/src/cli/lib/install-from-github.ts +35 -24
  145. package/src/cli/lib/merge-plugin-tree.ts +22 -4
  146. package/src/cli/lib/plugin-surfaces.ts +27 -0
  147. package/src/config/feature-flag-registry.json +35 -19
  148. package/src/config/webhook-routing.ts +8 -0
  149. package/src/context/compactor.ts +31 -2
  150. package/src/daemon/__tests__/provider-rejection-log-fields.test.ts +272 -0
  151. package/src/daemon/conversation-agent-loop-handlers.ts +4 -1
  152. package/src/daemon/conversation-error.ts +13 -0
  153. package/src/daemon/conversation-messaging.ts +22 -2
  154. package/src/daemon/conversation-process.ts +11 -0
  155. package/src/daemon/conversation-store.ts +10 -0
  156. package/src/daemon/conversation-surfaces.ts +21 -8
  157. package/src/daemon/conversation.ts +12 -10
  158. package/src/daemon/lifecycle.ts +6 -2
  159. package/src/daemon/message-types/conversations.ts +5 -7
  160. package/src/daemon/provider-rejection-log-fields.ts +124 -0
  161. package/src/daemon/resource-pressure-guard-lifecycle.ts +66 -0
  162. package/src/daemon/resource-pressure-guard.ts +387 -0
  163. package/src/daemon/shutdown-handlers.ts +2 -0
  164. package/src/daemon/startup-error.ts +16 -0
  165. package/src/daemon/trust-context.ts +14 -10
  166. package/src/daemon/unsendable-image-notice.ts +76 -0
  167. package/src/hooks/registry.ts +65 -51
  168. package/src/ipc/__tests__/socket-path.test.ts +15 -7
  169. package/src/ipc/gateway-client.test.ts +1 -1
  170. package/src/ipc/gateway-client.ts +14 -21
  171. package/src/ipc/socket-cleanup.ts +2 -11
  172. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +1 -1
  173. package/src/messaging/provider-message-metadata.ts +128 -0
  174. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +116 -68
  175. package/src/messaging/providers/channel-transport.ts +90 -13
  176. package/src/messaging/providers/discord/send.ts +16 -0
  177. package/src/messaging/providers/discord/transport.ts +11 -1
  178. package/src/messaging/providers/index.ts +109 -16
  179. package/src/messaging/providers/slack/message-metadata.ts +45 -0
  180. package/src/messaging/providers/slack/render-transcript.ts +1 -4
  181. package/src/messaging/providers/slack/send.test.ts +6 -9
  182. package/src/messaging/providers/slack/send.ts +40 -28
  183. package/src/messaging/providers/slack/transport.ts +22 -26
  184. package/src/messaging/providers/telegram-bot/send.test.ts +2 -8
  185. package/src/messaging/providers/telegram-bot/transport.ts +3 -6
  186. package/src/messaging/read-provider-metadata.test.ts +157 -0
  187. package/src/messaging/read-provider-metadata.ts +51 -0
  188. package/src/notifications/__tests__/assistant-reply-producer.test.ts +94 -0
  189. package/src/notifications/__tests__/edit-notification.test.ts +174 -2
  190. package/src/notifications/__tests__/home-feed-side-effect.test.ts +536 -4
  191. package/src/notifications/adapters/macos.ts +55 -0
  192. package/src/notifications/adapters/slack.ts +10 -5
  193. package/src/notifications/assistant-reply-producer.ts +37 -4
  194. package/src/notifications/conversation-pairing.ts +111 -21
  195. package/src/notifications/edit-notification.ts +38 -8
  196. package/src/notifications/emit-signal.ts +12 -14
  197. package/src/notifications/home-feed-side-effect.ts +218 -15
  198. package/src/notifications/types.ts +5 -0
  199. package/src/permissions/AGENTS.md +16 -0
  200. package/src/permissions/checker.test.ts +75 -122
  201. package/src/permissions/checker.ts +44 -560
  202. package/src/permissions/confirmation-guardian-request.test.ts +28 -3
  203. package/src/permissions/confirmation-guardian-request.ts +5 -1
  204. package/src/persistence/conversation-crud.ts +23 -20
  205. package/src/persistence/conversation-queries.ts +14 -1
  206. package/src/persistence/conversation-types.ts +22 -0
  207. package/src/persistence/delivery-crud.ts +122 -15
  208. package/src/plugin-api/__tests__/import-graph-partial-mock.test.ts +67 -0
  209. package/src/plugin-api/conversation-turn.ts +27 -0
  210. package/src/plugin-api/credential-scope.test.ts +15 -0
  211. package/src/plugin-api/credential-scope.ts +14 -0
  212. package/src/plugin-api/index.ts +19 -1
  213. package/src/plugin-api/resolve-credential.ts +15 -10
  214. package/src/plugin-api/store-credential.ts +148 -0
  215. package/src/plugin-api/system-card.ts +36 -0
  216. package/src/plugin-api/vision-support.test.ts +82 -0
  217. package/src/plugin-api/vision-support.ts +14 -2
  218. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +361 -110
  219. package/src/plugins/defaults/image-fallback/__tests__/vision-recovery.test.ts +4 -0
  220. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +58 -0
  221. package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +64 -23
  222. package/src/plugins/defaults/image-recovery/detect.ts +24 -1
  223. package/src/plugins/defaults/main.ts +15 -0
  224. package/src/plugins/defaults/memory/AGENTS.md +11 -3
  225. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
  226. package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +9 -12
  227. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
  228. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
  229. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +114 -0
  230. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
  231. package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
  232. package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
  233. package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
  234. package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
  235. package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
  236. package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +1 -61
  237. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +68 -6
  238. package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
  239. package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
  240. package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
  241. package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
  242. package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
  243. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
  244. package/src/plugins/defaults/memory/substrate/static-context.ts +0 -29
  245. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +3 -1
  246. package/src/plugins/defaults/memory/v3/card.ts +9 -9
  247. package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
  248. package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
  249. package/src/plugins/defaults/memory/v3/edge.ts +13 -57
  250. package/src/plugins/mtime-cache.ts +1 -1
  251. package/src/plugins/pipeline.ts +14 -7
  252. package/src/plugins/plugin-execution-context.ts +35 -11
  253. package/src/plugins/plugin-tree-walk.ts +63 -4
  254. package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
  255. package/src/providers/anthropic/client.ts +332 -241
  256. package/src/providers/connection-resolution.ts +2 -1
  257. package/src/providers/content-blocks.ts +22 -0
  258. package/src/providers/gemini/client.ts +5 -2
  259. package/src/providers/inference/__tests__/adapter-factory-litellm.test.ts +47 -1
  260. package/src/providers/inference/__tests__/adapter-factory-ollama.test.ts +83 -0
  261. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +98 -1
  262. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +38 -0
  263. package/src/providers/inference/__tests__/base-url-security.test.ts +10 -0
  264. package/src/providers/inference/__tests__/connections-ollama.test.ts +90 -0
  265. package/src/providers/inference/__tests__/missing-credential-guard.test.ts +117 -0
  266. package/src/providers/inference/adapter-factory.ts +33 -2
  267. package/src/providers/inference/auth.ts +13 -2
  268. package/src/providers/inference/credential-usage.ts +37 -0
  269. package/src/providers/inference/missing-credential-guard.ts +110 -0
  270. package/src/providers/inference/resolve-auth.ts +7 -7
  271. package/src/providers/media-resolve.ts +176 -15
  272. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +576 -46
  273. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
  274. package/src/providers/openai/chat-completions-provider.ts +322 -42
  275. package/src/routes/route-host-protocol.ts +7 -0
  276. package/src/routes/worker.ts +31 -10
  277. package/src/runtime/AGENTS.md +35 -0
  278. package/src/runtime/__tests__/runtime-http-port-collision.test.ts +131 -0
  279. package/src/runtime/__tests__/web-presence.test.ts +234 -0
  280. package/src/runtime/assistant-event-hub.ts +38 -0
  281. package/src/runtime/channel-reply-delivery.ts +54 -31
  282. package/src/runtime/channel-retry-sweep.ts +6 -4
  283. package/src/runtime/effective-capabilities.test.ts +19 -0
  284. package/src/runtime/effective-capabilities.ts +25 -0
  285. package/src/runtime/guardian-reply-router.ts +6 -2
  286. package/src/runtime/http-errors.ts +1 -0
  287. package/src/runtime/http-server.ts +20 -5
  288. package/src/runtime/routes/__tests__/client-routes.test.ts +150 -0
  289. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +133 -0
  290. package/src/runtime/routes/__tests__/credential-delete-in-use.test.ts +155 -0
  291. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +52 -1
  292. package/src/runtime/routes/__tests__/monitoring-routes.test.ts +1 -0
  293. package/src/runtime/routes/__tests__/pending-interactions-route.test.ts +175 -0
  294. package/src/runtime/routes/__tests__/plugins-routes.test.ts +88 -35
  295. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
  296. package/src/runtime/routes/__tests__/system-card-turn-termination.test.ts +107 -0
  297. package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
  298. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +75 -4
  299. package/src/runtime/routes/approval-routes.ts +37 -4
  300. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +16 -22
  301. package/src/runtime/routes/canned-message-complete.ts +68 -29
  302. package/src/runtime/routes/client-routes.ts +113 -0
  303. package/src/runtime/routes/conversation-list-routes.ts +22 -7
  304. package/src/runtime/routes/conversation-management-routes.ts +15 -9
  305. package/src/runtime/routes/conversation-routes.ts +36 -22
  306. package/src/runtime/routes/credential-in-use.ts +85 -0
  307. package/src/runtime/routes/credential-routes.ts +55 -85
  308. package/src/runtime/routes/guardian-approval-interception.ts +22 -22
  309. package/src/runtime/routes/guardian-approval-reply-helpers.ts +14 -12
  310. package/src/runtime/routes/identity-routes.ts +5 -121
  311. package/src/runtime/routes/inbound-message-handler.ts +71 -27
  312. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +16 -17
  313. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +77 -50
  314. package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -97
  315. package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -77
  316. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +17 -8
  317. package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -7
  318. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -70
  319. package/src/runtime/routes/index.ts +2 -0
  320. package/src/runtime/routes/inference-provider-connection-routes.ts +9 -7
  321. package/src/runtime/routes/monitoring-routes.ts +9 -1
  322. package/src/runtime/routes/plugins-routes.ts +17 -5
  323. package/src/runtime/routes/resource-pressure-routes.ts +22 -0
  324. package/src/runtime/routes/secret-routes.ts +39 -8
  325. package/src/runtime/routes/settings-routes.ts +6 -6
  326. package/src/runtime/routes/surface-action-routes.ts +20 -19
  327. package/src/runtime/routes/user-route-dispatcher.ts +31 -2
  328. package/src/runtime/routes/user-route-resolution.ts +18 -1
  329. package/src/runtime/slack-reply-session.test.ts +23 -13
  330. package/src/runtime/slack-reply-session.ts +38 -55
  331. package/src/runtime/web-presence.ts +90 -0
  332. package/src/skills/validate-input.ts +177 -40
  333. package/src/subagent/__tests__/consult-context-gating.test.ts +6 -10
  334. package/src/subagent/consult-context.ts +7 -23
  335. package/src/tools/credentials/broker.ts +24 -79
  336. package/src/tools/credentials/ref-parse.ts +35 -0
  337. package/src/tools/credentials/resolve.ts +4 -10
  338. package/src/tools/credentials/store.ts +168 -0
  339. package/src/tools/credentials/tool-policy.ts +67 -0
  340. package/src/tools/executor.ts +53 -15
  341. package/src/tools/network/__tests__/web-search.test.ts +41 -1
  342. package/src/tools/network/url-safety.ts +9 -16
  343. package/src/tools/network/web-search.ts +21 -3
  344. package/src/tools/permission-checker.ts +43 -52
  345. package/src/tools/schema-transforms.ts +40 -5
  346. package/src/tools/shared/input-repairs.ts +160 -0
  347. package/src/tools/skills/skill-tool-factory.ts +18 -4
  348. package/src/tools/subagent/spawn.ts +0 -1
  349. package/src/tools/tool-approval-handler.ts +16 -10
  350. package/src/tools/tool-types.ts +26 -13
  351. package/src/tools/types.ts +6 -6
  352. package/src/util/__tests__/cgroup-memory.test.ts +3 -0
  353. package/src/util/cgroup-memory.ts +3 -0
  354. package/src/util/container-cpu-sampler.ts +250 -0
  355. package/src/util/image-conversion.ts +178 -14
  356. package/src/util/platform.ts +93 -10
  357. package/src/permissions/ipc-risk-types.ts +0 -143
  358. package/src/permissions/risk-types.ts +0 -76
@@ -69,6 +69,7 @@ mock.module("../../../../util/logger.js", () => ({
69
69
  // ---------------------------------------------------------------------------
70
70
 
71
71
  const { registerMemoryV2Command } = await import("../memory-v2.js");
72
+ const { registerMemoryValidateCommand } = await import("../memory-validate.js");
72
73
 
73
74
  // ---------------------------------------------------------------------------
74
75
  // Test helpers
@@ -88,6 +89,7 @@ function buildProgram(): Command {
88
89
  const memory = program.command("memory");
89
90
  applyCommandHelp(memory, memoryHelp);
90
91
  registerMemoryV2Command(memory);
92
+ registerMemoryValidateCommand(memory);
91
93
  return program;
92
94
  }
93
95
 
@@ -287,7 +289,7 @@ describe("memory v2 validate", () => {
287
289
  result: {
288
290
  pageCount: 0,
289
291
  edgeCount: 0,
290
- missingEdgeEndpoints: [],
292
+ danglingLinks: [],
291
293
  oversizedPages: [],
292
294
  parseFailures: [],
293
295
  },
@@ -306,7 +308,7 @@ describe("memory v2 validate", () => {
306
308
  result: {
307
309
  pageCount: 49,
308
310
  edgeCount: 166,
309
- missingEdgeEndpoints: [],
311
+ danglingLinks: [],
310
312
  oversizedPages: [],
311
313
  parseFailures: [],
312
314
  },
@@ -318,7 +320,7 @@ describe("memory v2 validate", () => {
318
320
  expect(logOutput.some((line) => line.includes("Pages: 49"))).toBe(true);
319
321
  expect(logOutput.some((line) => line.includes("Edges: 166"))).toBe(true);
320
322
  expect(
321
- logOutput.some((line) => line.includes("Missing edge endpoints: none")),
323
+ logOutput.some((line) => line.includes("Dangling links: none")),
322
324
  ).toBe(true);
323
325
  expect(
324
326
  logOutput.some((line) => line.includes("Oversized pages: none")),
@@ -334,7 +336,9 @@ describe("memory v2 validate", () => {
334
336
  result: {
335
337
  pageCount: 10,
336
338
  edgeCount: 20,
337
- missingEdgeEndpoints: [{ from: "people/alice", to: "people/missing" }],
339
+ danglingLinks: [
340
+ { from: "people/alice", to: "people/missing", kind: "links" },
341
+ ],
338
342
  oversizedPages: [{ slug: "arcs/big-day", chars: 12345 }],
339
343
  parseFailures: [
340
344
  { slug: "people/broken", error: "missing frontmatter" },
@@ -345,9 +349,11 @@ describe("memory v2 validate", () => {
345
349
  const { exitCode } = await runCommand(["memory", "v2", "validate"]);
346
350
 
347
351
  expect(exitCode).toBe(1);
348
- expect(logOutput.some((line) => line.includes("people/missing"))).toBe(
349
- true,
350
- );
352
+ expect(
353
+ logOutput.some((line) =>
354
+ line.includes("people/alice → people/missing (links)"),
355
+ ),
356
+ ).toBe(true);
351
357
  expect(logOutput.some((line) => line.includes("arcs/big-day"))).toBe(true);
352
358
  expect(logOutput.some((line) => line.includes("people/broken"))).toBe(true);
353
359
  });
@@ -360,3 +366,47 @@ describe("memory v2 validate", () => {
360
366
  expect(exitCode).toBe(1);
361
367
  });
362
368
  });
369
+
370
+ describe("memory validate (top-level, same report)", () => {
371
+ test("sends memory_v2_validate and prints the report", async () => {
372
+ mockIpcResult = {
373
+ ok: true,
374
+ result: {
375
+ pageCount: 49,
376
+ edgeCount: 166,
377
+ danglingLinks: [],
378
+ oversizedPages: [],
379
+ parseFailures: [],
380
+ },
381
+ };
382
+
383
+ const { exitCode } = await runCommand(["memory", "validate"]);
384
+
385
+ expect(exitCode).toBe(0);
386
+ expect(lastIpcCall!.method).toBe("memory_v2_validate");
387
+ expect(logOutput.some((line) => line.includes("Pages: 49"))).toBe(true);
388
+ expect(
389
+ logOutput.some((line) => line.includes("Dangling links: none")),
390
+ ).toBe(true);
391
+ });
392
+
393
+ test("exits non-zero on violations, like the v2 spelling", async () => {
394
+ mockIpcResult = {
395
+ ok: true,
396
+ result: {
397
+ pageCount: 1,
398
+ edgeCount: 0,
399
+ danglingLinks: [{ from: "a", to: "missing", kind: "wikilink" }],
400
+ oversizedPages: [],
401
+ parseFailures: [],
402
+ },
403
+ };
404
+
405
+ const { exitCode } = await runCommand(["memory", "validate"]);
406
+
407
+ expect(exitCode).toBe(1);
408
+ expect(
409
+ logOutput.some((line) => line.includes("a → missing (wikilink)")),
410
+ ).toBe(true);
411
+ });
412
+ });
@@ -23,7 +23,7 @@ The 'items' subgroup exposes full CRUD over individual memory items
23
23
 
24
24
  The memory subsystem retrieves concept pages two ways: the v2 concept-page
25
25
  activation model (prose pages with directed edges) and the v3 section-lane
26
- model (section-grain lanes cached as live shadow state). Each subgroup exposes
26
+ model (section-grain lanes held in memory inside the assistant). Each subgroup exposes
27
27
  operator-facing maintenance verbs — reindexing, backfills, validation, and evals.
28
28
 
29
29
  Examples:
@@ -34,7 +34,7 @@ Examples:
34
34
  $ assistant memory items list --search "coffee"
35
35
  $ assistant memory items update 9f2c4f3a-3f1a-41e4-88e7-abc123 --statement "Prefers tea"
36
36
  $ assistant memory items delete 9f2c4f3a-3f1a-41e4-88e7-abc123
37
- $ assistant memory v2 validate
37
+ $ assistant memory validate
38
38
  $ assistant memory v3 rebuild-index
39
39
  $ assistant memory ingest --dir .mv3/staging --dry-run`,
40
40
  subcommands: [
@@ -43,8 +43,9 @@ Examples:
43
43
  description:
44
44
  "Content-based list, delete, and update of memory graph nodes",
45
45
  helpText: `
46
- Memory nodes are raw graph records (content, type, fidelity) produced by the
47
- memory v2 subsystem. Unlike 'memory items', which addresses nodes by UUID, these
46
+ Memory nodes are raw graph records (content, type, fidelity) in the memory
47
+ graph store, which every memory tier writes to. Unlike 'memory items', which
48
+ addresses nodes by UUID, these
48
49
  commands address nodes by content text — matching the way an operator refers to
49
50
  a remembered fact without first looking up its ID.
50
51
 
@@ -390,7 +391,6 @@ except reembed-skills which runs synchronously inside the assistant.
390
391
  Read-only subcommands print diagnostic reports without mutating state.
391
392
 
392
393
  Examples:
393
- $ assistant memory v2 validate
394
394
  $ assistant memory v2 reembed
395
395
  $ assistant memory v2 reembed-skills
396
396
  $ assistant memory v2 activation`,
@@ -400,9 +400,10 @@ Examples:
400
400
  description:
401
401
  "Refresh dense + sparse vectors for every concept page in Qdrant",
402
402
  helpText: `
403
- Fans out an embed_concept_page job per concept page slug (plus the four
404
- reserved meta-file slugs) so each page's dense and sparse vectors get
405
- recomputed against the current embedding backend. Useful after upgrading
403
+ Fans out an embed_concept_page job per concept page slug so each page's
404
+ dense and sparse vectors get recomputed against the current embedding
405
+ backend (the direct-injected memory/*.md meta files are not embedded and are
406
+ not enqueued). Useful after upgrading
406
407
  the embedding model or recovering a corrupted Qdrant collection.
407
408
 
408
409
  The fan-out runs on the background memory worker — this command returns
@@ -449,20 +450,13 @@ Examples:
449
450
  {
450
451
  name: "validate",
451
452
  description:
452
- "Print a diagnostic report of v2 workspace state (read-only)",
453
+ "Same report as 'memory validate' (read-only concept-page check)",
453
454
  helpText: `
454
- Walks the v2 concept-page tree on disk and reports:
455
- - Page count
456
- - Edge count (total and unique outgoing targets)
457
- - Missing outgoing edge targets (orphan edges)
458
- - Oversized pages (over the per-folder size cap)
459
- - Parse failures (missing or malformed frontmatter)
460
-
461
- Read-only — does not mutate the workspace. Exits non-zero if any
462
- violations are reported.
455
+ Identical to 'assistant memory validate'; prefer that spelling. The report
456
+ covers the concept-page store, which is the same under memory v2 and v3.
463
457
 
464
458
  Examples:
465
- $ assistant memory v2 validate`,
459
+ $ assistant memory validate`,
466
460
  },
467
461
  {
468
462
  name: "ema",
@@ -600,9 +594,9 @@ Examples:
600
594
  name: "v3",
601
595
  description: "Memory v3 live-lane maintenance (section-lane model)",
602
596
  helpText: `
603
- The v3 memory subsystem retrieves concept pages over section-grain lanes and
604
- caches them as live shadow lanes inside the assistant. These commands maintain
605
- that live state safely.
597
+ The v3 memory subsystem retrieves concept pages over section-grain lanes held
598
+ in memory inside the assistant. These commands maintain that live state
599
+ safely.
606
600
 
607
601
  Examples:
608
602
  $ assistant memory v3 rebuild-index
@@ -614,7 +608,7 @@ Examples:
614
608
  name: "rebuild-index",
615
609
  description: "Invalidate the v3 lanes so the next turn rebuilds",
616
610
  helpText: `
617
- Drops the assistant's cached v3 shadow lanes so the section index is rebuilt
611
+ Drops the assistant's in-memory v3 lanes so the section index is rebuilt
618
612
  from the current on-disk state on the next turn. Useful after editing concept
619
613
  pages out-of-band.
620
614
 
@@ -635,10 +629,10 @@ Examples:
635
629
  Embeds EVERY concept page's sections — including synthetic skill and CLI
636
630
  capability rows — into the section dense store in one pass, then advances
637
631
  the maintain checkpoint so the next incremental pass only re-embeds future
638
- edits. Use this once on an existing install before the section-lane A/B and
639
- cutover: the dense collection starts empty, and the periodic maintenance
640
- pass only re-embeds pages edited since its last run (and never the synthetic
641
- rows), so most of the corpus would otherwise never be embedded.
632
+ edits. Use this once on an install whose section dense store is empty or
633
+ predates v3: the periodic maintenance pass only re-embeds pages edited since
634
+ its last run (and never the synthetic rows), so most of the corpus would
635
+ otherwise never be embedded.
642
636
 
643
637
  Idempotent and safe to re-run. Runs inside the assistant so it uses the live
644
638
  configuration and advances the checkpoint the assistant reads.
@@ -804,6 +798,26 @@ Example:
804
798
  },
805
799
  ],
806
800
  },
801
+ {
802
+ name: "validate",
803
+ description:
804
+ "Check the concept-page store for dangling links, oversized pages, and parse failures (read-only)",
805
+ helpText: `
806
+ Walks memory/concepts/ on disk and reports:
807
+ - Page count and edge count
808
+ - Dangling links: an edges: entry, a links: entry, or an inline
809
+ [[wikilink]] whose target page does not exist (targets under skills/
810
+ and cli-commands/ resolve against the registered capability catalog)
811
+ - Oversized pages (over the configured per-page character cap)
812
+ - Parse failures (malformed frontmatter)
813
+
814
+ Read-only. Exits non-zero if anything is reported. Works on every memory
815
+ tier, including before memory.v3.live or memory.v2.enabled is set, so it
816
+ doubles as the pre-flip check for a migration.
817
+
818
+ Examples:
819
+ $ assistant memory validate`,
820
+ },
807
821
  {
808
822
  name: "ingest",
809
823
  description:
@@ -8,6 +8,7 @@ import { registerMemoryIngestCommand } from "./memory-ingest.js";
8
8
  import { registerMemoryRetrospectiveCommand } from "./memory-retrospective.js";
9
9
  import { registerMemoryV2Command } from "./memory-v2.js";
10
10
  import { registerMemoryV3Command } from "./memory-v3.js";
11
+ import { registerMemoryValidateCommand } from "./memory-validate.js";
11
12
  import { registerMemoryNodesCommand } from "./nodes.js";
12
13
  import { registerMemoryWorkerCommand } from "./worker.js";
13
14
 
@@ -24,6 +25,7 @@ export function registerMemoryCommand(program: Command): void {
24
25
  registerMemoryV2Command(memory);
25
26
  registerMemoryV3Command(memory);
26
27
  registerMemoryIngestCommand(memory);
28
+ registerMemoryValidateCommand(memory);
27
29
  registerMemoryRetrospectiveCommand(memory);
28
30
  registerMemoryWorkerCommand(memory);
29
31
  },
@@ -12,8 +12,9 @@
12
12
  * from the current skill set.
13
13
  * - `activation` — refresh persisted activation state for every
14
14
  * conversation that has a stored row.
15
- * - `validate` — print a diagnostic report (page count, edge count, and
16
- * violation lists). Does not mutate the workspace.
15
+ * - `validate`: {@link runMemoryValidate}, also registered as the top-level
16
+ * `memory validate` (`memory-validate.ts`); kept here while this
17
+ * namespace exists.
17
18
  */
18
19
 
19
20
  import type { Command } from "commander";
@@ -59,6 +60,60 @@ async function runBackfillOp(op: MemoryV2BackfillOp): Promise<void> {
59
60
  log.info(`Queued ${op} job: ${result.result!.jobId}`);
60
61
  }
61
62
 
63
+ /**
64
+ * Print the validate report; sets a non-zero exit code on any violation.
65
+ * Registered as `memory validate` (`memory-validate.ts`) and `memory v2
66
+ * validate`.
67
+ */
68
+ export async function runMemoryValidate(): Promise<void> {
69
+ const result = await cliIpcCall<MemoryV2ValidateResult>(
70
+ "memory_v2_validate",
71
+ { body: {} },
72
+ );
73
+
74
+ if (!result.ok) {
75
+ log.error(result.error ?? "Failed to validate memory state");
76
+ process.exitCode = 1;
77
+ return;
78
+ }
79
+
80
+ const report = result.result!;
81
+ log.info(`Pages: ${report.pageCount}`);
82
+ log.info(`Edges: ${report.edgeCount}`);
83
+ log.info(
84
+ `Dangling links: ${
85
+ report.danglingLinks.length === 0 ? "none" : report.danglingLinks.length
86
+ }`,
87
+ );
88
+ for (const d of report.danglingLinks) {
89
+ log.info(` - ${d.from} → ${d.to} (${d.kind})`);
90
+ }
91
+ log.info(
92
+ `Oversized pages: ${
93
+ report.oversizedPages.length === 0 ? "none" : report.oversizedPages.length
94
+ }`,
95
+ );
96
+ for (const p of report.oversizedPages) {
97
+ log.info(` - ${p.slug}: ${p.chars} chars`);
98
+ }
99
+ log.info(
100
+ `Parse failures: ${
101
+ report.parseFailures.length === 0 ? "none" : report.parseFailures.length
102
+ }`,
103
+ );
104
+ for (const p of report.parseFailures) {
105
+ log.info(` - ${p.slug}: ${p.error}`);
106
+ }
107
+
108
+ if (
109
+ report.danglingLinks.length > 0 ||
110
+ report.oversizedPages.length > 0 ||
111
+ report.parseFailures.length > 0
112
+ ) {
113
+ process.exitCode = 1;
114
+ }
115
+ }
116
+
62
117
  // ---------------------------------------------------------------------------
63
118
  // Registration
64
119
  // ---------------------------------------------------------------------------
@@ -97,58 +152,7 @@ export function registerMemoryV2Command(memory: Command): void {
97
152
 
98
153
  // ── validate ──────────────────────────────────────────────────────────
99
154
 
100
- subcommand(v2, "validate").action(async () => {
101
- const result = await cliIpcCall<MemoryV2ValidateResult>(
102
- "memory_v2_validate",
103
- { body: {} },
104
- );
105
-
106
- if (!result.ok) {
107
- log.error(result.error ?? "Failed to validate memory v2 state");
108
- process.exitCode = 1;
109
- return;
110
- }
111
-
112
- const report = result.result!;
113
- log.info(`Pages: ${report.pageCount}`);
114
- log.info(`Edges: ${report.edgeCount}`);
115
- log.info(
116
- `Missing edge endpoints: ${
117
- report.missingEdgeEndpoints.length === 0
118
- ? "none"
119
- : report.missingEdgeEndpoints.length
120
- }`,
121
- );
122
- for (const m of report.missingEdgeEndpoints) {
123
- log.info(` - ${m.from} → ${m.to}`);
124
- }
125
- log.info(
126
- `Oversized pages: ${
127
- report.oversizedPages.length === 0
128
- ? "none"
129
- : report.oversizedPages.length
130
- }`,
131
- );
132
- for (const p of report.oversizedPages) {
133
- log.info(` - ${p.slug}: ${p.chars} chars`);
134
- }
135
- log.info(
136
- `Parse failures: ${
137
- report.parseFailures.length === 0 ? "none" : report.parseFailures.length
138
- }`,
139
- );
140
- for (const p of report.parseFailures) {
141
- log.info(` - ${p.slug}: ${p.error}`);
142
- }
143
-
144
- if (
145
- report.missingEdgeEndpoints.length > 0 ||
146
- report.oversizedPages.length > 0 ||
147
- report.parseFailures.length > 0
148
- ) {
149
- process.exitCode = 1;
150
- }
151
- });
155
+ subcommand(v2, "validate").action(runMemoryValidate);
152
156
 
153
157
  // ── ema ───────────────────────────────────────────────────────────────
154
158
 
@@ -0,0 +1,18 @@
1
+ /**
2
+ * `assistant memory validate`: the read-only concept-page diagnostic.
3
+ *
4
+ * The report covers the concept-page substrate, which is the same store
5
+ * under memory v2 and v3, so the command is tier-agnostic. The report
6
+ * function lives in `memory-v2.ts` (the host file already allowed to read
7
+ * the memory plugin's route types) and is also registered there as
8
+ * `assistant memory v2 validate` for as long as that namespace exists.
9
+ */
10
+
11
+ import type { Command } from "commander";
12
+
13
+ import { subcommand } from "../../lib/cli-command-help.js";
14
+ import { runMemoryValidate } from "./memory-v2.js";
15
+
16
+ export function registerMemoryValidateCommand(memory: Command): void {
17
+ subcommand(memory, "validate").action(runMemoryValidate);
18
+ }
@@ -56,6 +56,7 @@ interface LatestSample {
56
56
  memoryStat: {
57
57
  anonBytes: number | null;
58
58
  fileBytes: number | null;
59
+ inactiveFileBytes: number | null;
59
60
  kernelBytes: number | null;
60
61
  slabReclaimableBytes: number | null;
61
62
  slabUnreclaimableBytes: number | null;
@@ -10,37 +10,12 @@ import {
10
10
 
11
11
  export const pluginsHelp: CliCommandHelp = {
12
12
  name: "plugins",
13
- description:
14
- "List, search, install, and manage external plugins (`list` shows what is installed, `search` queries the marketplace)",
13
+ description: "List, search, install, and manage plugins.",
15
14
  helpText: `
16
- Examples:
17
- $ assistant plugins install example
18
- $ assistant plugins install example --force
19
- $ assistant plugins install https://github.com/owner/repo
20
- $ assistant plugins install https://github.com/owner/repo/tree/main/sub/path --name my-plugin
21
- $ assistant plugins install example --ref my-feature-branch
22
- $ assistant plugins versions example
23
- $ assistant plugins versions example --json
24
- $ assistant plugins install example --pin <sha> --force
25
- $ assistant plugins list
26
- $ assistant plugins list --json
27
- $ assistant plugins list --all
28
- $ assistant plugins list --all --json
29
- $ assistant plugins inspect example
30
- $ assistant plugins inspect example --json
31
- $ assistant plugins diff example
32
- $ assistant plugins diff example --json
33
- $ assistant plugins upgrade example
34
- $ assistant plugins upgrade example --dry-run
35
- $ assistant plugins upgrade example --strategy ours
36
- $ assistant plugins upgrade example --strategy theirs
37
- $ assistant plugins upgrade example --strategy assistant
38
- $ assistant plugins search example
39
- $ assistant plugins search "^example"
40
- $ assistant plugins search example --json
41
- $ assistant plugins uninstall example
42
- $ assistant plugins enable example
43
- $ assistant plugins disable example`,
15
+ Plugins are superpowers: installable extensions that add skills, tools, integrations,
16
+ and so much more from the Vellum Community. When the user asks to set up,
17
+ install, connect, or integrate a product, service, or app, run
18
+ 'assistant plugins search <name>' first before searching the web.`,
44
19
  subcommands: [
45
20
  {
46
21
  name: "install",
@@ -79,6 +54,10 @@ during the install, and the install asks for confirmation before finalizing:
79
54
  schedules run automatically in the background once the plugin is installed.
80
55
  Pass --force to skip the prompt (required for non-interactive installs).
81
56
 
57
+ A plugin that ships a setup skill (skills/setup/ or
58
+ skills/<name>-setup/) prints a line after install telling the user to
59
+ load that skill to finish setup.
60
+
82
61
  A GitHub URL (anything containing a slash) installs directly from that repo,
83
62
  bypassing the marketplace whitelist. Such a plugin is UNTRUSTED — it has not
84
63
  been reviewed and its hooks/tools run with full assistant access — so the
@@ -168,13 +147,31 @@ Examples:
168
147
  name: "search",
169
148
  args: "<query>",
170
149
  description:
171
- "Search the plugins/marketplace.json catalog for plugin names matching <query> (case-insensitive regex)",
150
+ "Search the plugin marketplace. Query is a case-insensitive regex against plugin names",
172
151
  options: [
173
152
  {
174
153
  flags: "--json",
175
154
  description: "Emit machine-readable JSON instead of a table",
176
155
  },
177
156
  ],
157
+ helpText: `
158
+ When to use:
159
+ First stop when the user asks to set up, install, connect, or integrate a
160
+ product, service, or app (for example "Setup <app> for me",
161
+ "connect this service"). Search here before searching the web.
162
+
163
+ Arguments:
164
+ query Case-insensitive regex matched against plugin names, not the full
165
+ user sentence. Use the product or plugin name. Anchors like
166
+ ^example work.
167
+
168
+ If a match is found, install it with 'assistant plugins install <name>'.
169
+ If nothing matches, try 'assistant skills search <query>', then web search.
170
+
171
+ Examples:
172
+ $ assistant plugins search example
173
+ $ assistant plugins search "^example"
174
+ $ assistant plugins search example --json`,
178
175
  },
179
176
  {
180
177
  name: "publish",
@@ -301,6 +301,16 @@ export function registerPluginsCommand(program: Command): void {
301
301
  console.log(
302
302
  `Installed ${label} "${result.name}" (${result.fileCount} file${result.fileCount === 1 ? "" : "s"})${pinned} → ${result.target}`,
303
303
  );
304
+ const { skills } = libs.surfaces.detectPluginSurfaces(
305
+ result.target,
306
+ );
307
+ const setupSkill = libs.surfaces.findPluginSetupSkill(
308
+ result.name,
309
+ skills,
310
+ );
311
+ if (setupSkill !== undefined) {
312
+ console.log(libs.surfaces.formatPluginSetupHint(setupSkill));
313
+ }
304
314
  } catch (err) {
305
315
  if (err instanceof libs.installGitHub.PluginInstallDeclinedError) {
306
316
  // The consent gate already printed the outcome and set the exit
@@ -6,21 +6,8 @@ export const skillsHelp: CliCommandHelp = {
6
6
  name: "skills",
7
7
  description: "Browse and install skills from the Vellum catalog",
8
8
  helpText: `
9
- Manage skills from the Vellum catalog. Skills extend the assistant's
10
- capabilities with pre-built workflows and tools.
11
-
12
- Examples:
13
- $ assistant skills list
14
- $ assistant skills list --json
15
- $ assistant skills inspect slack
16
- $ assistant skills inspect resend-setup --json
17
- $ assistant skills search react
18
- $ assistant skills search react --limit 5 --json
19
- $ assistant skills install weather
20
- $ assistant skills install weather --overwrite
21
- $ assistant skills uninstall weather
22
- $ assistant skills add vercel-labs/skills@find-skills
23
- $ assistant skills add vercel-labs/skills/find-skills --overwrite`,
9
+ Manage skills from the Vellum catalog. Skills are instructions of
10
+ workflows and tools that teach the assistant when dynamically relevant.`,
24
11
  subcommands: [
25
12
  {
26
13
  name: "list",
@@ -70,15 +57,25 @@ Examples:
70
57
  { flags: "--json", description: "Machine-readable JSON output" },
71
58
  ],
72
59
  helpText: `
60
+ When to use:
61
+ Second stop after plugin search when the user asks to set up, install, or
62
+ add a capability (for example "Setup <app> for me", "add a skill for file management").
63
+ Search here before searching the web.
64
+
73
65
  Arguments:
74
66
  query Free-text search term matched against skill names, descriptions,
75
- and tags. Searches the Vellum catalog, the skills.sh community
67
+ and tags. Use the product or capability name, not the full user
68
+ sentence. Searches the Vellum catalog, the skills.sh community
76
69
  registry, and the clawhub registry.
77
70
 
78
71
  Displays results from all sources with clear labels. When a skill ID
79
72
  exists in both the Vellum catalog and a community registry, a conflict
80
73
  note is shown with guidance on which install command to use.
81
74
 
75
+ If a catalog match is found, install it with 'assistant skills install <id>'.
76
+ If a community match is found, add it with 'assistant skills add <source>'.
77
+ If nothing matches, try web search.
78
+
82
79
  Examples:
83
80
  $ assistant skills search react
84
81
  $ assistant skills search "file management" --limit 3
@@ -5,6 +5,7 @@
5
5
  * IPC route (`trust_rules_list`).
6
6
  */
7
7
 
8
+ import type { TrustRulesListIpcResponse } from "@vellumai/gateway-client";
8
9
  import type { Command } from "commander";
9
10
 
10
11
  import { cliIpcCall } from "../../ipc/cli-client.js";
@@ -13,18 +14,6 @@ import { registerCommand } from "../lib/register-command.js";
13
14
  import { log } from "../logger.js";
14
15
  import { trustHelp } from "./trust.help.js";
15
16
 
16
- // -- Types --------------------------------------------------------------------
17
-
18
- interface TrustRule {
19
- id: string;
20
- tool: string;
21
- pattern: string;
22
- risk: string;
23
- origin: string;
24
- userModified: boolean;
25
- updatedAt: string;
26
- }
27
-
28
17
  // -- Registration -------------------------------------------------------------
29
18
 
30
19
  export function registerTrustCommand(program: Command): void {
@@ -44,7 +33,7 @@ export function registerTrustCommand(program: Command): void {
44
33
  ...(opts.tool ? { tool: opts.tool } : {}),
45
34
  };
46
35
 
47
- const result = await cliIpcCall<{ rules: TrustRule[] }>(
36
+ const result = await cliIpcCall<TrustRulesListIpcResponse>(
48
37
  "trust_rules_list",
49
38
  { body: params },
50
39
  );
@@ -86,7 +75,7 @@ export function registerTrustCommand(program: Command): void {
86
75
  "MODIFIED",
87
76
  ];
88
77
 
89
- const rows: string[][] = rules.map((r: TrustRule) => [
78
+ const rows: string[][] = rules.map((r) => [
90
79
  r.id.slice(0, 16),
91
80
  r.tool,
92
81
  r.pattern,
@@ -303,6 +303,44 @@ describe("installPlugin — install lifecycle", () => {
303
303
  expect(existsSync(join(target, "README.md"))).toBe(true);
304
304
  });
305
305
 
306
+ test("--force keeps live config.json instead of a pin-shipped default", async () => {
307
+ // GIVEN an install with user config, and a clone that materializes a default
308
+ const target = join(pluginsDir, "caveman");
309
+ mkdirSync(target, { recursive: true });
310
+ writeFileSync(join(target, "package.json"), '{"name":"caveman"}');
311
+ writeFileSync(
312
+ join(target, "config.json"),
313
+ '{"provider":"photon","ingressMode":"live"}\n',
314
+ );
315
+ mkdirSync(join(target, "data"), { recursive: true });
316
+ writeFileSync(join(target, "data", "cursor.json"), '{"n":1}\n');
317
+
318
+ const fetch = makeContentsFetch({ tree: {}, manifest: CAVEMAN_MANIFEST });
319
+ const runGit = fakeGitRunner({
320
+ tree: {
321
+ "package.json": '{"name":"caveman"}',
322
+ "README.md": "# caveman",
323
+ "config.json": '{"provider":"comms","ingressMode":"webhook"}\n',
324
+ },
325
+ commit: CAVEMAN_SHA,
326
+ });
327
+
328
+ // WHEN we reinstall with --force
329
+ await installPlugin(
330
+ { name: "caveman", force: true, ref: "main" },
331
+ { fetch, runGit, workspacePluginsDir: pluginsDir },
332
+ );
333
+
334
+ // THEN user-owned state survives and the pin's default config does not win
335
+ expect(readFileSync(join(target, "config.json"), "utf-8")).toBe(
336
+ '{"provider":"photon","ingressMode":"live"}\n',
337
+ );
338
+ expect(readFileSync(join(target, "data", "cursor.json"), "utf-8")).toBe(
339
+ '{"n":1}\n',
340
+ );
341
+ expect(existsSync(join(target, "README.md"))).toBe(true);
342
+ });
343
+
306
344
  test("commitOverride materializes a specific commit, keeping repo from the manifest", async () => {
307
345
  // GIVEN a manifest pinning the current SHA, but an override to an older one
308
346
  const OLD_SHA = "1".repeat(40);