@vellumai/assistant 0.8.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (506) hide show
  1. package/ARCHITECTURE.md +2 -7
  2. package/Dockerfile +75 -1
  3. package/bun.lock +11 -1
  4. package/docker-entrypoint.sh +5 -0
  5. package/docker-init-apt-root.sh +94 -0
  6. package/docker-kata-apt-env.sh +39 -0
  7. package/docs/plugins.md +88 -47
  8. package/docs/skills.md +9 -7
  9. package/examples/plugins/echo/README.md +27 -27
  10. package/examples/plugins/echo/package.json +3 -0
  11. package/examples/plugins/echo/register.ts +31 -31
  12. package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
  13. package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
  14. package/openapi.yaml +325 -3
  15. package/package.json +3 -1
  16. package/scripts/generate-openapi.ts +83 -10
  17. package/scripts/sync-llm-catalog.ts +2 -2
  18. package/scripts/sync-web-search-catalog.ts +47 -25
  19. package/src/__tests__/agent-image-optimize.test.ts +11 -3
  20. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
  21. package/src/__tests__/anthropic-provider.test.ts +45 -0
  22. package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
  23. package/src/__tests__/app-executors.test.ts +220 -4
  24. package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
  25. package/src/__tests__/bundled-asset.test.ts +6 -6
  26. package/src/__tests__/channel-availability-routes.test.ts +206 -0
  27. package/src/__tests__/channel-delivery-store.test.ts +289 -1
  28. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
  29. package/src/__tests__/clawhub.test.ts +75 -16
  30. package/src/__tests__/compactor-tail-resolution.test.ts +41 -0
  31. package/src/__tests__/config-schema.test.ts +21 -0
  32. package/src/__tests__/config-set-route.test.ts +80 -0
  33. package/src/__tests__/config-sounds-sync.test.ts +97 -0
  34. package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
  35. package/src/__tests__/context-search-conversations-source.test.ts +117 -2
  36. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
  37. package/src/__tests__/context-search-workspace-source.test.ts +7 -0
  38. package/src/__tests__/context-token-estimator.test.ts +1 -0
  39. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
  40. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  41. package/src/__tests__/conversation-agent-loop-overflow.test.ts +92 -92
  42. package/src/__tests__/conversation-agent-loop.test.ts +2 -0
  43. package/src/__tests__/conversation-error.test.ts +42 -3
  44. package/src/__tests__/conversation-fork-crud.test.ts +82 -0
  45. package/src/__tests__/conversation-inference-profile-route.test.ts +40 -4
  46. package/src/__tests__/conversation-lifecycle.test.ts +173 -0
  47. package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
  48. package/src/__tests__/conversation-pairing.test.ts +54 -0
  49. package/src/__tests__/conversation-process-callsite.test.ts +4 -1
  50. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
  51. package/src/__tests__/conversation-queue.test.ts +4 -1
  52. package/src/__tests__/conversation-runtime-assembly.test.ts +76 -9
  53. package/src/__tests__/conversation-slash-queue.test.ts +59 -1
  54. package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
  55. package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
  56. package/src/__tests__/conversation-sync-tags.test.ts +235 -0
  57. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  58. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  59. package/src/__tests__/credential-security-invariants.test.ts +3 -2
  60. package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
  61. package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
  62. package/src/__tests__/disk-pressure-tools.test.ts +1 -0
  63. package/src/__tests__/dm-backfill.test.ts +121 -10
  64. package/src/__tests__/document-tool-security.test.ts +258 -0
  65. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  66. package/src/__tests__/edit-propagation.test.ts +33 -0
  67. package/src/__tests__/empty-response-pipeline.test.ts +0 -4
  68. package/src/__tests__/external-plugin-loader.test.ts +60 -36
  69. package/src/__tests__/filing-service.test.ts +140 -0
  70. package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
  71. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +43 -62
  72. package/src/__tests__/helpers/tar-fixtures.ts +39 -0
  73. package/src/__tests__/helpers/wait-for.ts +21 -0
  74. package/src/__tests__/history-repair-pipeline.test.ts +0 -3
  75. package/src/__tests__/history-repair.test.ts +73 -0
  76. package/src/__tests__/host-app-control-proxy.test.ts +266 -10
  77. package/src/__tests__/image-credentials.test.ts +1 -1
  78. package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
  79. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +1 -1
  80. package/src/__tests__/inference-profile-reaper.test.ts +4 -2
  81. package/src/__tests__/inference-profile-session-handler.test.ts +18 -6
  82. package/src/__tests__/inference-profile-session-ipc.test.ts +17 -5
  83. package/src/__tests__/injector-chain.test.ts +10 -8
  84. package/src/__tests__/install-skill-routing.test.ts +155 -37
  85. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +92 -3
  86. package/src/__tests__/list-messages-page-latest.test.ts +55 -0
  87. package/src/__tests__/llm-call-pipeline.test.ts +0 -3
  88. package/src/__tests__/llm-catalog-parity.test.ts +55 -13
  89. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +34 -0
  90. package/src/__tests__/llm-request-log-source-factory.test.ts +29 -53
  91. package/src/__tests__/llm-usage-store.test.ts +114 -0
  92. package/src/__tests__/managed-profile-guard.test.ts +31 -29
  93. package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
  94. package/src/__tests__/managed-store.test.ts +84 -192
  95. package/src/__tests__/media-generate-image.test.ts +1 -1
  96. package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
  97. package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
  98. package/src/__tests__/oauth-commands-routes.test.ts +168 -16
  99. package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
  100. package/src/__tests__/openai-provider.test.ts +24 -0
  101. package/src/__tests__/openai-responses-cutover-guard.test.ts +17 -9
  102. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
  103. package/src/__tests__/persistence-pipeline.test.ts +0 -2
  104. package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +1 -1
  105. package/src/__tests__/platform.test.ts +2 -0
  106. package/src/__tests__/plugin-api-shim.test.ts +125 -0
  107. package/src/__tests__/plugin-bootstrap.test.ts +10 -36
  108. package/src/__tests__/plugin-external-api.test.ts +68 -0
  109. package/src/__tests__/plugin-registry.test.ts +0 -77
  110. package/src/__tests__/plugin-route-contribution.test.ts +0 -1
  111. package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
  112. package/src/__tests__/plugin-tool-contribution.test.ts +16 -15
  113. package/src/__tests__/plugin-types.test.ts +3 -13
  114. package/src/__tests__/process-message-background-slack.test.ts +8 -1
  115. package/src/__tests__/process-message-display-content.test.ts +421 -0
  116. package/src/__tests__/provider-catalog-visibility.test.ts +142 -0
  117. package/src/__tests__/provider-error-scenarios.test.ts +111 -0
  118. package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +8 -8
  119. package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
  120. package/src/__tests__/schedule-routes.test.ts +50 -3
  121. package/src/__tests__/schedule-store.test.ts +94 -0
  122. package/src/__tests__/scheduler-reuse-conversation.test.ts +54 -7
  123. package/src/__tests__/schema-transforms.test.ts +20 -0
  124. package/src/__tests__/search-skills-unified.test.ts +0 -5
  125. package/src/__tests__/server-history-render.test.ts +43 -0
  126. package/src/__tests__/skill-load-feature-flag.test.ts +0 -12
  127. package/src/__tests__/skill-load-tool.test.ts +27 -89
  128. package/src/__tests__/skill-memory.test.ts +23 -3
  129. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
  130. package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
  131. package/src/__tests__/skills-install-extract.test.ts +49 -38
  132. package/src/__tests__/skills-install-staging.test.ts +159 -0
  133. package/src/__tests__/skills-uninstall.test.ts +9 -41
  134. package/src/__tests__/skills.test.ts +51 -58
  135. package/src/__tests__/slack-channel-config.test.ts +9 -0
  136. package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
  137. package/src/__tests__/system-prompt.test.ts +737 -63
  138. package/src/__tests__/terminal-tools.test.ts +28 -1
  139. package/src/__tests__/thread-backfill.test.ts +557 -27
  140. package/src/__tests__/title-generate-pipeline.test.ts +0 -13
  141. package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
  142. package/src/__tests__/tool-error-pipeline.test.ts +0 -3
  143. package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
  144. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  145. package/src/__tests__/tool-executor.test.ts +16 -4
  146. package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
  147. package/src/__tests__/turn-events-store.test.ts +256 -0
  148. package/src/__tests__/twilio-routes.test.ts +4 -0
  149. package/src/__tests__/user-plugin-loader.test.ts +0 -7
  150. package/src/__tests__/voice-session-bridge.test.ts +198 -0
  151. package/src/__tests__/web-search-catalog-parity.test.ts +32 -10
  152. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +115 -3
  153. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +50 -0
  154. package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
  155. package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
  156. package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
  157. package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
  158. package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
  159. package/src/acp/resolve-agent.ts +1 -1
  160. package/src/agent/image-optimize.ts +13 -5
  161. package/src/calls/voice-session-bridge.ts +61 -42
  162. package/src/channels/types.ts +108 -0
  163. package/src/cli/__tests__/unknown-command.test.ts +24 -0
  164. package/src/cli/commands/__tests__/changelog.test.ts +304 -319
  165. package/src/cli/commands/__tests__/schedules.test.ts +491 -0
  166. package/src/cli/commands/changelog.ts +106 -42
  167. package/src/cli/commands/conversations.ts +102 -17
  168. package/src/cli/commands/default-action.ts +10 -53
  169. package/src/cli/commands/notifications.ts +329 -317
  170. package/src/cli/commands/plugins.ts +185 -0
  171. package/src/cli/commands/schedules.ts +391 -0
  172. package/src/cli/commands/telemetry.ts +40 -0
  173. package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
  174. package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
  175. package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
  176. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
  177. package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
  178. package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
  179. package/src/cli/lib/cli-colors.ts +12 -0
  180. package/src/cli/lib/confirm-prompt.ts +79 -0
  181. package/src/cli/lib/install-from-github.ts +304 -0
  182. package/src/cli/lib/list-installed-plugins.ts +137 -0
  183. package/src/cli/lib/uninstall-plugin.ts +82 -0
  184. package/src/cli/lib/unknown-command.ts +111 -0
  185. package/src/cli/program.ts +38 -2
  186. package/src/config/bundled-skills/app-builder/SKILL.md +23 -21
  187. package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
  188. package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
  189. package/src/config/bundled-skills/document/SKILL.md +23 -3
  190. package/src/config/bundled-skills/document/TOOLS.json +53 -0
  191. package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
  192. package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
  193. package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
  194. package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
  195. package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
  196. package/src/config/bundled-tool-registry.ts +6 -0
  197. package/src/config/feature-flag-registry.json +41 -1
  198. package/src/config/loader.ts +64 -38
  199. package/src/config/schema.ts +7 -10
  200. package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
  201. package/src/config/schemas/channels.ts +8 -0
  202. package/src/config/schemas/compaction.ts +28 -0
  203. package/src/config/schemas/heartbeat.ts +9 -0
  204. package/src/config/schemas/llm-request-logs.ts +31 -7
  205. package/src/config/schemas/llm.ts +3 -0
  206. package/src/config/schemas/memory-retrieval.ts +18 -0
  207. package/src/config/schemas/tools.ts +14 -0
  208. package/src/config/skills.ts +3 -96
  209. package/src/context/compactor.ts +1047 -0
  210. package/src/context/token-estimator.ts +2 -2
  211. package/src/context/window-manager.ts +197 -1520
  212. package/src/credential-execution/managed-catalog.ts +37 -0
  213. package/src/credential-health/credential-health-service.ts +280 -19
  214. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +34 -0
  215. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
  216. package/src/daemon/__tests__/conversation-tool-setup.test.ts +74 -0
  217. package/src/daemon/approval-generators.ts +8 -6
  218. package/src/daemon/config-watcher.ts +94 -31
  219. package/src/daemon/conversation-agent-loop.ts +169 -9
  220. package/src/daemon/conversation-error.ts +171 -37
  221. package/src/daemon/conversation-lifecycle.ts +53 -40
  222. package/src/daemon/conversation-messaging.ts +25 -6
  223. package/src/daemon/conversation-process.ts +49 -12
  224. package/src/daemon/conversation-runtime-assembly.ts +16 -1
  225. package/src/daemon/conversation-slash.ts +12 -5
  226. package/src/daemon/conversation-store.ts +11 -4
  227. package/src/daemon/conversation-tool-setup.ts +39 -7
  228. package/src/daemon/conversation.ts +33 -1
  229. package/src/daemon/external-plugins-bootstrap.ts +217 -181
  230. package/src/daemon/first-greeting.ts +22 -2
  231. package/src/daemon/handlers/config-model.ts +6 -5
  232. package/src/daemon/handlers/config-slack-channel.ts +15 -3
  233. package/src/daemon/handlers/shared.ts +14 -5
  234. package/src/daemon/handlers/skills.ts +111 -108
  235. package/src/daemon/history-repair.ts +28 -1
  236. package/src/daemon/host-app-control-proxy.ts +98 -23
  237. package/src/daemon/lifecycle.ts +45 -35
  238. package/src/daemon/meet-host-supervisor.ts +5 -4
  239. package/src/daemon/memory-v2-startup.ts +49 -0
  240. package/src/daemon/message-protocol.ts +1 -0
  241. package/src/daemon/message-types/conversations.ts +25 -0
  242. package/src/daemon/message-types/messages.ts +61 -0
  243. package/src/daemon/message-types/subagents.ts +1 -0
  244. package/src/daemon/message-types/sync.ts +1 -0
  245. package/src/daemon/pkb-reminder-builder.test.ts +1 -1
  246. package/src/daemon/pkb-reminder-builder.ts +1 -1
  247. package/src/daemon/plugin-source-watcher.ts +146 -0
  248. package/src/daemon/process-message.ts +21 -3
  249. package/src/daemon/server.ts +11 -2
  250. package/src/daemon/skill-memory-refresh.ts +29 -0
  251. package/src/documents/document-store.ts +221 -3
  252. package/src/embedded/plugin-api.ts +40 -0
  253. package/src/filing/filing-service.ts +39 -0
  254. package/src/heartbeat/__tests__/heartbeat-service.test.ts +91 -6
  255. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  256. package/src/heartbeat/heartbeat-service.ts +41 -0
  257. package/src/home/__tests__/feed-types.test.ts +40 -0
  258. package/src/home/feed-types.ts +22 -0
  259. package/src/home/post-connect-feed.ts +1 -0
  260. package/src/index.ts +18 -1
  261. package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
  262. package/src/mcp/client.ts +20 -4
  263. package/src/media/image-credentials.ts +3 -3
  264. package/src/memory/__tests__/bookmark-crud.test.ts +33 -27
  265. package/src/memory/__tests__/conversation-queries.test.ts +263 -0
  266. package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
  267. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +119 -14
  268. package/src/memory/__tests__/message-content.test.ts +35 -0
  269. package/src/memory/bookmark-crud.ts +42 -10
  270. package/src/memory/context-search/sources/conversations.ts +62 -2
  271. package/src/memory/context-search/sources/workspace.ts +4 -0
  272. package/src/memory/conversation-crud.ts +63 -19
  273. package/src/memory/conversation-queries.ts +110 -10
  274. package/src/memory/db-init.ts +6 -0
  275. package/src/memory/delivery-crud.ts +152 -5
  276. package/src/memory/embedding-backend.ts +4 -4
  277. package/src/memory/external-conversation-store.ts +66 -5
  278. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +66 -9
  279. package/src/memory/graph/conversation-graph-memory.ts +31 -15
  280. package/src/memory/graph/tools.ts +3 -3
  281. package/src/memory/indexer.ts +34 -29
  282. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +73 -0
  283. package/src/memory/jobs/embed-concept-page.ts +20 -11
  284. package/src/memory/jobs-worker.ts +6 -1
  285. package/src/memory/llm-request-log-source-clickhouse.ts +17 -10
  286. package/src/memory/llm-request-log-source.ts +19 -52
  287. package/src/memory/llm-usage-store.ts +125 -5
  288. package/src/memory/memory-retrospective-startup-cleanup.ts +72 -5
  289. package/src/memory/message-content.ts +1 -1
  290. package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
  291. package/src/memory/migrations/229-delete-private-conversations.test.ts +38 -1
  292. package/src/memory/migrations/229-delete-private-conversations.ts +7 -0
  293. package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
  294. package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
  295. package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
  296. package/src/memory/migrations/index.ts +6 -0
  297. package/src/memory/migrations/registry.ts +8 -0
  298. package/src/memory/onboarding-events-store.ts +106 -0
  299. package/src/memory/schema/bookmarks.ts +0 -2
  300. package/src/memory/schema/calls.ts +1 -0
  301. package/src/memory/schema/inference.ts +1 -3
  302. package/src/memory/schema/infrastructure.ts +12 -0
  303. package/src/memory/turn-events-store.ts +127 -2
  304. package/src/memory/v2/__tests__/activation.test.ts +0 -8
  305. package/src/memory/v2/__tests__/injection.test.ts +98 -8
  306. package/src/memory/v2/__tests__/migration.test.ts +87 -0
  307. package/src/memory/v2/__tests__/page-index.test.ts +83 -0
  308. package/src/memory/v2/__tests__/prompts-router.test.ts +58 -6
  309. package/src/memory/v2/__tests__/qdrant.test.ts +66 -3
  310. package/src/memory/v2/__tests__/router.test.ts +15 -0
  311. package/src/memory/v2/__tests__/skill-store.test.ts +387 -8
  312. package/src/memory/v2/injection.ts +32 -6
  313. package/src/memory/v2/migration.ts +49 -19
  314. package/src/memory/v2/page-index.ts +35 -5
  315. package/src/memory/v2/prompts/router.ts +11 -8
  316. package/src/memory/v2/prompts/sweep.ts +2 -2
  317. package/src/memory/v2/qdrant.ts +135 -7
  318. package/src/memory/v2/router.ts +9 -8
  319. package/src/memory/v2/skill-store.ts +120 -35
  320. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
  321. package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
  322. package/src/messaging/providers/slack/adapter.ts +43 -5
  323. package/src/messaging/providers/slack/client.ts +27 -0
  324. package/src/messaging/providers/slack/deep-link.ts +65 -0
  325. package/src/messaging/providers/slack/download.ts +104 -0
  326. package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
  327. package/src/messaging/providers/slack/message-metadata.ts +27 -0
  328. package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
  329. package/src/messaging/providers/slack/render-transcript.ts +69 -5
  330. package/src/messaging/providers/slack/types.ts +20 -1
  331. package/src/notifications/conversation-pairing.ts +2 -1
  332. package/src/notifications/decision-engine.ts +2 -1
  333. package/src/notifications/emit-signal.ts +20 -1
  334. package/src/notifications/home-feed-side-effect.ts +54 -0
  335. package/src/notifications/signal.ts +3 -1
  336. package/src/oauth/connection-resolver.ts +8 -4
  337. package/src/oauth/platform-connection.ts +6 -2
  338. package/src/oauth/seed-providers.ts +10 -1
  339. package/src/permissions/checker.ts +2 -0
  340. package/src/permissions/ipc-risk-types.ts +1 -0
  341. package/src/permissions/question-prompter.test.ts +416 -0
  342. package/src/permissions/question-prompter.ts +294 -0
  343. package/src/platform/client.test.ts +1 -1
  344. package/src/platform/client.ts +1 -1
  345. package/src/plugin-api/constants.ts +26 -0
  346. package/src/plugin-api/index.ts +34 -1
  347. package/src/plugin-api/types.ts +104 -22
  348. package/src/plugins/defaults/circuit-breaker.ts +0 -5
  349. package/src/plugins/defaults/compaction.ts +0 -4
  350. package/src/plugins/defaults/empty-response.ts +0 -2
  351. package/src/plugins/defaults/history-repair.ts +0 -2
  352. package/src/plugins/defaults/injectors.ts +36 -3
  353. package/src/plugins/defaults/llm-call.ts +0 -2
  354. package/src/plugins/defaults/memory-retrieval.ts +0 -1
  355. package/src/plugins/defaults/overflow-reduce.ts +0 -1
  356. package/src/plugins/defaults/persistence.ts +0 -2
  357. package/src/plugins/defaults/title-generate.ts +0 -5
  358. package/src/plugins/defaults/token-estimate.ts +0 -2
  359. package/src/plugins/defaults/tool-error.ts +0 -7
  360. package/src/plugins/defaults/tool-execute.ts +0 -2
  361. package/src/plugins/defaults/tool-result-truncate.ts +0 -4
  362. package/src/plugins/ensure-plugin-api-shim.ts +96 -0
  363. package/src/plugins/external-api.ts +104 -0
  364. package/src/plugins/external-plugin-loader.ts +105 -32
  365. package/src/plugins/feature-gate.ts +22 -0
  366. package/src/plugins/pipeline.ts +37 -0
  367. package/src/plugins/registry.ts +48 -80
  368. package/src/plugins/types.ts +31 -26
  369. package/src/plugins/user-loader.ts +21 -2
  370. package/src/proactive-artifact/aux-message-injector.ts +11 -0
  371. package/src/proactive-artifact/job.test.ts +37 -5
  372. package/src/prompts/__tests__/system-prompt.test.ts +12 -0
  373. package/src/prompts/__tests__/task-progress-hint-section.test.ts +99 -0
  374. package/src/prompts/normalize-onboarding.ts +27 -0
  375. package/src/prompts/sections.ts +302 -0
  376. package/src/prompts/system-prompt.ts +63 -166
  377. package/src/prompts/templates/BOOTSTRAP.md +17 -1
  378. package/src/prompts/templates/system-sections.ts +173 -0
  379. package/src/providers/__tests__/inference.test.ts +22 -7
  380. package/src/providers/anthropic/client.ts +28 -28
  381. package/src/providers/connection-resolution.ts +7 -0
  382. package/src/providers/inference/adapter-factory.ts +41 -4
  383. package/src/providers/inference/connections.ts +74 -29
  384. package/src/providers/inference/resolve-auth.ts +12 -4
  385. package/src/providers/model-catalog.ts +294 -12
  386. package/src/providers/openai/chat-completions-provider.ts +10 -2
  387. package/src/providers/openrouter/client.ts +7 -0
  388. package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -1
  389. package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
  390. package/src/providers/provider-availability.ts +17 -2
  391. package/src/providers/provider-catalog-visibility.ts +36 -0
  392. package/src/providers/registry.ts +22 -14
  393. package/src/providers/retry.ts +47 -1
  394. package/src/runtime/__tests__/agent-wake.test.ts +152 -0
  395. package/src/runtime/agent-wake.ts +42 -14
  396. package/src/runtime/auth/route-policy.ts +8 -1
  397. package/src/runtime/btw-sidechain.ts +2 -0
  398. package/src/runtime/http-types.ts +19 -0
  399. package/src/runtime/migrations/origin-mode.ts +1 -1
  400. package/src/runtime/pending-interactions.ts +1 -0
  401. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +17 -0
  402. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +5 -1
  403. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +107 -20
  404. package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
  405. package/src/runtime/routes/__tests__/tts-routes.test.ts +64 -1
  406. package/src/runtime/routes/acp-routes-list.test.ts +143 -0
  407. package/src/runtime/routes/acp-routes.ts +5 -3
  408. package/src/runtime/routes/auth-routes.ts +1 -1
  409. package/src/runtime/routes/bookmark-routes.ts +5 -3
  410. package/src/runtime/routes/btw-routes.ts +5 -1
  411. package/src/runtime/routes/channel-availability-routes.ts +121 -0
  412. package/src/runtime/routes/conversation-cli-routes.ts +44 -3
  413. package/src/runtime/routes/conversation-list-routes.ts +3 -20
  414. package/src/runtime/routes/conversation-management-routes.ts +17 -42
  415. package/src/runtime/routes/conversation-query-routes.ts +40 -35
  416. package/src/runtime/routes/conversation-routes.ts +90 -11
  417. package/src/runtime/routes/documents-routes.ts +25 -86
  418. package/src/runtime/routes/group-routes.ts +5 -0
  419. package/src/runtime/routes/inbound-conversation.ts +28 -8
  420. package/src/runtime/routes/inbound-message-handler.ts +236 -41
  421. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +111 -0
  422. package/src/runtime/routes/inbound-stages/background-dispatch.ts +32 -1
  423. package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
  424. package/src/runtime/routes/index.ts +6 -0
  425. package/src/runtime/routes/inference-profile-session-handler.ts +17 -44
  426. package/src/runtime/routes/inference-profile-session-reaper.ts +7 -21
  427. package/src/runtime/routes/inference-provider-connection-routes.ts +65 -21
  428. package/src/runtime/routes/integrations/slack/share.ts +4 -52
  429. package/src/runtime/routes/integrations/slack/token.ts +43 -0
  430. package/src/runtime/routes/integrations/twilio.ts +6 -13
  431. package/src/runtime/routes/notification-routes.ts +1 -1
  432. package/src/runtime/routes/oauth-commands-routes.ts +105 -15
  433. package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
  434. package/src/runtime/routes/question-routes.ts +259 -0
  435. package/src/runtime/routes/rename-conversation-routes.ts +2 -33
  436. package/src/runtime/routes/schedule-routes.ts +4 -7
  437. package/src/runtime/routes/subagents-routes.ts +57 -18
  438. package/src/runtime/routes/telemetry-routes.ts +27 -0
  439. package/src/runtime/routes/tts-routes.ts +27 -2
  440. package/src/runtime/routes/workspace-routes.test.ts +43 -0
  441. package/src/runtime/routes/workspace-routes.ts +28 -0
  442. package/src/runtime/services/conversation-serializer.ts +39 -7
  443. package/src/runtime/sync/resource-sync-events.ts +93 -1
  444. package/src/schedule/schedule-store.ts +27 -2
  445. package/src/schedule/scheduler.ts +9 -1
  446. package/src/security/__tests__/untrusted-content.test.ts +86 -0
  447. package/src/security/untrusted-content.ts +93 -8
  448. package/src/skills/catalog-files.ts +1 -1
  449. package/src/skills/catalog-install.ts +233 -116
  450. package/src/skills/clawhub.ts +70 -13
  451. package/src/skills/managed-store.ts +4 -119
  452. package/src/skills/skillssh-registry.ts +27 -48
  453. package/src/subagent/manager.ts +15 -7
  454. package/src/telemetry/types.ts +113 -1
  455. package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
  456. package/src/telemetry/usage-telemetry-reporter.ts +113 -7
  457. package/src/tools/apps/executors.ts +58 -7
  458. package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
  459. package/src/tools/ask-question/ask-question-tool.ts +304 -0
  460. package/src/tools/browser/browser-execution.ts +15 -11
  461. package/src/tools/computer-use/definitions.ts +3 -3
  462. package/src/tools/credentials/vault.ts +1 -1
  463. package/src/tools/document/document-tool.ts +124 -1
  464. package/src/tools/filesystem/edit.ts +1 -1
  465. package/src/tools/filesystem/list.ts +1 -1
  466. package/src/tools/filesystem/read.ts +1 -1
  467. package/src/tools/filesystem/write.ts +5 -2
  468. package/src/tools/host-filesystem/transfer.ts +1 -1
  469. package/src/tools/host-terminal/host-shell.ts +1 -1
  470. package/src/tools/permission-checker.ts +1 -1
  471. package/src/tools/registry.ts +17 -7
  472. package/src/tools/schedule/create.ts +2 -2
  473. package/src/tools/schema-transforms.ts +7 -2
  474. package/src/tools/side-effects.ts +1 -0
  475. package/src/tools/skills/delete-managed.ts +4 -4
  476. package/src/tools/skills/execute.ts +1 -1
  477. package/src/tools/skills/scaffold-managed.ts +3 -2
  478. package/src/tools/subagent/notify-parent.ts +1 -1
  479. package/src/tools/system/request-permission.ts +2 -2
  480. package/src/tools/terminal/safe-env.ts +60 -1
  481. package/src/tools/tool-manifest.ts +2 -0
  482. package/src/tools/types.ts +72 -21
  483. package/src/tools/ui-surface/definitions.ts +6 -5
  484. package/src/tts/__tests__/provider-adapters.test.ts +76 -2
  485. package/src/tts/providers/elevenlabs-provider.ts +75 -1
  486. package/src/types/onboarding-context.ts +2 -0
  487. package/src/util/errors.ts +17 -0
  488. package/src/util/platform.ts +10 -0
  489. package/src/watcher/__tests__/engine.test.ts +22 -0
  490. package/src/watcher/engine.ts +6 -2
  491. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +80 -15
  492. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +35 -22
  493. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +3 -1
  494. package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
  495. package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
  496. package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
  497. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
  498. package/src/workspace/migrations/registry.ts +8 -0
  499. package/src/workspace/migrations/runner.ts +39 -9
  500. package/src/workspace/migrations/types.ts +4 -0
  501. package/examples/plugins/echo/bun.lock +0 -25
  502. package/src/__tests__/context-window-manager.test.ts +0 -2481
  503. package/src/context/__tests__/compact-prompt.test.ts +0 -63
  504. package/src/context/prompts/compact.md +0 -26
  505. package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
  506. /package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +0 -0
