@vellumai/assistant 0.8.10 → 0.8.11-staging.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (400) hide show
  1. package/bun.lock +62 -1
  2. package/docs/workspace-tools.md +196 -0
  3. package/examples/plugins/echo/README.md +3 -3
  4. package/knip.json +1 -0
  5. package/openapi.yaml +460 -128
  6. package/package.json +2 -1
  7. package/scripts/build-plugin-api.ts +299 -0
  8. package/src/__tests__/agent-loop-callsite-precedence.test.ts +7 -0
  9. package/src/__tests__/agent-loop-compaction-events.test.ts +197 -0
  10. package/src/__tests__/agent-loop-exit-reason.test.ts +93 -96
  11. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +2 -0
  12. package/src/__tests__/agent-loop-output-hooks.test.ts +274 -1
  13. package/src/__tests__/agent-loop-override-profile.test.ts +3 -0
  14. package/src/__tests__/agent-loop-provider-error-recording.test.ts +4 -0
  15. package/src/__tests__/agent-loop-thinking.test.ts +4 -0
  16. package/src/__tests__/agent-loop.test.ts +578 -5
  17. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -1
  18. package/src/__tests__/approval-cascade.test.ts +1 -0
  19. package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
  20. package/src/__tests__/btw-routes.test.ts +0 -1
  21. package/src/__tests__/build-persisted-content.test.ts +75 -1
  22. package/src/__tests__/catalog-install-normalize.test.ts +141 -0
  23. package/src/__tests__/ces-startup-timeout.test.ts +60 -0
  24. package/src/__tests__/compaction-events.test.ts +1 -0
  25. package/src/__tests__/config-managed-gemini-defaults.test.ts +2 -46
  26. package/src/__tests__/context-overflow-reducer.test.ts +264 -124
  27. package/src/__tests__/context-window-manager-overflow-rung.test.ts +351 -0
  28. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  29. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +13 -5
  30. package/src/__tests__/conversation-agent-loop-overflow.test.ts +284 -455
  31. package/src/__tests__/conversation-agent-loop.test.ts +131 -551
  32. package/src/__tests__/conversation-app-control-instantiation.test.ts +13 -0
  33. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
  34. package/src/__tests__/conversation-fork-crud.test.ts +259 -0
  35. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  36. package/src/__tests__/conversation-lifecycle.test.ts +257 -1
  37. package/src/__tests__/conversation-process-callsite.test.ts +1 -0
  38. package/src/__tests__/conversation-provider-retry-repair.test.ts +38 -377
  39. package/src/__tests__/conversation-queue.test.ts +1 -39
  40. package/src/__tests__/conversation-runtime-assembly.test.ts +119 -8
  41. package/src/__tests__/conversation-skill-tools.test.ts +491 -5
  42. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  43. package/src/__tests__/conversation-slash-unknown.test.ts +1 -0
  44. package/src/__tests__/conversation-speed-override.test.ts +1 -0
  45. package/src/__tests__/conversation-store.test.ts +74 -0
  46. package/src/__tests__/conversation-surfaces-app-control.test.ts +4 -1
  47. package/src/__tests__/conversation-tool-setup-attribution.test.ts +323 -0
  48. package/src/__tests__/conversation-tool-setup-tools-disabled.test.ts +34 -0
  49. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
  50. package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
  51. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -0
  52. package/src/__tests__/corrected-target.test.ts +93 -0
  53. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -5
  54. package/src/__tests__/credential-execution-tools.test.ts +23 -11
  55. package/src/__tests__/credential-security-invariants.test.ts +6 -1
  56. package/src/__tests__/db-schedule-syntax-migration.test.ts +80 -0
  57. package/src/__tests__/device-id.test.ts +70 -1
  58. package/src/__tests__/embedding-managed-proxy-selection.test.ts +6 -40
  59. package/src/__tests__/empty-response-hook.test.ts +242 -66
  60. package/src/__tests__/external-plugin-loader.test.ts +0 -31
  61. package/src/__tests__/get-skill-detail-audit.test.ts +43 -1
  62. package/src/__tests__/guardian-routing-invariants.test.ts +91 -0
  63. package/src/__tests__/history-repair-hook.test.ts +228 -3
  64. package/src/__tests__/host-app-control-proxy.test.ts +45 -0
  65. package/src/__tests__/host-browser-proxy.test.ts +254 -9
  66. package/src/__tests__/identity-routes.test.ts +1 -0
  67. package/src/__tests__/image-recovery-hook.test.ts +387 -0
  68. package/src/__tests__/injector-chain.test.ts +5 -4
  69. package/src/__tests__/injector-v3-suppression.test.ts +373 -47
  70. package/src/__tests__/intent-routing.test.ts +7 -0
  71. package/src/__tests__/memory-retrieval-hook.test.ts +117 -15
  72. package/src/__tests__/notification-decision-strategy.test.ts +3 -3
  73. package/src/__tests__/oauth-store.test.ts +0 -85
  74. package/src/__tests__/{context-overflow-policy.test.ts → overflow-policy.test.ts} +1 -1
  75. package/src/__tests__/parallel-tool.benchmark.test.ts +4 -0
  76. package/src/__tests__/persist-unsendable-image-downscale.test.ts +29 -9
  77. package/src/__tests__/persist-unsendable-image.test.ts +4 -4
  78. package/src/__tests__/persistence-secret-redaction.test.ts +78 -0
  79. package/src/__tests__/plugin-bootstrap.test.ts +82 -73
  80. package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
  81. package/src/__tests__/plugin-types.test.ts +0 -8
  82. package/src/__tests__/provider-catalog-visibility.test.ts +1 -9
  83. package/src/__tests__/prune-old-conversations-job.test.ts +99 -0
  84. package/src/__tests__/registry.test.ts +240 -1
  85. package/src/__tests__/require-fresh-approval.test.ts +3 -0
  86. package/src/__tests__/schedule-routes.test.ts +116 -1
  87. package/src/__tests__/schedule-store.test.ts +28 -0
  88. package/src/__tests__/schedule-tools.test.ts +94 -1
  89. package/src/__tests__/server-history-render.test.ts +39 -0
  90. package/src/__tests__/skill-projection-feature-flag.test.ts +13 -0
  91. package/src/__tests__/skill-projection.benchmark.test.ts +25 -7
  92. package/src/__tests__/skills.test.ts +202 -0
  93. package/src/__tests__/slim-skill-category.test.ts +195 -0
  94. package/src/__tests__/strip-memory-injections.test.ts +33 -39
  95. package/src/__tests__/test-support/tool-invocation-seed.ts +79 -0
  96. package/src/__tests__/title-generate-hook.test.ts +9 -7
  97. package/src/__tests__/tool-audit-listener.test.ts +264 -1
  98. package/src/__tests__/tool-error-hook.test.ts +4 -3
  99. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -0
  100. package/src/__tests__/tool-executor-lifecycle-events.test.ts +273 -0
  101. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -0
  102. package/src/__tests__/tool-start-timestamp.test.ts +218 -0
  103. package/src/__tests__/tools-get-route.test.ts +202 -0
  104. package/src/__tests__/workspace-tool-loader.test.ts +319 -0
  105. package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
  106. package/src/agent/loop.ts +569 -319
  107. package/src/api/events/tool-result.ts +9 -0
  108. package/src/api/events/tool-use-start.ts +7 -0
  109. package/src/api/index.ts +10 -0
  110. package/src/api/responses/conversation-message.ts +135 -27
  111. package/src/api/responses/memory-v3-selection-log.ts +4 -4
  112. package/src/approvals/guardian-request-resolvers.ts +26 -0
  113. package/src/browser-session/backends/host-bridge.ts +29 -0
  114. package/src/browser-session/index.ts +1 -0
  115. package/src/browser-session/types.ts +5 -1
  116. package/src/cli/commands/__tests__/schedules.test.ts +62 -4
  117. package/src/cli/commands/__tests__/skills.test.ts +53 -0
  118. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  119. package/src/cli/commands/inference-providers.ts +0 -8
  120. package/src/cli/commands/plugins.ts +2 -2
  121. package/src/cli/commands/schedules.ts +27 -4
  122. package/src/cli/commands/skills.ts +187 -146
  123. package/src/cli/commands/tools.ts +106 -0
  124. package/src/cli/lib/__tests__/install-from-github.test.ts +256 -328
  125. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +6 -2
  126. package/src/cli/lib/__tests__/plugin-details.test.ts +10 -16
  127. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +2 -2
  128. package/src/cli/lib/__tests__/search-plugins.test.ts +145 -240
  129. package/src/cli/lib/install-from-github.ts +187 -117
  130. package/src/cli/lib/plugin-catalog-cache.ts +9 -9
  131. package/src/cli/lib/plugin-details.ts +38 -68
  132. package/src/cli/lib/plugin-marketplace.ts +42 -14
  133. package/src/cli/lib/search-plugins.ts +29 -129
  134. package/src/cli/program.ts +2 -0
  135. package/src/config/bundled-skills/acp/SKILL.md +1 -0
  136. package/src/config/bundled-skills/app-builder/SKILL.md +1 -0
  137. package/src/config/bundled-skills/app-control/SKILL.md +1 -0
  138. package/src/config/bundled-skills/computer-use/SKILL.md +1 -0
  139. package/src/config/bundled-skills/contacts/SKILL.md +1 -0
  140. package/src/config/bundled-skills/document-editor/SKILL.md +1 -0
  141. package/src/config/bundled-skills/followups/SKILL.md +1 -0
  142. package/src/config/bundled-skills/image-studio/SKILL.md +1 -0
  143. package/src/config/bundled-skills/media-processing/SKILL.md +1 -0
  144. package/src/config/bundled-skills/messaging/SKILL.md +1 -0
  145. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -0
  146. package/src/config/bundled-skills/playbooks/SKILL.md +1 -0
  147. package/src/config/bundled-skills/schedule/SKILL.md +1 -0
  148. package/src/config/bundled-skills/schedule/TOOLS.json +11 -3
  149. package/src/config/bundled-skills/sequences/SKILL.md +1 -0
  150. package/src/config/bundled-skills/settings/SKILL.md +1 -0
  151. package/src/config/bundled-skills/skill-management/SKILL.md +101 -1
  152. package/src/config/bundled-skills/subagent/SKILL.md +1 -0
  153. package/src/config/bundled-skills/transcribe/SKILL.md +1 -0
  154. package/src/config/env-registry.ts +23 -0
  155. package/src/config/feature-flag-registry.json +17 -81
  156. package/src/config/loader.ts +5 -22
  157. package/src/config/schema.ts +2 -0
  158. package/src/config/schemas/__tests__/compaction-logs.test.ts +56 -0
  159. package/src/config/schemas/__tests__/memory-v2.test.ts +0 -1
  160. package/src/config/schemas/__tests__/memory-v3.test.ts +61 -1
  161. package/src/config/schemas/compaction-logs.ts +79 -0
  162. package/src/config/schemas/memory-v2.ts +0 -8
  163. package/src/config/schemas/memory-v3.ts +104 -33
  164. package/src/config/seed-inference-profiles.ts +1 -1
  165. package/src/config/skills.ts +117 -47
  166. package/src/context/compactor.ts +11 -0
  167. package/src/context/strip-injections.ts +38 -4
  168. package/src/credential-execution/feature-gates.ts +0 -21
  169. package/src/credential-execution/startup-timeout.ts +32 -4
  170. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +18 -0
  171. package/src/daemon/conversation-agent-loop-handlers.ts +140 -91
  172. package/src/daemon/conversation-agent-loop.ts +123 -658
  173. package/src/daemon/conversation-error.ts +6 -33
  174. package/src/daemon/conversation-lifecycle.ts +1 -1
  175. package/src/daemon/conversation-runtime-assembly.ts +183 -22
  176. package/src/daemon/conversation-skill-tools.ts +137 -8
  177. package/src/daemon/conversation-slash.ts +0 -14
  178. package/src/daemon/conversation-store.ts +2 -19
  179. package/src/daemon/conversation-tool-setup.ts +87 -1
  180. package/src/daemon/conversation.ts +119 -50
  181. package/src/daemon/external-plugins-bootstrap.ts +36 -95
  182. package/src/daemon/handlers/config-channels.ts +11 -2
  183. package/src/daemon/handlers/shared.ts +9 -1
  184. package/src/daemon/handlers/skills.ts +10 -4
  185. package/src/daemon/host-app-control-proxy.ts +72 -57
  186. package/src/daemon/host-browser-proxy.ts +117 -22
  187. package/src/daemon/lifecycle.ts +34 -5
  188. package/src/daemon/message-protocol.ts +0 -7
  189. package/src/daemon/message-types/schedules.ts +1 -0
  190. package/src/daemon/message-types/skills.ts +17 -0
  191. package/src/daemon/providers-setup.ts +3 -0
  192. package/src/daemon/server.ts +3 -3
  193. package/src/daemon/tool-setup-types.ts +9 -3
  194. package/src/daemon/trust-context.ts +23 -0
  195. package/src/daemon/workspace-tools-watcher.ts +324 -0
  196. package/src/events/tool-audit-listener.ts +78 -16
  197. package/src/events/tool-metrics-listener.ts +2 -5
  198. package/src/memory/__tests__/compaction-log-writer-clickhouse.test.ts +227 -0
  199. package/src/memory/__tests__/conversation-queries.test.ts +176 -0
  200. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +20 -32
  201. package/src/memory/compaction-log-writer-clickhouse.ts +418 -0
  202. package/src/memory/conversation-crud.ts +134 -3
  203. package/src/memory/conversation-queries.ts +64 -7
  204. package/src/memory/db-init.ts +14 -0
  205. package/src/memory/embedding-backend.test.ts +130 -1
  206. package/src/memory/embedding-backend.ts +79 -106
  207. package/src/memory/embedding-gemini.ts +5 -0
  208. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +12 -0
  209. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +19 -0
  210. package/src/memory/graph/conversation-graph-memory.ts +36 -25
  211. package/src/memory/graph/tool-handlers.ts +3 -0
  212. package/src/memory/job-handlers/cleanup.ts +3 -1
  213. package/src/memory/jobs-store.ts +0 -28
  214. package/src/memory/jobs-worker.ts +10 -22
  215. package/src/memory/memory-marker.ts +29 -0
  216. package/src/memory/memory-retrospective-startup-cleanup.ts +1 -1
  217. package/src/memory/migrations/268-add-memory-v3-selections.ts +6 -0
  218. package/src/memory/migrations/270-schedule-description.ts +36 -0
  219. package/src/memory/migrations/275-tool-invocations-add-skill-id.test.ts +81 -0
  220. package/src/memory/migrations/275-tool-invocations-add-skill-id.ts +20 -0
  221. package/src/memory/migrations/276-tool-invocations-created-at-id-index.test.ts +68 -0
  222. package/src/memory/migrations/276-tool-invocations-created-at-id-index.ts +20 -0
  223. package/src/memory/migrations/277-add-memory-v3-ever-injected.ts +29 -0
  224. package/src/memory/migrations/278-tool-invocations-telemetry-columns.test.ts +96 -0
  225. package/src/memory/migrations/278-tool-invocations-telemetry-columns.ts +39 -0
  226. package/src/memory/migrations/279-create-skill-loaded-events.test.ts +84 -0
  227. package/src/memory/migrations/279-create-skill-loaded-events.ts +26 -0
  228. package/src/memory/migrations/280-conversations-surfaced-at.test.ts +88 -0
  229. package/src/memory/migrations/280-conversations-surfaced-at.ts +24 -0
  230. package/src/memory/migrations/index.ts +10 -0
  231. package/src/memory/migrations/registry.ts +8 -0
  232. package/src/memory/schema/conversations.ts +16 -0
  233. package/src/memory/schema/infrastructure.ts +26 -0
  234. package/src/memory/skill-loaded-events-store.test.ts +160 -0
  235. package/src/memory/skill-loaded-events-store.ts +95 -0
  236. package/src/memory/tool-executed-events-store.test.ts +219 -0
  237. package/src/memory/tool-executed-events-store.ts +102 -0
  238. package/src/memory/tool-usage-store.ts +15 -3
  239. package/src/memory/v2/__tests__/consolidation-job.test.ts +117 -12
  240. package/src/memory/v2/__tests__/consolidation-prompt-flag-gating-guard.test.ts +189 -0
  241. package/src/memory/v2/__tests__/injected-block-slugs.test.ts +90 -0
  242. package/src/memory/v2/__tests__/page-store.test.ts +33 -0
  243. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +88 -15
  244. package/src/memory/v2/activation-store.ts +50 -1
  245. package/src/memory/v2/consolidation-job.ts +113 -29
  246. package/src/memory/v2/injected-block-slugs.ts +79 -0
  247. package/src/memory/v2/injection.ts +6 -1
  248. package/src/memory/v2/prompts/consolidation.ts +414 -13
  249. package/src/memory/v2/router.ts +2 -28
  250. package/src/memory/v2/static-context.ts +1 -1
  251. package/src/memory/v2/types.ts +16 -0
  252. package/src/notifications/__tests__/copy-composer.test.ts +244 -0
  253. package/src/notifications/access-request-copy.ts +298 -0
  254. package/src/notifications/adapters/slack.ts +3 -3
  255. package/src/notifications/adapters/telegram.ts +2 -1
  256. package/src/notifications/copy-composer.ts +49 -267
  257. package/src/notifications/decision-engine.ts +16 -35
  258. package/src/notifications/home-feed-side-effect.ts +1 -6
  259. package/src/oauth/oauth-store.ts +0 -9
  260. package/src/permissions/checker.test.ts +83 -1
  261. package/src/permissions/checker.ts +25 -2
  262. package/src/permissions/gateway-threshold-reader.test.ts +182 -0
  263. package/src/permissions/gateway-threshold-reader.ts +80 -0
  264. package/src/platform/client.ts +1 -3
  265. package/src/platform/feature-gate.ts +3 -12
  266. package/src/plugin-api/constants.ts +4 -2
  267. package/src/plugin-api/index.ts +63 -11
  268. package/src/plugin-api/types.ts +236 -71
  269. package/src/plugins/defaults/compaction/compact.ts +66 -2
  270. package/src/plugins/defaults/compaction/context-overflow-reducer.ts +240 -32
  271. package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
  272. package/src/{daemon/context-overflow-policy.ts → plugins/defaults/compaction/overflow-policy.ts} +1 -1
  273. package/src/plugins/defaults/compaction/window-manager.ts +303 -1
  274. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +173 -0
  275. package/src/plugins/defaults/empty-response/hooks/stop.ts +11 -115
  276. package/src/plugins/defaults/empty-response/nudge-state-store.ts +46 -0
  277. package/src/plugins/defaults/history-repair/hooks/post-model-call.ts +50 -0
  278. package/src/plugins/defaults/history-repair/hooks/stop.ts +22 -0
  279. package/src/plugins/defaults/history-repair/repair-state-store.ts +51 -0
  280. package/src/plugins/defaults/history-repair/terminal.ts +39 -2
  281. package/src/plugins/defaults/image-recovery/detect.ts +25 -0
  282. package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +73 -0
  283. package/src/plugins/defaults/image-recovery/hooks/stop.ts +22 -0
  284. package/src/plugins/defaults/image-recovery/image-recovery-state-store.ts +48 -0
  285. package/src/plugins/defaults/image-recovery/package.json +14 -0
  286. package/src/{daemon/persist-unsendable-image.ts → plugins/defaults/image-recovery/recover.ts} +67 -14
  287. package/src/plugins/defaults/index.ts +71 -5
  288. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +76 -112
  289. package/src/plugins/defaults/memory-retrieval/hooks/{user-prompt-submit-temp.ts → user-prompt-submit.ts} +83 -74
  290. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +14 -8
  291. package/src/plugins/defaults/memory-retrieval/injectors.ts +2 -18
  292. package/src/plugins/defaults/memory-retrieval/package.json +14 -0
  293. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1157 -0
  294. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +683 -0
  295. package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +161 -140
  296. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +160 -0
  297. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +335 -316
  298. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +145 -53
  299. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +38 -1
  300. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +18 -8
  301. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +112 -71
  302. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +192 -51
  303. package/src/plugins/defaults/memory-v3-shadow/__tests__/types.test.ts +4 -16
  304. package/src/plugins/defaults/memory-v3-shadow/card.test.ts +173 -0
  305. package/src/plugins/defaults/memory-v3-shadow/card.ts +116 -0
  306. package/src/plugins/defaults/memory-v3-shadow/core-set.test.ts +104 -0
  307. package/src/plugins/defaults/memory-v3-shadow/core-set.ts +59 -0
  308. package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.test.ts +305 -0
  309. package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.ts +278 -0
  310. package/src/plugins/defaults/memory-v3-shadow/hot-set.test.ts +138 -0
  311. package/src/plugins/defaults/memory-v3-shadow/hot-set.ts +85 -0
  312. package/src/plugins/defaults/memory-v3-shadow/injector.ts +331 -24
  313. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +119 -13
  314. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +169 -114
  315. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +47 -16
  316. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +144 -66
  317. package/src/plugins/defaults/memory-v3-shadow/prune.test.ts +758 -0
  318. package/src/plugins/defaults/memory-v3-shadow/prune.ts +471 -0
  319. package/src/plugins/defaults/memory-v3-shadow/render-injection.ts +68 -16
  320. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +19 -12
  321. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +96 -43
  322. package/src/plugins/defaults/memory-v3-shadow/types.ts +34 -17
  323. package/src/plugins/defaults/title-generate/hooks/stop.ts +9 -11
  324. package/src/plugins/pipeline.ts +8 -5
  325. package/src/plugins/types.ts +5 -51
  326. package/src/providers/cache-control.ts +26 -0
  327. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +1 -2
  328. package/src/providers/model-catalog.ts +13 -1
  329. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +147 -0
  330. package/src/providers/openai/chat-completions-provider.ts +46 -0
  331. package/src/providers/openai/responses-provider.ts +45 -0
  332. package/src/providers/registry.ts +0 -8
  333. package/src/runtime/__tests__/agent-wake.test.ts +0 -1
  334. package/src/runtime/agent-wake.ts +13 -0
  335. package/src/runtime/routes/__tests__/acp-routes.test.ts +151 -0
  336. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +12 -50
  337. package/src/runtime/routes/__tests__/conversation-surface-routes.test.ts +322 -0
  338. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +0 -62
  339. package/src/runtime/routes/__tests__/plugins-routes.test.ts +31 -11
  340. package/src/runtime/routes/acp-routes.test.ts +106 -0
  341. package/src/runtime/routes/acp-routes.ts +248 -2
  342. package/src/runtime/routes/browser-tabs-routes.ts +1 -1
  343. package/src/runtime/routes/channel-verification-routes.ts +14 -5
  344. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +0 -14
  345. package/src/runtime/routes/consolidation-routes.ts +6 -82
  346. package/src/runtime/routes/conversation-list-routes.ts +6 -0
  347. package/src/runtime/routes/conversation-management-routes.ts +71 -0
  348. package/src/runtime/routes/identity-routes.ts +8 -0
  349. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
  350. package/src/runtime/routes/inference-provider-connection-routes.ts +0 -45
  351. package/src/runtime/routes/plugins-routes.ts +34 -45
  352. package/src/runtime/routes/schedule-routes.ts +43 -5
  353. package/src/runtime/routes/settings-routes.ts +140 -15
  354. package/src/runtime/routes/skills-routes.ts +18 -6
  355. package/src/runtime/services/__tests__/conversation-serializer.test.ts +140 -0
  356. package/src/runtime/services/conversation-serializer.ts +38 -1
  357. package/src/runtime/verification-outbound-actions.ts +147 -2
  358. package/src/runtime/verification-templates.ts +29 -3
  359. package/src/schedule/schedule-store.ts +19 -0
  360. package/src/skills/catalog-install.ts +77 -13
  361. package/src/tasks/task-scheduler.ts +1 -0
  362. package/src/telemetry/types.ts +66 -1
  363. package/src/telemetry/usage-telemetry-reporter.test.ts +542 -13
  364. package/src/telemetry/usage-telemetry-reporter.ts +213 -20
  365. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +49 -2
  366. package/src/tools/browser/__tests__/browser-status.test.ts +29 -5
  367. package/src/tools/browser/browser-execution.ts +27 -9
  368. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +380 -4
  369. package/src/tools/browser/cdp-client/__tests__/host-bridge-cdp-client.test.ts +107 -0
  370. package/src/tools/browser/cdp-client/__tests__/types.test.ts +6 -1
  371. package/src/tools/browser/cdp-client/factory.ts +217 -17
  372. package/src/tools/browser/cdp-client/host-bridge-cdp-client.ts +67 -0
  373. package/src/tools/browser/cdp-client/types.ts +22 -2
  374. package/src/tools/credential-execution/make-authenticated-request.ts +2 -1
  375. package/src/tools/credential-execution/manage-secure-command-tool.ts +169 -164
  376. package/src/tools/credential-execution/run-authenticated-command.ts +2 -1
  377. package/src/tools/executor.ts +39 -7
  378. package/src/tools/registry.ts +387 -5
  379. package/src/tools/schedule/create.ts +16 -0
  380. package/src/tools/schedule/list.ts +12 -4
  381. package/src/tools/schedule/update.ts +12 -0
  382. package/src/tools/skills/load.ts +11 -6
  383. package/src/tools/terminal/safe-env.ts +2 -0
  384. package/src/tools/types.ts +65 -9
  385. package/src/tools/workspace-tools/loader.ts +673 -0
  386. package/src/usage/attribution.ts +28 -0
  387. package/src/util/device-id.ts +17 -3
  388. package/src/util/platform.ts +16 -0
  389. package/tsconfig.plugin-api.json +13 -0
  390. package/src/__tests__/plugin-external-api.test.ts +0 -68
  391. package/src/__tests__/plugin-skill-contribution.test.ts +0 -355
  392. package/src/daemon/message-types/browser.ts +0 -10
  393. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
  394. package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/eval-turns.json +0 -36
  395. package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/live-turns.json +0 -37
  396. package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-eviction.test.ts +0 -106
  397. package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-skeleton.test.ts +0 -44
  398. package/src/plugins/defaults/memory-v3-shadow/working-set.ts +0 -91
  399. package/src/plugins/external-api.ts +0 -114
  400. package/src/plugins/plugin-skill-contributions.ts +0 -292
