@vellumai/assistant 0.8.2 → 0.8.4

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 (503) hide show
  1. package/ARCHITECTURE.md +11 -12
  2. package/docker-entrypoint.sh +13 -2
  3. package/docker-init-apt-root.sh +79 -6
  4. package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
  5. package/openapi.yaml +945 -36
  6. package/package.json +1 -1
  7. package/src/__tests__/agent-loop-exit-reason.test.ts +271 -0
  8. package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
  9. package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
  10. package/src/__tests__/agent-loop.test.ts +88 -3
  11. package/src/__tests__/anthropic-provider.test.ts +272 -0
  12. package/src/__tests__/approval-cascade.test.ts +1 -1
  13. package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
  14. package/src/__tests__/channel-delivery-store.test.ts +193 -0
  15. package/src/__tests__/channel-reply-delivery.test.ts +284 -5
  16. package/src/__tests__/channel-retry-sweep.test.ts +274 -1
  17. package/src/__tests__/compaction-events.test.ts +1 -1
  18. package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
  19. package/src/__tests__/compactor-tail-resolution.test.ts +107 -1
  20. package/src/__tests__/config-get-vision-flag.test.ts +136 -0
  21. package/src/__tests__/config-loader-backfill.test.ts +115 -18
  22. package/src/__tests__/config-watcher.test.ts +1 -1
  23. package/src/__tests__/context-token-estimator.test.ts +112 -57
  24. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  25. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +54 -3
  26. package/src/__tests__/conversation-agent-loop-overflow.test.ts +31 -6
  27. package/src/__tests__/conversation-agent-loop.test.ts +77 -3
  28. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
  29. package/src/__tests__/conversation-clean-command.test.ts +137 -0
  30. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
  31. package/src/__tests__/conversation-fork-crud.test.ts +161 -0
  32. package/src/__tests__/conversation-lifecycle.test.ts +1 -1
  33. package/src/__tests__/conversation-load-cleaned-at.test.ts +279 -0
  34. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  35. package/src/__tests__/conversation-media-retry.test.ts +19 -8
  36. package/src/__tests__/conversation-pairing.test.ts +2 -2
  37. package/src/__tests__/conversation-process-callsite.test.ts +1 -1
  38. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -1
  39. package/src/__tests__/conversation-queue.test.ts +1 -1
  40. package/src/__tests__/conversation-runtime-assembly.test.ts +290 -85
  41. package/src/__tests__/conversation-seed-composer.test.ts +66 -4
  42. package/src/__tests__/conversation-slash-commands.test.ts +36 -8
  43. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  44. package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
  45. package/src/__tests__/conversation-speed-override.test.ts +1 -1
  46. package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
  47. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -1
  48. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  49. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  50. package/src/__tests__/credential-security-invariants.test.ts +6 -0
  51. package/src/__tests__/cu-unified-flow.test.ts +10 -1
  52. package/src/__tests__/date-context.test.ts +45 -0
  53. package/src/__tests__/dm-backfill.test.ts +64 -0
  54. package/src/__tests__/dm-persistence.test.ts +33 -0
  55. package/src/__tests__/document-find-replace.test.ts +501 -0
  56. package/src/__tests__/external-plugin-loader.test.ts +91 -19
  57. package/src/__tests__/first-greeting.test.ts +23 -2
  58. package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
  59. package/src/__tests__/guardian-dispatch.test.ts +1 -0
  60. package/src/__tests__/headless-browser-navigate.test.ts +172 -0
  61. package/src/__tests__/heartbeat-service.test.ts +24 -164
  62. package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
  63. package/src/__tests__/host-app-control-proxy.test.ts +241 -0
  64. package/src/__tests__/host-bash-proxy.test.ts +6 -0
  65. package/src/__tests__/host-browser-proxy.test.ts +10 -0
  66. package/src/__tests__/host-cu-proxy.test.ts +8 -1
  67. package/src/__tests__/host-file-proxy.test.ts +8 -1
  68. package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
  69. package/src/__tests__/host-transfer-proxy.test.ts +8 -1
  70. package/src/__tests__/identity-routes.test.ts +57 -0
  71. package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
  72. package/src/__tests__/injector-background-turn.test.ts +153 -0
  73. package/src/__tests__/injector-chain.test.ts +7 -0
  74. package/src/__tests__/injector-document-comments.test.ts +378 -0
  75. package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
  76. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +9 -2
  77. package/src/__tests__/list-messages-attachments.test.ts +21 -17
  78. package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
  79. package/src/__tests__/list-messages-page-latest.test.ts +130 -14
  80. package/src/__tests__/list-messages-tool-merge.test.ts +17 -16
  81. package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
  82. package/src/__tests__/llm-catalog-parity.test.ts +3 -0
  83. package/src/__tests__/llm-context-normalization.test.ts +0 -2
  84. package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
  85. package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
  86. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -0
  87. package/src/__tests__/llm-resolver.test.ts +340 -3
  88. package/src/__tests__/log-export-routes.test.ts +99 -2
  89. package/src/__tests__/managed-profile-guard.test.ts +10 -0
  90. package/src/__tests__/message-queue-steer.test.ts +114 -0
  91. package/src/__tests__/notification-decision-fallback.test.ts +0 -91
  92. package/src/__tests__/notification-decision-strategy.test.ts +14 -31
  93. package/src/__tests__/notification-deep-link.test.ts +15 -0
  94. package/src/__tests__/notification-guardian-path.test.ts +1 -2
  95. package/src/__tests__/notification-platform-adapter.test.ts +5 -4
  96. package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
  97. package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
  98. package/src/__tests__/openai-provider.test.ts +323 -3
  99. package/src/__tests__/openai-responses-cutover-guard.test.ts +3 -3
  100. package/src/__tests__/openai-responses-provider.test.ts +4 -4
  101. package/src/__tests__/openrouter-provider-only.test.ts +51 -3
  102. package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
  103. package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
  104. package/src/__tests__/pending-interactions-resolved-event.test.ts +190 -0
  105. package/src/__tests__/platform-proxy-context.test.ts +6 -1
  106. package/src/__tests__/platform.test.ts +0 -3
  107. package/src/__tests__/plugin-source-watcher.test.ts +302 -0
  108. package/src/__tests__/plugin-tool-contribution.test.ts +3 -3
  109. package/src/__tests__/plugin-types.test.ts +2 -2
  110. package/src/__tests__/process-message-background-slack.test.ts +1 -51
  111. package/src/__tests__/process-message-display-content.test.ts +21 -16
  112. package/src/__tests__/provider-catalog-visibility.test.ts +16 -0
  113. package/src/__tests__/provider-platform-proxy-integration.test.ts +27 -25
  114. package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
  115. package/src/__tests__/server-history-render.test.ts +83 -4
  116. package/src/__tests__/steer-tool-repair.test.ts +249 -0
  117. package/src/__tests__/system-prompt.test.ts +57 -101
  118. package/src/__tests__/terminal-tools.test.ts +11 -1
  119. package/src/__tests__/thinking-block-replay.test.ts +113 -0
  120. package/src/__tests__/thread-backfill.test.ts +370 -22
  121. package/src/__tests__/tool-executor.test.ts +90 -1
  122. package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
  123. package/src/__tests__/twilio-routes.test.ts +1 -1
  124. package/src/__tests__/web-fetch.test.ts +2 -2
  125. package/src/__tests__/workspace-git-service.test.ts +88 -5
  126. package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
  127. package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
  128. package/src/a2a/__tests__/agent-card.test.ts +98 -0
  129. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
  130. package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
  131. package/src/a2a/__tests__/task-store.test.ts +246 -0
  132. package/src/a2a/agent-card.ts +58 -0
  133. package/src/a2a/feature-gate.ts +8 -0
  134. package/src/a2a/protocol-constants.ts +21 -0
  135. package/src/a2a/protocol-errors.ts +50 -0
  136. package/src/a2a/protocol-types.ts +162 -0
  137. package/src/a2a/task-store.ts +168 -0
  138. package/src/agent/attachments.ts +1 -0
  139. package/src/agent/loop.ts +208 -22
  140. package/src/background-wake/next-wake.test.ts +289 -0
  141. package/src/background-wake/next-wake.ts +172 -0
  142. package/src/browser/operations.ts +15 -0
  143. package/src/channels/config.ts +9 -0
  144. package/src/channels/types.ts +14 -0
  145. package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
  146. package/src/cli/commands/__tests__/memory-v2.test.ts +9 -12
  147. package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
  148. package/src/cli/commands/__tests__/schedules.test.ts +469 -0
  149. package/src/cli/commands/conversations.ts +128 -1
  150. package/src/cli/commands/inference-providers.ts +147 -1
  151. package/src/cli/commands/memory-v2.ts +308 -0
  152. package/src/cli/commands/notifications.ts +89 -37
  153. package/src/cli/commands/plugins.ts +67 -0
  154. package/src/cli/commands/schedules.ts +297 -5
  155. package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
  156. package/src/cli/lib/install-from-github.ts +8 -9
  157. package/src/cli/lib/search-plugins.ts +163 -0
  158. package/src/cli/program.ts +14 -0
  159. package/src/cli/utils/conversation-id.ts +17 -5
  160. package/src/config/assistant-feature-flags.ts +24 -54
  161. package/src/config/bundled-skills/app-builder/SKILL.md +117 -1
  162. package/src/config/bundled-skills/document-editor/SKILL.md +115 -0
  163. package/src/config/bundled-skills/document-editor/TOOLS.json +240 -0
  164. package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
  165. package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
  166. package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
  167. package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
  168. package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
  169. package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
  170. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
  171. package/src/config/bundled-skills/schedule/SKILL.md +8 -0
  172. package/src/config/bundled-tool-registry.ts +22 -12
  173. package/src/config/call-site-defaults.ts +124 -0
  174. package/src/config/feature-flag-registry.json +111 -23
  175. package/src/config/llm-resolver.ts +66 -1
  176. package/src/config/schema.ts +2 -0
  177. package/src/config/schemas/__tests__/memory-v2.test.ts +7 -3
  178. package/src/config/schemas/call-site-catalog.ts +21 -0
  179. package/src/config/schemas/channels.ts +9 -0
  180. package/src/config/schemas/conversations.ts +10 -0
  181. package/src/config/schemas/heartbeat.ts +14 -0
  182. package/src/config/schemas/llm.ts +4 -3
  183. package/src/config/schemas/memory-retrospective.ts +1 -1
  184. package/src/config/schemas/memory-v2.ts +51 -4
  185. package/src/config/schemas/memory.ts +3 -1
  186. package/src/config/seed-inference-profiles.ts +99 -29
  187. package/src/context/compactor.ts +80 -13
  188. package/src/context/token-estimator.ts +72 -31
  189. package/src/context/window-manager.ts +25 -0
  190. package/src/credential-health/credential-health-service.ts +34 -19
  191. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -22
  192. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
  193. package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
  194. package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
  195. package/src/daemon/conversation-agent-loop-handlers.ts +231 -23
  196. package/src/daemon/conversation-agent-loop.ts +252 -56
  197. package/src/daemon/conversation-lifecycle.ts +142 -116
  198. package/src/daemon/conversation-messaging.ts +3 -0
  199. package/src/daemon/conversation-process.ts +273 -0
  200. package/src/daemon/conversation-queue-manager.ts +14 -0
  201. package/src/daemon/conversation-runtime-assembly.ts +144 -75
  202. package/src/daemon/conversation-slash.ts +37 -5
  203. package/src/daemon/conversation-surfaces.ts +45 -2
  204. package/src/daemon/conversation-tool-setup.ts +7 -0
  205. package/src/daemon/conversation.ts +42 -12
  206. package/src/daemon/date-context.ts +40 -0
  207. package/src/daemon/first-greeting.ts +10 -0
  208. package/src/daemon/guardian-action-generators.ts +1 -125
  209. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
  210. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
  211. package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
  212. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
  213. package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
  214. package/src/daemon/handlers/config-a2a.ts +449 -0
  215. package/src/daemon/handlers/config-model.test.ts +1 -0
  216. package/src/daemon/handlers/conversations.ts +80 -0
  217. package/src/daemon/handlers/shared.ts +92 -29
  218. package/src/daemon/host-app-control-proxy.ts +69 -18
  219. package/src/daemon/host-bash-proxy.ts +1 -1
  220. package/src/daemon/host-cu-proxy.ts +1 -1
  221. package/src/daemon/host-file-proxy.ts +1 -1
  222. package/src/daemon/host-proxy-preactivation.ts +85 -18
  223. package/src/daemon/host-transfer-proxy.ts +1 -1
  224. package/src/daemon/lifecycle.ts +67 -65
  225. package/src/daemon/memory-v2-startup.ts +49 -13
  226. package/src/daemon/message-protocol.ts +4 -0
  227. package/src/daemon/message-types/conversations.ts +8 -0
  228. package/src/daemon/message-types/document-comments.ts +50 -0
  229. package/src/daemon/message-types/messages.ts +68 -1
  230. package/src/daemon/message-types/notifications.ts +21 -0
  231. package/src/daemon/message-types/surfaces.ts +3 -1
  232. package/src/daemon/message-types/web-activity.ts +57 -0
  233. package/src/daemon/pkb-reminder-builder.test.ts +10 -53
  234. package/src/daemon/pkb-reminder-builder.ts +4 -19
  235. package/src/daemon/plugin-source-watcher.ts +135 -3
  236. package/src/daemon/process-message.ts +72 -12
  237. package/src/daemon/query-complexity-router.ts +75 -0
  238. package/src/daemon/skill-memory-refresh.ts +5 -1
  239. package/src/daemon/trust-context.ts +6 -0
  240. package/src/daemon/wake-target-adapter.ts +2 -0
  241. package/src/documents/document-comments-store.test.ts +338 -0
  242. package/src/documents/document-comments-store.ts +237 -0
  243. package/src/documents/document-store.ts +202 -0
  244. package/src/export/__tests__/transcript-formatter.test.ts +121 -0
  245. package/src/export/transcript-formatter.ts +54 -20
  246. package/src/heartbeat/__tests__/heartbeat-service.test.ts +44 -1
  247. package/src/heartbeat/heartbeat-service.ts +35 -191
  248. package/src/home/__tests__/feed-types.test.ts +40 -0
  249. package/src/home/__tests__/suggested-prompts.test.ts +33 -2
  250. package/src/home/feed-types.ts +20 -3
  251. package/src/home/home-content-refresh.ts +52 -0
  252. package/src/home/home-greeting-cache.ts +69 -0
  253. package/src/home/home-greeting.ts +94 -0
  254. package/src/home/suggested-prompts.ts +177 -9
  255. package/src/ipc/cli-client.ts +147 -45
  256. package/src/memory/__tests__/conversation-queries.test.ts +220 -0
  257. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
  258. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
  259. package/src/memory/__tests__/memory-retrospective-job.test.ts +407 -10
  260. package/src/memory/conversation-crud.ts +133 -43
  261. package/src/memory/conversation-queries.ts +87 -1
  262. package/src/memory/conversation-title-service.ts +26 -4
  263. package/src/memory/db-init.ts +22 -0
  264. package/src/memory/delivery-crud.ts +41 -0
  265. package/src/memory/delivery-status.ts +141 -15
  266. package/src/memory/external-conversation-store.ts +32 -1
  267. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +84 -3
  268. package/src/memory/graph/conversation-graph-memory.ts +18 -6
  269. package/src/memory/graph/tools.ts +6 -37
  270. package/src/memory/invite-store.ts +53 -0
  271. package/src/memory/jobs-worker.ts +21 -1
  272. package/src/memory/llm-request-log-source-clickhouse.ts +7 -2
  273. package/src/memory/llm-request-log-store.ts +92 -1
  274. package/src/memory/memory-retrospective-constants.ts +28 -0
  275. package/src/memory/memory-retrospective-enqueue.ts +4 -22
  276. package/src/memory/memory-retrospective-job.ts +438 -21
  277. package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
  278. package/src/memory/memory-v2-activation-log-store.ts +26 -8
  279. package/src/memory/migrations/100-core-tables.ts +1 -0
  280. package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
  281. package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
  282. package/src/memory/migrations/251-a2a-tasks.ts +49 -0
  283. package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
  284. package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
  285. package/src/memory/migrations/253-document-comments.ts +47 -0
  286. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
  287. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
  288. package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
  289. package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
  290. package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
  291. package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
  292. package/src/memory/migrations/index.ts +20 -0
  293. package/src/memory/migrations/registry.ts +33 -0
  294. package/src/memory/onboarding-events-store.ts +7 -0
  295. package/src/memory/schema/a2a.ts +15 -0
  296. package/src/memory/schema/calls.ts +1 -0
  297. package/src/memory/schema/conversations.ts +3 -0
  298. package/src/memory/schema/index.ts +1 -0
  299. package/src/memory/schema/inference.ts +2 -0
  300. package/src/memory/schema/infrastructure.ts +2 -0
  301. package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
  302. package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
  303. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
  304. package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
  305. package/src/memory/v2/__tests__/injection.test.ts +221 -17
  306. package/src/memory/v2/__tests__/page-index.test.ts +365 -1
  307. package/src/memory/v2/__tests__/router.test.ts +489 -1
  308. package/src/memory/v2/__tests__/static-context.test.ts +12 -1
  309. package/src/memory/v2/activation-store.ts +14 -16
  310. package/src/memory/v2/cli-command-content.ts +19 -0
  311. package/src/memory/v2/cli-command-store.ts +304 -0
  312. package/src/memory/v2/consolidation-job.ts +14 -0
  313. package/src/memory/v2/frontmatter-sweep.ts +7 -1
  314. package/src/memory/v2/injection-events.ts +101 -0
  315. package/src/memory/v2/injection.ts +69 -29
  316. package/src/memory/v2/page-index.ts +246 -19
  317. package/src/memory/v2/page-store.ts +18 -0
  318. package/src/memory/v2/router.ts +209 -55
  319. package/src/memory/v2/static-context.ts +4 -4
  320. package/src/memory/v2/types.ts +23 -0
  321. package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
  322. package/src/messaging/providers/a2a/deliver.ts +156 -0
  323. package/src/messaging/providers/gmail/client.ts +9 -2
  324. package/src/messaging/providers/index.ts +18 -3
  325. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
  326. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
  327. package/src/messaging/providers/slack/adapter.ts +178 -25
  328. package/src/messaging/providers/slack/api.test.ts +54 -0
  329. package/src/messaging/providers/slack/api.ts +119 -3
  330. package/src/messaging/providers/slack/client.ts +12 -0
  331. package/src/messaging/providers/slack/deep-link.ts +20 -1
  332. package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
  333. package/src/messaging/providers/slack/message-metadata.ts +156 -0
  334. package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
  335. package/src/messaging/providers/slack/render-transcript.ts +176 -49
  336. package/src/messaging/providers/slack/send.test.ts +77 -0
  337. package/src/messaging/providers/slack/send.ts +8 -2
  338. package/src/messaging/providers/slack/types.ts +14 -0
  339. package/src/notifications/__tests__/broadcaster.test.ts +203 -0
  340. package/src/notifications/__tests__/decision-engine.test.ts +283 -0
  341. package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
  342. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +5 -1
  343. package/src/notifications/__tests__/home-feed-side-effect.test.ts +521 -36
  344. package/src/notifications/adapters/macos.ts +12 -2
  345. package/src/notifications/broadcaster.ts +29 -4
  346. package/src/notifications/conversation-seed-composer.ts +14 -2
  347. package/src/notifications/copy-composer.ts +17 -64
  348. package/src/notifications/decision-engine.ts +111 -44
  349. package/src/notifications/deferred-emit.ts +135 -0
  350. package/src/notifications/deterministic-checks.ts +96 -0
  351. package/src/notifications/emit-signal.ts +10 -1
  352. package/src/notifications/home-feed-side-effect.ts +136 -27
  353. package/src/notifications/signal.ts +0 -4
  354. package/src/notifications/types.ts +8 -0
  355. package/src/oauth/connect-orchestrator.ts +3 -0
  356. package/src/oauth/credential-token-resolver.ts +2 -0
  357. package/src/oauth/manual-token-connection.ts +19 -0
  358. package/src/oauth/oauth-store.ts +12 -0
  359. package/src/oauth/platform-connection.test.ts +43 -3
  360. package/src/oauth/platform-connection.ts +13 -4
  361. package/src/oauth/seed-providers.ts +22 -0
  362. package/src/permissions/prompter.ts +5 -2
  363. package/src/permissions/secret-prompter.ts +4 -1
  364. package/src/plugins/defaults/injectors.ts +118 -26
  365. package/src/plugins/external-plugin-loader.ts +82 -10
  366. package/src/plugins/types.ts +16 -7
  367. package/src/prompts/__tests__/system-prompt.test.ts +44 -45
  368. package/src/prompts/__tests__/task-progress-hint-section.test.ts +4 -8
  369. package/src/prompts/normalize-onboarding.ts +40 -0
  370. package/src/prompts/sections.ts +32 -14
  371. package/src/prompts/system-prompt.ts +105 -76
  372. package/src/prompts/template-detection.ts +37 -0
  373. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
  374. package/src/prompts/templates/BOOTSTRAP.md +13 -5
  375. package/src/prompts/templates/VOICE.md +3 -0
  376. package/src/prompts/templates/system-sections.ts +51 -10
  377. package/src/providers/__tests__/inference.test.ts +2 -0
  378. package/src/providers/anthropic/client.ts +132 -5
  379. package/src/providers/call-site-routing.ts +24 -6
  380. package/src/providers/connection-resolution.ts +63 -13
  381. package/src/providers/fireworks/client.ts +20 -2
  382. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
  383. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
  384. package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
  385. package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
  386. package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
  387. package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
  388. package/src/providers/inference/adapter-factory.ts +24 -21
  389. package/src/providers/inference/auth.ts +15 -3
  390. package/src/providers/inference/backfill.ts +14 -1
  391. package/src/providers/inference/codex-token-refresh.ts +128 -0
  392. package/src/providers/inference/connections.ts +85 -5
  393. package/src/providers/inference/resolve-auth.ts +50 -5
  394. package/src/providers/model-catalog.ts +244 -242
  395. package/src/providers/model-intents.ts +3 -3
  396. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
  397. package/src/providers/openai/chat-completions-provider.ts +215 -25
  398. package/src/providers/openai/responses-provider.ts +9 -3
  399. package/src/providers/openrouter/client.ts +46 -4
  400. package/src/providers/platform-proxy/constants.ts +3 -4
  401. package/src/providers/provider-catalog-visibility.ts +3 -1
  402. package/src/providers/provider-send-message.ts +27 -12
  403. package/src/providers/registry.ts +30 -1
  404. package/src/providers/types.ts +25 -0
  405. package/src/runtime/__tests__/agent-wake.test.ts +214 -0
  406. package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
  407. package/src/runtime/agent-wake.ts +212 -57
  408. package/src/runtime/auth/route-policy.ts +20 -3
  409. package/src/runtime/background-job-runner.ts +26 -0
  410. package/src/runtime/channel-reply-delivery.ts +182 -47
  411. package/src/runtime/channel-retry-sweep.ts +141 -16
  412. package/src/runtime/http-server.ts +7 -16
  413. package/src/runtime/http-types.ts +7 -51
  414. package/src/runtime/pending-interactions.ts +51 -8
  415. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
  416. package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
  417. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +121 -5
  418. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
  419. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
  420. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
  421. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +271 -0
  422. package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
  423. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
  424. package/src/runtime/routes/approval-routes.ts +4 -1
  425. package/src/runtime/routes/channel-availability-routes.ts +5 -0
  426. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
  427. package/src/runtime/routes/consolidation-routes.ts +100 -0
  428. package/src/runtime/routes/content-source-routes.ts +78 -0
  429. package/src/runtime/routes/conversation-cli-routes.ts +146 -1
  430. package/src/runtime/routes/conversation-query-routes.ts +130 -12
  431. package/src/runtime/routes/conversation-routes.ts +288 -76
  432. package/src/runtime/routes/document-comments-routes.ts +287 -0
  433. package/src/runtime/routes/documents-routes.ts +33 -0
  434. package/src/runtime/routes/home-feed-routes.ts +6 -3
  435. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  436. package/src/runtime/routes/host-browser-routes.ts +8 -1
  437. package/src/runtime/routes/identity-routes.ts +21 -0
  438. package/src/runtime/routes/inbound-message-handler.ts +288 -58
  439. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
  440. package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
  441. package/src/runtime/routes/index.ts +14 -4
  442. package/src/runtime/routes/inference-provider-connection-routes.ts +192 -3
  443. package/src/runtime/routes/integrations/a2a.ts +294 -0
  444. package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
  445. package/src/runtime/routes/log-export-routes.ts +39 -0
  446. package/src/runtime/routes/memory-v2-routes.ts +217 -0
  447. package/src/runtime/routes/notification-routes.ts +19 -2
  448. package/src/runtime/routes/question-routes.ts +4 -1
  449. package/src/runtime/routes/sanity-routes.ts +159 -0
  450. package/src/runtime/routes/slack-channel-routes.ts +187 -0
  451. package/src/runtime/routes/subagents-routes.ts +41 -0
  452. package/src/runtime/services/conversation-serializer.ts +30 -4
  453. package/src/schedule/integration-status.ts +3 -1
  454. package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
  455. package/src/security/oauth2-device-code.ts +307 -0
  456. package/src/security/oauth2.ts +26 -9
  457. package/src/security/secure-keys.ts +5 -0
  458. package/src/skills/catalog-install.ts +6 -2
  459. package/src/subagent/manager.ts +2 -0
  460. package/src/tools/browser/__tests__/pinned-tabs.test.ts +80 -0
  461. package/src/tools/browser/browser-execution.ts +93 -0
  462. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
  463. package/src/tools/browser/cdp-client/__tests__/types.test.ts +1 -0
  464. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +10 -0
  465. package/src/tools/browser/cdp-client/extension-cdp-client.ts +15 -1
  466. package/src/tools/browser/cdp-client/factory.ts +87 -3
  467. package/src/tools/browser/cdp-client/local-cdp-client.ts +9 -0
  468. package/src/tools/browser/cdp-client/types.ts +36 -0
  469. package/src/tools/browser/pinned-tabs.ts +90 -0
  470. package/src/tools/document/document-comment-tool.test.ts +379 -0
  471. package/src/tools/document/document-comment-tool.ts +156 -0
  472. package/src/tools/document/document-tool.ts +128 -2
  473. package/src/tools/memory/register.ts +1 -9
  474. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
  475. package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
  476. package/src/tools/network/domain-normalize.ts +17 -0
  477. package/src/tools/network/web-fetch.ts +213 -64
  478. package/src/tools/network/web-search.ts +191 -66
  479. package/src/tools/registry.ts +2 -2
  480. package/src/tools/terminal/safe-env.ts +3 -2
  481. package/src/tools/tool-approval-handler.ts +19 -12
  482. package/src/tools/types.ts +41 -2
  483. package/src/tools/ui-surface/definitions.ts +3 -1
  484. package/src/types/onboarding-context.ts +4 -0
  485. package/src/util/__tests__/favicon.test.ts +84 -0
  486. package/src/util/favicon.ts +40 -0
  487. package/src/util/platform.ts +0 -5
  488. package/src/workspace/git-service.ts +75 -4
  489. package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
  490. package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
  491. package/src/workspace/migrations/registry.ts +4 -0
  492. package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
  493. package/src/config/bundled-skills/document/SKILL.md +0 -54
  494. package/src/config/bundled-skills/document/TOOLS.json +0 -106
  495. package/src/daemon/seed-files.ts +0 -18
  496. package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
  497. package/src/runtime/guardian-action-conversation-turn.ts +0 -99
  498. package/src/runtime/routes/interface-routes.ts +0 -43
  499. /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
  500. /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
  501. /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
  502. /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
  503. /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
