@vellumai/assistant 0.8.10 → 0.8.11-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 (400) hide show
  1. package/bun.lock +62 -1
  2. package/docs/workspace-tools.md +196 -0
  3. package/examples/plugins/echo/README.md +3 -3
  4. package/knip.json +1 -0
  5. package/openapi.yaml +460 -128
  6. package/package.json +2 -1
  7. package/scripts/build-plugin-api.ts +299 -0
  8. package/src/__tests__/agent-loop-callsite-precedence.test.ts +7 -0
  9. package/src/__tests__/agent-loop-compaction-events.test.ts +197 -0
  10. package/src/__tests__/agent-loop-exit-reason.test.ts +93 -96
  11. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +2 -0
  12. package/src/__tests__/agent-loop-output-hooks.test.ts +274 -1
  13. package/src/__tests__/agent-loop-override-profile.test.ts +3 -0
  14. package/src/__tests__/agent-loop-provider-error-recording.test.ts +4 -0
  15. package/src/__tests__/agent-loop-thinking.test.ts +4 -0
  16. package/src/__tests__/agent-loop.test.ts +578 -5
  17. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -1
  18. package/src/__tests__/approval-cascade.test.ts +1 -0
  19. package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
  20. package/src/__tests__/btw-routes.test.ts +0 -1
  21. package/src/__tests__/build-persisted-content.test.ts +75 -1
  22. package/src/__tests__/catalog-install-normalize.test.ts +141 -0
  23. package/src/__tests__/ces-startup-timeout.test.ts +60 -0
  24. package/src/__tests__/compaction-events.test.ts +1 -0
  25. package/src/__tests__/config-managed-gemini-defaults.test.ts +2 -46
  26. package/src/__tests__/context-overflow-reducer.test.ts +264 -124
  27. package/src/__tests__/context-window-manager-overflow-rung.test.ts +351 -0
  28. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  29. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +13 -5
  30. package/src/__tests__/conversation-agent-loop-overflow.test.ts +284 -455
  31. package/src/__tests__/conversation-agent-loop.test.ts +131 -551
  32. package/src/__tests__/conversation-app-control-instantiation.test.ts +13 -0
  33. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
  34. package/src/__tests__/conversation-fork-crud.test.ts +259 -0
  35. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  36. package/src/__tests__/conversation-lifecycle.test.ts +257 -1
  37. package/src/__tests__/conversation-process-callsite.test.ts +1 -0
  38. package/src/__tests__/conversation-provider-retry-repair.test.ts +38 -377
  39. package/src/__tests__/conversation-queue.test.ts +1 -39
  40. package/src/__tests__/conversation-runtime-assembly.test.ts +119 -8
  41. package/src/__tests__/conversation-skill-tools.test.ts +491 -5
  42. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  43. package/src/__tests__/conversation-slash-unknown.test.ts +1 -0
  44. package/src/__tests__/conversation-speed-override.test.ts +1 -0
  45. package/src/__tests__/conversation-store.test.ts +74 -0
  46. package/src/__tests__/conversation-surfaces-app-control.test.ts +4 -1
  47. package/src/__tests__/conversation-tool-setup-attribution.test.ts +323 -0
  48. package/src/__tests__/conversation-tool-setup-tools-disabled.test.ts +34 -0
  49. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
  50. package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
  51. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -0
  52. package/src/__tests__/corrected-target.test.ts +93 -0
  53. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -5
  54. package/src/__tests__/credential-execution-tools.test.ts +23 -11
  55. package/src/__tests__/credential-security-invariants.test.ts +6 -1
  56. package/src/__tests__/db-schedule-syntax-migration.test.ts +80 -0
  57. package/src/__tests__/device-id.test.ts +70 -1
  58. package/src/__tests__/embedding-managed-proxy-selection.test.ts +6 -40
  59. package/src/__tests__/empty-response-hook.test.ts +242 -66
  60. package/src/__tests__/external-plugin-loader.test.ts +0 -31
  61. package/src/__tests__/get-skill-detail-audit.test.ts +43 -1
  62. package/src/__tests__/guardian-routing-invariants.test.ts +91 -0
  63. package/src/__tests__/history-repair-hook.test.ts +228 -3
  64. package/src/__tests__/host-app-control-proxy.test.ts +45 -0
  65. package/src/__tests__/host-browser-proxy.test.ts +254 -9
  66. package/src/__tests__/identity-routes.test.ts +1 -0
  67. package/src/__tests__/image-recovery-hook.test.ts +387 -0
  68. package/src/__tests__/injector-chain.test.ts +5 -4
  69. package/src/__tests__/injector-v3-suppression.test.ts +373 -47
  70. package/src/__tests__/intent-routing.test.ts +7 -0
  71. package/src/__tests__/memory-retrieval-hook.test.ts +117 -15
  72. package/src/__tests__/notification-decision-strategy.test.ts +3 -3
  73. package/src/__tests__/oauth-store.test.ts +0 -85
  74. package/src/__tests__/{context-overflow-policy.test.ts → overflow-policy.test.ts} +1 -1
  75. package/src/__tests__/parallel-tool.benchmark.test.ts +4 -0
  76. package/src/__tests__/persist-unsendable-image-downscale.test.ts +29 -9
  77. package/src/__tests__/persist-unsendable-image.test.ts +4 -4
  78. package/src/__tests__/persistence-secret-redaction.test.ts +78 -0
  79. package/src/__tests__/plugin-bootstrap.test.ts +82 -73
  80. package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
  81. package/src/__tests__/plugin-types.test.ts +0 -8
  82. package/src/__tests__/provider-catalog-visibility.test.ts +1 -9
  83. package/src/__tests__/prune-old-conversations-job.test.ts +99 -0
  84. package/src/__tests__/registry.test.ts +240 -1
  85. package/src/__tests__/require-fresh-approval.test.ts +3 -0
  86. package/src/__tests__/schedule-routes.test.ts +116 -1
  87. package/src/__tests__/schedule-store.test.ts +28 -0
  88. package/src/__tests__/schedule-tools.test.ts +94 -1
  89. package/src/__tests__/server-history-render.test.ts +39 -0
  90. package/src/__tests__/skill-projection-feature-flag.test.ts +13 -0
  91. package/src/__tests__/skill-projection.benchmark.test.ts +25 -7
  92. package/src/__tests__/skills.test.ts +202 -0
  93. package/src/__tests__/slim-skill-category.test.ts +195 -0
  94. package/src/__tests__/strip-memory-injections.test.ts +33 -39
  95. package/src/__tests__/test-support/tool-invocation-seed.ts +79 -0
  96. package/src/__tests__/title-generate-hook.test.ts +9 -7
  97. package/src/__tests__/tool-audit-listener.test.ts +264 -1
  98. package/src/__tests__/tool-error-hook.test.ts +4 -3
  99. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -0
  100. package/src/__tests__/tool-executor-lifecycle-events.test.ts +273 -0
  101. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -0
  102. package/src/__tests__/tool-start-timestamp.test.ts +218 -0
  103. package/src/__tests__/tools-get-route.test.ts +202 -0
  104. package/src/__tests__/workspace-tool-loader.test.ts +319 -0
  105. package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
  106. package/src/agent/loop.ts +569 -319
  107. package/src/api/events/tool-result.ts +9 -0
  108. package/src/api/events/tool-use-start.ts +7 -0
  109. package/src/api/index.ts +10 -0
  110. package/src/api/responses/conversation-message.ts +135 -27
  111. package/src/api/responses/memory-v3-selection-log.ts +4 -4
  112. package/src/approvals/guardian-request-resolvers.ts +26 -0
  113. package/src/browser-session/backends/host-bridge.ts +29 -0
  114. package/src/browser-session/index.ts +1 -0
  115. package/src/browser-session/types.ts +5 -1
  116. package/src/cli/commands/__tests__/schedules.test.ts +62 -4
  117. package/src/cli/commands/__tests__/skills.test.ts +53 -0
  118. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  119. package/src/cli/commands/inference-providers.ts +0 -8
  120. package/src/cli/commands/plugins.ts +2 -2
  121. package/src/cli/commands/schedules.ts +27 -4
  122. package/src/cli/commands/skills.ts +187 -146
  123. package/src/cli/commands/tools.ts +106 -0
  124. package/src/cli/lib/__tests__/install-from-github.test.ts +256 -328
  125. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +6 -2
  126. package/src/cli/lib/__tests__/plugin-details.test.ts +10 -16
  127. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +2 -2
  128. package/src/cli/lib/__tests__/search-plugins.test.ts +145 -240
  129. package/src/cli/lib/install-from-github.ts +187 -117
  130. package/src/cli/lib/plugin-catalog-cache.ts +9 -9
  131. package/src/cli/lib/plugin-details.ts +38 -68
  132. package/src/cli/lib/plugin-marketplace.ts +42 -14
  133. package/src/cli/lib/search-plugins.ts +29 -129
  134. package/src/cli/program.ts +2 -0
  135. package/src/config/bundled-skills/acp/SKILL.md +1 -0
  136. package/src/config/bundled-skills/app-builder/SKILL.md +1 -0
  137. package/src/config/bundled-skills/app-control/SKILL.md +1 -0
  138. package/src/config/bundled-skills/computer-use/SKILL.md +1 -0
  139. package/src/config/bundled-skills/contacts/SKILL.md +1 -0
  140. package/src/config/bundled-skills/document-editor/SKILL.md +1 -0
  141. package/src/config/bundled-skills/followups/SKILL.md +1 -0
  142. package/src/config/bundled-skills/image-studio/SKILL.md +1 -0
  143. package/src/config/bundled-skills/media-processing/SKILL.md +1 -0
  144. package/src/config/bundled-skills/messaging/SKILL.md +1 -0
  145. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -0
  146. package/src/config/bundled-skills/playbooks/SKILL.md +1 -0
  147. package/src/config/bundled-skills/schedule/SKILL.md +1 -0
  148. package/src/config/bundled-skills/schedule/TOOLS.json +11 -3
  149. package/src/config/bundled-skills/sequences/SKILL.md +1 -0
  150. package/src/config/bundled-skills/settings/SKILL.md +1 -0
  151. package/src/config/bundled-skills/skill-management/SKILL.md +101 -1
  152. package/src/config/bundled-skills/subagent/SKILL.md +1 -0
  153. package/src/config/bundled-skills/transcribe/SKILL.md +1 -0
  154. package/src/config/env-registry.ts +23 -0
  155. package/src/config/feature-flag-registry.json +17 -81
  156. package/src/config/loader.ts +5 -22
  157. package/src/config/schema.ts +2 -0
  158. package/src/config/schemas/__tests__/compaction-logs.test.ts +56 -0
  159. package/src/config/schemas/__tests__/memory-v2.test.ts +0 -1
  160. package/src/config/schemas/__tests__/memory-v3.test.ts +61 -1
  161. package/src/config/schemas/compaction-logs.ts +79 -0
  162. package/src/config/schemas/memory-v2.ts +0 -8
  163. package/src/config/schemas/memory-v3.ts +104 -33
  164. package/src/config/seed-inference-profiles.ts +1 -1
  165. package/src/config/skills.ts +117 -47
  166. package/src/context/compactor.ts +11 -0
  167. package/src/context/strip-injections.ts +38 -4
  168. package/src/credential-execution/feature-gates.ts +0 -21
  169. package/src/credential-execution/startup-timeout.ts +32 -4
  170. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +18 -0
  171. package/src/daemon/conversation-agent-loop-handlers.ts +140 -91
  172. package/src/daemon/conversation-agent-loop.ts +123 -658
  173. package/src/daemon/conversation-error.ts +6 -33
  174. package/src/daemon/conversation-lifecycle.ts +1 -1
  175. package/src/daemon/conversation-runtime-assembly.ts +183 -22
  176. package/src/daemon/conversation-skill-tools.ts +137 -8
  177. package/src/daemon/conversation-slash.ts +0 -14
  178. package/src/daemon/conversation-store.ts +2 -19
  179. package/src/daemon/conversation-tool-setup.ts +87 -1
  180. package/src/daemon/conversation.ts +119 -50
  181. package/src/daemon/external-plugins-bootstrap.ts +36 -95
  182. package/src/daemon/handlers/config-channels.ts +11 -2
  183. package/src/daemon/handlers/shared.ts +9 -1
  184. package/src/daemon/handlers/skills.ts +10 -4
  185. package/src/daemon/host-app-control-proxy.ts +72 -57
  186. package/src/daemon/host-browser-proxy.ts +117 -22
  187. package/src/daemon/lifecycle.ts +34 -5
  188. package/src/daemon/message-protocol.ts +0 -7
  189. package/src/daemon/message-types/schedules.ts +1 -0
  190. package/src/daemon/message-types/skills.ts +17 -0
  191. package/src/daemon/providers-setup.ts +3 -0
  192. package/src/daemon/server.ts +3 -3
  193. package/src/daemon/tool-setup-types.ts +9 -3
  194. package/src/daemon/trust-context.ts +23 -0
  195. package/src/daemon/workspace-tools-watcher.ts +324 -0
  196. package/src/events/tool-audit-listener.ts +78 -16
  197. package/src/events/tool-metrics-listener.ts +2 -5
  198. package/src/memory/__tests__/compaction-log-writer-clickhouse.test.ts +227 -0
  199. package/src/memory/__tests__/conversation-queries.test.ts +176 -0
  200. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +20 -32
  201. package/src/memory/compaction-log-writer-clickhouse.ts +418 -0
  202. package/src/memory/conversation-crud.ts +134 -3
  203. package/src/memory/conversation-queries.ts +64 -7
  204. package/src/memory/db-init.ts +14 -0
  205. package/src/memory/embedding-backend.test.ts +130 -1
  206. package/src/memory/embedding-backend.ts +79 -106
  207. package/src/memory/embedding-gemini.ts +5 -0
  208. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +12 -0
  209. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +19 -0
  210. package/src/memory/graph/conversation-graph-memory.ts +36 -25
  211. package/src/memory/graph/tool-handlers.ts +3 -0
  212. package/src/memory/job-handlers/cleanup.ts +3 -1
  213. package/src/memory/jobs-store.ts +0 -28
  214. package/src/memory/jobs-worker.ts +10 -22
  215. package/src/memory/memory-marker.ts +29 -0
  216. package/src/memory/memory-retrospective-startup-cleanup.ts +1 -1
  217. package/src/memory/migrations/268-add-memory-v3-selections.ts +6 -0
  218. package/src/memory/migrations/270-schedule-description.ts +36 -0
  219. package/src/memory/migrations/275-tool-invocations-add-skill-id.test.ts +81 -0
  220. package/src/memory/migrations/275-tool-invocations-add-skill-id.ts +20 -0
  221. package/src/memory/migrations/276-tool-invocations-created-at-id-index.test.ts +68 -0
  222. package/src/memory/migrations/276-tool-invocations-created-at-id-index.ts +20 -0
  223. package/src/memory/migrations/277-add-memory-v3-ever-injected.ts +29 -0
  224. package/src/memory/migrations/278-tool-invocations-telemetry-columns.test.ts +96 -0
  225. package/src/memory/migrations/278-tool-invocations-telemetry-columns.ts +39 -0
  226. package/src/memory/migrations/279-create-skill-loaded-events.test.ts +84 -0
  227. package/src/memory/migrations/279-create-skill-loaded-events.ts +26 -0
  228. package/src/memory/migrations/280-conversations-surfaced-at.test.ts +88 -0
  229. package/src/memory/migrations/280-conversations-surfaced-at.ts +24 -0
  230. package/src/memory/migrations/index.ts +10 -0
  231. package/src/memory/migrations/registry.ts +8 -0
  232. package/src/memory/schema/conversations.ts +16 -0
  233. package/src/memory/schema/infrastructure.ts +26 -0
  234. package/src/memory/skill-loaded-events-store.test.ts +160 -0
  235. package/src/memory/skill-loaded-events-store.ts +95 -0
  236. package/src/memory/tool-executed-events-store.test.ts +219 -0
  237. package/src/memory/tool-executed-events-store.ts +102 -0
  238. package/src/memory/tool-usage-store.ts +15 -3
  239. package/src/memory/v2/__tests__/consolidation-job.test.ts +117 -12
  240. package/src/memory/v2/__tests__/consolidation-prompt-flag-gating-guard.test.ts +189 -0
  241. package/src/memory/v2/__tests__/injected-block-slugs.test.ts +90 -0
  242. package/src/memory/v2/__tests__/page-store.test.ts +33 -0
  243. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +88 -15
  244. package/src/memory/v2/activation-store.ts +50 -1
  245. package/src/memory/v2/consolidation-job.ts +113 -29
  246. package/src/memory/v2/injected-block-slugs.ts +79 -0
  247. package/src/memory/v2/injection.ts +6 -1
  248. package/src/memory/v2/prompts/consolidation.ts +414 -13
  249. package/src/memory/v2/router.ts +2 -28
  250. package/src/memory/v2/static-context.ts +1 -1
  251. package/src/memory/v2/types.ts +16 -0
  252. package/src/notifications/__tests__/copy-composer.test.ts +244 -0
  253. package/src/notifications/access-request-copy.ts +298 -0
  254. package/src/notifications/adapters/slack.ts +3 -3
  255. package/src/notifications/adapters/telegram.ts +2 -1
  256. package/src/notifications/copy-composer.ts +49 -267
  257. package/src/notifications/decision-engine.ts +16 -35
  258. package/src/notifications/home-feed-side-effect.ts +1 -6
  259. package/src/oauth/oauth-store.ts +0 -9
  260. package/src/permissions/checker.test.ts +83 -1
  261. package/src/permissions/checker.ts +25 -2
  262. package/src/permissions/gateway-threshold-reader.test.ts +182 -0
  263. package/src/permissions/gateway-threshold-reader.ts +80 -0
  264. package/src/platform/client.ts +1 -3
  265. package/src/platform/feature-gate.ts +3 -12
  266. package/src/plugin-api/constants.ts +4 -2
  267. package/src/plugin-api/index.ts +63 -11
  268. package/src/plugin-api/types.ts +236 -71
  269. package/src/plugins/defaults/compaction/compact.ts +66 -2
  270. package/src/plugins/defaults/compaction/context-overflow-reducer.ts +240 -32
  271. package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
  272. package/src/{daemon/context-overflow-policy.ts → plugins/defaults/compaction/overflow-policy.ts} +1 -1
  273. package/src/plugins/defaults/compaction/window-manager.ts +303 -1
  274. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +173 -0
  275. package/src/plugins/defaults/empty-response/hooks/stop.ts +11 -115
  276. package/src/plugins/defaults/empty-response/nudge-state-store.ts +46 -0
  277. package/src/plugins/defaults/history-repair/hooks/post-model-call.ts +50 -0
  278. package/src/plugins/defaults/history-repair/hooks/stop.ts +22 -0
  279. package/src/plugins/defaults/history-repair/repair-state-store.ts +51 -0
  280. package/src/plugins/defaults/history-repair/terminal.ts +39 -2
  281. package/src/plugins/defaults/image-recovery/detect.ts +25 -0
  282. package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +73 -0
  283. package/src/plugins/defaults/image-recovery/hooks/stop.ts +22 -0
  284. package/src/plugins/defaults/image-recovery/image-recovery-state-store.ts +48 -0
  285. package/src/plugins/defaults/image-recovery/package.json +14 -0
  286. package/src/{daemon/persist-unsendable-image.ts → plugins/defaults/image-recovery/recover.ts} +67 -14
  287. package/src/plugins/defaults/index.ts +71 -5
  288. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +76 -112
  289. package/src/plugins/defaults/memory-retrieval/hooks/{user-prompt-submit-temp.ts → user-prompt-submit.ts} +83 -74
  290. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +14 -8
  291. package/src/plugins/defaults/memory-retrieval/injectors.ts +2 -18
  292. package/src/plugins/defaults/memory-retrieval/package.json +14 -0
  293. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1157 -0
  294. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +683 -0
  295. package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +161 -140
  296. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +160 -0
  297. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +335 -316
  298. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +145 -53
  299. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +38 -1
  300. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +18 -8
  301. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +112 -71
  302. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +192 -51
  303. package/src/plugins/defaults/memory-v3-shadow/__tests__/types.test.ts +4 -16
  304. package/src/plugins/defaults/memory-v3-shadow/card.test.ts +173 -0
  305. package/src/plugins/defaults/memory-v3-shadow/card.ts +116 -0
  306. package/src/plugins/defaults/memory-v3-shadow/core-set.test.ts +104 -0
  307. package/src/plugins/defaults/memory-v3-shadow/core-set.ts +59 -0
  308. package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.test.ts +305 -0
  309. package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.ts +278 -0
  310. package/src/plugins/defaults/memory-v3-shadow/hot-set.test.ts +138 -0
  311. package/src/plugins/defaults/memory-v3-shadow/hot-set.ts +85 -0
  312. package/src/plugins/defaults/memory-v3-shadow/injector.ts +331 -24
  313. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +119 -13
  314. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +169 -114
  315. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +47 -16
  316. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +144 -66
  317. package/src/plugins/defaults/memory-v3-shadow/prune.test.ts +758 -0
  318. package/src/plugins/defaults/memory-v3-shadow/prune.ts +471 -0
  319. package/src/plugins/defaults/memory-v3-shadow/render-injection.ts +68 -16
  320. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +19 -12
  321. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +96 -43
  322. package/src/plugins/defaults/memory-v3-shadow/types.ts +34 -17
  323. package/src/plugins/defaults/title-generate/hooks/stop.ts +9 -11
  324. package/src/plugins/pipeline.ts +8 -5
  325. package/src/plugins/types.ts +5 -51
  326. package/src/providers/cache-control.ts +26 -0
  327. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +1 -2
  328. package/src/providers/model-catalog.ts +13 -1
  329. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +147 -0
  330. package/src/providers/openai/chat-completions-provider.ts +46 -0
  331. package/src/providers/openai/responses-provider.ts +45 -0
  332. package/src/providers/registry.ts +0 -8
  333. package/src/runtime/__tests__/agent-wake.test.ts +0 -1
  334. package/src/runtime/agent-wake.ts +13 -0
  335. package/src/runtime/routes/__tests__/acp-routes.test.ts +151 -0
  336. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +12 -50
  337. package/src/runtime/routes/__tests__/conversation-surface-routes.test.ts +322 -0
  338. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +0 -62
  339. package/src/runtime/routes/__tests__/plugins-routes.test.ts +31 -11
  340. package/src/runtime/routes/acp-routes.test.ts +106 -0
  341. package/src/runtime/routes/acp-routes.ts +248 -2
  342. package/src/runtime/routes/browser-tabs-routes.ts +1 -1
  343. package/src/runtime/routes/channel-verification-routes.ts +14 -5
  344. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +0 -14
  345. package/src/runtime/routes/consolidation-routes.ts +6 -82
  346. package/src/runtime/routes/conversation-list-routes.ts +6 -0
  347. package/src/runtime/routes/conversation-management-routes.ts +71 -0
  348. package/src/runtime/routes/identity-routes.ts +8 -0
  349. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
  350. package/src/runtime/routes/inference-provider-connection-routes.ts +0 -45
  351. package/src/runtime/routes/plugins-routes.ts +34 -45
  352. package/src/runtime/routes/schedule-routes.ts +43 -5
  353. package/src/runtime/routes/settings-routes.ts +140 -15
  354. package/src/runtime/routes/skills-routes.ts +18 -6
  355. package/src/runtime/services/__tests__/conversation-serializer.test.ts +140 -0
  356. package/src/runtime/services/conversation-serializer.ts +38 -1
  357. package/src/runtime/verification-outbound-actions.ts +147 -2
  358. package/src/runtime/verification-templates.ts +29 -3
  359. package/src/schedule/schedule-store.ts +19 -0
  360. package/src/skills/catalog-install.ts +77 -13
  361. package/src/tasks/task-scheduler.ts +1 -0
  362. package/src/telemetry/types.ts +66 -1
  363. package/src/telemetry/usage-telemetry-reporter.test.ts +542 -13
  364. package/src/telemetry/usage-telemetry-reporter.ts +213 -20
  365. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +49 -2
  366. package/src/tools/browser/__tests__/browser-status.test.ts +29 -5
  367. package/src/tools/browser/browser-execution.ts +27 -9
  368. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +380 -4
  369. package/src/tools/browser/cdp-client/__tests__/host-bridge-cdp-client.test.ts +107 -0
  370. package/src/tools/browser/cdp-client/__tests__/types.test.ts +6 -1
  371. package/src/tools/browser/cdp-client/factory.ts +217 -17
  372. package/src/tools/browser/cdp-client/host-bridge-cdp-client.ts +67 -0
  373. package/src/tools/browser/cdp-client/types.ts +22 -2
  374. package/src/tools/credential-execution/make-authenticated-request.ts +2 -1
  375. package/src/tools/credential-execution/manage-secure-command-tool.ts +169 -164
  376. package/src/tools/credential-execution/run-authenticated-command.ts +2 -1
  377. package/src/tools/executor.ts +39 -7
  378. package/src/tools/registry.ts +387 -5
  379. package/src/tools/schedule/create.ts +16 -0
  380. package/src/tools/schedule/list.ts +12 -4
  381. package/src/tools/schedule/update.ts +12 -0
  382. package/src/tools/skills/load.ts +11 -6
  383. package/src/tools/terminal/safe-env.ts +2 -0
  384. package/src/tools/types.ts +65 -9
  385. package/src/tools/workspace-tools/loader.ts +673 -0
  386. package/src/usage/attribution.ts +28 -0
  387. package/src/util/device-id.ts +17 -3
  388. package/src/util/platform.ts +16 -0
  389. package/tsconfig.plugin-api.json +13 -0
  390. package/src/__tests__/plugin-external-api.test.ts +0 -68
  391. package/src/__tests__/plugin-skill-contribution.test.ts +0 -355
  392. package/src/daemon/message-types/browser.ts +0 -10
  393. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
  394. package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/eval-turns.json +0 -36
  395. package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/live-turns.json +0 -37
  396. package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-eviction.test.ts +0 -106
  397. package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-skeleton.test.ts +0 -44
  398. package/src/plugins/defaults/memory-v3-shadow/working-set.ts +0 -91
  399. package/src/plugins/external-api.ts +0 -114
  400. package/src/plugins/plugin-skill-contributions.ts +0 -292