@@ -124,6 +124,15 @@ export const ToolResultEventSchema = z.object({
124
124
  approvalReason: z.string().optional(),
125
125
  riskThreshold: z.string().optional(),
126
126
  activityMetadata: ToolActivityMetadataSchema.optional(),
127
+ /**
128
+ * Unix ms when the daemon finished executing the tool. Pairs with
129
+ * `ToolUseStartEvent.startedAt` so clients can render a final duration that
130
+ * stays on the daemon's clock, matching the live elapsed-time counter and
131
+ * avoiding skew between a server-stamped start and a browser-stamped end.
132
+ * Absent on streams from older daemons; clients fall back to their own
133
+ * receipt time.
134
+ */
135
+ completedAt: z.number().optional(),
127
136
  });
128
137
 
129
138
  export type ToolResultEvent = z.infer<typeof ToolResultEventSchema>;
@@ -25,6 +25,13 @@ export const ToolUseStartEventSchema = z.object({
25
25
  toolUseId: z.string().optional(),
26
26
  messageId: z.string().optional(),
27
27
  conversationId: z.string().optional(),
28
+ /**
29
+ * Unix ms when the daemon began executing the tool. Lets clients anchor a
30
+ * live elapsed-time counter to the server clock instead of the moment the
31
+ * event was received over SSE. Absent on streams from older daemons that
32
+ * pre-date this field; clients fall back to their own receipt time.
33
+ */
34
+ startedAt: z.number().optional(),
28
35
  });
