@vellumai/assistant 0.11.4 → 0.11.5-staging.2

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 (367) 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__/config-loader-backfill.test.ts +19 -10
  36. package/src/__tests__/container-cpu-sampler.test.ts +153 -0
  37. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
  38. package/src/__tests__/conversation-attachments.test.ts +0 -1
  39. package/src/__tests__/conversation-error.test.ts +17 -0
  40. package/src/__tests__/conversation-lifecycle.test.ts +20 -26
  41. package/src/__tests__/conversation-pairing.test.ts +186 -0
  42. package/src/__tests__/conversation-runtime-assembly.test.ts +21 -2
  43. package/src/__tests__/credential-broker-server-use.test.ts +24 -5
  44. package/src/__tests__/credential-routes.test.ts +22 -3
  45. package/src/__tests__/credential-security-invariants.test.ts +2 -1
  46. package/src/__tests__/daemon-credential-client.test.ts +88 -0
  47. package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
  48. package/src/__tests__/dm-backfill.test.ts +63 -0
  49. package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
  50. package/src/__tests__/edit-propagation.test.ts +107 -4
  51. package/src/__tests__/events-client-registration.test.ts +28 -0
  52. package/src/__tests__/file-write-tool.test.ts +4 -2
  53. package/src/__tests__/guardian-prompt-notice-privacy.test.ts +133 -0
  54. package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +143 -97
  55. package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
  56. package/src/__tests__/host-proxy-interface.test.ts +11 -1
  57. package/src/__tests__/host-shell-tool.test.ts +23 -4
  58. package/src/__tests__/image-conversion.test.ts +143 -1
  59. package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
  60. package/src/__tests__/input-repairs.test.ts +207 -0
  61. package/src/__tests__/live-workspace-guard.test.ts +75 -0
  62. package/src/__tests__/managed-profile-guard.test.ts +4 -2
  63. package/src/__tests__/mcp-abort-signal.test.ts +1 -1
  64. package/src/__tests__/mcp-client-auth.test.ts +1 -1
  65. package/src/__tests__/mcp-tool-annotations-risk.test.ts +1 -1
  66. package/src/__tests__/media-resolve-image-validation.test.ts +310 -0
  67. package/src/__tests__/mtime-cache.test.ts +2 -0
  68. package/src/__tests__/notification-vellum-adapter.test.ts +124 -1
  69. package/src/__tests__/openai-provider.test.ts +22 -0
  70. package/src/__tests__/personal-memory-auth-bypass.test.ts +22 -6
  71. package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
  72. package/src/__tests__/platform.test.ts +16 -1
  73. package/src/__tests__/plugin-api-resolve-credential.test.ts +22 -13
  74. package/src/__tests__/plugin-api-shim.test.ts +5 -0
  75. package/src/__tests__/plugin-api-store-credential.test.ts +268 -0
  76. package/src/__tests__/plugin-config-data-migration.test.ts +8 -1
  77. package/src/__tests__/plugin-disabled-state.test.ts +2 -0
  78. package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
  79. package/src/__tests__/plugin-execution-context.test.ts +73 -0
  80. package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -1
  81. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +0 -1
  82. package/src/__tests__/reaction-persistence.test.ts +200 -7
  83. package/src/__tests__/require-fresh-approval.test.ts +0 -4
  84. package/src/__tests__/resource-pressure-guard.test.ts +428 -0
  85. package/src/__tests__/resource-pressure-routes.test.ts +113 -0
  86. package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
  87. package/src/__tests__/run-conversation-turn-persistence.test.ts +27 -1
  88. package/src/__tests__/secret-routes-platform-proxy.test.ts +7 -0
  89. package/src/__tests__/skill-tool-factory.test.ts +161 -0
  90. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  91. package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
  92. package/src/__tests__/tool-executor.test.ts +63 -38
  93. package/src/__tests__/tool-policy.test.ts +97 -1
  94. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +7 -4
  95. package/src/__tests__/user-plugin-loader.test.ts +2 -0
  96. package/src/__tests__/validate-input.test.ts +243 -7
  97. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  98. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -0
  99. package/src/__tests__/voice-session-bridge.test.ts +42 -0
  100. package/src/acp/__tests__/acp-claude-oauth.test.ts +97 -29
  101. package/src/acp/__tests__/prepare-agent-env.test.ts +376 -153
  102. package/src/acp/acp-claude-oauth.ts +38 -21
  103. package/src/acp/prepare-agent-env.ts +146 -55
  104. package/src/agent/loop-tool-dedup.test.ts +161 -0
  105. package/src/agent/loop.ts +68 -22
  106. package/src/api/constants/app-tools.ts +34 -0
  107. package/src/api/events/resource-pressure-status-changed.ts +53 -0
  108. package/src/api/index.ts +19 -0
  109. package/src/api/responses/resource-pressure-status.ts +25 -0
  110. package/src/approvals/guardian-channel-delivery.ts +70 -6
  111. package/src/approvals/guardian-request-resolvers.ts +32 -66
  112. package/src/calls/__tests__/voice-session-bridge.test.ts +114 -0
  113. package/src/calls/voice-session-bridge.ts +60 -6
  114. package/src/channels/__tests__/message-audience.test.ts +49 -0
  115. package/src/channels/__tests__/types.test.ts +17 -3
  116. package/src/channels/message-audience.ts +40 -0
  117. package/src/channels/types.ts +16 -12
  118. package/src/cli/__tests__/catalog-search-help.test.ts +50 -0
  119. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +31 -0
  120. package/src/cli/commands/__tests__/conversations-search.test.ts +289 -0
  121. package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -0
  122. package/src/cli/commands/__tests__/inference-providers.test.ts +68 -0
  123. package/src/cli/commands/__tests__/keys.test.ts +89 -8
  124. package/src/cli/commands/__tests__/plugins.test.ts +57 -1
  125. package/src/cli/commands/channel-verification-sessions.help.ts +11 -9
  126. package/src/cli/commands/channel-verification-sessions.ts +11 -21
  127. package/src/cli/commands/conversations.help.ts +34 -0
  128. package/src/cli/commands/conversations.ts +125 -0
  129. package/src/cli/commands/inference-providers.ts +9 -4
  130. package/src/cli/commands/inference.help.ts +9 -4
  131. package/src/cli/commands/keys.help.ts +13 -1
  132. package/src/cli/commands/keys.ts +26 -15
  133. package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
  134. package/src/cli/commands/memory/index.help.ts +41 -27
  135. package/src/cli/commands/memory/index.ts +2 -0
  136. package/src/cli/commands/memory/memory-v2.ts +58 -54
  137. package/src/cli/commands/memory/memory-validate.ts +18 -0
  138. package/src/cli/commands/monitoring.ts +1 -0
  139. package/src/cli/commands/plugins.help.ts +28 -31
  140. package/src/cli/commands/plugins.ts +10 -0
  141. package/src/cli/commands/skills.help.ts +13 -16
  142. package/src/cli/commands/trust.ts +3 -14
  143. package/src/cli/lib/__tests__/install-from-github.test.ts +38 -0
  144. package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +34 -0
  145. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +32 -1
  146. package/src/cli/lib/__tests__/toggle-plugin.test.ts +2 -1
  147. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +64 -0
  148. package/src/cli/lib/bundled-marketplace.json +13 -0
  149. package/src/cli/lib/daemon-credential-client.ts +25 -3
  150. package/src/cli/lib/install-from-github.ts +35 -24
  151. package/src/cli/lib/merge-plugin-tree.ts +22 -4
  152. package/src/cli/lib/plugin-surfaces.ts +27 -0
  153. package/src/config/__tests__/balanced-model-experiment.test.ts +7 -7
  154. package/src/config/__tests__/default-profile-catalog.test.ts +3 -3
  155. package/src/config/default-profile-catalog.ts +5 -6
  156. package/src/config/feature-flag-registry.json +32 -32
  157. package/src/config/webhook-routing.ts +8 -0
  158. package/src/context/compactor.ts +31 -2
  159. package/src/daemon/__tests__/provider-rejection-log-fields.test.ts +272 -0
  160. package/src/daemon/conversation-agent-loop-handlers.ts +4 -1
  161. package/src/daemon/conversation-error.ts +13 -0
  162. package/src/daemon/conversation-messaging.ts +22 -2
  163. package/src/daemon/conversation-process.ts +11 -0
  164. package/src/daemon/conversation-store.ts +10 -0
  165. package/src/daemon/conversation-surfaces.ts +21 -8
  166. package/src/daemon/conversation.ts +12 -10
  167. package/src/daemon/lifecycle.ts +6 -2
  168. package/src/daemon/message-types/conversations.ts +5 -7
  169. package/src/daemon/provider-rejection-log-fields.ts +124 -0
  170. package/src/daemon/resource-pressure-guard-lifecycle.ts +66 -0
  171. package/src/daemon/resource-pressure-guard.ts +387 -0
  172. package/src/daemon/shutdown-handlers.ts +2 -0
  173. package/src/daemon/startup-error.ts +16 -0
  174. package/src/daemon/trust-context.ts +14 -10
  175. package/src/daemon/unsendable-image-notice.ts +76 -0
  176. package/src/hooks/registry.ts +65 -51
  177. package/src/ipc/__tests__/socket-path.test.ts +15 -7
  178. package/src/ipc/gateway-client.test.ts +1 -1
  179. package/src/ipc/gateway-client.ts +14 -21
  180. package/src/ipc/socket-cleanup.ts +2 -11
  181. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +1 -1
  182. package/src/messaging/provider-message-metadata.ts +128 -0
  183. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +116 -68
  184. package/src/messaging/providers/channel-transport.ts +90 -13
  185. package/src/messaging/providers/discord/send.ts +16 -0
  186. package/src/messaging/providers/discord/transport.ts +11 -1
  187. package/src/messaging/providers/index.ts +109 -16
  188. package/src/messaging/providers/slack/message-metadata.ts +45 -0
  189. package/src/messaging/providers/slack/render-transcript.ts +1 -4
  190. package/src/messaging/providers/slack/send.test.ts +6 -9
  191. package/src/messaging/providers/slack/send.ts +40 -28
  192. package/src/messaging/providers/slack/transport.ts +22 -26
  193. package/src/messaging/providers/telegram-bot/send.test.ts +2 -8
  194. package/src/messaging/providers/telegram-bot/transport.ts +3 -6
  195. package/src/messaging/read-provider-metadata.test.ts +157 -0
  196. package/src/messaging/read-provider-metadata.ts +51 -0
  197. package/src/notifications/__tests__/assistant-reply-producer.test.ts +94 -0
  198. package/src/notifications/__tests__/edit-notification.test.ts +174 -2
  199. package/src/notifications/__tests__/home-feed-side-effect.test.ts +536 -4
  200. package/src/notifications/adapters/macos.ts +55 -0
  201. package/src/notifications/adapters/slack.ts +10 -5
  202. package/src/notifications/assistant-reply-producer.ts +37 -4
  203. package/src/notifications/conversation-pairing.ts +111 -21
  204. package/src/notifications/edit-notification.ts +38 -8
  205. package/src/notifications/emit-signal.ts +12 -14
  206. package/src/notifications/home-feed-side-effect.ts +218 -15
  207. package/src/notifications/types.ts +5 -0
  208. package/src/permissions/AGENTS.md +16 -0
  209. package/src/permissions/checker.test.ts +75 -122
  210. package/src/permissions/checker.ts +44 -560
  211. package/src/permissions/confirmation-guardian-request.test.ts +28 -3
  212. package/src/permissions/confirmation-guardian-request.ts +5 -1
  213. package/src/persistence/conversation-crud.ts +23 -20
  214. package/src/persistence/conversation-queries.ts +14 -1
  215. package/src/persistence/conversation-types.ts +22 -0
  216. package/src/persistence/delivery-crud.ts +122 -15
  217. package/src/plugin-api/__tests__/import-graph-partial-mock.test.ts +67 -0
  218. package/src/plugin-api/conversation-turn.ts +27 -0
  219. package/src/plugin-api/credential-scope.test.ts +15 -0
  220. package/src/plugin-api/credential-scope.ts +14 -0
  221. package/src/plugin-api/index.ts +19 -1
  222. package/src/plugin-api/resolve-credential.ts +15 -10
  223. package/src/plugin-api/store-credential.ts +148 -0
  224. package/src/plugin-api/system-card.ts +36 -0
  225. package/src/plugin-api/vision-support.test.ts +82 -0
  226. package/src/plugin-api/vision-support.ts +14 -2
  227. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +361 -110
  228. package/src/plugins/defaults/image-fallback/__tests__/vision-recovery.test.ts +4 -0
  229. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +58 -0
  230. package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +64 -23
  231. package/src/plugins/defaults/image-recovery/detect.ts +24 -1
  232. package/src/plugins/defaults/main.ts +15 -0
  233. package/src/plugins/defaults/memory/AGENTS.md +11 -3
  234. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
  235. package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +9 -12
  236. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
  237. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
  238. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +114 -0
  239. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
  240. package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
  241. package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
  242. package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
  243. package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
  244. package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
  245. package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +1 -61
  246. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +68 -6
  247. package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
  248. package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
  249. package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
  250. package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
  251. package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
  252. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
  253. package/src/plugins/defaults/memory/substrate/static-context.ts +0 -29
  254. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +3 -1
  255. package/src/plugins/defaults/memory/v3/card.ts +9 -9
  256. package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
  257. package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
  258. package/src/plugins/defaults/memory/v3/edge.ts +13 -57
  259. package/src/plugins/mtime-cache.ts +1 -1
  260. package/src/plugins/pipeline.ts +14 -7
  261. package/src/plugins/plugin-execution-context.ts +35 -11
  262. package/src/plugins/plugin-tree-walk.ts +63 -4
  263. package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
  264. package/src/providers/anthropic/client.ts +332 -241
  265. package/src/providers/connection-resolution.ts +2 -1
  266. package/src/providers/content-blocks.ts +22 -0
  267. package/src/providers/gemini/client.ts +5 -2
  268. package/src/providers/inference/__tests__/adapter-factory-litellm.test.ts +47 -1
  269. package/src/providers/inference/__tests__/adapter-factory-ollama.test.ts +83 -0
  270. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +98 -1
  271. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +38 -0
  272. package/src/providers/inference/__tests__/base-url-security.test.ts +10 -0
  273. package/src/providers/inference/__tests__/connections-ollama.test.ts +90 -0
  274. package/src/providers/inference/__tests__/missing-credential-guard.test.ts +117 -0
  275. package/src/providers/inference/adapter-factory.ts +33 -2
  276. package/src/providers/inference/auth.ts +13 -2
  277. package/src/providers/inference/credential-usage.ts +37 -0
  278. package/src/providers/inference/missing-credential-guard.ts +110 -0
  279. package/src/providers/inference/resolve-auth.ts +7 -7
  280. package/src/providers/media-resolve.ts +176 -15
  281. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +576 -46
  282. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
  283. package/src/providers/openai/chat-completions-provider.ts +322 -42
  284. package/src/routes/route-host-protocol.ts +7 -0
  285. package/src/routes/worker.ts +31 -10
  286. package/src/runtime/AGENTS.md +35 -0
  287. package/src/runtime/__tests__/runtime-http-port-collision.test.ts +131 -0
  288. package/src/runtime/__tests__/web-presence.test.ts +234 -0
  289. package/src/runtime/assistant-event-hub.ts +38 -0
  290. package/src/runtime/channel-reply-delivery.ts +54 -31
  291. package/src/runtime/channel-retry-sweep.ts +6 -4
  292. package/src/runtime/effective-capabilities.test.ts +19 -0
  293. package/src/runtime/effective-capabilities.ts +25 -0
  294. package/src/runtime/guardian-reply-router.ts +6 -2
  295. package/src/runtime/http-errors.ts +1 -0
  296. package/src/runtime/http-server.ts +20 -5
  297. package/src/runtime/routes/__tests__/client-routes.test.ts +150 -0
  298. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +133 -0
  299. package/src/runtime/routes/__tests__/credential-delete-in-use.test.ts +155 -0
  300. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +52 -1
  301. package/src/runtime/routes/__tests__/monitoring-routes.test.ts +1 -0
  302. package/src/runtime/routes/__tests__/pending-interactions-route.test.ts +175 -0
  303. package/src/runtime/routes/__tests__/plugins-routes.test.ts +88 -35
  304. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
  305. package/src/runtime/routes/__tests__/system-card-turn-termination.test.ts +107 -0
  306. package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
  307. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +75 -4
  308. package/src/runtime/routes/approval-routes.ts +37 -4
  309. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +16 -22
  310. package/src/runtime/routes/canned-message-complete.ts +68 -29
  311. package/src/runtime/routes/client-routes.ts +113 -0
  312. package/src/runtime/routes/conversation-list-routes.ts +22 -7
  313. package/src/runtime/routes/conversation-management-routes.ts +15 -9
  314. package/src/runtime/routes/conversation-routes.ts +36 -22
  315. package/src/runtime/routes/credential-in-use.ts +85 -0
  316. package/src/runtime/routes/credential-routes.ts +55 -85
  317. package/src/runtime/routes/guardian-approval-interception.ts +22 -22
  318. package/src/runtime/routes/guardian-approval-reply-helpers.ts +14 -12
  319. package/src/runtime/routes/identity-routes.ts +5 -121
  320. package/src/runtime/routes/inbound-message-handler.ts +71 -27
  321. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +16 -17
  322. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +77 -50
  323. package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -97
  324. package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -77
  325. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +17 -8
  326. package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -7
  327. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -70
  328. package/src/runtime/routes/index.ts +2 -0
  329. package/src/runtime/routes/inference-provider-connection-routes.ts +9 -7
  330. package/src/runtime/routes/monitoring-routes.ts +9 -1
  331. package/src/runtime/routes/plugins-routes.ts +17 -5
  332. package/src/runtime/routes/resource-pressure-routes.ts +22 -0
  333. package/src/runtime/routes/secret-routes.ts +39 -8
  334. package/src/runtime/routes/settings-routes.ts +6 -6
  335. package/src/runtime/routes/surface-action-routes.ts +20 -19
  336. package/src/runtime/routes/user-route-dispatcher.ts +31 -2
  337. package/src/runtime/routes/user-route-resolution.ts +18 -1
  338. package/src/runtime/slack-reply-session.test.ts +23 -13
  339. package/src/runtime/slack-reply-session.ts +38 -55
  340. package/src/runtime/web-presence.ts +90 -0
  341. package/src/skills/validate-input.ts +177 -40
  342. package/src/subagent/__tests__/consult-context-gating.test.ts +6 -10
  343. package/src/subagent/consult-context.ts +7 -23
  344. package/src/tools/credentials/broker.ts +24 -79
  345. package/src/tools/credentials/ref-parse.ts +35 -0
  346. package/src/tools/credentials/resolve.ts +4 -10
  347. package/src/tools/credentials/store.ts +168 -0
  348. package/src/tools/credentials/tool-policy.ts +67 -0
  349. package/src/tools/executor.ts +53 -15
  350. package/src/tools/network/__tests__/web-search.test.ts +41 -1
  351. package/src/tools/network/url-safety.ts +9 -16
  352. package/src/tools/network/web-search.ts +21 -3
  353. package/src/tools/permission-checker.ts +43 -52
  354. package/src/tools/schema-transforms.ts +40 -5
  355. package/src/tools/shared/input-repairs.ts +160 -0
  356. package/src/tools/skills/skill-tool-factory.ts +18 -4
  357. package/src/tools/subagent/spawn.ts +0 -1
  358. package/src/tools/tool-approval-handler.ts +16 -10
  359. package/src/tools/tool-types.ts +26 -13
  360. package/src/tools/types.ts +6 -6
  361. package/src/util/__tests__/cgroup-memory.test.ts +3 -0
  362. package/src/util/cgroup-memory.ts +3 -0
  363. package/src/util/container-cpu-sampler.ts +250 -0
  364. package/src/util/image-conversion.ts +178 -14
  365. package/src/util/platform.ts +93 -10
  366. package/src/permissions/ipc-risk-types.ts +0 -143
  367. package/src/permissions/risk-types.ts +0 -76