@@ -23,6 +23,7 @@ interface ScheduleRecord {
23
23
  maxRetries: number;
24
24
  retryBackoffMs: number;
25
25
  description: string | null;
26
+ cadenceDescription: string | null;
26
27
  mode: string;
27
28
  status: string;
28
29
  routingIntent: string;
@@ -64,9 +65,9 @@ export function registerSchedulesCommand(program: Command): void {
64
65
  Schedules are recurring or one-shot jobs run by the assistant.
65
66
 
66
67
  This CLI namespace is intentionally landing incrementally. Today it supports
67
- listing schedules, viewing recent run history, enabling/disabling schedules,
68
- manually executing a schedule one time, and cancelling pending one-shot schedules;
69
- create, delete, and run inspection will follow as separate slices.
68
+ creating schedules, listing schedules, viewing recent run history,
69
+ enabling/disabling schedules, manually executing a schedule one time, cancelling
70
+ pending one-shot schedules, and deleting schedules.
70
71
 
71
72
  Examples:
72
73
  $ assistant schedules list
@@ -318,6 +319,10 @@ Examples:
318
319
  "-e, --expression <expr>",
319
320
  "Cron or RRULE expression that schedules the fire times",
320
321
  )
322
+ .requiredOption(
323
+ "-d, --description <text>",
324
+ "Authored description explaining what the schedule is for",
325
+ )
321
326
  .requiredOption(
322
327
  "-m, --message <text>",
323
328
  "Message body sent to the assistant on each fire",
@@ -333,6 +338,7 @@ Examples:
333
338
  `
334
339
  Options:
335
340
  -e, --expression <expr> Cron (e.g. '*/30 * * * *') or RRULE expression.
341
+ -d, --description <text> Authored description explaining what the schedule is for.
336
342
  -m, --message <text> Message body sent on each fire.
337
343
  -t, --timezone <tz> IANA timezone applied to the expression.
338
344
  --no-enabled Create the schedule disabled. Defaults to enabled.
@@ -349,13 +355,16 @@ Behavior:
349
355
  Examples:
350
356
  $ assistant schedules create "Heartbeat" \\
351
357
  --expression '*/30 * * * *' \\
358
+ --description 'Checks service heartbeat every 30 minutes' \\
352
359
  --message 'run heartbeat'
353
360
  $ assistant schedules create "Morning summary" \\
354
361
  --expression '0 9 * * MON-FRI' \\
362
+ --description 'Summarizes weekday activity' \\
355
363
  --timezone America/New_York \\
356
364
  --message 'write the morning summary'
357
365
  $ assistant schedules create "Drafted" \\
358
366
  --expression '0 0 * * *' \\
367
+ --description 'Placeholder daily schedule' \\
359
368
  --message 'placeholder' \\
360
369
  --no-enabled --json`,
361
370
  )
@@ -364,6 +373,7 @@ Examples:
364
373
  name: string,
365
374
  opts: {
366
375
  expression: string;
376
+ description: string;
367
377
  message: string;
368
378
  timezone?: string;
369
379
  enabled: boolean;
@@ -383,9 +393,22 @@ Examples:
383
393
  return;
384
394
  }
385
395
 
396
+ const description = opts.description.trim();
397
+ if (!description) {
398
+ const error = "description is required";
399
+ if (opts.json) {
400
+ writeOutput(cmd, { ok: false, error });
401
+ } else {
402
+ log.error(error);
403
+ }
404
+ process.exitCode = 1;
405
+ return;
406
+ }
407
+
386
408
  const body: Record<string, unknown> = {
387
409
  name: scheduleName,
388
410
  expression: opts.expression,
411
+ description,
389
412
  message: opts.message,
390
413
  enabled: opts.enabled,
391
414
  };
@@ -662,7 +685,7 @@ async function toggleScheduleEnabled(
662
685
 
663
686
  function describeSchedule(schedule: ScheduleRecord): string {
664
687
  if (schedule.isOneShot) return "one-shot";
665
- const expression = schedule.description ?? schedule.expression ?? "—";
688
+ const expression = schedule.cadenceDescription ?? schedule.expression ?? "—";
666
689
  return schedule.timezone
667
690
  ? `${expression} (${schedule.timezone})`
668
691
  : expression;
@@ -97,6 +97,7 @@ Examples:
97
97
  origin: string;
98
98
  kind: string;
99
99
  status: string;
100
+ owner?: { kind: string; id: string };
100
101
  }>;
101
102
  }>("listSkills", { queryParams: {} });
102
103
  if (!r.ok)
@@ -104,16 +105,27 @@ Examples:
104
105
  { ok: false, error: r.error, statusCode: r.statusCode },
105
106
  opts.json ?? false,
106
107
  );
