@vellumai/assistant 0.8.0 → 0.8.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 (692) hide show
  1. package/AGENTS.md +11 -0
  2. package/Dockerfile +5 -4
  3. package/README.md +2 -2
  4. package/docker-entrypoint.sh +16 -0
  5. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  6. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  7. package/eslint.config.mjs +12 -0
  8. package/knip.json +2 -1
  9. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  10. package/openapi.yaml +4847 -1698
  11. package/package.json +3 -1
  12. package/scripts/generate-openapi.ts +52 -4
  13. package/scripts/sync-llm-catalog.ts +165 -0
  14. package/scripts/sync-web-search-catalog.ts +107 -0
  15. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  16. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  17. package/src/__tests__/anthropic-provider.test.ts +92 -2
  18. package/src/__tests__/app-control-flow.test.ts +7 -0
  19. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  20. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  21. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  22. package/src/__tests__/btw-routes.test.ts +1 -0
  23. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  24. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  25. package/src/__tests__/channel-policy.test.ts +12 -0
  26. package/src/__tests__/checker.test.ts +89 -0
  27. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
  28. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  29. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  30. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  31. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  32. package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
  33. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  34. package/src/__tests__/config-schema.test.ts +14 -3
  35. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  36. package/src/__tests__/config-set-route.test.ts +198 -0
  37. package/src/__tests__/config-watcher.test.ts +6 -0
  38. package/src/__tests__/contacts-tools.test.ts +51 -199
  39. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  40. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  41. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  42. package/src/__tests__/context-search-fanout.test.ts +20 -157
  43. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  44. package/src/__tests__/context-search-types.test.ts +7 -2
  45. package/src/__tests__/context-window-manager.test.ts +389 -1
  46. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  47. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  48. package/src/__tests__/conversation-error.test.ts +38 -0
  49. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  50. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  51. package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
  52. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  53. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  54. package/src/__tests__/conversation-process-callsite.test.ts +21 -1
  55. package/src/__tests__/conversation-runtime-assembly.test.ts +4 -4
  56. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  57. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  58. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  59. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  60. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  61. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  62. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  63. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  64. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  65. package/src/__tests__/filing-service.test.ts +23 -3
  66. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  67. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  68. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  69. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -8
  70. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  71. package/src/__tests__/heartbeat-service.test.ts +50 -233
  72. package/src/__tests__/history-repair.test.ts +89 -0
  73. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  74. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  75. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  76. package/src/__tests__/host-browser-routes.test.ts +325 -33
  77. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  78. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  79. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  80. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  81. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  82. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  83. package/src/__tests__/install-skill-routing.test.ts +2 -2
  84. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +15 -0
  85. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  86. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  87. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  88. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  89. package/src/__tests__/llm-resolver.test.ts +46 -0
  90. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  91. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  92. package/src/__tests__/mcp-cli.test.ts +182 -220
  93. package/src/__tests__/mcp-health-check.test.ts +56 -27
  94. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  95. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  96. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  97. package/src/__tests__/oauth-cli.test.ts +38 -2009
  98. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  99. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  100. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  101. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  102. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  103. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  104. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  105. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  106. package/src/__tests__/plugin-types.test.ts +13 -11
  107. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  108. package/src/__tests__/profile-entry-status.test.ts +43 -0
  109. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  110. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  111. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  112. package/src/__tests__/relay-server.test.ts +118 -0
  113. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  114. package/src/__tests__/schedule-retry.test.ts +56 -4
  115. package/src/__tests__/schedule-routes.test.ts +104 -0
  116. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  117. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  118. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  119. package/src/__tests__/scheduler-wake.test.ts +0 -63
  120. package/src/__tests__/secret-allowlist.test.ts +1 -0
  121. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  122. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  123. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  124. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  125. package/src/__tests__/skill-load-tool.test.ts +2 -4
  126. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  127. package/src/__tests__/suggestion-routes.test.ts +3 -3
  128. package/src/__tests__/sync-message-contract.test.ts +63 -0
  129. package/src/__tests__/task-scheduler.test.ts +88 -23
  130. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  131. package/src/__tests__/usage-cli.test.ts +11 -73
  132. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  133. package/src/__tests__/vercel-config.test.ts +168 -0
  134. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  135. package/src/__tests__/web-search.test.ts +303 -2
  136. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  137. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  138. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
  139. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  140. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  141. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  142. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  143. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  144. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  145. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  146. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  147. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  148. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  149. package/src/acp/resolve-agent.test.ts +25 -0
  150. package/src/acp/resolve-agent.ts +13 -2
  151. package/src/acp/session-manager.ts +14 -0
  152. package/src/approvals/guardian-request-resolvers.ts +32 -87
  153. package/src/calls/relay-server.ts +35 -0
  154. package/src/calls/relay-setup-router.ts +36 -0
  155. package/src/calls/types.ts +1 -0
  156. package/src/calls/voice-session-bridge.ts +23 -4
  157. package/src/channels/config.ts +14 -1
  158. package/src/channels/types.ts +1 -0
  159. package/src/cli/AGENTS.md +164 -4
  160. package/src/cli/__tests__/notifications.test.ts +54 -0
  161. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  162. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  163. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  164. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  165. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  166. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  167. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  168. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  169. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  170. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  171. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  172. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  173. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  174. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  175. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  176. package/src/cli/commands/__tests__/status.test.ts +249 -0
  177. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  178. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  179. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  180. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  181. package/src/cli/commands/attachment.ts +8 -3
  182. package/src/cli/commands/audit.ts +95 -64
  183. package/src/cli/commands/auth.ts +61 -58
  184. package/src/cli/commands/avatar.ts +276 -390
  185. package/src/cli/commands/backup.ts +409 -505
  186. package/src/cli/commands/bash.ts +9 -5
  187. package/src/cli/commands/browser.ts +28 -9
  188. package/src/cli/commands/cache.ts +9 -4
  189. package/src/cli/commands/changelog.ts +414 -0
  190. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  191. package/src/cli/commands/clients.ts +8 -3
  192. package/src/cli/commands/completions.ts +9 -9
  193. package/src/cli/commands/config.ts +102 -72
  194. package/src/cli/commands/contacts.ts +575 -696
  195. package/src/cli/commands/conversations-defer.ts +17 -69
  196. package/src/cli/commands/conversations-import.ts +90 -253
  197. package/src/cli/commands/conversations.ts +346 -436
  198. package/src/cli/commands/credential-execution.ts +9 -6
  199. package/src/cli/commands/credentials.ts +456 -736
  200. package/src/cli/commands/domain.ts +128 -206
  201. package/src/cli/commands/email.ts +606 -794
  202. package/src/cli/commands/gateway.ts +8 -1
  203. package/src/cli/commands/image-generation.ts +157 -205
  204. package/src/cli/commands/inference-providers.ts +352 -0
  205. package/src/cli/commands/inference-session.ts +415 -0
  206. package/src/cli/commands/inference.ts +87 -65
  207. package/src/cli/commands/keys.ts +8 -3
  208. package/src/cli/commands/mcp.ts +103 -287
  209. package/src/cli/commands/memory-v2.ts +162 -516
  210. package/src/cli/commands/notifications.ts +33 -7
  211. package/src/cli/commands/oauth/apps.ts +292 -261
  212. package/src/cli/commands/oauth/connect.ts +176 -297
  213. package/src/cli/commands/oauth/disconnect.ts +16 -215
  214. package/src/cli/commands/oauth/index.ts +49 -45
  215. package/src/cli/commands/oauth/mode.ts +43 -199
  216. package/src/cli/commands/oauth/ping.ts +17 -125
  217. package/src/cli/commands/oauth/providers.ts +732 -921
  218. package/src/cli/commands/oauth/request.ts +60 -350
  219. package/src/cli/commands/oauth/shared.ts +11 -121
  220. package/src/cli/commands/oauth/status.ts +31 -121
  221. package/src/cli/commands/oauth/token.ts +13 -55
  222. package/src/cli/commands/pending.ts +19 -10
  223. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  224. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  225. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  226. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  227. package/src/cli/commands/platform/connect.ts +16 -80
  228. package/src/cli/commands/platform/disconnect.ts +14 -112
  229. package/src/cli/commands/platform/index.ts +177 -246
  230. package/src/cli/commands/routes.ts +153 -336
  231. package/src/cli/commands/sequence.ts +316 -360
  232. package/src/cli/commands/skills.ts +449 -671
  233. package/src/cli/commands/status.ts +58 -37
  234. package/src/cli/commands/stt.ts +94 -262
  235. package/src/cli/commands/task.ts +14 -40
  236. package/src/cli/commands/trust.ts +8 -3
  237. package/src/cli/commands/tts.ts +162 -167
  238. package/src/cli/commands/ui.ts +35 -42
  239. package/src/cli/commands/usage.ts +188 -126
  240. package/src/cli/commands/watchers.ts +8 -3
  241. package/src/cli/commands/webhooks.ts +99 -193
  242. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  243. package/src/cli/lib/daemon-credential-client.ts +4 -5
  244. package/src/cli/lib/nested-value.ts +44 -0
  245. package/src/cli/lib/open-browser.ts +36 -0
  246. package/src/cli/lib/register-command.ts +19 -0
  247. package/src/cli/lib/time-ago.ts +34 -0
  248. package/src/cli/program.ts +2 -4
  249. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  250. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  251. package/src/cli/utils/conversation-id.ts +30 -0
  252. package/src/cli/utils/parse-duration.ts +41 -0
  253. package/src/config/acp-defaults.test.ts +5 -1
  254. package/src/config/acp-defaults.ts +11 -4
  255. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  256. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  257. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  258. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  259. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  260. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  261. package/src/config/bundled-tool-registry.ts +0 -2
  262. package/src/config/feature-flag-registry.json +16 -0
  263. package/src/config/llm-resolver.ts +16 -1
  264. package/src/config/loader.ts +76 -14
  265. package/src/config/raw-config-utils.ts +2 -30
  266. package/src/config/schema.ts +4 -0
  267. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  268. package/src/config/schemas/call-site-catalog.ts +29 -7
  269. package/src/config/schemas/llm-request-logs.ts +57 -0
  270. package/src/config/schemas/llm.ts +52 -2
  271. package/src/config/schemas/memory-retrospective.ts +48 -0
  272. package/src/config/schemas/memory-v2.ts +32 -1
  273. package/src/config/schemas/memory.ts +4 -0
  274. package/src/config/schemas/services.ts +15 -12
  275. package/src/config/seed-inference-profiles.ts +195 -134
  276. package/src/contacts/contact-store.ts +0 -61
  277. package/src/context/window-manager.ts +191 -5
  278. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +79 -0
  279. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  280. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  281. package/src/daemon/approval-generators.ts +23 -29
  282. package/src/daemon/config-watcher.ts +2 -0
  283. package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
  284. package/src/daemon/conversation-agent-loop.ts +127 -97
  285. package/src/daemon/conversation-error.ts +21 -0
  286. package/src/daemon/conversation-lifecycle.ts +46 -5
  287. package/src/daemon/conversation-process.ts +36 -19
  288. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  289. package/src/daemon/conversation-slash.ts +175 -23
  290. package/src/daemon/conversation-store.ts +17 -10
  291. package/src/daemon/conversation-surfaces.ts +76 -12
  292. package/src/daemon/conversation-tool-setup.ts +24 -14
  293. package/src/daemon/conversation.ts +48 -9
  294. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  295. package/src/daemon/guardian-action-generators.ts +7 -22
  296. package/src/daemon/handlers/config-model.ts +8 -126
  297. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  298. package/src/daemon/handlers/config-vercel.ts +3 -1
  299. package/src/daemon/handlers/skills.ts +84 -5
  300. package/src/daemon/history-repair.ts +33 -6
  301. package/src/daemon/host-app-control-proxy.ts +44 -19
  302. package/src/daemon/host-bash-proxy.ts +85 -158
  303. package/src/daemon/host-browser-proxy.ts +96 -35
  304. package/src/daemon/host-proxy-base.ts +13 -1
  305. package/src/daemon/host-proxy-preactivation.ts +25 -1
  306. package/src/daemon/identity-helpers.ts +19 -0
  307. package/src/daemon/lifecycle.ts +42 -43
  308. package/src/daemon/meet-host-supervisor.ts +15 -15
  309. package/src/daemon/memory-v2-startup.ts +9 -2
  310. package/src/daemon/message-protocol.ts +6 -0
  311. package/src/daemon/message-types/bookmarks.ts +18 -0
  312. package/src/daemon/message-types/conversations.ts +12 -9
  313. package/src/daemon/message-types/messages.ts +9 -1
  314. package/src/daemon/message-types/sync.ts +60 -0
  315. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  316. package/src/daemon/pkb-reminder-builder.ts +21 -7
  317. package/src/daemon/process-message.ts +56 -23
  318. package/src/daemon/server.ts +23 -18
  319. package/src/daemon/shutdown-handlers.ts +0 -2
  320. package/src/daemon/tool-setup-types.ts +9 -0
  321. package/src/daemon/tool-side-effects.ts +6 -4
  322. package/src/daemon/wake-target-adapter.ts +11 -0
  323. package/src/export/transcript-formatter.ts +61 -2
  324. package/src/filing/filing-service.ts +40 -53
  325. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  326. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  327. package/src/heartbeat/heartbeat-service.ts +148 -127
  328. package/src/home/__tests__/feed-types.test.ts +63 -131
  329. package/src/home/__tests__/feed-writer.test.ts +77 -278
  330. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  331. package/src/home/feed-types.ts +19 -73
  332. package/src/home/feed-writer.ts +25 -156
  333. package/src/home/post-connect-feed.ts +1 -3
  334. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  335. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  336. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  337. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  338. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  339. package/src/ipc/assistant-server.ts +55 -6
  340. package/src/ipc/cli-client.ts +370 -50
  341. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  342. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  343. package/src/ipc/skill-routes/events.ts +30 -3
  344. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  345. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  346. package/src/live-voice/live-voice-session-manager.ts +11 -4
  347. package/src/live-voice/live-voice-session.ts +14 -6
  348. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  349. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  350. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  351. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  352. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  353. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  354. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  355. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  356. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  357. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  358. package/src/memory/bookmark-crud.ts +179 -0
  359. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  360. package/src/memory/context-search/agent-protocol.ts +5 -1
  361. package/src/memory/context-search/agent-runner.ts +60 -85
  362. package/src/memory/context-search/limits.ts +1 -4
  363. package/src/memory/context-search/search.ts +23 -113
  364. package/src/memory/context-search/sources/conversations.ts +18 -6
  365. package/src/memory/context-search/sources/memory-v2.ts +39 -14
  366. package/src/memory/context-search/sources/memory.ts +7 -0
  367. package/src/memory/context-search/sources/workspace.ts +13 -10
  368. package/src/memory/context-search/types.ts +1 -1
  369. package/src/memory/conversation-bootstrap.ts +11 -0
  370. package/src/memory/conversation-crud.ts +312 -10
  371. package/src/memory/conversation-queries.ts +9 -5
  372. package/src/memory/conversation-title-service.ts +1 -0
  373. package/src/memory/conversation-types.ts +16 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +2 -1
  376. package/src/memory/embedding-runtime-manager.ts +1 -2
  377. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  378. package/src/memory/graph/conversation-graph-memory.ts +76 -5
  379. package/src/memory/graph/extraction.ts +4 -0
  380. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  381. package/src/memory/graph/tool-handlers.ts +17 -7
  382. package/src/memory/graph/tools.ts +44 -5
  383. package/src/memory/indexer.ts +17 -0
  384. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +13 -15
  385. package/src/memory/jobs/embed-concept-page.ts +45 -9
  386. package/src/memory/jobs-store.ts +51 -1
  387. package/src/memory/jobs-worker.ts +52 -3
  388. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  389. package/src/memory/llm-request-log-source-local.ts +26 -0
  390. package/src/memory/llm-request-log-source.ts +97 -0
  391. package/src/memory/llm-request-log-store.ts +1 -1
  392. package/src/memory/memory-retrospective-constants.ts +13 -0
  393. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  394. package/src/memory/memory-retrospective-job.ts +351 -0
  395. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  396. package/src/memory/memory-retrospective-state.ts +162 -0
  397. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  398. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  399. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  400. package/src/memory/message-content.ts +38 -1
  401. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  402. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  403. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  404. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  405. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  406. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  407. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  408. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  409. package/src/memory/migrations/243-provider-connections.ts +68 -0
  410. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  411. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  412. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  413. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  414. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  415. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  416. package/src/memory/migrations/index.ts +7 -0
  417. package/src/memory/published-pages-store.ts +16 -0
  418. package/src/memory/schema/bookmarks.ts +38 -0
  419. package/src/memory/schema/conversations.ts +2 -0
  420. package/src/memory/schema/index.ts +2 -0
  421. package/src/memory/schema/inference.ts +29 -0
  422. package/src/memory/schema/memory-core.ts +9 -0
  423. package/src/memory/search/semantic.ts +1 -4
  424. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  425. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  426. package/src/memory/v2/__tests__/activation.test.ts +11 -4
  427. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  428. package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
  429. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  430. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  431. package/src/memory/v2/__tests__/injection.test.ts +628 -10
  432. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  433. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  434. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  435. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  436. package/src/memory/v2/__tests__/qdrant.test.ts +72 -0
  437. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  438. package/src/memory/v2/__tests__/router.test.ts +516 -0
  439. package/src/memory/v2/__tests__/sim.test.ts +45 -1
  440. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  441. package/src/memory/v2/__tests__/static-context.test.ts +7 -22
  442. package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
  443. package/src/memory/v2/activation-store.ts +34 -5
  444. package/src/memory/v2/activation.ts +40 -27
  445. package/src/memory/v2/backfill-jobs.ts +17 -84
  446. package/src/memory/v2/consolidation-job.ts +85 -78
  447. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  448. package/src/memory/v2/injection.ts +440 -109
  449. package/src/memory/v2/migration.ts +117 -20
  450. package/src/memory/v2/page-index.ts +191 -0
  451. package/src/memory/v2/page-store.ts +3 -0
  452. package/src/memory/v2/prompts/consolidation.ts +9 -7
  453. package/src/memory/v2/prompts/router.ts +192 -0
  454. package/src/memory/v2/qdrant.ts +100 -87
  455. package/src/memory/v2/reranker.ts +14 -7
  456. package/src/memory/v2/router.ts +322 -0
  457. package/src/memory/v2/sim.ts +25 -12
  458. package/src/memory/v2/skill-store.ts +118 -29
  459. package/src/memory/v2/static-context.ts +16 -9
  460. package/src/memory/v2/sweep-job.ts +122 -96
  461. package/src/memory/v2/types.ts +10 -6
  462. package/src/memory/validation.ts +13 -0
  463. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  464. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  465. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  466. package/src/notifications/adapters/platform.ts +171 -0
  467. package/src/notifications/conversation-pairing.ts +2 -2
  468. package/src/notifications/copy-composer.ts +15 -0
  469. package/src/notifications/destination-resolver.ts +21 -0
  470. package/src/notifications/emit-signal.ts +28 -1
  471. package/src/notifications/home-feed-side-effect.ts +111 -0
  472. package/src/notifications/signal.ts +5 -0
  473. package/src/permissions/checker.ts +12 -0
  474. package/src/permissions/ipc-risk-types.ts +2 -0
  475. package/src/plugin-api/index.ts +13 -0
  476. package/src/plugin-api/package.json +12 -0
  477. package/src/plugin-api/types.ts +62 -0
  478. package/src/plugins/defaults/injectors.ts +19 -3
  479. package/src/plugins/external-plugin-loader.ts +294 -0
  480. package/src/plugins/types.ts +46 -30
  481. package/src/plugins/user-loader.ts +64 -41
  482. package/src/proactive-artifact/job.test.ts +12 -4
  483. package/src/proactive-artifact/job.ts +4 -0
  484. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  485. package/src/proactive-artifact/trigger-state.ts +4 -0
  486. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  487. package/src/prompts/system-prompt.ts +22 -1
  488. package/src/prompts/update-bulletin-job.ts +61 -73
  489. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  490. package/src/providers/__tests__/inference.test.ts +288 -0
  491. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  492. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  493. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  494. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  495. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  496. package/src/providers/anthropic/client.ts +95 -26
  497. package/src/providers/call-site-routing.ts +94 -16
  498. package/src/providers/connection-resolution.ts +163 -0
  499. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  500. package/src/providers/inference/adapter-factory.ts +173 -0
  501. package/src/providers/inference/auth.ts +112 -0
  502. package/src/providers/inference/backfill.ts +196 -0
  503. package/src/providers/inference/connections.ts +356 -0
  504. package/src/providers/inference/resolve-auth.ts +65 -0
  505. package/src/providers/model-catalog.ts +104 -6
  506. package/src/providers/openai/responses-provider.ts +4 -2
  507. package/src/providers/provider-env-vars.ts +17 -7
  508. package/src/providers/provider-secret-catalog.ts +49 -30
  509. package/src/providers/provider-send-message.ts +41 -20
  510. package/src/providers/registry.ts +143 -159
  511. package/src/providers/retry.ts +18 -10
  512. package/src/providers/search-provider-catalog.ts +121 -0
  513. package/src/runtime/AGENTS.md +18 -5
  514. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  515. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  516. package/src/runtime/actor-trust-resolver.ts +32 -10
  517. package/src/runtime/agent-wake.ts +35 -6
  518. package/src/runtime/assistant-event-hub.ts +3 -85
  519. package/src/runtime/auth/route-policy.ts +303 -8
  520. package/src/runtime/auth/same-actor.ts +2 -0
  521. package/src/runtime/background-job-runner.ts +339 -0
  522. package/src/runtime/btw-sidechain.ts +1 -0
  523. package/src/runtime/http-router.ts +36 -1
  524. package/src/runtime/http-server.ts +31 -5
  525. package/src/runtime/http-types.ts +2 -0
  526. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  527. package/src/runtime/middleware/request-logger.ts +62 -1
  528. package/src/runtime/pre-first-message-gate.ts +83 -0
  529. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  530. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  531. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  532. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  533. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  534. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  535. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  536. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
  537. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  538. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  539. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  540. package/src/runtime/routes/acp-routes.ts +10 -8
  541. package/src/runtime/routes/app-management-routes.ts +228 -3
  542. package/src/runtime/routes/approval-routes.ts +0 -18
  543. package/src/runtime/routes/audit-routes.ts +43 -0
  544. package/src/runtime/routes/auth-routes.ts +72 -0
  545. package/src/runtime/routes/avatar-routes.ts +273 -20
  546. package/src/runtime/routes/backup-routes.ts +406 -2
  547. package/src/runtime/routes/bookmark-routes.ts +154 -0
  548. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  549. package/src/runtime/routes/contact-routes.ts +0 -160
  550. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  551. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  552. package/src/runtime/routes/conversation-query-routes.ts +334 -86
  553. package/src/runtime/routes/conversation-routes.ts +31 -10
  554. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  555. package/src/runtime/routes/credential-routes.ts +540 -0
  556. package/src/runtime/routes/debug-routes.ts +2 -2
  557. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  558. package/src/runtime/routes/domain-routes.ts +167 -0
  559. package/src/runtime/routes/email-routes.ts +603 -0
  560. package/src/runtime/routes/errors.ts +2 -2
  561. package/src/runtime/routes/events-routes.ts +192 -0
  562. package/src/runtime/routes/home-feed-routes.ts +6 -78
  563. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  564. package/src/runtime/routes/host-browser-routes.ts +103 -22
  565. package/src/runtime/routes/http-adapter.ts +2 -0
  566. package/src/runtime/routes/identity-routes.ts +5 -0
  567. package/src/runtime/routes/image-generation-routes.ts +99 -0
  568. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  569. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  570. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  571. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
  572. package/src/runtime/routes/index.ts +36 -0
  573. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  574. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  575. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  576. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  577. package/src/runtime/routes/inference-send-routes.ts +115 -0
  578. package/src/runtime/routes/integrations/twilio.ts +1 -0
  579. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  580. package/src/runtime/routes/memory-v2-routes.ts +13 -398
  581. package/src/runtime/routes/notification-routes.ts +2 -0
  582. package/src/runtime/routes/oauth-apps.ts +112 -7
  583. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  584. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  585. package/src/runtime/routes/oauth-providers.ts +298 -8
  586. package/src/runtime/routes/platform-routes.ts +336 -0
  587. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  588. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  589. package/src/runtime/routes/playground/state.ts +2 -1
  590. package/src/runtime/routes/publish-routes.ts +221 -0
  591. package/src/runtime/routes/schedule-routes.ts +82 -0
  592. package/src/runtime/routes/sequence-routes.ts +291 -0
  593. package/src/runtime/routes/settings-routes.ts +2 -10
  594. package/src/runtime/routes/skills-routes.ts +31 -1
  595. package/src/runtime/routes/stt-routes.ts +240 -3
  596. package/src/runtime/routes/surface-action-routes.ts +43 -7
  597. package/src/runtime/routes/tts-routes.ts +67 -0
  598. package/src/runtime/routes/types.ts +32 -0
  599. package/src/runtime/routes/user-routes-cli.ts +243 -0
  600. package/src/runtime/routes/webhook-routes.ts +165 -0
  601. package/src/runtime/sync/resource-sync-events.ts +25 -0
  602. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  603. package/src/runtime/sync/sync-publisher.ts +21 -0
  604. package/src/schedule/scheduler.ts +200 -123
  605. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  606. package/src/security/secret-patterns.ts +3 -0
  607. package/src/sequence/engine.ts +38 -40
  608. package/src/subagent/manager.ts +20 -15
  609. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  610. package/src/tools/browser/browser-execution.ts +15 -4
  611. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  612. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  613. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  614. package/src/tools/browser/cdp-client/factory.ts +66 -5
  615. package/src/tools/browser/runtime-check.ts +77 -0
  616. package/src/tools/memory/register.test.ts +3 -3
  617. package/src/tools/memory/register.ts +9 -1
  618. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  619. package/src/tools/network/web-search.ts +280 -37
  620. package/src/tools/permission-checker.ts +13 -5
  621. package/src/tools/subagent/spawn.ts +3 -3
  622. package/src/tools/terminal/shell.ts +44 -0
  623. package/src/usage/attribution.ts +3 -2
  624. package/src/util/pricing.ts +86 -160
  625. package/src/watcher/__tests__/engine.test.ts +301 -0
  626. package/src/watcher/constants.ts +7 -0
  627. package/src/watcher/engine.ts +90 -90
  628. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  629. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  630. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  631. package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
  632. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  633. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  634. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  635. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  636. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  637. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  638. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  639. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  640. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  641. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  642. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  643. package/src/workspace/migrations/registry.ts +22 -0
  644. package/src/workspace/migrations/runner.ts +13 -2
  645. package/src/workspace/migrations/types.ts +13 -3
  646. package/src/workspace/provider-commit-message-generator.ts +3 -2
  647. package/src/__tests__/context-search-pkb-source.test.ts +0 -498
  648. package/src/__tests__/credentials-cli.test.ts +0 -1225
  649. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  650. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  651. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  652. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  653. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  654. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  655. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  656. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  657. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  658. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  659. package/src/cli/commands/autonomy.ts +0 -365
  660. package/src/cli/commands/memory.ts +0 -424
  661. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
  662. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  663. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  664. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  665. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  666. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  667. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  668. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  669. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  670. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  671. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  672. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  673. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  674. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  675. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  676. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  677. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  678. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  679. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  680. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  681. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  682. package/src/home/assistant-feed-authoring.ts +0 -135
  683. package/src/home/emit-feed-event.ts +0 -169
  684. package/src/home/feed-scheduler.ts +0 -281
  685. package/src/home/platform-gmail-digest.ts +0 -163
  686. package/src/home/rewrite-command-preview.ts +0 -66
  687. package/src/home/rewrite-feed-title.ts +0 -58
  688. package/src/home/rollup-producer.ts +0 -426
  689. package/src/memory/admin.ts +0 -326
  690. package/src/memory/context-search/sources/pkb.ts +0 -476
  691. package/src/memory/graph/compaction.ts +0 -299
  692. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -1,57 +1,45 @@