@@ -218,8 +218,12 @@ Examples:
218
218
  $ assistant inference providers create local-llm \\
219
219
  --provider openai-compatible \\
220
220
  --base-url http://localhost:1234/v1 --model my-model
221
+ $ assistant inference providers create ollama-home \\
222
+ --provider ollama --base-url http://192.168.1.50:11434/v1
221
223
  $ assistant inference providers update anthropic-personal \\
222
224
  --credential credential/anthropic/api_key
225
+ $ assistant inference providers update ollama \\
226
+ --base-url http://127.0.0.1:11434/v1
223
227
  $ assistant inference providers delete anthropic-personal
224
228
 
225
229
  After creating or updating a provider, validate it with a live call through
@@ -268,7 +272,7 @@ a profile that uses it:
268
272
  {
269
273
  flags: "--base-url <url>",
270
274
  description:
271
- "Endpoint base URL (required for --provider openai-compatible)",
275
+ "Endpoint base URL (required for openai-compatible; optional for ollama)",
272
276
  },
273
277
  ],
274
278
  },
@@ -290,7 +294,8 @@ a profile that uses it:
290
294
  },
291
295
  {
292
296
  flags: "--base-url <url>",
293
- description: "Endpoint base URL (openai-compatible providers)",
297
+ description:
298
+ "Endpoint base URL (openai-compatible or ollama)",
294
299
  },