@@ -1,9 +1,14 @@
1
1
  import type { Command } from "commander";
2
2
 
3
- import { cliIpcCall } from "../../ipc/cli-client.js";
3
+ import {
4
+ cliIpcCall,
5
+ exitCodeFromIpcResult,
6
+ exitFromIpcResult,
7
+ } from "../../ipc/cli-client.js";
4
8
  import { registerCommand } from "../lib/register-command.js";
5
9
  import { log } from "../logger.js";
6
10
  import { shouldOutputJson, writeOutput } from "../output.js";
11
+ import { tryResolveConversationId } from "../utils/conversation-id.js";
7
12
 
8
13
  // ---------------------------------------------------------------------------
9
14
  // Command registration
@@ -26,11 +31,14 @@ source channel, event name, and attention hints. The decision engine evaluates
26
31
  whether and where to deliver the notification based on connected channels,
27
32
  urgency, and user preferences.
28
33
 
34
+ Minimal usage: only --message is required. Add --urgent for a push + visual
35
+ flag in the inbox. Source channel/event name fall back to assistant_tool /
36
+ assistant.share when omitted.
37
+
29
38
  Examples:
30
- $ assistant notifications send --source-channel assistant_tool --source-event-name user.send_notification --message "Build finished"
31
- $ assistant notifications send --source-channel scheduler --source-event-name schedule.notify --message "Stand-up in 5 minutes" --urgency high
32
- $ assistant notifications send --source-channel watcher --source-event-name watcher.notification --message "File changed" --no-requires-action --is-async-background
33
- $ assistant notifications send --source-channel assistant_tool --source-event-name user.send_notification --message "Deploy complete" --preferred-channels vellum,telegram --json`,
39
+ $ assistant notifications send --message "Build finished"
40
+ $ assistant notifications send --message "Pager: prod is down" --urgent
41
+ $ assistant notifications send --message "Build green" --conversation-id 649c4645-3a6f-4ded-a713-504f02ca806b`,
34
42
  );