1
- import { existsSync } from "node:fs";
2
- import { join } from "node:path";
3
-
4
1
  import type { Command } from "commander";
5
2
 
6
- import { getConfig } from "../../config/loader.js";
7
- import { resolveSkillStates } from "../../config/skill-state.js";
8
- import { loadSkillCatalog } from "../../config/skills.js";
9
- import type { CatalogSkill } from "../../skills/catalog-install.js";
10
- import {
11
- fetchCatalog,
12
- getRepoSkillsDir,
13
- installSkillLocally,
14
- readLocalCatalog,
15
- uninstallSkillLocally,
16
- } from "../../skills/catalog-install.js";
17
- import { filterByQuery } from "../../skills/catalog-search.js";
18
- import { clawhubSearch } from "../../skills/clawhub.js";
19
- import { readInstallMeta } from "../../skills/install-meta.js";
20
- import type {
21
- AuditResponse,
22
- SkillsShSearchResult,
23
- } from "../../skills/skillssh-registry.js";
24
- import {
25
- fetchSkillAudits,
26
- formatAuditBadges,
27
- installExternalSkill,
28
- resolveSkillSource,
29
- searchSkillsRegistry,
30
- } from "../../skills/skillssh-registry.js";
31
- import { getWorkspaceSkillsDir } from "../../util/platform.js";
3
+ import { cliIpcCall, exitFromIpcResult } from "../../ipc/cli-client.js";
4
+ import { registerCommand } from "../lib/register-command.js";
32
5
  import { log } from "../logger.js";