295
300
  ],
296
301
  },
@@ -345,7 +350,7 @@ matching \`assistant inference providers <verb>\` command.`,
345
350
  {
346
351
  flags: "--base-url <url>",
347
352
  description:
348
- "Endpoint base URL (required for --provider openai-compatible)",
353
+ "Endpoint base URL (required for openai-compatible; optional for ollama)",
349
354
  },
350
355
  ],
351
356
  },
@@ -367,7 +372,7 @@ matching \`assistant inference providers <verb>\` command.`,
367
372
  {
368
373
  flags: "--base-url <url>",
369
374
  description:
370
- "Endpoint base URL (openai-compatible providers)",
375
+ "Endpoint base URL (openai-compatible or ollama)",
371
376
  },
372
377
  ],
373
378
  },
@@ -46,6 +46,13 @@ Examples:
46
46
  name: "delete",
47
47
  args: "<provider>",
48
48
  description: "Delete a stored API key",
49
+ options: [
50
+ {
51
+ flags: "--force",
52
+ description:
53
+ "Delete even when LLM provider connections resolve their auth through the key; those connections stop answering until a new key is stored",
54
+ },
55
+ ],
49
56
  helpText: `
50
57
  Arguments:
51
58
  provider Provider name whose key should be removed from secure storage
@@ -53,9 +60,14 @@ Arguments:
53
60
  Removes the API key for the given provider from secure local storage. If
54
61
  no key exists for the provider, exits with an error.
55
62
 
63
+ The delete is refused while an LLM provider connection resolves its auth
64
+ through the key; the error names the connections that depend on it. Run
65
+ 'assistant inference providers list' to inspect them, and pass --force to delete
66
+ anyway.
67
+
56
68
  Examples:
57
69
  $ assistant keys delete openai
58
- $ assistant keys delete anthropic`,
70
+ $ assistant keys delete anthropic --force`,
59
71
  },
60
72
  ],
61
73
  };
@@ -123,21 +123,32 @@ Examples:
123
123
  },
124
124
  );
125
125
 
126
- subcommand(keys, "delete").action(async (provider: string) => {
127
- const { deleteSecureKeyViaDaemon } =
128
- await import("../lib/daemon-credential-client.js");
129
- const delResult = await deleteSecureKeyViaDaemon("api_key", provider);
130
- if (delResult.result === "deleted") {
131
- log.info(`Deleted API key for "${provider}"`);
132
- } else if (delResult.result === "error") {
133
- const detail = delResult.error ? `: ${delResult.error}` : "";
134
- log.error(`Failed to delete API key for "${provider}"${detail}`);
135
- process.exit(1);
136
- } else {
137
- log.error(`No API key found for "${provider}"`);
138
- process.exit(1);
139
- }
140
- });
126
+ subcommand(keys, "delete").action(
127
+ async (provider: string, opts: { force?: boolean }) => {
128
+ const { deleteSecureKeyViaDaemon } =
129
+ await import("../lib/daemon-credential-client.js");
130
+ const delResult = await deleteSecureKeyViaDaemon(
131
+ "api_key",
132
+ provider,
133
+ opts.force === true,
134
+ );
135
+ if (delResult.result === "deleted") {
136
+ log.info(`Deleted API key for "${provider}"`);
137
+ } else if (delResult.result === "error") {
138
+ const detail = delResult.error ? `: ${delResult.error}` : "";
139
+ log.error(`Failed to delete API key for "${provider}"${detail}`);
140
+ if (delResult.code === "CREDENTIAL_IN_USE") {
141
+ log.error(
142
+ `Run 'assistant inference providers list' to inspect those connections, or 'assistant keys delete ${provider} --force' to delete the key anyway.`,
143
+ );
144
+ }
145
+ process.exit(1);
146
+ } else {
147
+ log.error(`No API key found for "${provider}"`);
148
+ process.exit(1);
149
+ }
150
+ },
151
+ );
141
152
  },
142
153
  });
143
154
  }
@@ -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