108
+ // Source labels the extension a skill ships from. Plugin-resident
109
+ // skills are intentionally mapped to kind:bundled/origin:vellum for
110
+ // older clients, so their real attribution lives on `owner` —
111
+ // surface it as `plugin:<id>` instead of collapsing to "bundled".
112
+ const sourceLabel = (s: {
113
+ origin: string;
114
+ kind: string;
115
+ owner?: { kind: string; id: string };
116
+ }): string => {
117
+ if (s.owner) return `${s.owner.kind}:${s.owner.id}`;
118
+ if (s.origin === "vellum" && s.kind === "bundled") return "bundled";
119
+ return s.origin;
120
+ };
107
121
  const allSkills = r
108
122
  .result!.skills.map((s) => ({
109
123
  id: s.id,
110
124
  name: s.name,
111
125
  description: s.description,
112
126
  emoji: s.emoji,
113
- source:
114
- s.origin === "vellum" && s.kind === "bundled"
115
- ? "bundled"
116
- : s.origin,
127
+ source: sourceLabel(s),
128
+ owner: s.owner,
117
129
  state: s.status,
118
130
  }))
119
131
  .sort((a, b) => a.id.localeCompare(b.id));
@@ -125,12 +137,22 @@ Examples:
125
137
  log.info("No skills available.");
