@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
@@ -6,6 +6,9 @@
6
6
  * extensible for future per-device metadata.
7
7
  *
8
8
  * Path resolution:
9
+ * - All modes: the `VELLUM_DEVICE_ID` env var takes precedence when set
10
+ * and is never written to device.json (see getDeviceIdOverride in
11
+ * config/env-registry.ts).
9
12
  * - Containerized (IS_CONTAINERIZED=true): `/home/assistant/.vellum/device.json`
10
13
  * — the assistant user's persistent home dir, kept off the shared data
11
14
  * volume. Not affected by VELLUM_ENVIRONMENT because the container fs
@@ -24,7 +27,10 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
24
27
  import { homedir } from "node:os";
25
28
  import { join } from "node:path";
26
29
 
27
- import { getIsContainerized } from "../config/env-registry.js";
30
+ import {
31
+ getDeviceIdOverride,
32
+ getIsContainerized,
33
+ } from "../config/env-registry.js";
28
34
  import { getLogger } from "./logger.js";
29
35
  import { getXdgVellumConfigDirName } from "./platform.js";
30
36
 
@@ -66,8 +72,9 @@ function resolveDeviceIdPaths(): { dir: string; file: string } {
66
72
  *
67
73
  * Resolution order:
68
74
  * 1. Cached in-memory value (populated on first call)
69
- * 2. `deviceId` field from device.json
70
- * 3. Generate a new UUID, persist it to device.json, and return it
75
+ * 2. `VELLUM_DEVICE_ID` env var (CLI-injected; see env-registry)
76
+ * 3. `deviceId` field from device.json
77
+ * 4. Generate a new UUID, persist it to device.json, and return it
71
78
  *
72
79
  * On any read/write error the generated UUID is still cached so the
73
80
  * process uses a consistent ID for the remainder of its lifetime.
@@ -77,6 +84,13 @@ export function getDeviceId(): string {
77
84
  return cached;
78
85
  }
79
86
 
87
+ const fromEnv = getDeviceIdOverride();
88
+ if (fromEnv) {
89
+ cached = fromEnv;
90
+ log.info({ deviceId: cached }, "Resolved device ID from VELLUM_DEVICE_ID");
91
+ return cached;
92
+ }
93
+
80
94
  const { dir: vellumDir, file: filePath } = resolveDeviceIdPaths();
81
95
  const generated = randomUUID();
82
96
 
@@ -282,6 +282,22 @@ export function getWorkspacePluginsDir(): string {
282
282
  return join(getWorkspaceDir(), "plugins");
283
283
  }
284
284
 
285
+ /**
286
+ * Returns $VELLUM_WORKSPACE_DIR/tools — user-defined tool overrides.
287
+ *
288
+ * Each subdirectory `<name>/` provides either an override of a core tool of
289
+ * the same name or a net-new tool. The single canonical location removes
290
+ * the "which plugin wins" ambiguity that would arise if multiple plugins
291
+ * could register competing overrides for the same tool.
292
+ *
293
+ * Files under this directory are dynamic-imported by the workspace-tool
294
+ * loader on daemon start; the file risk classifier escalates writes under
295
+ * this path to High for the same reason `plugins/` is escalated.
296
+ */
297
+ export function getWorkspaceToolsDir(): string {
298
+ return join(getWorkspaceDir(), "tools");
299
+ }
300
+
285
301
  /** Returns $VELLUM_WORKSPACE_DIR/routes — user-defined HTTP route handlers. */
286
302
  export function getWorkspaceRoutesDir(): string {
287
303
  return join(getWorkspaceDir(), "routes");
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "noEmit": false,
5
+ "declaration": true,
6
+ "declarationMap": false,
7
+ "emitDeclarationOnly": true,
8
+ "sourceMap": false,
9
+ "outDir": "./.plugin-api-build/dts",
10
+ "rootDir": "./src"
11
+ },
12
+ "include": ["src/plugin-api/index.ts"]
13
+ }
@@ -1,68 +0,0 @@
1
- /**
2
- * Tests for the `globalThis.__vellumPluginRuntime` bridge.
3
- *
4
- * The bridge exists so workspace-local plugins (`<workspaceDir>/plugins/*`)
5
- * can register with the daemon's bundled module instances even when the
6
- * daemon is a `bun --compile` binary. Absolute-path imports against a
7
- * compiled binary load fresh disk copies into a disjoint module graph; the
8
- * bridge sidesteps that by attaching a stable handle to globalThis.
9
- */
10
-
11
- import { afterEach, beforeEach, describe, expect, test } from "bun:test";
12
-
13
- import {
14
- getPluginRuntime,
15
- installPluginRuntime,
16
- uninstallPluginRuntimeForTests,
17
- } from "../plugins/external-api.js";
18
- import { registerPlugin } from "../plugins/registry.js";
19
- import { assistantEventHub } from "../runtime/assistant-event-hub.js";
20
- import { getSecureKeyAsync } from "../security/secure-keys.js";
21
-
22
- describe("plugin external-api bridge", () => {
23
- beforeEach(() => {
24
- uninstallPluginRuntimeForTests();
25
- });
26
-
27
- afterEach(() => {
28
- uninstallPluginRuntimeForTests();
29
- });
30
-
31
- test("installs a runtime handle on globalThis", () => {
32
- expect(getPluginRuntime()).toBeUndefined();
33
- installPluginRuntime();
34
- const runtime = getPluginRuntime();
35
- expect(runtime).toBeDefined();
36
- expect(runtime?.version).toBe(1);
37
- });
38
-
39
- test("exposes the canonical registerPlugin / hub / secrets references", () => {
40
- installPluginRuntime();
41
- const runtime = getPluginRuntime();
42
- expect(runtime?.registerPlugin).toBe(registerPlugin);
43
- expect(runtime?.assistantEventHub).toBe(assistantEventHub);
44
- expect(runtime?.getSecureKeyAsync).toBe(getSecureKeyAsync);
45
- });
46
-
47
- test("plugins can read the runtime via the documented globalThis key", () => {
48
- installPluginRuntime();
49
- // Mirror the access pattern documented for plugin authors.
50
- const runtime = (
51
- globalThis as { __vellumPluginRuntime?: { version: number } }
52
- ).__vellumPluginRuntime;
53
- expect(runtime).toBeDefined();
54
- expect(runtime?.version).toBe(1);
55
- });
56
-
57
- test("install is idempotent — repeat calls preserve the same handle", () => {
58
- installPluginRuntime();
59
- const first = getPluginRuntime();
60
- installPluginRuntime();
61
- installPluginRuntime();
62
- expect(getPluginRuntime()).toBe(first);
63
- });
64
-
65
- test("getPluginRuntime returns undefined when the bridge is not installed", () => {
66
- expect(getPluginRuntime()).toBeUndefined();
67
- });
68
- });
@@ -1,355 +0,0 @@
1
- /**
2
- * Tests for plugin-contributed skills (PR 33).
3
- *
4
- * Covers:
5
- * - A plugin declaring `skills: [...]` has its entries registered after
6
- * bootstrap's `init()` succeeds.
7
- * - The registered skill is discoverable via `loadSkillCatalog` and
8
- * resolvable via `loadSkillBySelector` (the exact entry points the model's
9
- * `skill_load` / `skill_execute` flow use).
10
- * - Shutdown (runShutdownHooks) unregisters the plugin's skills so repeated
11
- * bootstraps don't leak catalog entries.
12
- * - Ref-counted register/unregister semantics match the tool registry's
13
- * per-skill-id semantics (PR 13 precedent).
14
- *
15
- * Strategy mirrors `plugin-bootstrap.test.ts`: stub the credential store so
16
- * bootstrap doesn't hit real backends, and `resetPluginRegistryForTests` /
17
- * `resetPluginSkillContributionsForTests` between cases for isolation.
18
- */
19
-
20
- import { rm } from "node:fs/promises";
21
- import { tmpdir } from "node:os";
22
- import { join } from "node:path";
23
- import { beforeEach, describe, expect, mock, test } from "bun:test";
24
-
25
- // Stub credential store before importing bootstrap so the module captures
26
- // the fake binding.
27
- const getSecureKeyAsyncMock = mock(
28
- async (_account: string): Promise<string | undefined> => undefined,
29
- );
30
- mock.module("../security/secure-keys.js", () => ({
31
- getSecureKeyAsync: getSecureKeyAsyncMock,
32
- }));
33
-
34
- import { loadSkillBySelector, loadSkillCatalog } from "../config/skills.js";
35
- import { bootstrapPlugins } from "../daemon/external-plugins-bootstrap.js";
36
- import { runShutdownHooks } from "../daemon/shutdown-registry.js";
37
- import {
38
- getPluginContributedSkillDefinition,
39
- getPluginContributedSkillSummaries,
40
- getPluginSkillRefCount,
41
- registerPluginSkills,
42
- resetPluginSkillContributionsForTests,
43
- unregisterPluginSkills,
44
- } from "../plugins/plugin-skill-contributions.js";
45
- import {
46
- registerPlugin,
47
- resetPluginRegistryForTests,
48
- } from "../plugins/registry.js";
49
- import {
50
- type Plugin,
51
- PluginExecutionError,
52
- type PluginSkillRegistration,
53
- } from "../plugins/types.js";
54
-
55
- // Per-process temp tree so bootstrap's plugin-storage directory creation
56
- // doesn't touch the developer's real ~/.vellum.
57
- const TEST_WORKSPACE_DIR = join(
58
- tmpdir(),
59
- `vellum-plugin-skill-test-${process.pid}`,
60
- );
61
- process.env.VELLUM_WORKSPACE_DIR = TEST_WORKSPACE_DIR;
62
-
63
- /** Build a plugin that contributes one or more skills. */
64
- function buildSkillPlugin(
65
- name: string,
66
- skills: PluginSkillRegistration[],
67
- extras: Partial<Omit<Plugin, "manifest" | "skills">> = {},
68
- ): Plugin {
69
- return {
70
- manifest: {
71
- name,
72
- version: "0.0.1",
73
- },
74
- skills,
75
- ...extras,
76
- };
77
- }
78
-
79
- describe("plugin skill contributions", () => {
80
- beforeEach(async () => {
81
- resetPluginRegistryForTests();
82
- resetPluginSkillContributionsForTests();
83
- getSecureKeyAsyncMock.mockReset();
84
- getSecureKeyAsyncMock.mockImplementation(async () => undefined);
85
- await rm(TEST_WORKSPACE_DIR, { recursive: true, force: true });
86
- });
87
-
88
- test("plugin skills are registered after bootstrap and exposed by the catalog", async () => {
89
- const skill: PluginSkillRegistration = {
90
- id: "plugin-demo-skill",
91
- name: "plugin-demo",
92
- displayName: "Plugin Demo",
93
- description: "A skill contributed by a plugin",
94
- body: "# Plugin Demo\n\nThis is the plugin-provided body.",
95
- activationHints: ["demo", "plugin"],
96
- };
97
-
98
- registerPlugin(buildSkillPlugin("demo-plugin", [skill]));
99
- await bootstrapPlugins();
100
-
101
- // Ref count bumped to exactly 1 so we can tell register and unregister
102
- // are balanced downstream.
103
- expect(getPluginSkillRefCount("demo-plugin")).toBe(1);
104
-
105
- // In-memory registry query surfaces the summary form.
106
- const summaries = getPluginContributedSkillSummaries();
107
- const registered = summaries.find((s) => s.id === "plugin-demo-skill");
108
- expect(registered).toBeDefined();
109
- expect(registered?.source).toBe("plugin");
110
- expect(registered?.name).toBe("plugin-demo");
111
- expect(registered?.displayName).toBe("Plugin Demo");
112
- expect(registered?.activationHints).toEqual(["demo", "plugin"]);
113
- // Summary must not carry the body — bodies are definition-only.
114
- expect((registered as unknown as { body?: unknown }).body).toBeUndefined();
115
-
116
- // The full definition is retrievable by id.
117
- const def = getPluginContributedSkillDefinition("plugin-demo-skill");
118
- expect(def).toBeDefined();
119
- expect(def?.body).toContain("This is the plugin-provided body");
120
- });
121
-
122
- test("catalog and loadSkillBySelector discover plugin-contributed skills (skill_load pathway)", async () => {
123
- const skill: PluginSkillRegistration = {
124
- id: "catalog-visible-skill",
125
- name: "catalog-visible",
126
- description: "A plugin skill expected to surface in loadSkillCatalog",
127
- body: "# Catalog-Visible Skill\n\nBody content for skill_load.",
128
- };
129
-
130
- registerPlugin(buildSkillPlugin("catalog-plugin", [skill]));
131
- await bootstrapPlugins();
132
-
133
- // loadSkillCatalog is the exact entry point `skill_load` consults via
134
- // `loadSkillBySelector` -> `resolveSkillSelector`.
135
- const catalog = loadSkillCatalog();
136
- const found = catalog.find((s) => s.id === "catalog-visible-skill");
137
- expect(found).toBeDefined();
138
- expect(found?.source).toBe("plugin");
139
- expect(found?.description).toBe(skill.description);
140
-
141
- // loadSkillBySelector is what SkillLoadTool.execute calls — it must
142
- // return a fully-populated SkillDefinition, including the body.
143
- const lookup = loadSkillBySelector("catalog-visible-skill");
144
- expect(lookup.error).toBeUndefined();
145
- expect(lookup.skill).toBeDefined();
146
- expect(lookup.skill?.id).toBe("catalog-visible-skill");
147
- expect(lookup.skill?.body).toContain("Body content for skill_load");
148
-
149
- // And name-based resolution (what users type when the model picks a
150
- // skill by name) works the same way.
151
- const byName = loadSkillBySelector("catalog-visible");
152
- expect(byName.skill?.id).toBe("catalog-visible-skill");
153
- });
154
-
155
- test("shutdown unregisters plugin skills so the catalog no longer lists them", async () => {
156
- const skill: PluginSkillRegistration = {
157
- id: "ephemeral-skill",
158
- name: "ephemeral",
159
- description: "Disappears after shutdown",
160
- body: "Only visible while the plugin is alive.",
161
- };
162
-
163
- registerPlugin(buildSkillPlugin("ephemeral-plugin", [skill]));
164
- await bootstrapPlugins();
165
-
166
- // Sanity: present before shutdown.
167
- expect(loadSkillCatalog().some((s) => s.id === "ephemeral-skill")).toBe(
168
- true,
169
- );
170
- expect(getPluginSkillRefCount("ephemeral-plugin")).toBe(1);
171
-
172
- await runShutdownHooks("test-shutdown");
173
-
174
- // After shutdown, the plugin's skill is gone from both the in-memory
175
- // registry and any catalog view that consults it.
176
- expect(getPluginSkillRefCount("ephemeral-plugin")).toBe(0);
177
- expect(
178
- getPluginContributedSkillDefinition("ephemeral-skill"),
179
- ).toBeUndefined();
180
-
181
- const catalogAfter = loadSkillCatalog();
182
- expect(catalogAfter.some((s) => s.id === "ephemeral-skill")).toBe(false);
183
-
184
- // And the selector lookup the model would use fails closed.
185
- const lookup = loadSkillBySelector("ephemeral-skill");
186
- expect(lookup.skill).toBeUndefined();
187
- });
188
-
189
- test("bootstrap is a no-op for plugins without a skills list", async () => {
190
- // A plugin with no `skills` field must not bump ref counts or
191
- // populate the catalog at all.
192
- registerPlugin({
193
- manifest: {
194
- name: "no-skills-plugin",
195
- version: "0.0.1",
196
- },
197
- });
198
-
199
- await bootstrapPlugins();
200
-
201
- expect(getPluginSkillRefCount("no-skills-plugin")).toBe(0);
202
- expect(getPluginContributedSkillSummaries()).toEqual([]);
203
- });
204
-
205
- test("duplicate skill id across plugins fails bootstrap with the plugin named", async () => {
206
- const shared: PluginSkillRegistration = {
207
- id: "contested-id",
208
- name: "contested",
209
- description: "First",
210
- body: "from first plugin",
211
- };
212
- const duplicate: PluginSkillRegistration = {
213
- id: "contested-id",
214
- name: "contested",
215
- description: "Second",
216
- body: "from second plugin",
217
- };
218
-
219
- registerPlugin(buildSkillPlugin("first-plugin", [shared]));
220
- registerPlugin(buildSkillPlugin("second-plugin", [duplicate]));
221
-
222
- let caught: unknown;
223
- try {
224
- await bootstrapPlugins();
225
- } catch (err) {
226
- caught = err;
227
- }
228
- expect(caught).toBeInstanceOf(PluginExecutionError);
229
- // The error must identify which plugin tripped the collision so
230
- // operators can deploy a fix.
231
- const msg = (caught as PluginExecutionError).message;
232
- expect(msg).toContain("second-plugin");
233
- expect(msg).toContain("contested-id");
234
- });
235
-
236
- test("intra-batch duplicate skill id in one plugin is rejected at registration", () => {
237
- // Directly exercise the registry (no bootstrap) — a single plugin
238
- // declaring the same id twice is a configuration bug and must fail
239
- // loudly rather than silently overwrite.
240
- expect(() =>
241
- registerPluginSkills("dup-plugin", [
242
- {
243
- id: "dup-id",
244
- name: "one",
245
- description: "first",
246
- body: "A",
247
- },
248
- {
249
- id: "dup-id",
250
- name: "two",
251
- description: "second",
252
- body: "B",
253
- },
254
- ]),
255
- ).toThrow(PluginExecutionError);
256
- expect(() =>
257
- registerPluginSkills("dup-plugin", [
258
- { id: "x", name: "one", description: "a", body: "A" },
259
- { id: "x", name: "two", description: "b", body: "B" },
260
- ]),
261
- ).toThrow(/declared skill "x" more than once/);
262
- });
263
-
264
- test("ref-counted unregister: second unregister call after repeated registers drops skills", () => {
265
- const registrations: PluginSkillRegistration[] = [
266
- {
267
- id: "refcount-skill",
268
- name: "refcount",
269
- description: "Ref-count demo",
270
- body: "stays until the counter hits zero",
271
- },
272
- ];
273
-
274
- registerPluginSkills("refcount-plugin", registrations);
275
- // Second call is the "same plugin registered again" pattern (hot
276
- // reload). It must bump the counter without re-inserting.
277
- registerPluginSkills("refcount-plugin", registrations);
278
- expect(getPluginSkillRefCount("refcount-plugin")).toBe(2);
279
- expect(getPluginContributedSkillDefinition("refcount-skill")).toBeDefined();
280
-
281
- // One unregister decrements only — skill must still be registered.
282
- unregisterPluginSkills("refcount-plugin");
283
- expect(getPluginSkillRefCount("refcount-plugin")).toBe(1);
284
- expect(getPluginContributedSkillDefinition("refcount-skill")).toBeDefined();
285
-
286
- // Second unregister drops the entry for real.
287
- unregisterPluginSkills("refcount-plugin");
288
- expect(getPluginSkillRefCount("refcount-plugin")).toBe(0);
289
- expect(
290
- getPluginContributedSkillDefinition("refcount-skill"),
291
- ).toBeUndefined();
292
-
293
- // Third unregister (over-decrement) is a no-op, not a throw — mirrors
294
- // the tool-registry behavior so shutdown races don't crash the
295
- // daemon.
296
- expect(() => unregisterPluginSkills("refcount-plugin")).not.toThrow();
297
- });
298
-
299
- test("managed (filesystem) skill with the same id overrides a plugin-contributed skill", async () => {
300
- // Plugin skills sit below managed/workspace in the catalog precedence
301
- // chain so a user can shadow a plugin-provided skill by dropping a
302
- // SKILL.md with the same id under ~/.vellum/workspace/skills. The test
303
- // harness configures VELLUM_WORKSPACE_DIR via the bun test preload, so
304
- // we can synthesize a filesystem skill for the same id and assert it
305
- // wins.
306
- const { mkdirSync, writeFileSync, rmSync, existsSync } =
307
- await import("node:fs");
308
-
309
- const workspaceDir = process.env.VELLUM_WORKSPACE_DIR;
310
- // Skip the filesystem override check when the harness did not provide a
311
- // workspace dir — the other tests in this file still cover catalog
312
- // visibility, which is the core of PR 33.
313
- if (!workspaceDir) {
314
- return;
315
- }
316
-
317
- const skillsDir = join(workspaceDir, "skills", "shared-id");
318
- mkdirSync(skillsDir, { recursive: true });
319
- writeFileSync(
320
- join(skillsDir, "SKILL.md"),
321
- [
322
- "---",
323
- 'name: "filesystem-version"',
324
- 'description: "User-authored override"',
325
- "---",
326
- "",
327
- "# Filesystem Override",
328
- ].join("\n"),
329
- );
330
-
331
- const pluginSkill: PluginSkillRegistration = {
332
- id: "shared-id",
333
- name: "plugin-version",
334
- description: "Plugin-provided skill that should be shadowed",
335
- body: "plugin body",
336
- };
337
- registerPlugin(buildSkillPlugin("shadow-plugin", [pluginSkill]));
338
-
339
- try {
340
- await bootstrapPlugins();
341
-
342
- const catalog = loadSkillCatalog();
343
- const entry = catalog.find((s) => s.id === "shared-id");
344
- // The filesystem SKILL.md wins — source flips to "managed" and the
345
- // plugin's metadata is not what we see.
346
- expect(entry).toBeDefined();
347
- expect(entry?.source).toBe("managed");
348
- expect(entry?.name).toBe("filesystem-version");
349
- } finally {
350
- if (existsSync(skillsDir)) {
351
- rmSync(skillsDir, { recursive: true, force: true });
352
- }
353
- }
354
- });
355
- });
@@ -1,10 +0,0 @@
1
- // Browser interaction types.
2
- // CDP request/response messaging was removed — Playwright's connectOverCDP is broken
3
- // under Bun's runtime. Browser is now launched directly via Playwright.
4
-
5
- // --- Domain-level union aliases (consumed by the barrel file) ---
6
- // These must exist (even as `never`) so the barrel union compiles.
7
-
8
- export type _BrowserClientMessages = never;
9
-
10
- export type _BrowserServerMessages = never;