33
6
 
34
7
  // ---------------------------------------------------------------------------
35
- // Helpers
8
+ // Internal helpers
36
9
  // ---------------------------------------------------------------------------
37
10
 
38
- function formatDate(iso: string): string {
39
- try {
40
- const d = new Date(iso);
41
- const date = d.toLocaleDateString("en-US", {
42
- year: "numeric",
43
- month: "short",
44
- day: "numeric",
45
- });
46
- const time = d.toLocaleTimeString("en-US", {
47
- hour: "numeric",
48
- minute: "2-digit",
49
- hour12: true,
50
- });
51
- return `${date} ${time}`;
52
- } catch {
53
- return iso;
11
+ /**
12
+ * Map an IPC failure to a CLI exit code, mirroring `exitFromIpcResult`'s
13
+ * status→exit table without calling `process.exit` (so callers can flush
14
+ * stdout before the process tears down).
15
+ */
16
+ function exitCodeFromStatus(statusCode: number | undefined): number {
17
+ if (statusCode === undefined) return 10;
18
+ if (statusCode >= 500) return 3;
19
+ if (statusCode >= 400) return 2;
20
+ return 1;
21
+ }
22
+
23
+ /**
24
+ * Surface an IPC failure on a CLI command that supports `--json`. When `json`
25
+ * is true, emit a `{ok:false,error}` document to stdout and set `exitCode`
26
+ * without writing to stderr — so machine readers can parse output uniformly
27
+ * across success and failure paths. When `json` is false, fall back to
28
+ * `exitFromIpcResult` for the existing stderr-write + `process.exit`
29
+ * behaviour, preserving the human-mode UX.
30
+ */
31
+ function exitFromCliResult(
32
+ r: { ok: false; error?: string; statusCode?: number },
33
+ json: boolean,
34
+ ): void {
35
+ if (json) {
36
+ console.log(
37
+ JSON.stringify({ ok: false, error: r.error ?? "Unknown error" }),
38
+ );
39
+ process.exitCode = exitCodeFromStatus(r.statusCode);
40
+ return;
54
41
  }
42
+ exitFromIpcResult(r);
55
43
  }
56
44
 
57
45
  // ---------------------------------------------------------------------------
@@ -59,13 +47,14 @@ function formatDate(iso: string): string {
59
47
  // ---------------------------------------------------------------------------
60
48
 
61
49
  export function registerSkillsCommand(program: Command): void {
62
- const skills = program
63
- .command("skills")
64
- .description("Browse and install skills from the Vellum catalog");
65
-
66
- skills.addHelpText(
67
- "after",
68
- `
50
+ registerCommand(program, {
51
+ name: "skills",
52
+ transport: "ipc",
53
+ description: "Browse and install skills from the Vellum catalog",
54
+ build: (skills) => {
55
+ skills.addHelpText(
56
+ "after",
57
+ `
69
58
  Manage skills from the Vellum catalog. Skills extend the assistant's
70
59
  capabilities with pre-built workflows and tools.
71
60
 
@@ -81,15 +70,15 @@ Examples:
81
70
  $ assistant skills uninstall weather
82
71
  $ assistant skills add vercel-labs/skills@find-skills
83
72
  $ assistant skills add vercel-labs/skills/find-skills --overwrite`,
84
- );
85
-
86
- skills
87
- .command("list")
88
- .description("List bundled and installed skills")
89
- .option("--json", "Machine-readable JSON output")
90
- .addHelpText(
91
- "after",
92
- `
73
+ );
74
+
75
+ skills
76
+ .command("list")
77
+ .description("List bundled and installed skills")
78
+ .option("--json", "Machine-readable JSON output")
79
+ .addHelpText(
80
+ "after",
81
+ `
93
82
  Lists all bundled and installed skills with their source, state, and
94
83
  description. Use 'assistant skills inspect <id>' for detailed metadata
95
84
  or 'assistant skills search' to discover catalog skills.
@@ -97,70 +86,61 @@ or 'assistant skills search' to discover catalog skills.
97
86
  Examples:
98
87
  $ assistant skills list
99
88
  $ assistant skills list --json`,
100
- )
101
- .action(async (opts: { json?: boolean }) => {
102
- try {
103
- const localCatalog = loadSkillCatalog();
104
- const config = getConfig();
105
- const resolved = resolveSkillStates(localCatalog, config);
106
-
107
- // Flat alphabetical list — source is a property, not a section
108
- const allSkills = resolved
109
- .map((r) => {
110
- const s = r.summary;
111
- const source =
112
- s.source === "bundled" || s.source === "plugin"
113
- ? "bundled"
114
- : s.source; // managed, workspace, extra
115
- return {
89
+ )
90
+ .action(async (opts: { json?: boolean }, _cmd) => {
91
+ const r = await cliIpcCall<{
92
+ skills: Array<{
93
+ id: string;
94
+ name: string;
95
+ description: string;
96
+ emoji?: string;
97
+ origin: string;
98
+ kind: string;
99
+ status: string;
100
+ }>;
101
+ }>("listSkills", { queryParams: {} });
102
+ if (!r.ok)
103
+ return exitFromCliResult(
104
+ { ok: false, error: r.error, statusCode: r.statusCode },
105
+ opts.json ?? false,
106
+ );
107
+ const allSkills = r
108
+ .result!.skills.map((s) => ({
116
109
  id: s.id,
117
- name: s.displayName,
110
+ name: s.name,
118
111
  description: s.description,
119
112
  emoji: s.emoji,
120
- source,
121
- state: r.state,
122
- };
123
- })
124
- .sort((a, b) => a.id.localeCompare(b.id));
125
-
126
- if (opts.json) {
127
- console.log(JSON.stringify({ ok: true, skills: allSkills }));
128
- return;
129
- }
130
-
131
- if (allSkills.length === 0) {
132
- log.info("No skills available.");
133
- return;
134
- }
135
-
136
- log.info(`Skills (${allSkills.length}):\n`);
137
- for (const s of allSkills) {
138
- const emoji = s.emoji ? `${s.emoji} ` : "";
139
- const tags = [
140
- s.source,
141
- ...(s.state === "disabled" ? ["disabled"] : []),
142
- ];
143
- log.info(` ${emoji}${s.id} [${tags.join(", ")}]`);
144
- log.info(` ${s.name} — ${s.description}`);
145
- }
146
- } catch (err) {
147
- const msg = err instanceof Error ? err.message : String(err);
148
- if (opts.json) {
149
- console.log(JSON.stringify({ ok: false, error: msg }));
150
- } else {
151
- log.error(`Error: ${msg}`);
152
- }
153
- process.exitCode = 1;
154
- }
155
- });
156
-
157
- skills
158
- .command("inspect <skill-id>")
159
- .description("Show detailed information about a skill")
160
- .option("--json", "Machine-readable JSON output")
161
- .addHelpText(
162
- "after",
163
- `
113
+ source:
114
+ s.origin === "vellum" && s.kind === "bundled"
115
+ ? "bundled"
116
+ : s.origin,
117
+ state: s.status,
118
+ }))
119
+ .sort((a, b) => a.id.localeCompare(b.id));
120
+ if (opts.json) {
121
+ console.log(JSON.stringify({ ok: true, skills: allSkills }));
122
+ return;
123
+ }
124
+ if (allSkills.length === 0) {
125
+ log.info("No skills available.");
126
+ return;
127
+ }
128
+ log.info(`Skills (${allSkills.length}):\n`);
129
+ for (const s of allSkills) {
130
+ 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}`);
134
+ }
135
+ });
136
+
137
+ skills
138
+ .command("inspect <skill-id>")
139
+ .description("Show detailed information about a skill")
140
+ .option("--json", "Machine-readable JSON output")
141
+ .addHelpText(
142
+ "after",
143
+ `
164
144
  Arguments:
165
145
  skill-id Skill identifier. Run 'assistant skills list' to see available IDs.
166
146
 
@@ -171,154 +151,103 @@ entries, tool manifest, activation hints, and feature flags.
171
151
  Examples:
172
152
  $ assistant skills inspect slack
173
153
  $ assistant skills inspect resend-setup --json`,
174
- )
175
- .action(async (skillId: string, opts: { json?: boolean }) => {
176
- try {
177
- const localCatalog = loadSkillCatalog();
178
- const config = getConfig();
179
- const resolved = resolveSkillStates(localCatalog, config);
180
-
181
- const match = resolved.find((r) => r.summary.id === skillId);
182
- if (!match) {
183
- throw new Error(
184
- `Skill "${skillId}" not found. Run 'assistant skills list' to see available skills.`,
185
- );
186
- }
187
-
188
- const { summary, state, configEntry } = match;
189
- const installMeta = readInstallMeta(summary.directoryPath);
190
-
191
- const detail: Record<string, unknown> = {
192
- id: summary.id,
193
- name: summary.displayName,
194
- description: summary.description,
195
- emoji: summary.emoji ?? null,
196
- source: summary.source,
197
- state,
198
- directoryPath: summary.directoryPath,
199
- featureFlag: summary.featureFlag ?? null,
200
- activationHints: summary.activationHints ?? null,
201
- avoidWhen: summary.avoidWhen ?? null,
202
- includes: summary.includes ?? null,
203
- toolManifest: summary.toolManifest
204
- ? {
205
- valid: summary.toolManifest.valid,
206
- toolCount: summary.toolManifest.toolCount,
207
- toolNames: summary.toolManifest.toolNames,
208
- }
209
- : null,
210
- installMeta: installMeta ?? null,
211
- config: configEntry
212
- ? {
213
- enabled: configEntry.enabled !== false,
214
- envKeys: configEntry.env
215
- ? Object.keys(configEntry.env)
216
- : [],
217
- configKeys: configEntry.config
218
- ? Object.keys(configEntry.config)
219
- : [],
220
- }
221
- : null,
222
- };
223
-
224
- if (opts.json) {
225
- console.log(JSON.stringify({ ok: true, skill: detail }));
226
- return;
227
- }
228
-
229
- const emoji = summary.emoji ? `${summary.emoji} ` : "";
230
- log.info(`${emoji}${summary.displayName} (${summary.id})`);
231
- log.info(` ${summary.description}\n`);
232
- log.info(` Source: ${summary.source}`);
233
- log.info(` State: ${state}`);
234
- log.info(` Path: ${summary.directoryPath}`);
235
- if (summary.featureFlag) {
236
- log.info(` Flag: ${summary.featureFlag}`);
237
- }
238
- if (summary.includes?.length) {
239
- log.info(` Includes: ${summary.includes.join(", ")}`);
240
- }
241
- if (summary.activationHints?.length) {
242
- log.info(` Hints: ${summary.activationHints.join("; ")}`);
243
- }
244
- if (summary.avoidWhen?.length) {
245
- log.info(` Avoid: ${summary.avoidWhen.join("; ")}`);
246
- }
247
-
248
- if (summary.toolManifest) {
249
- const tm = summary.toolManifest;
250
- log.info(
251
- `\n Tools: ${tm.valid ? `${tm.toolCount} tool(s)` : "invalid manifest"}`,
252
- );
253
- if (tm.toolNames.length > 0) {
254
- for (const name of tm.toolNames) {
255
- log.info(` - ${name}`);
256
- }
257
- }
258
- }
259
-
260
- if (installMeta) {
261
- log.info(`\n Install metadata:`);
262
- log.info(` Origin: ${installMeta.origin}`);
263
- log.info(` Installed: ${installMeta.installedAt}`);
264
- if (installMeta.installedBy) {
265
- log.info(` Installed by: ${installMeta.installedBy}`);
266
- }
267
- if (installMeta.version) {
268
- log.info(` Version: ${installMeta.version}`);
269
- }
270
- if (installMeta.slug) {
271
- log.info(` Slug: ${installMeta.slug}`);
272
- }
273
- if (installMeta.sourceRepo) {
274
- log.info(` Source repo: ${installMeta.sourceRepo}`);
275
- }
276
- if (installMeta.contentHash) {
277
- log.info(` Hash: ${installMeta.contentHash}`);
278
- }
279
- if (installMeta.backfilledBy) {
280
- log.info(` Backfilled: ${installMeta.backfilledBy}`);
281
- }
282
- }
283
-
284
- if (configEntry) {
285
- log.info(`\n Config:`);
286
- log.info(
287
- ` Enabled: ${configEntry.enabled !== false ? "yes" : "no"}`,
288
- );
289
- if (configEntry.env && Object.keys(configEntry.env).length > 0) {
290
- log.info(` Env vars: ${Object.keys(configEntry.env).join(", ")}`);
154
+ )
155
+ .action(async (skillId: string, opts: { json?: boolean }, _cmd) => {
156
+ const r = await cliIpcCall<{
157
+ id: string;
158
+ name: string;
159
+ description: string;
160
+ emoji: string | null;
161
+ source: string;
162
+ state: string;
163
+ directoryPath: string;
164
+ featureFlag: string | null;
165
+ includes: string[] | null;
166
+ activationHints: string[] | null;
167
+ avoidWhen: string[] | null;
168
+ toolManifest: {
169
+ valid: boolean;
170
+ toolCount: number;
171
+ toolNames: string[];
172
+ } | null;
173
+ installMeta: Record<string, unknown> | null;
174
+ config: {
175
+ enabled: boolean;
176
+ envKeys: string[];
177
+ configKeys: string[];
178
+ } | null;
179
+ }>("skillsLocalInspect", { pathParams: { id: skillId } });
180
+ if (!r.ok)
181
+ return exitFromCliResult(
182
+ { ok: false, error: r.error, statusCode: r.statusCode },
183
+ opts.json ?? false,
184
+ );
185
+ const detail = r.result!;
186
+ if (opts.json) {
187
+ console.log(JSON.stringify({ ok: true, skill: detail }));
188
+ return;
291
189
  }
292
- if (
293
- configEntry.config &&
294
- Object.keys(configEntry.config).length > 0
295
- ) {
190
+ const emoji = detail.emoji ? `${detail.emoji} ` : "";
191
+ log.info(`${emoji}${detail.name} (${detail.id})`);
192
+ log.info(` ${detail.description}\n`);
193
+ log.info(` Source: ${detail.source}`);
194
+ log.info(` State: ${detail.state}`);
195
+ log.info(` Path: ${detail.directoryPath}`);
196
+ if (detail.featureFlag) log.info(` Flag: ${detail.featureFlag}`);
197
+ if (detail.includes?.length)
198
+ log.info(` Includes: ${detail.includes.join(", ")}`);
199
+ if (detail.activationHints?.length)
200
+ log.info(` Hints: ${detail.activationHints.join("; ")}`);
201
+ if (detail.avoidWhen?.length)
202
+ log.info(` Avoid: ${detail.avoidWhen.join("; ")}`);
203
+ if (detail.toolManifest) {
204
+ const tm = detail.toolManifest;
296
205
  log.info(
297
- ` Config keys: ${Object.keys(configEntry.config).join(", ")}`,
206
+ `\n Tools: ${tm.valid ? `${tm.toolCount} tool(s)` : "invalid manifest"}`,
298
207
  );
208
+ for (const name of tm.toolNames) log.info(` - ${name}`);
209
+ }
210
+ if (detail.installMeta) {
211
+ log.info(`\n Install metadata:`);
212
+ if (detail.installMeta.origin)
213
+ log.info(` Origin: ${detail.installMeta.origin}`);
214
+ if (detail.installMeta.installedAt)
215
+ log.info(` Installed: ${detail.installMeta.installedAt}`);
216
+ if (detail.installMeta.installedBy)
217
+ log.info(` Installed by: ${detail.installMeta.installedBy}`);
218
+ if (detail.installMeta.version)
219
+ log.info(` Version: ${detail.installMeta.version}`);
220
+ if (detail.installMeta.slug)
221
+ log.info(` Slug: ${detail.installMeta.slug}`);
222
+ if (detail.installMeta.sourceRepo)
223
+ log.info(` Source repo: ${detail.installMeta.sourceRepo}`);
224
+ if (detail.installMeta.contentHash)
225
+ log.info(` Hash: ${detail.installMeta.contentHash}`);
226
+ if (detail.installMeta.backfilledBy)
227
+ log.info(` Backfilled: ${detail.installMeta.backfilledBy}`);
228
+ }
229
+ if (detail.config) {
230
+ log.info(`\n Config:`);
231
+ log.info(` Enabled: ${detail.config.enabled ? "yes" : "no"}`);
232
+ if (detail.config.envKeys.length)
233
+ log.info(` Env vars: ${detail.config.envKeys.join(", ")}`);
234
+ if (detail.config.configKeys.length)
235
+ log.info(
236
+ ` Config keys: ${detail.config.configKeys.join(", ")}`,
237
+ );
299
238
  }
300
- }
301
- } catch (err) {
302
- const msg = err instanceof Error ? err.message : String(err);
303
- if (opts.json) {
304
- console.log(JSON.stringify({ ok: false, error: msg }));
305
- } else {
306
- log.error(`Error: ${msg}`);
307
- }
308
- process.exitCode = 1;
309
- }
310
- });
311
-
312
- skills
313
- .command("search <query>")
314
- .description(
315
- "Search the Vellum catalog, skills.sh, and clawhub community registries",
316
- )
317
- .option("--limit <n>", "Maximum number of community results", "10")
318
- .option("--json", "Machine-readable JSON output")
319
- .addHelpText(
320
- "after",
321
- `
239
+ });
240
+
241
+ skills
242
+ .command("search <query>")
243
+ .description(
244
+ "Search the Vellum catalog, skills.sh, and clawhub community registries",
245
+ )
246
+ .option("--limit <n>", "Maximum number of community results", "10")
247
+ .option("--json", "Machine-readable JSON output")
248
+ .addHelpText(
249
+ "after",
250
+ `
322
251
  Arguments:
323
252
  query Free-text search term matched against skill names, descriptions,
324
253
  and tags. Searches the Vellum catalog, the skills.sh community
@@ -332,302 +261,157 @@ Examples:
332
261
  $ assistant skills search react
333
262
  $ assistant skills search "file management" --limit 3
334
263
  $ assistant skills search deploy --json`,
335
- )
336
- .action(async (query: string, opts: { limit: string; json?: boolean }) => {
337
- const json = opts.json ?? false;
338
- const limit = parseInt(opts.limit, 10) || 10;
339
-
340
- try {
341
- // ── Bundled + installed skill search ─────────────────────────
342
- const localCatalog = loadSkillCatalog();
343
- const bundledMatches = filterByQuery(localCatalog, query, [
344
- (s) => s.id,
345
- (s) => s.displayName,
346
- (s) => s.description,
347
- ]);
348
-
349
- // ── Vellum catalog search ────────────────────────────────────
350
- const repoSkillsDir = getRepoSkillsDir();
351
- let catalog: CatalogSkill[];
352
- if (repoSkillsDir) {
353
- catalog = readLocalCatalog(repoSkillsDir);
354
- } else {
355
- try {
356
- catalog = await fetchCatalog();
357
- } catch {
358
- catalog = [];
359
- }
360
- }
361
- const localIds = new Set(localCatalog.map((s) => s.id));
362
-
363
- const catalogMatches = filterByQuery(catalog, query, [
364
- (s) => s.id,
365
- (s) => s.name,
366
- (s) => s.description,
367
- ]);
368
-
369
- // ── Community registry searches (non-fatal on failure) ────────
370
- // Run skills.sh and clawhub searches in parallel.
371
- let registryResults: SkillsShSearchResult[] = [];
372
- let registryError: string | undefined;
373
- let clawhubResults: Awaited<
374
- ReturnType<typeof clawhubSearch>
375
- >["skills"] = [];
376
- let clawhubError: string | undefined;
377
-
378
- const [skillsShResult, clawhubResult] = await Promise.allSettled([
379
- searchSkillsRegistry(query, limit),
380
- clawhubSearch(query, { limit }),
381
- ]);
382
-
383
- if (skillsShResult.status === "fulfilled") {
384
- registryResults = skillsShResult.value;
385
- } else {
386
- registryError =
387
- skillsShResult.reason instanceof Error
388
- ? skillsShResult.reason.message
389
- : String(skillsShResult.reason);
390
- }
391
-
392
- if (clawhubResult.status === "fulfilled") {
393
- clawhubResults = clawhubResult.value.skills;
394
- } else {
395
- clawhubError =
396
- clawhubResult.reason instanceof Error
397
- ? clawhubResult.reason.message
398
- : String(clawhubResult.reason);
399
- }
400
-
401
- if (
402
- bundledMatches.length === 0 &&
403
- catalogMatches.length === 0 &&
404
- registryResults.length === 0 &&
405
- clawhubResults.length === 0
406
- ) {
264
+ )
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
+ : [];
285
+
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
+
407
328
  if (json) {
408
329
  console.log(
409
330
  JSON.stringify({
410
331
  ok: true,
411
- bundled: [],
412
- catalog: [],
413
- community: [],
414
- clawhub: [],
415
- audits: {},
416
- ...(registryError ? { registryError } : {}),
417
- ...(clawhubError ? { clawhubError } : {}),
332
+ catalog: vellumSkills,
333
+ community: skillsshResults,
334
+ clawhub: clawhubResults,
335
+ ...(catalogR.ok ? {} : { catalogError: catalogR.error }),
336
+ ...(communityR.ok ? {} : { communityError: communityR.error }),
418
337
  }),
419
338
  );
420
- } else {
421
- log.info(`No skills found for "${query}".`);
422
- if (registryError) {
423
- log.warn(`(skills.sh registry unavailable: ${registryError})`);
424
- }
425
- if (clawhubError) {
426
- log.warn(`(clawhub registry unavailable: ${clawhubError})`);
427
- }
428
- }
429
- return;
430
- }
431
-
432
- // ── Fetch audits for community results ───────────────────────
433
- const allAudits: AuditResponse = {};
434
- if (registryResults.length > 0) {
435
- const sourceToSlugs = new Map<string, string[]>();
436
- for (const r of registryResults) {
437
- const slugs = sourceToSlugs.get(r.source) ?? [];
438
- slugs.push(r.skillId);
439
- sourceToSlugs.set(r.source, slugs);
339
+ return;
440
340
  }
441
- for (const [source, slugs] of sourceToSlugs) {
442
- try {
443
- const audits = await fetchSkillAudits(source, slugs);
444
- for (const [skillId, auditData] of Object.entries(audits)) {
445
- allAudits[`${source}/${skillId}`] = auditData;
446
- }
447
- } catch {
448
- // Audit fetch failures are non-fatal
449
- }
341
+
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;
450
349
  }
451
- }
452
-
453
- if (json) {
454
- console.log(
455
- JSON.stringify({
456
- ok: true,
457
- bundled: bundledMatches.map((s) => ({
458
- id: s.id,
459
- name: s.displayName,
460
- description: s.description,
461
- emoji: s.emoji,
462
- source: s.source,
463
- })),
464
- catalog: catalogMatches,
465
- community: registryResults,
466
- clawhub: clawhubResults,
467
- audits: allAudits,
468
- ...(registryError ? { registryError } : {}),
469
- ...(clawhubError ? { clawhubError } : {}),
470
- }),
471
- );
472
- return;
473
- }
474
-
475
- // ── Installed-state detection ─────────────────────────────────
476
- const skillsDir = getWorkspaceSkillsDir();
477
- const isInstalled = (id: string) =>
478
- existsSync(join(skillsDir, id, "SKILL.md"));
479
- const getInstalledDate = (id: string): string | undefined => {
480
- const meta = readInstallMeta(join(skillsDir, id));
481
- return meta?.installedAt;
482
- };
483
-
484
- // ── Display installed results ─────────────────────────────────
485
- if (bundledMatches.length > 0) {
486
- log.info(`Installed skills (${bundledMatches.length}):\n`);
487
- for (const s of bundledMatches) {
488
- const emoji = s.emoji ? `${s.emoji} ` : "";
489
- const tag =
490
- s.source === "bundled" || s.source === "plugin"
491
- ? " [bundled]"
492
- : "";
493
- log.info(` ${emoji}${s.displayName}${tag}`);
494
- if (s.displayName !== s.id) {
495
- log.info(` ID: ${s.id}`);
496
- }
497
- log.info(` ${s.description}`);
498
- if (s.source !== "bundled" && s.source !== "plugin") {
499
- const meta = readInstallMeta(s.directoryPath);
500
- if (meta?.installedAt) {
501
- log.info(` Installed: ${formatDate(meta.installedAt)}`);
502
- }
350
+
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("");
503
363
  }
504
- log.info("");
505
364
  }
506
- }
507
365
 
508
- // ── Display catalog results ──────────────────────────────────
509
- if (catalogMatches.length > 0) {
510
- log.info(`Vellum catalog (${catalogMatches.length}):\n`);
511
- for (const s of catalogMatches) {
512
- const emoji = s.emoji ? `${s.emoji} ` : "";
513
- const installed = isInstalled(s.id);
514
- const badge = installed ? " [installed]" : "";
515
- log.info(` ${emoji}${s.name}${badge}`);
516
- if (s.name !== s.id) {
517
- log.info(` ID: ${s.id}`);
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("");
518
383
  }
519
- log.info(` ${s.description}`);
520
- if (s.updatedAt) {
521
- log.info(` Updated: ${formatDate(s.updatedAt)}`);
522
- }
523
- if (installed) {
524
- const installedDate = getInstalledDate(s.id);
525
- if (installedDate) {
526
- log.info(` Installed: ${formatDate(installedDate)}`);
527
- }
528
- } else {
529
- log.info(` Install: assistant skills install ${s.id}`);
530
- }
531
-
532
- log.info("");
384
+ } else if (!communityR.ok) {
385
+ log.warn(
386
+ `\n(skills.sh registry unavailable: ${communityR.error})`,
387
+ );
533
388
  }
534
- }
535
-
536
- // ── Display community results ────────────────────────────────
537
- if (registryResults.length > 0) {
538
- log.info(`Community — skills.sh (${registryResults.length}):\n`);
539
- for (const r of registryResults) {
540
- const installed = isInstalled(r.skillId);
541
- const installedFromVellum = localIds.has(r.skillId);
542
- const badge = installedFromVellum
543
- ? " [installed from catalog]"
544
- : installed
545
- ? " [installed]"
546
- : "";
547
- log.info(` ${r.name}${badge}`);
548
- if (r.name !== r.skillId) {
549
- log.info(` ID: ${r.skillId}`);
550
- }
551
- log.info(` Source: ${r.source}`);
552
- log.info(` Installs: ${r.installs}`);
553
- const auditData = allAudits[`${r.source}/${r.skillId}`];
554
- if (auditData) {
555
- log.info(` ${formatAuditBadges(auditData)}`);
556
- } else {
557
- log.info(" Security: no audit data");
558
- }
559
- if (!installed) {
560
- log.info(
561
- ` Install: assistant skills add ${r.source}@${r.skillId}`,
562
- );
563
- }
564
389
 
565
- log.info("");
566
- }
567
- } else if (registryError) {
568
- log.warn(`\n(skills.sh registry unavailable: ${registryError})`);
569
- }
570
-
571
- // ── Display clawhub results ─────────────────────────────────
572
- if (clawhubResults.length > 0) {
573
- log.info(`Community — Clawhub (${clawhubResults.length}):\n`);
574
- for (const r of clawhubResults) {
575
- const installed = isInstalled(r.slug);
576
- const installedFromVellum = localIds.has(r.slug);
577
- const badge = installedFromVellum
578
- ? " [installed from catalog]"
579
- : installed
580
- ? " [installed]"
581
- : "";
582
- log.info(` ${r.name}${badge}`);
583
- if (r.name !== r.slug) {
584
- log.info(` ID: ${r.slug}`);
585
- }
586
- if (r.author) {
587
- log.info(` Author: ${r.author}`);
588
- }
589
- if (r.description) {
590
- log.info(` ${r.description}`);
591
- }
592
- if (r.createdAt > 0) {
593
- log.info(
594
- ` Updated: ${formatDate(new Date(r.createdAt).toISOString())}`,
595
- );
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("");
596
403
  }
597
- if (r.stars > 0) {
598
- log.info(` Stars: ${r.stars}`);
599
- }
600
- if (r.installs > 0) {
601
- log.info(` Installs: ${r.installs}`);
602
- }
603
- if (!installed) {
604
- log.info(` Install: npx clawhub install ${r.slug}`);
605
- }
606
-
607
- log.info("");
608
404
  }
609
- } else if (clawhubError) {
610
- log.warn(`\n(clawhub registry unavailable: ${clawhubError})`);
611
- }
612
- } catch (err) {
613
- const msg = err instanceof Error ? err.message : String(err);
614
- if (json) {
615
- console.log(JSON.stringify({ ok: false, error: msg }));
616
- } else {
617
- log.error(`Error: ${msg}`);
618
- }
619
- process.exitCode = 1;
620
- }
621
- });
622
-
623
- skills
624
- .command("install <skill-id>")
625
- .description("Install a skill from the catalog")
626
- .option("--overwrite", "Replace an already installed skill")
627
- .option("--json", "Machine-readable JSON output")
628
- .addHelpText(
629
- "after",
630
- `
405
+ });
406
+
407
+ skills
408
+ .command("install <skill-id>")
409
+ .description("Install a skill from the catalog")
410
+ .option("--overwrite", "Replace an already installed skill")
411
+ .option("--json", "Machine-readable JSON output")
412
+ .addHelpText(
413
+ "after",
414
+ `
631
415
  Arguments:
632
416
  skill-id Skill identifier from the Vellum catalog. Run 'assistant skills list'
633
417
  to see available IDs. For community skills, use 'assistant skills add'.
@@ -639,62 +423,54 @@ Examples:
639
423
  $ assistant skills install weather
640
424
  $ assistant skills install weather --overwrite
641
425
  $ assistant skills install weather --json`,
642
- )
643
- .action(
644
- async (
645
- skillId: string,
646
- opts: { overwrite?: boolean; json?: boolean },
647
- ) => {
648
- const json = opts.json ?? false;
649
-
650
- try {
651
- // In dev mode, also check the repo-local skills/ directory
652
- const repoSkillsDir = getRepoSkillsDir();
653
- let localSkills: CatalogSkill[] = [];
654
- if (repoSkillsDir) {
655
- localSkills = readLocalCatalog(repoSkillsDir);
656
- }
657
-
658
- // Check local catalog first, then fall back to remote
659
- let entry = localSkills.find((s) => s.id === skillId);
660
- if (!entry) {
661
- const catalog = await fetchCatalog();
662
- entry = catalog.find((s) => s.id === skillId);
663
- }
664
-
665
- if (!entry) {
666
- throw new Error(
667
- `Skill "${skillId}" not found in the Vellum catalog`,
426
+ )
427
+ .action(
428
+ async (
429
+ skillId: string,
430
+ opts: { overwrite?: boolean; json?: boolean },
431
+ _cmd,
432
+ ) => {
433
+ const json = opts.json ?? false;
434
+
435
+ // 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 } },
668
439
  );
669
- }
670
-
671
- // Fetch, extract, and install
672
- await installSkillLocally(skillId, entry, opts.overwrite ?? false);
673
-
674
- if (json) {
675
- console.log(JSON.stringify({ ok: true, skillId }));
676
- } else {
677
- log.info(`Installed skill "${skillId}".`);
678
- }
679
- } catch (err) {
680
- const msg = err instanceof Error ? err.message : String(err);
681
- if (json) {
682
- console.log(JSON.stringify({ ok: false, error: msg }));
683
- } else {
684
- log.error(`Error: ${msg}`);
685
- }
686
- process.exitCode = 1;
687
- }
688
- },
689
- );
440
+ if (!installR.ok) {
441
+ if (json) {
442
+ console.log(
443
+ JSON.stringify({
444
+ ok: false,
445
+ error: installR.error,
446
+ }),
447
+ );
448
+ process.exitCode = 1;
449
+ return;
450
+ }
451
+ log.error(installR.error);
452
+ log.error(
453
+ `Run 'assistant skills search ${skillId}' to check available skills.`,
454
+ );
455
+ process.exitCode = 1;
456
+ return;
457
+ }
690
458
 
691
- skills
692
- .command("uninstall <skill-id>")
693
- .description("Uninstall a previously installed skill")
694
- .option("--json", "Machine-readable JSON output")
695
- .addHelpText(
696
- "after",
697
- `
459
+ if (json) {
460
+ console.log(JSON.stringify({ ok: true, skillId }));
461
+ } else {
462
+ log.info(`Installed skill "${skillId}".`);
463
+ }
464
+ },
465
+ );
466
+
467
+ skills
468
+ .command("uninstall <skill-id>")
469
+ .description("Uninstall a previously installed skill")
470
+ .option("--json", "Machine-readable JSON output")
471
+ .addHelpText(
472
+ "after",
473
+ `
698
474
  Arguments:
699
475
  skill-id Skill identifier to remove. Run 'assistant skills list' to see
700
476
  installed skills.
@@ -704,39 +480,33 @@ Removes the skill directory from the workspace. This action cannot be undone.
704
480
  Examples:
705
481
  $ assistant skills uninstall weather
706
482
  $ assistant skills uninstall weather --json`,
707
- )
708
- .action(async (skillId: string, opts: { json?: boolean }) => {
709
- const json = opts.json ?? false;
710
-
711
- try {
712
- uninstallSkillLocally(skillId);
713
-
714
- if (json) {
715
- console.log(JSON.stringify({ ok: true, skillId }));
716
- } else {
717
- log.info(`Uninstalled skill "${skillId}".`);
718
- }
719
- } catch (err) {
720
- const msg = err instanceof Error ? err.message : String(err);
721
- if (json) {
722
- console.log(JSON.stringify({ ok: false, error: msg }));
723
- } else {
724
- log.error(`Error: ${msg}`);
725
- }
726
- process.exitCode = 1;
727
- }
728
- });
729
-
730
- skills
731
- .command("add <source>")
732
- .description(
733
- "Install a community skill from the skills.sh registry (GitHub)",
734
- )
735
- .option("--overwrite", "Replace an already installed skill")
736
- .option("--json", "Machine-readable JSON output")
737
- .addHelpText(
738
- "after",
739
- `
483
+ )
484
+ .action(async (skillId: string, opts: { json?: boolean }, _cmd) => {
485
+ const r = await cliIpcCall<null>("deleteSkill", {
486
+ pathParams: { id: skillId },
487
+ });
488
+ if (!r.ok)
489
+ return exitFromCliResult(
490
+ { ok: false, error: r.error, statusCode: r.statusCode },
491
+ opts.json ?? false,
492
+ );
493
+ if (opts.json) {
494
+ console.log(JSON.stringify({ ok: true, skillId }));
495
+ } else {
496
+ log.info(`Uninstalled skill "${skillId}".`);
497
+ }
498
+ });
499
+
500
+ skills
501
+ .command("add <source>")
502
+ .description(
503
+ "Install a community skill from the skills.sh registry (GitHub)",
504
+ )
505
+ .option("--overwrite", "Replace an already installed skill")
506
+ .option("--json", "Machine-readable JSON output")
507
+ .addHelpText(
508
+ "after",
509
+ `
740
510
  Arguments:
741
511
  source Skill source in one of these formats:
742
512
  owner/repo@skill-name
@@ -752,42 +522,50 @@ Examples:
752
522
  $ assistant skills add vercel-labs/skills@find-skills
753
523
  $ assistant skills add vercel-labs/skills/find-skills
754
524
  $ assistant skills add vercel-labs/skills@find-skills --overwrite`,
755
- )
756
- .action(
757
- async (source: string, opts: { overwrite?: boolean; json?: boolean }) => {
758
- const json = opts.json ?? false;
759
-
760
- try {
761
- const { owner, repo, skillSlug, ref } = resolveSkillSource(source);
762
-
763
- await installExternalSkill(
764
- owner,
765
- repo,
766
- skillSlug,
767
- opts.overwrite ?? false,
768
- ref,
769
- );
770
-
771
- if (json) {
772
- console.log(
773
- JSON.stringify({
774
- ok: true,
775
- skillSlug,
776
- source: `${owner}/${repo}`,
777
- }),
525
+ )
526
+ .action(
527
+ async (
528
+ source: string,
529
+ opts: { overwrite?: boolean; json?: boolean },
530
+ _cmd,
531
+ ) => {
532
+ const json = opts.json ?? false;
533
+
534
+ // `add` is the community-install entry point (skills.sh-flavoured
535
+ // sources: `owner/repo@skill`, `owner/repo/skill`, or full GitHub
536
+ // URL). Pass `origin: "skillssh"` so the daemon routes via
537
+ // `resolveSkillSource()` + `installExternalSkill()` regardless of
538
+ // slug shape — the auto-detect (`looksLikeSkillsShSlug`) only
539
+ // recognises 3-segment `/`-delimited slugs, so the `@`-format
540
+ // documented in the help text otherwise misroutes to clawhub.
541
+ const r = await cliIpcCall<{ ok: boolean; skillId?: string }>(
542
+ "installSkill",
543
+ {
544
+ body: {
545
+ slug: source,
546
+ origin: "skillssh",
547
+ overwrite: opts.overwrite ?? false,
548
+ },
549
+ },
778
550
  );
779
- } else {
780
- log.info(`Installed skill "${skillSlug}" from ${owner}/${repo}.`);
781
- }
782
- } catch (err) {
783
- const msg = err instanceof Error ? err.message : String(err);
784
- if (json) {
785
- console.log(JSON.stringify({ ok: false, error: msg }));
786
- } else {
787
- log.error(`Error: ${msg}`);
788
- }
789
- process.exitCode = 1;
790
- }
791
- },
792
- );
551
+ if (!r.ok)
552
+ return exitFromCliResult(
553
+ { ok: false, error: r.error, statusCode: r.statusCode },
554
+ json,
555
+ );
556
+
557
+ if (json) {
558
+ console.log(
559
+ JSON.stringify({
560
+ ok: true,
561
+ skillId: r.result?.skillId ?? source,
562
+ }),
563
+ );
564
+ } else {
565
+ log.info(`Installed skill from ${source}.`);
566
+ }
567
+ },
568
+ );
569
+ },
570
+ });
793
571
  }