@@ -13,13 +13,14 @@ export function registerNotificationsCommand(program: Command): void {
13
13
  registerCommand(program, {
14
14
  name: "notifications",
15
15
  transport: "ipc",
16
- description: "Send and inspect notifications through the unified notification router",
16
+ description:
17
+ "Send and inspect notifications through the unified notification router",
17
18
  build: (notifications) => {
18
19
  notifications.option("--json", "Machine-readable compact JSON output");
19
20
 
20
- notifications.addHelpText(
21
- "after",
22
- `
21
+ notifications.addHelpText(
22
+ "after",
23
+ `
23
24
  Notifications flow through a unified pipeline: a signal is emitted with a
24
25
  source channel, event name, and attention hints. The decision engine evaluates
25
26
  whether and where to deliver the notification based on connected channels,
@@ -30,83 +31,85 @@ Examples:
30
31
  $ assistant notifications send --source-channel scheduler --source-event-name schedule.notify --message "Stand-up in 5 minutes" --urgency high
31
32
  $ assistant notifications send --source-channel watcher --source-event-name watcher.notification --message "File changed" --no-requires-action --is-async-background
32
33
  $ assistant notifications send --source-channel assistant_tool --source-event-name user.send_notification --message "Deploy complete" --preferred-channels vellum,telegram --json`,
33
- );
34
+ );
34
35
 
35
- // -------------------------------------------------------------------------
36
- // send
37
- // -------------------------------------------------------------------------
36
+ // -------------------------------------------------------------------------
37
+ // send
38
+ // -------------------------------------------------------------------------
38
39
 
39
- notifications
40
- .command("send")
41
- .description("Send a notification through the unified notification router")
42
- .requiredOption(
43
- "--source-channel <channel>",
44
- "Source channel producing this notification",
45
- )
46
- .requiredOption(
47
- "--source-event-name <name>",
48
- "Event name for audit, routing, and dedupe grouping",
49
- )
50
- .requiredOption(
51
- "--message <message>",
52
- "Notification message the user should receive",
53
- )
54
- .option("--title <title>", "Optional notification title")
55
- .option(
56
- "--urgency <urgency>",
57
- "Urgency hint: low, medium, high (default: medium)",
58
- )
59
- .option(
60
- "--requires-action",
61
- "Whether the notification expects user action (default: true)",
62
- )
63
- .option(
64
- "--no-requires-action",
65
- "Mark that the notification does not expect user action",
66
- )
67
- .option(
68
- "--is-async-background",
69
- "Whether the event is asynchronous/background work (default: false)",
70
- )
71
- .option(
72
- "--no-is-async-background",
73
- "Mark that the event is not asynchronous/background work",
74
- )
75
- .option(
76
- "--visible-in-source-now",
77
- "Set true when user is already viewing the source context (default: false)",
78
- )
79
- .option(
80
- "--no-visible-in-source-now",
81
- "Mark that the user is not viewing the source context",
82
- )
83
- .option(
84
- "--deadline-at <epoch>",
85
- "Optional deadline timestamp in epoch milliseconds",
86
- )
87
- .option(
88
- "--preferred-channels <channels>",
89
- "Comma-separated channel hints (e.g. vellum,telegram,slack)",
90
- )
91
- .option(
92
- "--session-id <id>",
93
- "Source session or conversation ID (default: cli-<timestamp>)",
94
- )
95
- .option(
96
- "--dedupe-key <key>",
97
- "Optional dedupe key to suppress duplicate notifications",
98
- )
99
- .option(
100
- "--deep-link-metadata <json>",
101
- "Optional JSON metadata clients can use for deep linking",
102
- )
103
- .option(
104
- "--conversation-id <id>",
105
- "Local vellum conversation ID to deliver into. When set, the notification reuses the specified conversation instead of starting a new one — bypasses the LLM's conversation-routing decision via affinity hint.",
106
- )
107
- .addHelpText(
108
- "after",
109
- `
40
+ notifications
41
+ .command("send")
42
+ .description(
43
+ "Send a notification through the unified notification router",
44
+ )
45
+ .requiredOption(
46
+ "--source-channel <channel>",
47
+ "Source channel producing this notification",
48
+ )
49
+ .requiredOption(
50
+ "--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",
56
+ )
57
+ .option("--title <title>", "Optional notification title")
58
+ .option(
59
+ "--urgency <urgency>",
60
+ "Urgency hint: low, medium, high, critical (default: medium)",
61
+ )
62
+ .option(
63
+ "--requires-action",
64
+ "Whether the notification expects user action (default: true)",
65
+ )
66
+ .option(
67
+ "--no-requires-action",
68
+ "Mark that the notification does not expect user action",
69
+ )
70
+ .option(
71
+ "--is-async-background",
72
+ "Whether the event is asynchronous/background work (default: false)",
73
+ )
74
+ .option(
75
+ "--no-is-async-background",
76
+ "Mark that the event is not asynchronous/background work",
77
+ )
78
+ .option(
79
+ "--visible-in-source-now",
80
+ "Set true when user is already viewing the source context (default: false)",
81
+ )
82
+ .option(
83
+ "--no-visible-in-source-now",
84
+ "Mark that the user is not viewing the source context",
85
+ )
86
+ .option(
87
+ "--deadline-at <epoch>",
88
+ "Optional deadline timestamp in epoch milliseconds",
89
+ )
90
+ .option(
91
+ "--preferred-channels <channels>",
92
+ "Comma-separated channel hints (e.g. vellum,telegram,slack)",
93
+ )
94
+ .option(
95
+ "--session-id <id>",
96
+ "Source session or conversation ID (default: cli-<timestamp>)",
97
+ )
98
+ .option(
99
+ "--dedupe-key <key>",
100
+ "Optional dedupe key to suppress duplicate notifications",
101
+ )
102
+ .option(
103
+ "--deep-link-metadata <json>",
104
+ "Optional JSON metadata clients can use for deep linking",
105
+ )
106
+ .option(
107
+ "--conversation-id <id>",
108
+ "Local vellum conversation ID to deliver into. When set, the notification reuses the specified conversation instead of starting a new one — bypasses the LLM's conversation-routing decision via affinity hint.",
109
+ )
110
+ .addHelpText(
111
+ "after",
112
+ `
110
113
  Arguments:
111
114
  --source-channel One of the registered source channels (see "assistant notifications --help")
112
115
  --source-event-name One of the registered event names (see "assistant notifications --help")
@@ -128,180 +131,189 @@ Examples:
128
131
  $ assistant notifications send --source-channel scheduler --source-event-name schedule.notify --message "Meeting in 5 min" --urgency high --title "Reminder"
129
132
  $ assistant notifications send --source-channel watcher --source-event-name watcher.notification --message "Detected change" --no-requires-action --is-async-background --json
130
133
  $ assistant notifications send --source-channel assistant_tool --source-event-name user.send_notification --message "Build green" --conversation-id 649c4645-3a6f-4ded-a713-504f02ca806b`,
131
- )
132
- .action(
133
- async (
134
- opts: {
135
- sourceChannel: string;
136
- sourceEventName: string;
137
- message: string;
138
- title?: string;
139
- urgency?: string;
140
- requiresAction: boolean;
141
- isAsyncBackground: boolean;
142
- visibleInSourceNow: boolean;
143
- deadlineAt?: string;
144
- preferredChannels?: string;
145
- sessionId?: string;
146
- dedupeKey?: string;
147
- deepLinkMetadata?: string;
148
- conversationId?: string;
149
- },
150
- cmd: Command,
151
- ) => {
152
- try {
153
- // Validate --message (keep basic validation for immediate CLI feedback)
154
- const message = opts.message.trim();
155
- if (message.length === 0) {
156
- writeOutput(cmd, {
157
- ok: false,
158
- error: "Message must be a non-empty string",
159
- });
160
- process.exitCode = 1;
161
- return;
162
- }
134
+ )
135
+ .action(
136
+ async (
137
+ opts: {
138
+ sourceChannel: string;
139
+ sourceEventName: string;
140
+ message: string;
141
+ title?: string;
142
+ urgency?: string;
143
+ requiresAction: boolean;
144
+ isAsyncBackground: boolean;
145
+ visibleInSourceNow: boolean;
146
+ deadlineAt?: string;
147
+ preferredChannels?: string;
148
+ sessionId?: string;
149
+ dedupeKey?: string;
150
+ deepLinkMetadata?: string;
151
+ conversationId?: string;
152
+ },
153
+ cmd: Command,
154
+ ) => {
155
+ try {
156
+ // Validate --message (keep basic validation for immediate CLI feedback)
157
+ const message = opts.message.trim();
158
+ if (message.length === 0) {
159
+ writeOutput(cmd, {
160
+ ok: false,
161
+ error: "Message must be a non-empty string",
162
+ });
163
+ process.exitCode = 1;
164
+ return;
165
+ }
163
166
 
164
- // Validate --urgency
165
- const urgency = opts.urgency ?? "medium";
166
- if (urgency !== "low" && urgency !== "medium" && urgency !== "high") {
167
- writeOutput(cmd, {
168
- ok: false,
169
- error: `Invalid urgency "${opts.urgency}". Must be one of: low, medium, high`,
170
- });
171
- process.exitCode = 1;
172
- return;
173
- }
167
+ // Validate --urgency
168
+ const urgency = opts.urgency ?? "medium";
169
+ if (
170
+ urgency !== "low" &&
171
+ urgency !== "medium" &&
172
+ urgency !== "high" &&
173
+ urgency !== "critical"
174
+ ) {
175
+ writeOutput(cmd, {
176
+ ok: false,
177
+ error: `Invalid urgency "${opts.urgency}". Must be one of: low, medium, high, critical`,
178
+ });
179
+ process.exitCode = 1;
180
+ return;
181
+ }
174
182
 
175
- // Parse --deadline-at
176
- let deadlineAt: number | undefined;
177
- if (opts.deadlineAt != null) {
178
- const parsed = Number(opts.deadlineAt);
179
- if (!Number.isFinite(parsed)) {
180
- writeOutput(cmd, {
181
- ok: false,
182
- error: `Invalid deadline-at "${opts.deadlineAt}". Must be a finite number (epoch milliseconds)`,
183
- });
184
- process.exitCode = 1;
185
- return;
186
- }
187
- deadlineAt = parsed;
188
- }
183
+ // Parse --deadline-at
184
+ let deadlineAt: number | undefined;
185
+ if (opts.deadlineAt != null) {
186
+ const parsed = Number(opts.deadlineAt);
187
+ if (!Number.isFinite(parsed)) {
188
+ writeOutput(cmd, {
189
+ ok: false,
190
+ error: `Invalid deadline-at "${opts.deadlineAt}". Must be a finite number (epoch milliseconds)`,
191
+ });
192
+ process.exitCode = 1;
193
+ return;
194
+ }
195
+ deadlineAt = parsed;
196
+ }
189
197
 
190
- // Parse --preferred-channels
191
- let preferredChannels: string[] | undefined;
192
- if (opts.preferredChannels) {
193
- preferredChannels = opts.preferredChannels
194
- .split(",")
195
- .map((ch) => ch.trim())
196
- .filter((ch) => ch.length > 0);
197
- }
198
+ // Parse --preferred-channels
199
+ let preferredChannels: string[] | undefined;
200
+ if (opts.preferredChannels) {
201
+ preferredChannels = opts.preferredChannels
202
+ .split(",")
203
+ .map((ch) => ch.trim())
204
+ .filter((ch) => ch.length > 0);
205
+ }
198
206
 
199
- // Parse --deep-link-metadata
200
- let deepLinkMetadata: Record<string, unknown> | undefined;
201
- if (opts.deepLinkMetadata != null) {
202
- try {
203
- deepLinkMetadata = JSON.parse(opts.deepLinkMetadata) as Record<
204
- string,
205
- unknown
206
- >;
207
- } catch {
208
- writeOutput(cmd, {
209
- ok: false,
210
- error: `Invalid deep-link-metadata: must be a valid JSON string`,
211
- });
212
- process.exitCode = 1;
213
- return;
214
- }
215
- }
207
+ // Parse --deep-link-metadata
208
+ let deepLinkMetadata: Record<string, unknown> | undefined;
209
+ if (opts.deepLinkMetadata != null) {
210
+ try {
211
+ deepLinkMetadata = JSON.parse(
212
+ opts.deepLinkMetadata,
213
+ ) as Record<string, unknown>;
214
+ } catch {
215
+ writeOutput(cmd, {
216
+ ok: false,
217
+ error: `Invalid deep-link-metadata: must be a valid JSON string`,
218
+ });
219
+ process.exitCode = 1;
220
+ return;
221
+ }
222
+ }
216
223
 
217
- const sourceContextId = opts.sessionId ?? `cli-${Date.now()}`;
224
+ const sourceContextId = opts.sessionId ?? `cli-${Date.now()}`;
218
225
 
219
- // Validate --conversation-id if provided
220
- const conversationId = opts.conversationId?.trim();
221
- if (opts.conversationId != null && !conversationId) {
222
- writeOutput(cmd, {
223
- ok: false,
224
- error: "Conversation ID must be a non-empty string",
225
- });
226
- process.exitCode = 1;
227
- return;
228
- }
226
+ // Validate --conversation-id if provided
227
+ const conversationId = opts.conversationId?.trim();
228
+ if (opts.conversationId != null && !conversationId) {
229
+ writeOutput(cmd, {
230
+ ok: false,
231
+ error: "Conversation ID must be a non-empty string",
232
+ });
233
+ process.exitCode = 1;
234
+ return;
235
+ }
229
236
 
230
- const result = await cliIpcCall<{
231
- signalId: string;
232
- dispatched: boolean;
233
- deduplicated: boolean;
234
- reason: string;
235
- }>("emit_notification_signal", {
236
- body: {
237
- sourceChannel: opts.sourceChannel,
238
- sourceEventName: opts.sourceEventName,
239
- sourceContextId,
240
- attentionHints: {
241
- requiresAction: opts.requiresAction ?? true,
242
- urgency,
243
- deadlineAt,
244
- isAsyncBackground: opts.isAsyncBackground ?? false,
245
- visibleInSourceNow: opts.visibleInSourceNow ?? false,
246
- },
247
- contextPayload: {
248
- requestedMessage: message,
249
- requestedBySource: opts.sourceChannel,
250
- ...(opts.title ? { requestedTitle: opts.title } : {}),
251
- ...(preferredChannels?.length ? { preferredChannels } : {}),
252
- ...(deepLinkMetadata ? { deepLinkMetadata } : {}),
253
- },
254
- ...(opts.dedupeKey ? { dedupeKey: opts.dedupeKey } : {}),
255
- ...(conversationId
256
- ? { conversationAffinityHint: { vellum: conversationId } }
257
- : {}),
258
- throwOnError: true,
259
- },
260
- });
237
+ const result = await cliIpcCall<{
238
+ signalId: string;
239
+ dispatched: boolean;
240
+ deduplicated: boolean;
241
+ reason: string;
242
+ }>("emit_notification_signal", {
243
+ body: {
244
+ sourceChannel: opts.sourceChannel,
245
+ sourceEventName: opts.sourceEventName,
246
+ sourceContextId,
247
+ attentionHints: {
248
+ requiresAction: opts.requiresAction ?? true,
249
+ urgency,
250
+ deadlineAt,
251
+ isAsyncBackground: opts.isAsyncBackground ?? false,
252
+ visibleInSourceNow: opts.visibleInSourceNow ?? false,
253
+ },
254
+ contextPayload: {
255
+ requestedMessage: message,
256
+ requestedBySource: opts.sourceChannel,
257
+ ...(opts.title ? { requestedTitle: opts.title } : {}),
258
+ ...(preferredChannels?.length ? { preferredChannels } : {}),
259
+ ...(deepLinkMetadata ? { deepLinkMetadata } : {}),
260
+ },
261
+ ...(opts.dedupeKey ? { dedupeKey: opts.dedupeKey } : {}),
262
+ ...(conversationId
263
+ ? { conversationAffinityHint: { vellum: conversationId } }
264
+ : {}),
265
+ throwOnError: true,
266
+ },
267
+ });
261
268
 
262
- if (!result.ok) {
263
- writeOutput(cmd, { ok: false, error: result.error });
264
- process.exitCode = 1;
265
- return;
266
- }
269
+ if (!result.ok) {
270
+ writeOutput(cmd, { ok: false, error: result.error });
271
+ process.exitCode = 1;
272
+ return;
273
+ }
267
274
 
268
- const signal = result.result!;
275
+ const signal = result.result!;
269
276
 
270
- writeOutput(cmd, {
271
- ok: true,
272
- signalId: signal.signalId,
273
- dispatched: signal.dispatched,
274
- reason: signal.reason,
275
- });
277
+ writeOutput(cmd, {
278
+ ok: true,
279
+ signalId: signal.signalId,
280
+ dispatched: signal.dispatched,
281
+ reason: signal.reason,
282
+ });
276
283
 
277
- if (!shouldOutputJson(cmd)) {
278
- log.info(
279
- `Signal ${signal.signalId} emitted (dispatched: ${signal.dispatched})`,
280
- );
281
- if (signal.reason) {
282
- log.info(` Reason: ${signal.reason}`);
284
+ if (!shouldOutputJson(cmd)) {
285
+ log.info(
286
+ `Signal ${signal.signalId} emitted (dispatched: ${signal.dispatched})`,
287
+ );
288
+ if (signal.reason) {
289
+ log.info(` Reason: ${signal.reason}`);
290
+ }
291
+ }
292
+ } catch (err) {
293
+ const message = err instanceof Error ? err.message : String(err);
294
+ writeOutput(cmd, { ok: false, error: message });
295
+ process.exitCode = 1;
283
296
  }
284
- }
285
- } catch (err) {
286
- const message = err instanceof Error ? err.message : String(err);
287
- writeOutput(cmd, { ok: false, error: message });
288
- process.exitCode = 1;
289
- }
290
- },
291
- );
297
+ },
298
+ );
292
299
 
293
- // -------------------------------------------------------------------------
294
- // list
295
- // -------------------------------------------------------------------------
300
+ // -------------------------------------------------------------------------
301
+ // list
302
+ // -------------------------------------------------------------------------
296
303
 
297
- notifications
298
- .command("list")
299
- .description("List recent notification events from the local event store")
300
- .option("--limit <n>", "Maximum number of events to return (default: 20)")
301
- .option("--source-event-name <name>", "Filter by source event name")
302
- .addHelpText(
303
- "after",
304
- `
304
+ notifications
305
+ .command("list")
306
+ .description(
307
+ "List recent notification events from the local event store",
308
+ )
309
+ .option(
310
+ "--limit <n>",
311
+ "Maximum number of events to return (default: 20)",
312
+ )
313
+ .option("--source-event-name <name>", "Filter by source event name")
314
+ .addHelpText(
315
+ "after",
316
+ `
305
317
  Reads from the local notification events store, ordered by creation time
306
318
  (newest first). Each event represents a signal that was emitted through the
307
319
  notification pipeline.
@@ -311,92 +323,92 @@ Examples:
311
323
  $ assistant notifications list --limit 5
312
324
  $ assistant notifications list --source-event-name schedule.notify
313
325
  $ assistant notifications list --source-event-name schedule.notify --limit 10 --json`,
314
- )
315
- .action(
316
- async (
317
- opts: {
318
- limit?: string;
319
- sourceEventName?: string;
320
- },
321
- cmd: Command,
322
- ) => {
323
- try {
324
- // Validate --source-event-name (accept any non-empty string; custom
325
- // event names are valid since skills can emit arbitrary names)
326
- if (
327
- opts.sourceEventName != null &&
328
- opts.sourceEventName.trim().length === 0
329
- ) {
330
- writeOutput(cmd, {
331
- ok: false,
332
- error: "Source event name must be a non-empty string",
333
- });
334
- process.exitCode = 1;
335
- return;
336
- }
326
+ )
327
+ .action(
328
+ async (
329
+ opts: {
330
+ limit?: string;
331
+ sourceEventName?: string;
332
+ },
333
+ cmd: Command,
334
+ ) => {
335
+ try {
336
+ // Validate --source-event-name (accept any non-empty string; custom
337
+ // event names are valid since skills can emit arbitrary names)
338
+ if (
339
+ opts.sourceEventName != null &&
340
+ opts.sourceEventName.trim().length === 0
341
+ ) {
342
+ writeOutput(cmd, {
343
+ ok: false,
344
+ error: "Source event name must be a non-empty string",
345
+ });
346
+ process.exitCode = 1;
347
+ return;
348
+ }
337
349
 
338
- // Parse and validate --limit
339
- let limit = 20;
340
- if (opts.limit != null) {
341
- const parsed = Number(opts.limit);
342
- if (
343
- !Number.isFinite(parsed) ||
344
- !Number.isInteger(parsed) ||
345
- parsed < 1
346
- ) {
347
- writeOutput(cmd, {
348
- ok: false,
349
- error: `Invalid limit "${opts.limit}". Must be a positive integer`,
350
- });
351
- process.exitCode = 1;
352
- return;
353
- }
354
- limit = parsed;
355
- }
350
+ // Parse and validate --limit
351
+ let limit = 20;
352
+ if (opts.limit != null) {
353
+ const parsed = Number(opts.limit);
354
+ if (
355
+ !Number.isFinite(parsed) ||
356
+ !Number.isInteger(parsed) ||
357
+ parsed < 1
358
+ ) {
359
+ writeOutput(cmd, {
360
+ ok: false,
361
+ error: `Invalid limit "${opts.limit}". Must be a positive integer`,
362
+ });
363
+ process.exitCode = 1;
364
+ return;
365
+ }
366
+ limit = parsed;
367
+ }
356
368
 
357
- const result = await cliIpcCall<
358
- Array<{
359
- id: string;
360
- sourceEventName: string;
361
- sourceChannel: string;
362
- sourceContextId: string;
363
- urgency: string;
364
- dedupeKey: string | null;
365
- createdAt: string;
366
- }>
367
- >("list_notification_events", {
368
- body: { limit, sourceEventName: opts.sourceEventName },
369
- });
369
+ const result = await cliIpcCall<
370
+ Array<{
371
+ id: string;
372
+ sourceEventName: string;
373
+ sourceChannel: string;
374
+ sourceContextId: string;
375
+ urgency: string;
376
+ dedupeKey: string | null;
377
+ createdAt: string;
378
+ }>
379
+ >("list_notification_events", {
380
+ body: { limit, sourceEventName: opts.sourceEventName },
381
+ });
370
382
 
371
- if (!result.ok) {
372
- writeOutput(cmd, { ok: false, error: result.error });
373
- process.exitCode = 1;
374
- return;
375
- }
383
+ if (!result.ok) {
384
+ writeOutput(cmd, { ok: false, error: result.error });
385
+ process.exitCode = 1;
386
+ return;
387
+ }
376
388
 
377
- const events = result.result!;
389
+ const events = result.result!;
378
390
 
379
- writeOutput(cmd, { ok: true, events });
391
+ writeOutput(cmd, { ok: true, events });
380
392
 
381
- if (!shouldOutputJson(cmd)) {
382
- if (events.length === 0) {
383
- log.info("No notification events found");
384
- } else {
385
- log.info(`${events.length} event(s):\n`);
386
- for (const event of events) {
387
- log.info(
388
- ` ${event.createdAt} ${event.sourceEventName} ${event.urgency} ${event.sourceChannel}`,
389
- );
393
+ if (!shouldOutputJson(cmd)) {
394
+ if (events.length === 0) {
395
+ log.info("No notification events found");
396
+ } else {
397
+ log.info(`${events.length} event(s):\n`);
398
+ for (const event of events) {
399
+ log.info(
400
+ ` ${event.createdAt} ${event.sourceEventName} ${event.urgency} ${event.sourceChannel}`,
401
+ );
402
+ }
403
+ }
390
404
  }
405
+ } catch (err) {
406
+ const message = err instanceof Error ? err.message : String(err);
407
+ writeOutput(cmd, { ok: false, error: message });
408
+ process.exitCode = 1;
391
409
  }
392
- }
393
- } catch (err) {
394
- const message = err instanceof Error ? err.message : String(err);
395
- writeOutput(cmd, { ok: false, error: message });
396
- process.exitCode = 1;
397
- }
398
- },
399
- );
410
+ },
411
+ );
400
412
  },
401
413
  });
402
414
  }