126
138
  return;
127
139
  }
140
+ // Align ID / SOURCE / STATE into columns so source is scannable.
141
+ const idWidth = Math.max(2, ...allSkills.map((s) => s.id.length));
142
+ const srcWidth = Math.max(
143
+ 6,
144
+ ...allSkills.map((s) => s.source.length),
145
+ );
128
146
  log.info(`Skills (${allSkills.length}):\n`);
147
+ log.info(
148
+ ` ${"ID".padEnd(idWidth)} ${"SOURCE".padEnd(srcWidth)} STATE`,
149
+ );
129
150
  for (const s of allSkills) {
130
151
  const emoji = s.emoji ? `${s.emoji} ` : "";
131
- const tags = [s.source, ...(s.state === "disabled" ? ["disabled"] : [])];
132
- log.info(` ${emoji}${s.id} [${tags.join(", ")}]`);
133
- log.info(` ${s.name} — ${s.description}`);
152
+ log.info(
153
+ ` ${s.id.padEnd(idWidth)} ${s.source.padEnd(srcWidth)} ${s.state}`,
154
+ );
155
+ log.info(` ${emoji}${s.name} — ${s.description}`);
134
156
  }
135
157
  });
136
158
 
@@ -193,7 +215,8 @@ Examples:
193
215
  log.info(` Source: ${detail.source}`);