35
43
 
36
44
  // -------------------------------------------------------------------------
@@ -40,28 +48,33 @@ Examples:
40
48
  notifications
41
49
  .command("send")
42
50
  .description(
43
- "Send a notification through the unified notification router",
51
+ "Send a notification through the unified notification router. Only --message is required; pass --urgent for a push + visual flag.",
44
52
  )
45
53
  .requiredOption(
54
+ "--message <message>",
55
+ "Notification message the user should receive",
56
+ )
57
+ .option(
58
+ "--urgent",
59
+ "Mark this notification as urgent (fires push + visual flag in inbox)",
60
+ false,
61
+ )
62
+ .option(
46
63
  "--source-channel <channel>",
47
- "Source channel producing this notification",
64
+ "Source channel producing this notification (default: assistant_tool)",
48
65
  )
49
- .requiredOption(
66
+ .option(
50
67
  "--source-event-name <name>",
51
- "Event name for audit, routing, and dedupe grouping",
52
- )
53
- .requiredOption(
54
- "--message <message>",
55
- "Notification message the user should receive",
68
+ "Event name for audit, routing, and dedupe grouping (default: assistant.share)",
56
69
  )
57
70
  .option("--title <title>", "Optional notification title")
58
71
  .option(
59
72
  "--urgency <urgency>",
60
- "Urgency hint: low, medium, high, critical (default: medium)",
73
+ "Urgency hint: low, medium, high, critical (default: low; use --urgent for critical)",
61
74
  )
62
75
  .option(
63
76
  "--requires-action",
64
- "Whether the notification expects user action (default: true)",
77
+ "Whether the notification expects user action (default: false; use --urgent to force true)",
65
78
  )
66
79
  .option(
67
80
  "--no-requires-action",
@@ -111,15 +124,16 @@ Examples:
111
124
  "after",
112
125
  `
113
126
  Arguments:
114
- --source-channel One of the registered source channels (see "assistant notifications --help")
115
- --source-event-name One of the registered event names (see "assistant notifications --help")
116
127
  --message The notification body text (required, must be non-empty)
128
+ --urgent Shortcut that maps to urgency=critical + requires-action=true
117
129
 
118
130
  Behavioral notes:
119
131
  - The signal is emitted through the full notification pipeline: event store,
120
132
  decision engine, deterministic checks, and channel dispatch.
121
- - --requires-action defaults to true; use --no-requires-action to disable.
122
- - --urgency defaults to medium if not specified.
133
+ - --urgent overrides --urgency and --requires-action defaults so the signal
134
+ is treated as critical and requires user action. Explicit --urgency /
135
+ --requires-action flags still win for back-compat.
136
+ - Without --urgent, --urgency defaults to low and --requires-action to false.
123
137
  - --preferred-channels are hints only; the decision engine may override them.
124
138
  - --dedupe-key suppresses duplicate signals with the same key.
125
139
  - --conversation-id pins delivery to an existing vellum conversation
@@ -127,20 +141,20 @@ Behavioral notes:
127
141
  binding-based pairing for their external threads.
128
142
 
129
143
  Examples:
130
- $ assistant notifications send --source-channel assistant_tool --source-event-name user.send_notification --message "Task complete"
131
- $ assistant notifications send --source-channel scheduler --source-event-name schedule.notify --message "Meeting in 5 min" --urgency high --title "Reminder"
132
- $ assistant notifications send --source-channel watcher --source-event-name watcher.notification --message "Detected change" --no-requires-action --is-async-background --json
133
- $ assistant notifications send --source-channel assistant_tool --source-event-name user.send_notification --message "Build green" --conversation-id 649c4645-3a6f-4ded-a713-504f02ca806b`,
144
+ $ assistant notifications send --message "Task complete"
145
+ $ assistant notifications send --message "Pager: prod is down" --urgent
146
+ $ assistant notifications send --message "Build green" --conversation-id 649c4645-3a6f-4ded-a713-504f02ca806b`,
134
147
  )
135
148
  .action(
136
149
  async (
137
150
  opts: {
138
- sourceChannel: string;
139
- sourceEventName: string;
151
+ sourceChannel?: string;
152
+ sourceEventName?: string;
140
153
  message: string;
154
+ urgent: boolean;
141
155
  title?: string;
142
156
  urgency?: string;
143
- requiresAction: boolean;
157
+ requiresAction?: boolean;
144
158
  isAsyncBackground: boolean;
145
159
  visibleInSourceNow: boolean;
146
160
  deadlineAt?: string;
@@ -153,6 +167,11 @@ Examples:
153
167
  cmd: Command,
154
168
  ) => {
155
169
  try {
170
+ // Apply defaults for optional source fields (minimal-surface
171
+ // ergonomics; explicit values from the CLI still win).
172
+ const sourceChannel = opts.sourceChannel ?? "assistant_tool";
173
+ const sourceEventName = opts.sourceEventName ?? "assistant.share";
174
+
156
175
  // Validate --message (keep basic validation for immediate CLI feedback)
157
176
  const message = opts.message.trim();
158
177
  if (message.length === 0) {
@@ -164,8 +183,15 @@ Examples:
164
183
  return;
165
184
  }
166
185
 
186
+ // --urgent is a shortcut for urgency=critical + requiresAction=true.
187
+ // Explicit --urgency / --requires-action flags still win so the
188
+ // back-compat path keeps working during the deprecation window.
189
+ const urgentDefaults = opts.urgent
190
+ ? { urgency: "critical", requiresAction: true }
191
+ : { urgency: "low", requiresAction: false };
192
+
167
193
  // Validate --urgency
168
- const urgency = opts.urgency ?? "medium";
194
+ const urgency = opts.urgency ?? urgentDefaults.urgency;
169
195
  if (
170
196
  urgency !== "low" &&
171
197
  urgency !== "medium" &&
@@ -179,6 +205,8 @@ Examples:
179
205
  process.exitCode = 1;
180
206
  return;
181
207
  }
208
+ const requiresAction =
209
+ opts.requiresAction ?? urgentDefaults.requiresAction;
182
210
 
183
211
  // Parse --deadline-at
184
212
  let deadlineAt: number | undefined;
@@ -221,8 +249,6 @@ Examples:
221
249
  }
222
250
  }
223
251
 
224
- const sourceContextId = opts.sessionId ?? `cli-${Date.now()}`;
225
-
226
252
  // Validate --conversation-id if provided
227
253
  const conversationId = opts.conversationId?.trim();
228
254
  if (opts.conversationId != null && !conversationId) {
@@ -234,6 +260,26 @@ Examples:
234
260
  return;
235
261
  }
236
262
 
263
+ // Picks up __CONVERSATION_ID / __SKILL_CONTEXT_JSON env vars
264
+ // so deferred-emit can buffer notifications when called from a
265
+ // background job that hasn't confirmed success yet.
266
+ const originatingConversationId = tryResolveConversationId();
267
+
268
+ // The signal's `sourceContextId` doubles as the home-feed's
269
+ // navigation target — `resolveHomeFeedMirror` looks it up via
270
+ // `getConversation()` and only renders a "Go to Convo" button
271
+ // when it resolves to a real row. Prefer the conversation the
272
+ // CLI was invoked from (env-derived) so notifications emitted
273
+ // by background jobs and skills link back to their producing
274
+ // convo; an explicit --session-id still wins to preserve
275
+ // caller intent, and --conversation-id is the last resort
276
+ // before the unresolvable `cli-<ts>` sentinel.
277
+ const sourceContextId =
278
+ opts.sessionId ??
279
+ originatingConversationId ??
280
+ conversationId ??
281
+ `cli-${Date.now()}`;
282
+
237
283
  const result = await cliIpcCall<{
238
284
  signalId: string;
239
285
  dispatched: boolean;
@@ -241,11 +287,11 @@ Examples:
241
287
  reason: string;
242
288
  }>("emit_notification_signal", {
243
289
  body: {
244
- sourceChannel: opts.sourceChannel,
245
- sourceEventName: opts.sourceEventName,
290
+ sourceChannel,
291
+ sourceEventName,
246
292
  sourceContextId,
247
293
  attentionHints: {
248
- requiresAction: opts.requiresAction ?? true,
294
+ requiresAction,
249
295
  urgency,
250
296
  deadlineAt,
251
297
  isAsyncBackground: opts.isAsyncBackground ?? false,
@@ -253,7 +299,7 @@ Examples:
253
299
  },
254
300
  contextPayload: {
255
301
  requestedMessage: message,
256
- requestedBySource: opts.sourceChannel,
302
+ requestedBySource: sourceChannel,
257
303
  ...(opts.title ? { requestedTitle: opts.title } : {}),
258
304
  ...(preferredChannels?.length ? { preferredChannels } : {}),
259
305
  ...(deepLinkMetadata ? { deepLinkMetadata } : {}),
@@ -262,14 +308,20 @@ Examples:
262
308
  ...(conversationId
263
309
  ? { conversationAffinityHint: { vellum: conversationId } }
264
310
  : {}),
311
+ ...(originatingConversationId
312
+ ? { originatingConversationId }
313
+ : {}),
265
314
  throwOnError: true,
266
315
  },
267
316
  });
268
317
 
269
318
  if (!result.ok) {
270
- writeOutput(cmd, { ok: false, error: result.error });
271
- process.exitCode = 1;
272
- return;
319
+ if (shouldOutputJson(cmd)) {
320
+ writeOutput(cmd, { ok: false, error: result.error });
321
+ process.exitCode = exitCodeFromIpcResult(result);
322
+ return;
323
+ }
324
+ return exitFromIpcResult(result);
273
325
  }
274
326
 
275
327
  const signal = result.result!;
@@ -382,7 +434,7 @@ Examples:
382
434
 
383
435
  if (!result.ok) {
384
436
  writeOutput(cmd, { ok: false, error: result.error });
385
- process.exitCode = 1;
437
+ process.exitCode = exitCodeFromIpcResult(result);
386
438
  return;
387
439
  }
388
440
 
@@ -19,6 +19,10 @@ import {
19
19
  } from "../lib/install-from-github.js";
20
20
  import { listInstalledPlugins } from "../lib/list-installed-plugins.js";
21
21
  import { registerCommand } from "../lib/register-command.js";
22
+ import {
23
+ InvalidSearchPatternError,
24
+ searchPlugins,
25
+ } from "../lib/search-plugins.js";
22
26
  import {
23
27
  PluginNotInstalledError,
24
28
  uninstallPlugin,
@@ -42,6 +46,9 @@ Examples:
42
46
  $ assistant plugins install simple-memory --ref my-feature-branch
43
47
  $ assistant plugins list
44
48
  $ assistant plugins list --json
49
+ $ assistant plugins search memory
50
+ $ assistant plugins search "^simple"
51
+ $ assistant plugins search memory --json
45
52
  $ assistant plugins uninstall simple-memory`,
46
53
  );
47
54
 
@@ -134,6 +141,66 @@ Examples:
134
141
  );