29
36
 
30
37
  export type ToolUseStartEvent = z.infer<typeof ToolUseStartEventSchema>;
package/src/api/index.ts CHANGED
@@ -325,6 +325,8 @@ export {
325
325
  DictationRequestSchema,
326
326
  } from "./requests/dictation.js";
327
327
  export {
328
+ type ConversationAttachmentBlock,
329
+ ConversationAttachmentBlockSchema,
328
330
  type ConversationContentBlock,
329
331
  ConversationContentBlockSchema,
330
332
  type ConversationMessage,
@@ -339,6 +341,14 @@ export {
339
341
  ConversationSlackMessageSchema,
340
342
  type ConversationSubagentNotification,
341
343
  ConversationSubagentNotificationSchema,
344
+ type ConversationSurfaceBlock,
345
+ ConversationSurfaceBlockSchema,
346
+ type ConversationTextBlock,
347
+ ConversationTextBlockSchema,
348
+ type ConversationThinkingBlock,
349
+ ConversationThinkingBlockSchema,
350
+ type ConversationToolUseBlock,
351
+ ConversationToolUseBlockSchema,
342
352
  type PendingToolConfirmation,
343
353
  PendingToolConfirmationSchema,
344
354
  } from "./responses/conversation-message.js";
@@ -276,6 +276,53 @@ export type ConversationSlackMessage = z.infer<
276
276
  // Content block (unified ordered content)
277
277
  // ---------------------------------------------------------------------------
278
278
 
279
+ /** A run of assistant prose. */
280
+ export const ConversationTextBlockSchema = z.object({
281
+ type: z.literal("text"),
282
+ text: z.string(),
283
+ });
284
+ export type ConversationTextBlock = z.infer<typeof ConversationTextBlockSchema>;
285
+
286
+ /** A contiguous model reasoning run with its timing. */
287
+ export const ConversationThinkingBlockSchema = z.object({
288
+ type: z.literal("thinking"),
289
+ thinking: z.string(),
290
+ /** Unix ms when the model began emitting this reasoning block. */
291
+ startedAt: z.number().optional(),
292
+ /** Unix ms when this reasoning block completed. */
293
+ completedAt: z.number().optional(),
294
+ });
295
+ export type ConversationThinkingBlock = z.infer<
296
+ typeof ConversationThinkingBlockSchema
297
+ >;
298
+
299
+ /** A tool invocation carrying its paired result (`toolCall.result`). */
300
+ export const ConversationToolUseBlockSchema = z.object({
301
+ type: z.literal("tool_use"),
302
+ toolCall: ConversationMessageToolCallSchema,
303
+ });
304
+ export type ConversationToolUseBlock = z.infer<
305
+ typeof ConversationToolUseBlockSchema
306
+ >;
307
+
308
+ /** A vellum surface projection (no provider analog). */
309
+ export const ConversationSurfaceBlockSchema = z.object({
310
+ type: z.literal("surface"),
311
+ surface: ConversationMessageSurfaceSchema,
312
+ });
313
+ export type ConversationSurfaceBlock = z.infer<
314
+ typeof ConversationSurfaceBlockSchema
315
+ >;
316
+
317
+ /** A vellum attachment projection (no provider analog). */
318
+ export const ConversationAttachmentBlockSchema = z.object({
319
+ type: z.literal("attachment"),
320
+ attachment: ConversationMessageAttachmentSchema,
321
+ });
322
+ export type ConversationAttachmentBlock = z.infer<
323
+ typeof ConversationAttachmentBlockSchema
324
+ >;
325
+
279
326
  /**
280
327
  * A single ordered content block. `contentBlocks` is the unified, display-ready
281
328
  * projection of a message's model-native content — one ordered tagged array so
@@ -300,20 +347,11 @@ export type ConversationSlackMessage = z.infer<
300
347
  * it from the positional arrays, so it stays correct once those are retired.
301
348
  */
302
349
  export const ConversationContentBlockSchema = z.discriminatedUnion("type", [
303
- z.object({ type: z.literal("text"), text: z.string() }),
304
- z.object({ type: z.literal("thinking"), thinking: z.string() }),
305
- z.object({
306
- type: z.literal("tool_use"),
307
- toolCall: ConversationMessageToolCallSchema,
308
- }),
309
- z.object({
310
- type: z.literal("surface"),
311
- surface: ConversationMessageSurfaceSchema,
312
- }),
313
- z.object({
314
- type: z.literal("attachment"),
315
- attachment: ConversationMessageAttachmentSchema,
316
- }),
350
+ ConversationTextBlockSchema,
351
+ ConversationThinkingBlockSchema,
352
+ ConversationToolUseBlockSchema,
353
+ ConversationSurfaceBlockSchema,
354
+ ConversationAttachmentBlockSchema,
317
355
  ]);
318
356
  export type ConversationContentBlock = z.infer<
319
357
  typeof ConversationContentBlockSchema
@@ -350,23 +388,93 @@ export const ConversationMessageSchema = z.object({
350
388
  */
351
389
  role: z.enum(["user", "assistant"]),
352
390
  /**
353
- * Flat plain-text body (joined text segments). Redundant with
354
- * `textSegments`/`contentOrder` for clients that render from the positional
355
- * arrays (web, CLI), but the legacy Swift macOS client reads `content`
356
- * directly and drops any history row missing it (its
357
- * `HistoryReconstructionService` skips rows with empty text). The serializer
358
- * always emits it — do not remove without updating that client.
391
+ * @deprecated Superseded by `contentBlocks`. Flat plain-text body (joined
392
+ * text segments). Redundant with `textSegments`/`contentOrder` for clients
393
+ * that render from the positional arrays (web, CLI), but the legacy Swift
394
+ * macOS client reads `content` directly and drops any history row missing it
395
+ * (its `HistoryReconstructionService` skips rows with empty text). The
396
+ * serializer always emits it — do not remove without updating that client.
359
397
  */
360
- content: z.string().optional(),
398
+ content: z
399
+ .string()
400
+ .meta({
401
+ deprecated: true,
402
+ description:
403
+ "Deprecated: superseded by contentBlocks. Flat plain-text body (joined text segments).",
404
+ })
405
+ .optional(),
361
406
  /** Display timestamp as an ISO-8601 string. */
362
407
  timestamp: z.string(),
408
+ /**
409
+ * Flat list of attachment metadata for the row. Not yet supersedable by
410
+ * `contentBlocks`: `renderHistoryContent` emits an `attachment` content
411
+ * block only for file-block refs with an inline placement, so orphan rows
412
+ * (unmatched ids, count mismatch, no DB rows — see `alignAttachments`) ship
413
+ * here alone. Kept non-deprecated until `contentBlocks` reaches attachment
414
+ * parity, so clients that migrate off the positional arrays don't drop those
415
+ * chips.
416
+ */
363
417
  attachments: z.array(ConversationMessageAttachmentSchema),
364
- toolCalls: z.array(ConversationMessageToolCallSchema).optional(),
365
- surfaces: z.array(ConversationMessageSurfaceSchema).optional(),
366
- textSegments: z.array(z.string()).optional(),
367
- thinkingSegments: z.array(z.string()).optional(),
368
- /** Positional `"<type>:<index>"` content ordering (e.g. `"text:0"`, `"thinking:1"`). */
369
- contentOrder: z.array(z.string()).optional(),
418
+ /**
419
+ * @deprecated Superseded by `contentBlocks` (the `tool_use` variant). Flat
420
+ * list of tool calls for the row.
421
+ */
422
+ toolCalls: z
423
+ .array(ConversationMessageToolCallSchema)
424
+ .meta({
425
+ deprecated: true,
426
+ description:
427
+ "Deprecated: superseded by contentBlocks (the tool_use variant). Flat list of tool calls.",
428
+ })
429
+ .optional(),
430
+ /**
431
+ * @deprecated Superseded by `contentBlocks` (the `surface` variant). Flat
432
+ * list of surfaces for the row.
433
+ */
434
+ surfaces: z
435
+ .array(ConversationMessageSurfaceSchema)
436
+ .meta({
437
+ deprecated: true,
438
+ description:
439
+ "Deprecated: superseded by contentBlocks (the surface variant). Flat list of surfaces.",
440
+ })
441
+ .optional(),
442
+ /**
443
+ * @deprecated Superseded by `contentBlocks`. Text split by tool-call
444
+ * boundaries; positional sibling of `contentOrder`.
445
+ */
446
+ textSegments: z
447
+ .array(z.string())
448
+ .meta({
449
+ deprecated: true,
450
+ description:
451
+ "Deprecated: superseded by contentBlocks. Text segments split by tool-call boundaries.",
452
+ })
453
+ .optional(),
454
+ /**
455
+ * @deprecated Superseded by `contentBlocks`. Reasoning text extracted from
456
+ * thinking blocks; positional sibling of `contentOrder`.
457
+ */
458
+ thinkingSegments: z
459
+ .array(z.string())
460
+ .meta({
461
+ deprecated: true,
462
+ description:
463
+ "Deprecated: superseded by contentBlocks. Reasoning text extracted from thinking blocks.",
464
+ })
465
+ .optional(),
466
+ /**
467
+ * @deprecated Superseded by `contentBlocks`. Positional
468
+ * `"<type>:<index>"` content ordering (e.g. `"text:0"`, `"thinking:1"`).
469
+ */
470
+ contentOrder: z
471
+ .array(z.string())
472
+ .meta({
473
+ deprecated: true,
474
+ description:
475
+ 'Deprecated: superseded by contentBlocks. Positional "<type>:<index>" content ordering (e.g. "text:0", "thinking:1").',
476
+ })
477
+ .optional(),
370
478
  /**
371
479
  * Unified ordered content blocks — the display-ready projection of the
372
480
  * row's model-native content. Ships alongside the positional
@@ -29,10 +29,10 @@ import { z } from "zod";
29
29
 
30
30
  /**
31
31
  * One selected page in the v3 set. `source` is the lane that surfaced it —
32
- * the daemon emits `needle`, `dense`, `edge`, or `carry-forward` — but the
33
- * schema stays a permissive string so a new lane label (or a historical
34
- * pre-lane row) doesn't break parsing on the FE. `pinned` marks a slug carried
35
- * forward across turns.
32
+ * the daemon emits `core`, `hot`, `needle`, `dense`, or `edge` (historical
33
+ * rows may carry retired labels) — but the schema stays a permissive string
34
+ * so a new lane label (or a historical pre-lane row) doesn't break parsing on
35
+ * the FE. `pinned` marks a page the turn was centrally about.
36
36
  */
37
37
  export const MemoryV3SelectionRowSchema = z.object({
38
38
  slug: z.string(),
@@ -196,6 +196,32 @@ const pendingInteractionResolver: GuardianRequestResolver = {
196
196
  // resolveConfirmation() owns pendingInteractions deregistration.
197
197
  const userDecision: UserDecision =
198
198
  decision.action === "reject" ? "deny" : "allow";
199
+
200
+ // Route-owned confirmations (e.g. the ACP spawn/steer approval gate in
201
+ // acp-routes.ts) carry a `directResolve` and are NOT owned by any
202
+ // Conversation.prompter, so handleConfirmationResponse below would no-op
203
+ // and the caller would block until timeout. Resolve them directly, exactly
204
+ // as the POST /v1/confirm route does (see approval-routes.ts).
205
+ if (interaction.directResolve) {
206
+ pendingInteractions.resolve(
207
+ request.id,
208
+ userDecision === "allow" ? "approved" : "rejected",
209
+ );
210
+ interaction.directResolve(userDecision);
211
+ log.info(
212
+ {
213
+ event: "resolver_tool_approval_applied",
214
+ requestId: request.id,
215
+ action: decision.action,
216
+ conversationId: request.conversationId,
217
+ toolName: request.toolName,
218
+ directResolve: true,
219
+ },
220
+ "Tool approval resolver: direct-resolve interaction resolved",
221
+ );
222
+ return { ok: true, applied: true };
223
+ }
224
+
199
225
  const conversation = findConversation(interaction.conversationId);
200
226
  if (!conversation) {
201
227
  return {
@@ -0,0 +1,29 @@
1
+ import type { BrowserBackend, CdpCommand, CdpResult } from "../types.js";
2
+
3
+ /**
4
+ * Host-bridge backend for BrowserSessionManager. Wraps a caller-provided
5
+ * `sendCdp` transport that routes raw CDP commands through the daemon's
6
+ * HostBrowserProxy to the desktop client's SSE bridge, which executes
7
+ * them against the user's Chrome via its local remote-debugging port.
8
+ * Unlike the extension backend, the bridge has no `Vellum.*`
9
+ * pseudo-method support. The factory in
10
+ * `assistant/src/tools/browser/cdp-client/factory.ts` constructs one
11
+ * per tool invocation.
12
+ */
13
+ export interface HostBridgeBackendDeps {
14
+ /** Sends a raw CDP command via the desktop SSE bridge and returns the CDP result. */
15
+ sendCdp(command: CdpCommand, signal?: AbortSignal): Promise<CdpResult>;
16
+ isAvailable(): boolean;
17
+ dispose(): void;
18
+ }
19
+
20
+ export function createHostBridgeBackend(
21
+ deps: HostBridgeBackendDeps,
22
+ ): BrowserBackend {
23
+ return {
24
+ kind: "host-bridge",
25
+ isAvailable: deps.isAvailable,
26
+ send: deps.sendCdp,
27
+ dispose: deps.dispose,
28
+ };
29
+ }
@@ -21,6 +21,7 @@
21
21
  */
22
22
  export * from "./backends/cdp-inspect.js";
23
23
  export * from "./backends/extension.js";
24
+ export * from "./backends/host-bridge.js";
24
25
  export * from "./backends/local.js";
25
26
  export * from "./events.js";
26
27
  export * from "./manager.js";
@@ -1,4 +1,8 @@
1
- export type BrowserBackendKind = "extension" | "local" | "cdp-inspect";
1
+ export type BrowserBackendKind =
2
+ | "extension"
3
+ | "local"
4
+ | "cdp-inspect"
5
+ | "host-bridge";
2
6
 
3
7
  export interface CdpCommand {
4
8
  method: string;
@@ -151,7 +151,8 @@ describe("schedules list", () => {
151
151
  retryCount: 0,
152
152
  maxRetries: 3,
153
153
  retryBackoffMs: 60_000,
154
- description: "Every 30 minutes",
154
+ description: "Authored heartbeat check",
155
+ cadenceDescription: "Every 30 minutes",
155
156
  mode: "execute",
156
157
  status: "active",
157
158
  routingIntent: "all_channels",
@@ -175,6 +176,8 @@ describe("schedules list", () => {
175
176
  expect.objectContaining({
176
177
  id: "schedule-1",
177
178
  name: "Heartbeat",
179
+ description: "Authored heartbeat check",
180
+ cadenceDescription: "Every 30 minutes",
178
181
  }),
179
182
  ],
180
183
  });
@@ -201,7 +204,8 @@ describe("schedules list", () => {
201
204
  retryCount: 0,
202
205
  maxRetries: 3,
203
206
  retryBackoffMs: 60_000,
204
- description: "Every 30 minutes",
207
+ description: "Authored heartbeat check",
208
+ cadenceDescription: "Every 30 minutes",
205
209
  mode: "execute",
206
210
  status: "active",
207
211
  routingIntent: "all_channels",
@@ -219,6 +223,7 @@ describe("schedules list", () => {
219
223
  expect(logLines.join("\n")).toContain("ID");
220
224
  expect(logLines.join("\n")).toContain("Heartbeat");
221
225
  expect(logLines.join("\n")).toContain("Every 30 minutes (UTC)");
226
+ expect(logLines.join("\n")).not.toContain("Authored heartbeat check");
222
227
  });
223
228
 
224
229
  test("sets exit code on IPC failure", async () => {
@@ -376,6 +381,8 @@ describe("schedules create", () => {
376
381
  "Heartbeat",
377
382
  "--expression",
378
383
  "*/30 * * * *",
384
+ "--description",
385
+ "Checks service heartbeat",
379
386
  "--message",
380
387
  "run heartbeat",
381
388
  ]);
@@ -388,6 +395,7 @@ describe("schedules create", () => {
388
395
  body: {
389
396
  name: "Heartbeat",
390
397
  expression: "*/30 * * * *",
398
+ description: "Checks service heartbeat",
391
399
  message: "run heartbeat",
392
400
  enabled: true,
393
401
  },
@@ -397,6 +405,39 @@ describe("schedules create", () => {
397
405
  expect(logLines).toEqual(["Created schedule: Heartbeat"]);
398
406
  });
399
407
 
408
+ test("requires a description", async () => {
409
+ const { exitCode } = await runCommand([
410
+ "schedules",
411
+ "create",
412
+ "Heartbeat",
413
+ "--expression",
414
+ "*/30 * * * *",
415
+ "--message",
416
+ "run heartbeat",
417
+ ]);
418
+
419
+ expect(exitCode).not.toBe(0);
420
+ expect(ipcCalls).toEqual([]);
421
+ });
422
+
423
+ test("rejects an empty description", async () => {
424
+ const { exitCode } = await runCommand([
425
+ "schedules",
426
+ "create",
427
+ "Heartbeat",
428
+ "--expression",
429
+ "*/30 * * * *",
430
+ "--description",
431
+ " ",
432
+ "--message",
433
+ "run heartbeat",
434
+ ]);
435
+
436
+ expect(exitCode).not.toBe(0);
437
+ expect(ipcCalls).toEqual([]);
438
+ expect(errorLines).toEqual(["description is required"]);
439
+ });
440
+
400
441
  test("passes --timezone through to the request body", async () => {
401
442
  mockIpcResult = { ok: true, result: { schedules: [] } };
402
443
 
@@ -408,6 +449,8 @@ describe("schedules create", () => {
408
449
  "0 9 * * MON-FRI",
409
450
  "--message",
410
451
  "morning summary",
452
+ "--description",
453
+ "Summarizes weekday mornings",
411
454
  "--timezone",
412
455
  "America/New_York",
413
456
  ]);
@@ -421,6 +464,7 @@ describe("schedules create", () => {
421
464
  name: "Morning",
422
465
  expression: "0 9 * * MON-FRI",
423
466
  message: "morning summary",
467
+ description: "Summarizes weekday mornings",
424
468
  enabled: true,
425
469
  timezone: "America/New_York",
426
470
  },
@@ -440,6 +484,8 @@ describe("schedules create", () => {
440
484
  "0 0 * * *",
441
485
  "--message",
442
486
  "placeholder",
487
+ "--description",
488
+ "Draft schedule",
443
489
  "--no-enabled",
444
490
  ]);
445
491
 
@@ -452,6 +498,7 @@ describe("schedules create", () => {
452
498
  name: "Drafted",
453
499
  expression: "0 0 * * *",
454
500
  message: "placeholder",
501
+ description: "Draft schedule",
455
502
  enabled: false,
456
503
  },
457
504
  },
@@ -480,7 +527,8 @@ describe("schedules create", () => {
480
527
  retryCount: 0,
481
528
  maxRetries: 3,
482
529
  retryBackoffMs: 60_000,
483
- description: "Every 30 minutes",
530
+ description: "Checks service heartbeat",
531
+ cadenceDescription: "Every 30 minutes",
484
532
  mode: "execute",
485
533
  status: "active",
486
534
  routingIntent: "all_channels",
@@ -500,12 +548,20 @@ describe("schedules create", () => {
500
548
  "*/30 * * * *",
501
549
  "--message",
502
550
  "run heartbeat",
551
+ "--description",
552
+ "Checks service heartbeat",
503
553
  "--json",
504
554
  ]);
505
555
 
506
556
  expect(exitCode).toBe(0);
507
557
  expect(JSON.parse(stdout)).toEqual({
508
- schedules: [expect.objectContaining({ id: "new-schedule-id" })],
558
+ schedules: [
559
+ expect.objectContaining({
560
+ id: "new-schedule-id",
561
+ description: "Checks service heartbeat",
562
+ cadenceDescription: "Every 30 minutes",
563
+ }),
564
+ ],
509
565
  });
510
566
  expect(logLines).toEqual([]);
511
567
  });
@@ -524,6 +580,8 @@ describe("schedules create", () => {
524
580
  "not-a-cron",
525
581
  "--message",
526
582
  "noop",
583
+ "--description",
584
+ "Invalid test schedule",
527
585
  ]);
528
586
 
529
587
  expect(exitCode).toBe(10);
@@ -146,6 +146,59 @@ describe("skills list", () => {
146
146
  ).toEqual({});
147
147
  });
148
148
 
149
+ test("--json derives source from owner for plugin-resident skills", async () => {
150
+ /**
151
+ * Plugin-resident skills are mapped to kind:bundled/origin:vellum, so
152
+ * their attribution lives on `owner`. The CLI must surface that as
153
+ * `plugin:<id>` instead of collapsing to "bundled".
154
+ */
155
+
156
+ // GIVEN a plugin-resident skill (owner set) and a plain bundled skill
157
+ mockIpcResults = [
158
+ {
159
+ ok: true,
160
+ result: {
161
+ skills: [
162
+ {
163
+ id: "caveman",
164
+ name: "Caveman",
165
+ description: "Ultra-compressed communication mode",
166
+ origin: "vellum",
167
+ kind: "bundled",
168
+ status: "enabled",
169
+ owner: { kind: "plugin", id: "caveman" },
170
+ },
171
+ {
172
+ id: "weather",
173
+ name: "Weather",
174
+ description: "Get weather",
175
+ origin: "vellum",
176
+ kind: "bundled",
177
+ status: "enabled",
178
+ },
179
+ ],
180
+ },
181
+ },
182
+ ];
183
+
184
+ // WHEN listing skills as JSON
185
+ const { stdout } = await runCommand(["skills", "list", "--json"]);
186
+
187
+ // THEN the plugin skill's source is `plugin:<id>` and owner is preserved
188
+ const parsed = JSON.parse(stdout) as {
189
+ ok: boolean;
190
+ skills: Array<{ id: string; source: string; owner?: unknown }>;
191
+ };
192
+ const caveman = parsed.skills.find((s) => s.id === "caveman");
193
+ const weather = parsed.skills.find((s) => s.id === "weather");
194
+ expect(caveman?.source).toBe("plugin:caveman");
195
+ expect(caveman?.owner).toEqual({ kind: "plugin", id: "caveman" });
196
+
197
+ // AND a bundled skill with no owner keeps the "bundled" source label
198
+ expect(weather?.source).toBe("bundled");
199
+ expect(weather?.owner).toBeUndefined();
200
+ });
201
+
149
202
  test("IPC failure sets exitCode 1", async () => {
150
203
  mockIpcResults = [{ ok: false, error: "Connection refused" }];
151
204
 
@@ -79,7 +79,7 @@ export function registerChannelVerificationSessionsCommand(
79
79
  "after",
80
80
  `
81
81
  Verification sessions are used to verify guardian bindings and trusted
82
- contacts across channels (telegram, phone, slack). Three flows exist:
82
+ contacts across channels (telegram, phone, slack, email). Three flows exist:
83
83
 
84
84
  1. Inbound challenge — the assistant generates a secret code and waits
85
85
  for the guardian to send it back on the channel. Used when the
@@ -107,10 +107,10 @@ Examples:
107
107
  cvs
108
108
  .command("create")
109
109
  .description("Create a new verification session")
110
- .option("--channel <channel>", "Channel type (telegram, phone, slack)")
110
+ .option("--channel <channel>", "Channel type (telegram, phone, slack, email)")
111
111
  .option(
112
112
  "--destination <destination>",
113
- "Destination address for outbound verification (handle, phone number, or user ID)",
113
+ "Destination address for outbound verification (handle, phone number, user ID, or email address)",
114
114
  )
115
115
  .option("--rebind", "Replace existing guardian binding")
116
116
  .option(
@@ -140,7 +140,7 @@ Routes between three creation modes based on the provided options:
140
140
 
141
141
  2. Outbound: --channel <ch> --destination <dest>
142
142
  Sends a verification code to the given destination. Supports telegram
143
- (handle or chat ID), phone (E.164 number), and slack (user ID).
143
+ (handle or chat ID), phone (E.164 number), slack (user ID), and email.
144
144
  Use --rebind to replace an existing guardian binding.
145
145
 
146
146
  3. Inbound: --channel <ch> (no --destination)
@@ -240,7 +240,7 @@ Examples:
240
240
  )
241
241
  .requiredOption(
242
242
  "--channel <channel>",
243
- "Channel type (telegram, phone, slack)",
243
+ "Channel type (telegram, phone, slack, email)",
244
244
  )
245
245
  .option(
246
246
  "--origin-conversation-id <id>",
@@ -290,7 +290,7 @@ Examples:
290
290
  .description("Cancel all active verification sessions for a channel")
291
291
  .requiredOption(
292
292
  "--channel <channel>",
293
- "Channel type (telegram, phone, slack)",
293
+ "Channel type (telegram, phone, slack, email)",
294
294
  )
295
295
  .addHelpText(
296
296
  "after",
@@ -16,8 +16,6 @@
16
16
 
17
17
  import type { Command } from "commander";
18
18
 
19
- import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
20
- import { getConfig } from "../../config/loader.js";
21
19
  import { cliIpcCall } from "../../ipc/cli-client.js";
22
20
  import type { OAuth2Config } from "../../security/oauth2.js";
23
21
  import { startOAuth2Flow } from "../../security/oauth2.js";
@@ -343,12 +341,6 @@ function attachLoginChatgptSubcommand(providers: Command): void {
343
341
  .description("Authenticate with ChatGPT via browser OAuth flow")
344
342
  .option("--json", "Output as JSON")
345
343
  .action(async (opts: { json?: boolean }) => {
346
- const config = getConfig();
347
- if (!isAssistantFeatureFlagEnabled("chatgpt-subscription-auth", config)) {
348
- writeCliError("This feature is not yet available", opts.json);
349
- return;
350
- }
351
-
352
344
  try {
353
345
  // Step 1: Run browser-based PKCE OAuth flow
354
346
  process.stdout.write("Opening browser for ChatGPT authentication...\n");
@@ -55,7 +55,7 @@ Examples:
55
55
  plugins
56
56
  .command("install <name>")
57
57
  .description(
58
- "Install a plugin from vellum-ai/vellum-assistant/experimental/plugins/<name>",
58
+ "Install a plugin from the curated plugins/marketplace.json catalog",
59
59
  )
60
60
  .option("--force", "Overwrite an existing install")
61
61
  .option(
@@ -150,7 +150,7 @@ Examples:
150
150
  plugins
151
151
  .command("search <query>")
152
152
  .description(
153
- "Search vellum-ai/vellum-assistant/experimental/plugins for plugin names matching <query> (case-insensitive regex)",
153
+ "Search the plugins/marketplace.json catalog for plugin names matching <query> (case-insensitive regex)",
154
154
  )
155
155
  .option("--json", "Emit machine-readable JSON instead of a table")
156
156
  .action(async (query: string, opts: { json?: boolean }) => {