194
216
  log.info(` State: ${detail.state}`);
195
217
  log.info(` Path: ${detail.directoryPath}`);
196
- if (detail.featureFlag) log.info(` Flag: ${detail.featureFlag}`);
218
+ if (detail.featureFlag)
219
+ log.info(` Flag: ${detail.featureFlag}`);
197
220
  if (detail.includes?.length)
198
221
  log.info(` Includes: ${detail.includes.join(", ")}`);
199
222
  if (detail.activationHints?.length)
@@ -228,7 +251,9 @@ Examples:
228
251
  }
229
252
  if (detail.config) {
230
253
  log.info(`\n Config:`);
231
- log.info(` Enabled: ${detail.config.enabled ? "yes" : "no"}`);
254
+ log.info(
255
+ ` Enabled: ${detail.config.enabled ? "yes" : "no"}`,
256
+ );
232
257
  if (detail.config.envKeys.length)
233
258
  log.info(` Env vars: ${detail.config.envKeys.join(", ")}`);
234
259
  if (detail.config.configKeys.length)
@@ -262,147 +287,157 @@ Examples:
262
287
  $ assistant skills search "file management" --limit 3
263
288
  $ assistant skills search deploy --json`,
264
289
  )
265
- .action(async (query: string, opts: { limit: string; json?: boolean }) => {
266
- const json = opts.json ?? false;
267
- const limit = parseInt(opts.limit, 10) || 10;
268
-
269
- // Step 1: Vellum catalog (installed + remote available)
270
- const catalogR = await cliIpcCall<{
271
- skills: Array<{
272
- id: string;
273
- name: string;
274
- description: string;
275
- emoji?: string;
276
- origin: string;
277
- kind: string;
278
- status: string;
279
- updatedAt?: string;
280
- }>;
281
- }>("listSkills", { queryParams: { include: "catalog", q: query } });
282
- const vellumSkills = catalogR.ok
283
- ? catalogR.result!.skills.filter((s) => s.origin === "vellum")
284
- : [];
290
+ .action(
291
+ async (query: string, opts: { limit: string; json?: boolean }) => {
292
+ const json = opts.json ?? false;
293
+ const limit = parseInt(opts.limit, 10) || 10;
294
+
295
+ // Step 1: Vellum catalog (installed + remote available)
296
+ const catalogR = await cliIpcCall<{
297
+ skills: Array<{
298
+ id: string;
299
+ name: string;
300
+ description: string;
301
+ emoji?: string;
302
+ origin: string;
303
+ kind: string;
304
+ status: string;
305
+ updatedAt?: string;
306
+ }>;
307
+ }>("listSkills", { queryParams: { include: "catalog", q: query } });
308
+ const vellumSkills = catalogR.ok
309
+ ? catalogR.result!.skills.filter((s) => s.origin === "vellum")
310
+ : [];
311
+
312
+ // Step 2: community (skills.sh with audits + clawhub) + local bundled/installed
313
+ const communityR = await cliIpcCall<{
314
+ skills: Array<{
315
+ id: string;
316
+ name: string;
317
+ description: string;
318
+ emoji?: string;
319
+ origin: string;
320
+ kind: string;
321
+ status: string;
322
+ slug?: string;
323
+ author?: string;
324
+ stars?: number;
325
+ installs?: number;
326
+ publishedAt?: string;
327
+ version?: string;
328
+ sourceRepo?: string;
329
+ }>;
330
+ }>("searchSkills", {
331
+ queryParams: { q: query, limit: String(limit) },
332
+ });
333
+ const communitySkills = communityR.ok
334
+ ? communityR.result!.skills.filter((s) => s.origin !== "vellum")
335
+ : [];
336
+
337
+ // Deduplicate by id — vellum wins
338
+ const seen = new Set(vellumSkills.map((s) => s.id));
339
+ const dedupedCommunity = communitySkills.filter((s) => {
340
+ if (seen.has(s.id)) return false;
341
+ seen.add(s.id);
342
+ return true;
343
+ });
344
+ const clawhubResults = dedupedCommunity
345
+ .filter((s) => s.origin === "clawhub")
346
+ .slice(0, limit);
347
+ const skillsshResults = dedupedCommunity
348
+ .filter((s) => s.origin === "skillssh")
349
+ .slice(0, limit);
350
+
351
+ const hasResults =
352
+ vellumSkills.length > 0 ||
353
+ clawhubResults.length > 0 ||
354
+ skillsshResults.length > 0;
285
355
 
286
- // Step 2: community (skills.sh with audits + clawhub) + local bundled/installed
287
- const communityR = await cliIpcCall<{
288
- skills: Array<{
289
- id: string;
290
- name: string;
291
- description: string;
292
- emoji?: string;
293
- origin: string;
294
- kind: string;
295
- status: string;
296
- slug?: string;
297
- author?: string;
298
- stars?: number;
299
- installs?: number;
300
- publishedAt?: string;
301
- version?: string;
302
- sourceRepo?: string;
303
- }>;
304
- }>("searchSkills", { queryParams: { q: query, limit: String(limit) } });
305
- const communitySkills = communityR.ok
306
- ? communityR.result!.skills.filter((s) => s.origin !== "vellum")
307
- : [];
308
-
309
- // Deduplicate by id — vellum wins
310
- const seen = new Set(vellumSkills.map((s) => s.id));
311
- const dedupedCommunity = communitySkills.filter((s) => {
312
- if (seen.has(s.id)) return false;
313
- seen.add(s.id);
314
- return true;
315
- });
316
- const clawhubResults = dedupedCommunity
317
- .filter((s) => s.origin === "clawhub")
318
- .slice(0, limit);
319
- const skillsshResults = dedupedCommunity
320
- .filter((s) => s.origin === "skillssh")
321
- .slice(0, limit);
322
-
323
- const hasResults =
324
- vellumSkills.length > 0 ||
325
- clawhubResults.length > 0 ||
326
- skillsshResults.length > 0;
327
-
328
- if (json) {
329
- console.log(
330
- JSON.stringify({
331
- ok: true,
332
- catalog: vellumSkills,
333
- community: skillsshResults,
334
- clawhub: clawhubResults,
335
- ...(catalogR.ok ? {} : { catalogError: catalogR.error }),
336
- ...(communityR.ok ? {} : { communityError: communityR.error }),
337
- }),
338
- );
339
- return;
340
- }
356
+ if (json) {
357
+ console.log(
358
+ JSON.stringify({
359
+ ok: true,
360
+ catalog: vellumSkills,
361
+ community: skillsshResults,
362
+ clawhub: clawhubResults,
363
+ ...(catalogR.ok ? {} : { catalogError: catalogR.error }),
364
+ ...(communityR.ok
365
+ ? {}
366
+ : { communityError: communityR.error }),
367
+ }),
368
+ );
369
+ return;
370
+ }
341
371
 
342
- if (!hasResults) {
343
- log.info(`No skills found for "${query}".`);
344
- if (!catalogR.ok)
345
- log.warn(`(Vellum catalog unavailable: ${catalogR.error})`);
346
- if (!communityR.ok)
347
- log.warn(`(Community registry unavailable: ${communityR.error})`);
348
- return;
349
- }
372
+ if (!hasResults) {
373
+ log.info(`No skills found for "${query}".`);
374
+ if (!catalogR.ok)
375
+ log.warn(`(Vellum catalog unavailable: ${catalogR.error})`);
376
+ if (!communityR.ok)
377
+ log.warn(
378
+ `(Community registry unavailable: ${communityR.error})`,
379
+ );
380
+ return;
381
+ }
350
382
 
351
- if (vellumSkills.length > 0) {
352
- log.info(`Vellum catalog (${vellumSkills.length}):\n`);
353
- for (const s of vellumSkills) {
354
- const emoji = s.emoji ? `${s.emoji} ` : "";
355
- const badge = s.kind === "installed" ? " [installed]" : "";
356
- log.info(` ${emoji}${s.name}${badge}`);
357
- if (s.name !== s.id) log.info(` ID: ${s.id}`);
358
- log.info(` ${s.description}`);
359
- if (s.updatedAt) log.info(` Updated: ${s.updatedAt}`);
360
- if (s.kind !== "installed")
361
- log.info(` Install: assistant skills install ${s.id}`);
362
- log.info("");
383
+ if (vellumSkills.length > 0) {
384
+ log.info(`Vellum catalog (${vellumSkills.length}):\n`);
385
+ for (const s of vellumSkills) {
386
+ const emoji = s.emoji ? `${s.emoji} ` : "";
387
+ const badge = s.kind === "installed" ? " [installed]" : "";
388
+ log.info(` ${emoji}${s.name}${badge}`);
389
+ if (s.name !== s.id) log.info(` ID: ${s.id}`);
390
+ log.info(` ${s.description}`);
391
+ if (s.updatedAt) log.info(` Updated: ${s.updatedAt}`);
392
+ if (s.kind !== "installed")
393
+ log.info(` Install: assistant skills install ${s.id}`);
394
+ log.info("");
395
+ }
363
396
  }
364
- }
365
397
 
366
- if (skillsshResults.length > 0) {
367
- log.info(`Community — skills.sh (${skillsshResults.length}):\n`);
368
- for (const r of skillsshResults) {
369
- const badge = r.kind === "installed" ? " [installed]" : "";
370
- log.info(` ${r.name}${badge}`);
371
- if (r.name !== r.id) log.info(` ID: ${r.id}`);
372
- if (r.sourceRepo) log.info(` Source: ${r.sourceRepo}`);
373
- if (r.installs !== undefined)
374
- log.info(` Installs: ${r.installs}`);
375
- if (r.kind !== "installed")
376
- // Use the fully-qualified 3-segment id (owner/repo/skill) — this
377
- // matches the `owner/repo/skill-name` form accepted by
378
- // `resolveSkillSource()`. Building `sourceRepo@slug` fails for
379
- // skills.sh because the registry returns `slug` as the full id,
380
- // producing `owner/repo@owner/repo/skill` which the parser rejects.
381
- log.info(` Install: assistant skills add ${r.id}`);
382
- log.info("");
398
+ if (skillsshResults.length > 0) {
399
+ log.info(`Community — skills.sh (${skillsshResults.length}):\n`);
400
+ for (const r of skillsshResults) {
401
+ const badge = r.kind === "installed" ? " [installed]" : "";
402
+ log.info(` ${r.name}${badge}`);
403
+ if (r.name !== r.id) log.info(` ID: ${r.id}`);
404
+ if (r.sourceRepo) log.info(` Source: ${r.sourceRepo}`);
405
+ if (r.installs !== undefined)
406
+ log.info(` Installs: ${r.installs}`);
407
+ if (r.kind !== "installed")
408
+ // Use the fully-qualified 3-segment id (owner/repo/skill) — this
409
+ // matches the `owner/repo/skill-name` form accepted by
410
+ // `resolveSkillSource()`. Building `sourceRepo@slug` fails for
411
+ // skills.sh because the registry returns `slug` as the full id,
412
+ // producing `owner/repo@owner/repo/skill` which the parser rejects.
413
+ log.info(` Install: assistant skills add ${r.id}`);
414
+ log.info("");
415
+ }
416
+ } else if (!communityR.ok) {
417
+ log.warn(
418
+ `\n(skills.sh registry unavailable: ${communityR.error})`,
419
+ );
383
420
  }
384
- } else if (!communityR.ok) {
385
- log.warn(
386
- `\n(skills.sh registry unavailable: ${communityR.error})`,
387
- );
388
- }
389
421
 
390
- if (clawhubResults.length > 0) {
391
- log.info(`Community — Clawhub (${clawhubResults.length}):\n`);
392
- for (const r of clawhubResults) {
393
- const badge = r.kind === "installed" ? " [installed]" : "";
394
- log.info(` ${r.name}${badge}`);
395
- if (r.name !== r.id) log.info(` ID: ${r.id}`);
396
- if (r.author) log.info(` Author: ${r.author}`);
397
- if (r.description) log.info(` ${r.description}`);
398
- if (r.stars) log.info(` Stars: ${r.stars}`);
399
- if (r.installs) log.info(` Installs: ${r.installs}`);
400
- if (r.kind !== "installed")
401
- log.info(` Install: npx clawhub install ${r.slug ?? r.id}`);
402
- log.info("");
422
+ if (clawhubResults.length > 0) {
423
+ log.info(`Community — Clawhub (${clawhubResults.length}):\n`);
424
+ for (const r of clawhubResults) {
425
+ const badge = r.kind === "installed" ? " [installed]" : "";
426
+ log.info(` ${r.name}${badge}`);
427
+ if (r.name !== r.id) log.info(` ID: ${r.id}`);
428
+ if (r.author) log.info(` Author: ${r.author}`);
429
+ if (r.description) log.info(` ${r.description}`);
430
+ if (r.stars) log.info(` Stars: ${r.stars}`);
431
+ if (r.installs) log.info(` Installs: ${r.installs}`);
432
+ if (r.kind !== "installed")
433
+ log.info(
434
+ ` Install: npx clawhub install ${r.slug ?? r.id}`,
435
+ );
436
+ log.info("");
437
+ }
403
438
  }
404
- }
405
- });
439
+ },
440
+ );
406
441
 
407
442
  skills
408
443
  .command("install <skill-id>")
@@ -433,10 +468,16 @@ Examples:
433
468
  const json = opts.json ?? false;
434
469
 
435
470
  // Restrict to catalog-only; community installs use `skills add`.
436
- const installR = await cliIpcCall<{ ok: boolean; skillId?: string }>(
437
- "installSkill",
438
- { body: { slug: skillId, overwrite: opts.overwrite ?? false, catalogOnly: true } },
439
- );
471
+ const installR = await cliIpcCall<{
472
+ ok: boolean;
473
+ skillId?: string;
474
+ }>("installSkill", {
475
+ body: {
476
+ slug: skillId,
477
+ overwrite: opts.overwrite ?? false,
478
+ catalogOnly: true,
479
+ },
480
+ });
440
481
  if (!installR.ok) {
441
482
  if (json) {
442
483
  console.log(
@@ -0,0 +1,106 @@
1
+ /**
2
+ * `assistant tools` — inspect the tools registered with the running
3
+ * assistant (core built-ins plus skill-, plugin-, and MCP-contributed
4
+ * tools).
5
+ *
6
+ * Thin `ipc` wrapper: each subcommand forwards to a single daemon route and
7
+ * renders the response. The registry lives in the daemon, so these commands
8
+ * require the daemon to be running.
9
+ */
10
+
11
+ import type { Command } from "commander";
12
+
13
+ import { cliIpcCall, exitFromIpcResult } from "../../ipc/cli-client.js";
14
+ import { registerCommand } from "../lib/register-command.js";
15
+
16
+ interface ToolListEntry {
17
+ name: string;
18
+ description: string;
19
+ riskLevel: string;
20
+ category: string;
21
+ source: string;
22
+ }
23
+
24
+ interface ToolsGetResponse {
25
+ names: string[];
26
+ schemas: Record<string, unknown>;
27
+ tools: ToolListEntry[];
28
+ }
29
+
30
+ export function registerToolsCommand(program: Command): void {
31
+ registerCommand(program, {
32
+ name: "tools",
33
+ transport: "ipc",
34
+ description: "Inspect tools registered with the running assistant",
35
+ build: (tools) => {
36
+ tools.addHelpText(
37
+ "after",
38
+ `
39
+ Tools are registered with the daemon from four sources: core built-ins,
40
+ skills, external plugins, and MCP servers. The "source" column reports the
41
+ origin as "core" or "<kind>:<id>" (e.g. "plugin:echo", "skill:my-skill",
42
+ "mcp:linear"). The risk level is the author-asserted default band used for
43
+ permission gating, not the runtime-classified risk of a specific call.
44
+
45
+ By default the global registry is listed. Pass --conversation to scope the
46
+ list to the tools available to one conversation as of its most recent turn —
47
+ including skill/MCP tools it registered over its lifecycle.
48
+
49
+ Examples:
50
+ $ assistant tools list
51
+ $ assistant tools ls
52
+ $ assistant tools list --json
53
+ $ assistant tools list --conversation conv_abc123`,
54
+ );
55
+
56
+ tools
57
+ .command("list")
58
+ .alias("ls")
59
+ .description(
60
+ "List all registered tools with their source and risk level",
61
+ )
62
+ .option("--json", "Emit machine-readable JSON instead of a table")
63
+ .option(
64
+ "--conversation <id>",
65
+ "Scope to one conversation's tools as of its most recent turn — run 'assistant conversations list' to find the id",
66
+ )
67
+ .action(async (opts: { json?: boolean; conversation?: string }) => {
68
+ const response = await cliIpcCall<ToolsGetResponse>(
69
+ "tools_get",
70
+ opts.conversation
71
+ ? { queryParams: { conversationId: opts.conversation } }
72
+ : undefined,
73
+ );
74
+ if (!response.ok) {
75
+ return exitFromIpcResult(response);
76
+ }
77
+
78
+ const tools = response.result?.tools ?? [];
79
+
80
+ if (opts.json) {
81
+ console.log(JSON.stringify(tools, null, 2));
82
+ return;
83
+ }
84
+
85
+ if (tools.length === 0) {
86
+ console.log("No tools registered.");
87
+ return;
88
+ }
89
+
90
+ const nameW = Math.max(4, ...tools.map((t) => t.name.length));
91
+ const sourceW = Math.max(6, ...tools.map((t) => t.source.length));
92
+ const riskW = Math.max(4, ...tools.map((t) => t.riskLevel.length));
93
+
94
+ console.log(
95
+ `${"NAME".padEnd(nameW)} ${"SOURCE".padEnd(sourceW)} ${"RISK".padEnd(riskW)} DESCRIPTION`,
96
+ );
97
+ for (const t of tools) {
98
+ console.log(
99
+ `${t.name.padEnd(nameW)} ${t.source.padEnd(sourceW)} ${t.riskLevel.padEnd(riskW)} ${t.description}`,
100
+ );
101
+ }
102
+ console.log(`\n${tools.length} tool(s)`);
103
+ });
104
+ },
105
+ });
106
+ }