135
142
  });
136
143
 
144
+ plugins
145
+ .command("search <query>")
146
+ .description(
147
+ "Search vellum-ai/vellum-assistant/experimental/plugins for plugin names matching <query> (case-insensitive regex)",
148
+ )
149
+ .option("--json", "Emit machine-readable JSON instead of a table")
150
+ .action(async (query: string, opts: { json?: boolean }) => {
151
+ try {
152
+ const result = await searchPlugins(
153
+ { query },
154
+ { fetch: globalThis.fetch.bind(globalThis) },
155
+ );
156
+
157
+ // Log on every success path — JSON output, empty results, and
158
+ // populated tables alike — so observability doesn't depend on
159
+ // which formatting branch the caller landed in.
160
+ log.info(
161
+ {
162
+ query: result.query,
163
+ ref: result.ref,
164
+ matchCount: result.matches.length,
165
+ },
166
+ "external plugin search",
167
+ );
168
+
169
+ if (opts.json) {
170
+ process.stdout.write(JSON.stringify(result, null, 2) + "\n");
171
+ return;
172
+ }
173
+
174
+ if (result.matches.length === 0) {
175
+ console.log(`No plugins matched "${result.query}".`);
176
+ return;
177
+ }
178
+
179
+ const nameW = Math.max(
180
+ 4,
181
+ ...result.matches.map((m) => m.name.length),
182
+ );
183
+ const pad = (s: string, w: number) => s + " ".repeat(w - s.length);
184
+ console.log(`${pad("NAME", nameW)} PATH`);
185
+ for (const m of result.matches) {
186
+ console.log(`${pad(m.name, nameW)} ${m.path}`);
187
+ }
188
+ console.log("");
189
+ console.log(
190
+ `${result.matches.length} match${result.matches.length === 1 ? "" : "es"} for "${result.query}".`,
191
+ );
192
+ } catch (err) {
193
+ if (err instanceof InvalidSearchPatternError) {
194
+ console.error(err.message);
195
+ process.exitCode = 1;
196
+ return;
197
+ }
198
+ const message = err instanceof Error ? err.message : String(err);
199
+ console.error(`Plugin search failed: ${message}`);
200
+ process.exitCode = 1;
201
+ }
202
+ });
203
+
137
204
  plugins
138
205
  .command("uninstall <name>")
139
206
  .description("Remove a plugin from <workspaceDir>/plugins/<name>/")
@@ -1,6 +1,7 @@
1
1
  import type { Command } from "commander";
2
2
 
3
3
  import { cliIpcCall, exitFromIpcResult } from "../../ipc/cli-client.js";
4
+ import { confirmPrompt } from "../lib/confirm-prompt.js";
4
5
  import { registerCommand } from "../lib/register-command.js";
5
6
  import { log } from "../logger.js";
6
7
  import { writeOutput } from "../output.js";
@@ -60,18 +61,21 @@ export function registerSchedulesCommand(program: Command): void {
60
61
  schedules.addHelpText(
61
62
  "after",
62
63
  `
63
- Schedules are recurring or one-shot jobs run by the assistant daemon.
64
+ Schedules are recurring or one-shot jobs run by the assistant.
64
65
 
65
66
  This CLI namespace is intentionally landing incrementally. Today it supports
66
- listing schedules, viewing recent run history, and manually executing a schedule
67
- one time; create, delete, enable/disable, and run inspection will follow as
68
- separate slices.
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.
69
70
 
70
71
  Examples:
71
72
  $ assistant schedules list
72
73
  $ assistant schedules list --all
73
74
  $ assistant schedules runs <schedule-id>
74
75
  $ assistant schedules runs <schedule-id> --limit 25 --json
76
+ $ assistant schedules disable <schedule-id>
77
+ $ assistant schedules enable <schedule-id>
78
+ $ assistant schedules cancel <schedule-id>
75
79
  $ assistant schedules execute <schedule-id>`,
76
80
  );
77
81
 
@@ -203,7 +207,7 @@ Examples:
203
207
  "after",
204
208
  `
205
209
  Options:
206
- --limit <count> Max runs to return. The daemon clamps values to 1-100.
210
+ --limit <count> Max runs to return. The assistant clamps values to 1-100.
207
211
  --json Output the raw run list as compact JSON.
208
212
 
209
213
  Arguments:
@@ -307,6 +311,271 @@ Examples:
307
311
  },
308
312
  );
309
313
 
314
+ schedules
315
+ .command("create <name>")
316
+ .description("Create a new recurring schedule")
317
+ .requiredOption(
318
+ "-e, --expression <expr>",
319
+ "Cron or RRULE expression that schedules the fire times",
320
+ )
321
+ .requiredOption(
322
+ "-m, --message <text>",
323
+ "Message body sent to the assistant on each fire",
324
+ )
325
+ .option(
326
+ "-t, --timezone <tz>",
327
+ "IANA timezone for the expression (e.g. America/New_York)",
328
+ )
329
+ .option("--no-enabled", "Create the schedule in a disabled state")
330
+ .option("--json", "Machine-readable compact JSON output")
331
+ .addHelpText(
332
+ "after",
333
+ `
334
+ Options:
335
+ -e, --expression <expr> Cron (e.g. '*/30 * * * *') or RRULE expression.
336
+ -m, --message <text> Message body sent on each fire.
337
+ -t, --timezone <tz> IANA timezone applied to the expression.
338
+ --no-enabled Create the schedule disabled. Defaults to enabled.
339
+ --json Output the updated schedule list as compact JSON.
340
+
341
+ Arguments:
342
+ <name> Display name for the schedule.
343
+
344
+ Behavior:
345
+ Creates a recurring schedule in 'execute' mode. The IPC endpoint is
346
+ currently locked to execute mode; notify/script/wake schedules remain
347
+ reachable only through the in-assistant schedule_create LLM tool.
348
+
349
+ Examples:
350
+ $ assistant schedules create "Heartbeat" \\
351
+ --expression '*/30 * * * *' \\
352
+ --message 'run heartbeat'
353
+ $ assistant schedules create "Morning summary" \\
354
+ --expression '0 9 * * MON-FRI' \\
355
+ --timezone America/New_York \\
356
+ --message 'write the morning summary'
357
+ $ assistant schedules create "Drafted" \\
358
+ --expression '0 0 * * *' \\
359
+ --message 'placeholder' \\
360
+ --no-enabled --json`,
361
+ )
362
+ .action(
363
+ async (
364
+ name: string,
365
+ opts: {
366
+ expression: string;
367
+ message: string;
368
+ timezone?: string;
369
+ enabled: boolean;
370
+ json?: boolean;
371
+ },
372
+ cmd: Command,
373
+ ) => {
374
+ const scheduleName = name.trim();
375
+ if (!scheduleName) {
376
+ const error = "name is required";
377
+ if (opts.json) {
378
+ writeOutput(cmd, { ok: false, error });
379
+ } else {
380
+ log.error(error);
381
+ }
382
+ process.exitCode = 1;
383
+ return;
384
+ }
385
+
386
+ const body: Record<string, unknown> = {
387
+ name: scheduleName,
388
+ expression: opts.expression,
389
+ message: opts.message,
390
+ enabled: opts.enabled,
391
+ };
392
+ if (opts.timezone != null) body.timezone = opts.timezone;
393
+
394
+ const result = await cliIpcCall<ListSchedulesResponse>(
395
+ "createSchedule",
396
+ { body },
397
+ );
398
+
399
+ if (!result.ok) return exitFromIpcResult(result, cmd);
400
+
401
+ const response = result.result ?? { schedules: [] };
402
+ if (opts.json) {
403
+ writeOutput(cmd, response);
404
+ return;
405
+ }
406
+
407
+ log.info(`Created schedule: ${scheduleName}`);
408
+ },
409
+ );
410
+
411
+ schedules
412
+ .command("enable <id>")
413
+ .description("Enable a schedule")
414
+ .option("--json", "Machine-readable compact JSON output")
415
+ .addHelpText(
416
+ "after",
417
+ `
418
+ Options:
419
+ --json Output the updated schedule list as compact JSON.
420
+
421
+ Arguments:
422
+ <id> Schedule ID (UUID) — run 'assistant schedules list --all' to find it.
423
+
424
+ Behavior:
425
+ Enables the schedule so it can run on future matching times. This does not
426
+ execute the schedule immediately; use 'assistant schedules execute <id>' for
427
+ manual run-now behavior.
428
+
429
+ Examples:
430
+ $ assistant schedules enable 9f2c4f3a-3f1a-41e4-88e7-abc123
431
+ $ assistant schedules enable 9f2c4f3a-3f1a-41e4-88e7-abc123 --json`,
432
+ )
433
+ .action(async (id: string, opts: { json?: boolean }, cmd: Command) => {
434
+ await toggleScheduleEnabled(id, true, opts, cmd);
435
+ });
436
+
437
+ schedules
438
+ .command("disable <id>")
439
+ .description("Disable a schedule")
440
+ .option("--json", "Machine-readable compact JSON output")
441
+ .addHelpText(
442
+ "after",
443
+ `
444
+ Options:
445
+ --json Output the updated schedule list as compact JSON.
446
+
447
+ Arguments:
448
+ <id> Schedule ID (UUID) — run 'assistant schedules list --all' to find it.
449
+
450
+ Behavior:
451
+ Disables the schedule so future scheduled fires are skipped until it is
452
+ enabled again. Existing run history is preserved.
453
+
454
+ Examples:
455
+ $ assistant schedules disable 9f2c4f3a-3f1a-41e4-88e7-abc123
456
+ $ assistant schedules disable 9f2c4f3a-3f1a-41e4-88e7-abc123 --json`,
457
+ )
458
+ .action(async (id: string, opts: { json?: boolean }, cmd: Command) => {
459
+ await toggleScheduleEnabled(id, false, opts, cmd);
460
+ });
461
+
462
+ schedules
463
+ .command("cancel <id>")
464
+ .description("Cancel a pending one-shot schedule")
465
+ .option("--json", "Machine-readable compact JSON output")
466
+ .addHelpText(
467
+ "after",
468
+ `
469
+ Options:
470
+ --json Output the updated schedule list as compact JSON.
471
+
472
+ Arguments:
473
+ <id> Schedule ID (UUID) — run 'assistant schedules list --all' to find
474
+ pending one-shot/deferred schedules.
475
+
476
+ Behavior:
477
+ Cancels a pending one-shot schedule. Recurring schedules are not cancellable;
478
+ use 'assistant schedules disable <id>' to pause recurring schedules.
479
+
480
+ Examples:
481
+ $ assistant schedules cancel 9f2c4f3a-3f1a-41e4-88e7-abc123
482
+ $ assistant schedules cancel 9f2c4f3a-3f1a-41e4-88e7-abc123 --json`,
483
+ )
484
+ .action(async (id: string, opts: { json?: boolean }, cmd: Command) => {
485
+ const scheduleId = id.trim();
486
+ const result = await cliIpcCall<ListSchedulesResponse>(
487
+ "cancelSchedule",
488
+ { pathParams: { id: scheduleId } },
489
+ );
490
+
491
+ if (!result.ok) return exitFromIpcResult(result, cmd);
492
+
493
+ const response = result.result ?? { schedules: [] };
494
+ if (opts.json) {
495
+ writeOutput(cmd, response);
496
+ return;
497
+ }
498
+
499
+ log.info(`Cancelled schedule: ${scheduleId}`);
500
+ });
501
+
502
+ schedules
503
+ .command("delete <id>")
504
+ .description("Permanently delete a schedule and its run history")
505
+ .option("--force", "Skip the confirmation prompt")
506
+ .option("--json", "Machine-readable compact JSON output")
507
+ .addHelpText(
508
+ "after",
509
+ `
510
+ Options:
511
+ --force Skip the destructive y/N confirmation prompt. Required when stdin
512
+ is not a TTY (e.g. in scripts and CI).
513
+ --json Output the updated schedule list as compact JSON.
514
+
515
+ Arguments:
516
+ <id> Schedule ID (UUID) — run 'assistant schedules list --all' to find it.
517
+
518
+ Behavior:
519
+ Permanently removes the schedule and its run history. This cannot be undone.
520
+ To temporarily pause a recurring schedule, use
521
+ 'assistant schedules disable <id>' instead.
522
+
523
+ Examples:
524
+ $ assistant schedules delete 9f2c4f3a-3f1a-41e4-88e7-abc123
525
+ $ assistant schedules delete 9f2c4f3a-3f1a-41e4-88e7-abc123 --force
526
+ $ assistant schedules delete 9f2c4f3a-3f1a-41e4-88e7-abc123 --force --json`,
527
+ )
528
+ .action(
529
+ async (
530
+ id: string,
531
+ opts: { force?: boolean; json?: boolean },
532
+ cmd: Command,
533
+ ) => {
534
+ const scheduleId = id.trim();
535
+ if (!scheduleId) {
536
+ const error = "Schedule ID is required";
537
+ if (opts.json) {
538
+ writeOutput(cmd, { ok: false, error });
539
+ } else {
540
+ log.error(error);
541
+ }
542
+ process.exitCode = 1;
543
+ return;
544
+ }
545
+
546
+ if (!opts.force) {
547
+ const decision = await confirmPrompt({
548
+ question: `Delete schedule "${scheduleId}"? [y/N] `,
549
+ isTTY: Boolean(process.stdin.isTTY),
550
+ refuseNonInteractiveMessage: `Refusing to delete schedule "${scheduleId}" non-interactively. Pass --force to confirm.`,
551
+ });
552
+ if (decision === "non-interactive") {
553
+ process.exitCode = 1;
554
+ return;
555
+ }
556
+ if (decision === "denied") {
557
+ log.info("Delete cancelled.");
558
+ return;
559
+ }
560
+ }
561
+
562
+ const result = await cliIpcCall<ListSchedulesResponse>(
563
+ "deleteSchedule",
564
+ { pathParams: { id: scheduleId } },
565
+ );
566
+
567
+ if (!result.ok) return exitFromIpcResult(result, cmd);
568
+
569
+ const response = result.result ?? { schedules: [] };
570
+ if (opts.json) {
571
+ writeOutput(cmd, response);
572
+ return;
573
+ }
574
+
575
+ log.info(`Deleted schedule: ${scheduleId}`);
576
+ },
577
+ );
578
+
310
579
  schedules
311
580
  .command("execute <id>")
312
581
  .description("Execute a schedule one time immediately")
@@ -368,6 +637,29 @@ Examples:
368
637
  });
369
638
  }
370
639
 
640
+ async function toggleScheduleEnabled(
641
+ id: string,
642
+ enabled: boolean,
643
+ opts: { json?: boolean },
644
+ cmd: Command,
645
+ ): Promise<void> {
646
+ const scheduleId = id.trim();
647
+ const result = await cliIpcCall<ListSchedulesResponse>("toggleSchedule", {
648
+ pathParams: { id: scheduleId },
649
+ body: { enabled },
650
+ });
651
+
652
+ if (!result.ok) return exitFromIpcResult(result, cmd);
653
+
654
+ const response = result.result ?? { schedules: [] };
655
+ if (opts.json) {
656
+ writeOutput(cmd, response);
657
+ return;
658
+ }
659
+
660
+ log.info(`${enabled ? "Enabled" : "Disabled"} schedule: ${scheduleId}`);
661
+ }
662
+
371
663
  function describeSchedule(schedule: ScheduleRecord): string {
372
664
  if (schedule.isOneShot) return "one-shot";
373
665
  const expression = schedule.description ?? schedule.expression ?? "—";