@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
@@ -441,6 +441,57 @@ describe("GET /schedules — default defer exclusion", () => {
441
441
  expect(noSource.createdFromConversationArchivedAt).toBeNull();
442
442
  });
443
443
 
444
+ test("returns authored descriptions separately from cadence descriptions", () => {
445
+ createSchedule({
446
+ name: "Described schedule",
447
+ description: "Review the morning queue",
448
+ cronExpression: "0 9 * * *",
449
+ message: "review queue",
450
+ syntax: "cron",
451
+ });
452
+
453
+ const route = findRoute("schedules", "GET");
454
+ const result = route.handler({}) as {
455
+ schedules: Array<{
456
+ name: string;
457
+ description: string;
458
+ cadenceDescription: string;
459
+ }>;
460
+ };
461
+
462
+ expect(result.schedules).toHaveLength(1);
463
+ expect(result.schedules[0]).toMatchObject({
464
+ name: "Described schedule",
465
+ description: "Review the morning queue",
466
+ cadenceDescription: "Every day at 9:00 AM",
467
+ });
468
+ });
469
+
470
+ test("returns One-time as the cadence description for one-shot schedules", () => {
471
+ createSchedule({
472
+ name: "One-shot schedule",
473
+ description: "Send a one-time reminder",
474
+ cronExpression: null,
475
+ nextRunAt: Date.now() + 60_000,
476
+ message: "remember this",
477
+ });
478
+
479
+ const route = findRoute("schedules", "GET");
480
+ const result = route.handler({}) as {
481
+ schedules: Array<{
482
+ name: string;
483
+ description: string;
484
+ cadenceDescription: string;
485
+ }>;
486
+ };
487
+
488
+ expect(result.schedules[0]).toMatchObject({
489
+ name: "One-shot schedule",
490
+ description: "Send a one-time reminder",
491
+ cadenceDescription: "One-time",
492
+ });
493
+ });
494
+
444
495
  test("mutation responses also exclude deferred wakes", () => {
445
496
  createSchedule({
446
497
  name: "Agent schedule",
@@ -997,6 +1048,7 @@ describe("POST /schedules — create", () => {
997
1048
  test("creates a recurring execute schedule with defaults", () => {
998
1049
  const result = postCreate({
999
1050
  name: "Morning ping",
1051
+ description: "Start the morning workflow",
1000
1052
  expression: "0 9 * * *",
1001
1053
  message: "good morning",
1002
1054
  });
@@ -1006,6 +1058,7 @@ describe("POST /schedules — create", () => {
1006
1058
  expect(job.mode).toBe("execute");
1007
1059
  expect(job.expression).toBe("0 9 * * *");
1008
1060
  expect(job.syntax).toBe("cron");
1061
+ expect(job.description).toBe("Start the morning workflow");
1009
1062
  expect(job.enabled).toBe(true);
1010
1063
  expect(job.timezone).toBeNull();
1011
1064
  });
@@ -1013,12 +1066,14 @@ describe("POST /schedules — create", () => {
1013
1066
  test("trims whitespace and accepts an explicit timezone", () => {
1014
1067
  postCreate({
1015
1068
  name: " Trimmed ",
1069
+ description: " Trimmed description ",
1016
1070
  expression: " 0 9 * * * ",
1017
1071
  message: "hi",
1018
1072
  timezone: " America/New_York ",
1019
1073
  });
1020
1074
  const job = listSchedules()[0];
1021
1075
  expect(job.name).toBe("Trimmed");
1076
+ expect(job.description).toBe("Trimmed description");
1022
1077
  expect(job.expression).toBe("0 9 * * *");
1023
1078
  expect(job.timezone).toBe("America/New_York");
1024
1079
  });
@@ -1027,6 +1082,7 @@ describe("POST /schedules — create", () => {
1027
1082
  const expression = "DTSTART:20260101T000000Z\nRRULE:FREQ=WEEKLY;BYDAY=MO";
1028
1083
  postCreate({
1029
1084
  name: "Weekly",
1085
+ description: "Weekly wake",
1030
1086
  expression,
1031
1087
  message: "monday wake",
1032
1088
  });
@@ -1045,12 +1101,32 @@ describe("POST /schedules — create", () => {
1045
1101
  expect(() => postCreate({ name: "x", expression: "* * * * *" })).toThrow(
1046
1102
  "message is required",
1047
1103
  );
1104
+ expect(() =>
1105
+ postCreate({
1106
+ name: "x",
1107
+ description: " ",
1108
+ expression: "* * * * *",
1109
+ message: "hi",
1110
+ }),
1111
+ ).toThrow("description is required");
1112
+ });
1113
+
1114
+ test("defaults omitted create descriptions for backward compatibility", () => {
1115
+ postCreate({
1116
+ name: "Description fallback",
1117
+ expression: "0 9 * * *",
1118
+ message: "hi",
1119
+ });
1120
+
1121
+ const job = listSchedules()[0];
1122
+ expect(job.description).toBe("Description fallback");
1048
1123
  });
1049
1124
 
1050
1125
  test("rejects non-execute modes", () => {
1051
1126
  expect(() =>
1052
1127
  postCreate({
1053
1128
  name: "x",
1129
+ description: "Run the thing",
1054
1130
  expression: "* * * * *",
1055
1131
  message: "hi",
1056
1132
  mode: "notify",
@@ -1060,7 +1136,12 @@ describe("POST /schedules — create", () => {
1060
1136
 
1061
1137
  test("rejects an unparseable expression", () => {
1062
1138
  expect(() =>
1063
- postCreate({ name: "x", expression: "not-a-cron", message: "hi" }),
1139
+ postCreate({
1140
+ name: "x",
1141
+ description: "Run the thing",
1142
+ expression: "not-a-cron",
1143
+ message: "hi",
1144
+ }),
1064
1145
  ).toThrow("could not be parsed");
1065
1146
  });
1066
1147
 
@@ -1068,6 +1149,7 @@ describe("POST /schedules — create", () => {
1068
1149
  expect(() =>
1069
1150
  postCreate({
1070
1151
  name: "x",
1152
+ description: "Run the thing",
1071
1153
  expression: "99 99 99 99 99",
1072
1154
  message: "hi",
1073
1155
  }),
@@ -1077,6 +1159,7 @@ describe("POST /schedules — create", () => {
1077
1159
  test("respects enabled=false", () => {
1078
1160
  postCreate({
1079
1161
  name: "Off",
1162
+ description: "Disabled schedule",
1080
1163
  expression: "0 9 * * *",
1081
1164
  message: "hi",
1082
1165
  enabled: false,
@@ -1086,6 +1169,38 @@ describe("POST /schedules — create", () => {
1086
1169
  });
1087
1170
  });
1088
1171
 
1172
+ // ── PATCH /schedules/:id — description ───────────────────────────────────
1173
+
1174
+ describe("PATCH /schedules/:id — description", () => {
1175
+ beforeEach(() => {
1176
+ clearTables();
1177
+ });
1178
+
1179
+ test("updates authored descriptions", () => {
1180
+ const schedule = createSchedule({
1181
+ name: "Description update",
1182
+ description: "Original description",
1183
+ cronExpression: "0 9 * * *",
1184
+ message: "hi",
1185
+ syntax: "cron",
1186
+ });
1187
+
1188
+ const route = findRoute("schedules/:id", "PATCH");
1189
+ const result = route.handler({
1190
+ pathParams: { id: schedule.id },
1191
+ body: { description: "Updated description" },
1192
+ }) as {
1193
+ schedules: Array<{ id: string; description: string }>;
1194
+ };
1195
+
1196
+ expect(result.schedules[0]).toMatchObject({
1197
+ id: schedule.id,
1198
+ description: "Updated description",
1199
+ });
1200
+ expect(listSchedules()[0].description).toBe("Updated description");
1201
+ });
1202
+ });
1203
+
1089
1204
  // ── Wake mode support ─────────────────────────────────────────────────────
1090
1205
 
1091
1206
  describe("wake mode in schedule routes", () => {
@@ -160,6 +160,7 @@ describe("createSchedule (cron)", () => {
160
160
  expect(job.syntax).toBe("cron");
161
161
  expect(job.expression).toBe("0 9 * * *");
162
162
  expect(job.cronExpression).toBe("0 9 * * *");
163
+ expect(job.description).toBe("Morning ping");
163
164
  expect(job.nextRunAt).toBeGreaterThan(Date.now() - 1000);
164
165
  expect(job.enabled).toBe(true);
165
166
  });
@@ -167,6 +168,7 @@ describe("createSchedule (cron)", () => {
167
168
  test("persisted cron schedule is retrievable with new fields", () => {
168
169
  const job = createSchedule({
169
170
  name: "Hourly",
171
+ description: "Check the hourly status report",
170
172
  cronExpression: "0 * * * *",
171
173
  message: "hourly check",
172
174
  syntax: "cron",
@@ -177,6 +179,32 @@ describe("createSchedule (cron)", () => {
177
179
  expect(retrieved!.syntax).toBe("cron");
178
180
  expect(retrieved!.expression).toBe("0 * * * *");
179
181
  expect(retrieved!.cronExpression).toBe("0 * * * *");
182
+ expect(retrieved!.description).toBe("Check the hourly status report");
183
+ });
184
+
185
+ test("normalizes schedule descriptions on create and update", () => {
186
+ const job = createSchedule({
187
+ name: "Description normalization",
188
+ description: " Daily executive summary ",
189
+ cronExpression: "0 8 * * *",
190
+ message: "summarize the day",
191
+ syntax: "cron",
192
+ });
193
+
194
+ expect(job.description).toBe("Daily executive summary");
195
+
196
+ const raw = getRawDb()
197
+ .query("SELECT description FROM cron_jobs WHERE id = ?")
198
+ .get(job.id) as { description: string };
199
+ expect(raw.description).toBe("Daily executive summary");
200
+
201
+ const updated = updateSchedule(job.id, {
202
+ description: " Updated summary prompt ",
203
+ });
204
+ expect(updated).not.toBeNull();
205
+ expect(updated!.description).toBe("Updated summary prompt");
206
+ expect(getSchedule(job.id)!.description).toBe("Updated summary prompt");
207
+ expect(listSchedules()[0].description).toBe("Updated summary prompt");
180
208
  });
181
209
 
182
210
  test("defaults source conversation metadata to null", () => {
@@ -18,7 +18,7 @@ import type { Database } from "bun:sqlite";
18
18
 
19
19
  import { getDb } from "../memory/db-connection.js";
20
20
  import { initializeDb } from "../memory/db-init.js";
21
- import { executeScheduleCreate } from "../tools/schedule/create.js";
21
+ import { executeScheduleCreate as rawExecuteScheduleCreate } from "../tools/schedule/create.js";
22
22
  import { executeScheduleDelete } from "../tools/schedule/delete.js";
23
23
  import { executeScheduleList } from "../tools/schedule/list.js";
24
24
  import { executeScheduleUpdate } from "../tools/schedule/update.js";
@@ -41,6 +41,16 @@ const trustedCtx: ToolContext = {
41
41
  trustClass: "trusted_contact",
42
42
  };
43
43
 
44
+ function executeScheduleCreate(
45
+ input: Record<string, unknown>,
46
+ context: ToolContext,
47
+ ) {
48
+ return rawExecuteScheduleCreate(
49
+ { description: "Test schedule description", ...input },
50
+ context,
51
+ );
52
+ }
53
+
44
54
  // ── schedule_create ─────────────────────────────────────────────────
45
55
 
46
56
  describe("schedule_create tool", () => {
@@ -53,6 +63,7 @@ describe("schedule_create tool", () => {
53
63
  const result = await executeScheduleCreate(
54
64
  {
55
65
  name: "Daily standup",
66
+ description: "Remind the team to join the daily standup.",
56
67
  expression: "0 9 * * 1-5",
57
68
  message: "Time for standup!",
58
69
  },
@@ -62,8 +73,16 @@ describe("schedule_create tool", () => {
62
73
  expect(result.isError).toBe(false);
63
74
  expect(result.content).toContain("schedule created successfully");
64
75
  expect(result.content).toContain("Daily standup");
76
+ expect(result.content).toContain(
77
+ "Description: Remind the team to join the daily standup.",
78
+ );
65
79
  expect(result.content).toContain("Every weekday at 9:00 AM");
66
80
  expect(result.content).toContain("Enabled: true");
81
+
82
+ const row = getRawDb()
83
+ .query("SELECT description FROM cron_jobs LIMIT 1")
84
+ .get() as { description: string };
85
+ expect(row.description).toBe("Remind the team to join the daily standup.");
67
86
  });
68
87
 
69
88
  test("persists the creating conversation for recurring schedules", async () => {
@@ -126,6 +145,35 @@ describe("schedule_create tool", () => {
126
145
  expect(result.content).toContain("name is required");
127
146
  });
128
147
 
148
+ test("rejects missing description", async () => {
149
+ const result = await rawExecuteScheduleCreate(
150
+ {
151
+ name: "No description",
152
+ expression: "0 9 * * *",
153
+ message: "test",
154
+ },
155
+ ctx,
156
+ );
157
+
158
+ expect(result.isError).toBe(true);
159
+ expect(result.content).toContain("description is required");
160
+ });
161
+
162
+ test("rejects blank description", async () => {
163
+ const result = await rawExecuteScheduleCreate(
164
+ {
165
+ name: "Blank description",
166
+ description: " ",
167
+ expression: "0 9 * * *",
168
+ message: "test",
169
+ },
170
+ ctx,
171
+ );
172
+
173
+ expect(result.isError).toBe(true);
174
+ expect(result.content).toContain("description is required");
175
+ });
176
+
129
177
  test("rejects missing expression when no fire_at", async () => {
130
178
  const result = await executeScheduleCreate(
131
179
  {
@@ -195,6 +243,7 @@ describe("schedule_create with fire_at (one-shot)", () => {
195
243
  const result = await executeScheduleCreate(
196
244
  {
197
245
  name: "One-time reminder",
246
+ description: "Remind the user about a one-time event.",
198
247
  fire_at: futureDate,
199
248
  message: "Don't forget!",
200
249
  },
@@ -206,7 +255,15 @@ describe("schedule_create with fire_at (one-shot)", () => {
206
255
  expect(result.content).toContain("Type: one-shot");
207
256
  expect(result.content).toContain("Mode: execute");
208
257
  expect(result.content).toContain("One-time reminder");
258
+ expect(result.content).toContain(
259
+ "Description: Remind the user about a one-time event.",
260
+ );
209
261
  expect(result.content).toContain("Status: active");
262
+
263
+ const row = getRawDb()
264
+ .query("SELECT description FROM cron_jobs LIMIT 1")
265
+ .get() as { description: string };
266
+ expect(row.description).toBe("Remind the user about a one-time event.");
210
267
  });
211
268
 
212
269
  test("persists the creating conversation for one-shot schedules", async () => {
@@ -547,6 +604,7 @@ describe("schedule_list tool", () => {
547
604
  await executeScheduleCreate(
548
605
  {
549
606
  name: "Detail Job",
607
+ description: "Describe the detail job purpose.",
550
608
  expression: "30 14 * * *",
551
609
  message: "Afternoon check",
552
610
  },
@@ -561,6 +619,9 @@ describe("schedule_list tool", () => {
561
619
 
562
620
  expect(result.isError).toBe(false);
563
621
  expect(result.content).toContain("Schedule: Detail Job");
622
+ expect(result.content).toContain(
623
+ "Description: Describe the detail job purpose.",
624
+ );
564
625
  expect(result.content).toContain("Every day at 2:30 PM");
565
626
  expect(result.content).toContain("Message: Afternoon check");
566
627
  expect(result.content).toContain("Enabled: true");
@@ -598,6 +659,7 @@ describe("schedule_list with one-shot schedules", () => {
598
659
 
599
660
  expect(result.isError).toBe(false);
600
661
  expect(result.content).toContain("One-shot Event");
662
+ expect(result.content).toContain("Test schedule description");
601
663
  expect(result.content).toContain("one-shot");
602
664
  expect(result.content).toContain("fire at:");
603
665
  expect(result.content).toContain("active");
@@ -719,6 +781,37 @@ describe("schedule_update tool", () => {
719
781
  expect(result.content).toContain("New Name");
720
782
  });
721
783
 
784
+ test("updates the description of a schedule", async () => {
785
+ await executeScheduleCreate(
786
+ {
787
+ name: "Description update",
788
+ description: "Original purpose.",
789
+ expression: "0 9 * * *",
790
+ message: "test",
791
+ },
792
+ ctx,
793
+ );
794
+
795
+ const row = getRawDb().query("SELECT id FROM cron_jobs LIMIT 1").get() as {
796
+ id: string;
797
+ };
798
+ const result = await executeScheduleUpdate(
799
+ {
800
+ job_id: row.id,
801
+ description: "Updated purpose.",
802
+ },
803
+ ctx,
804
+ );
805
+
806
+ expect(result.isError).toBe(false);
807
+ expect(result.content).toContain("Description: Updated purpose.");
808
+
809
+ const dbRow = getRawDb()
810
+ .query("SELECT description FROM cron_jobs WHERE id = ?")
811
+ .get(row.id) as { description: string };
812
+ expect(dbRow.description).toBe("Updated purpose.");
813
+ });
814
+
722
815
  test("updates the cron expression", async () => {
723
816
  await executeScheduleCreate(
724
817
  {
@@ -808,6 +808,45 @@ describe("renderHistoryContent contentBlocks", () => {
808
808
  );
809
809
  });
810
810
 
811
+ test("surfaces persisted thinking timing onto the thinking block", () => {
812
+ // GIVEN a thinking block the daemon stamped with internal `_startedAt` /
813
+ // `_completedAt` timing at message_complete
814
+ const output = renderHistoryContent([
815
+ {
816
+ type: "thinking",
817
+ thinking: "reasoning",
818
+ signature: "sig",
819
+ _startedAt: 1000,
820
+ _completedAt: 1500,
821
+ },
822
+ ]);
823
+
824
+ // THEN the rendered block exposes them as the wire schema's
825
+ // startedAt/completedAt so the client can show the duration + hover state
826
+ expect(output.contentBlocks).toEqual([
827
+ {
828
+ type: "thinking",
829
+ thinking: "reasoning",
830
+ startedAt: 1000,
831
+ completedAt: 1500,
832
+ },
833
+ ]);
834
+ });
835
+
836
+ test("omits thinking timing when the block carries none", () => {
837
+ // GIVEN a thinking block with no persisted timing (older daemon / thinking
838
+ // streaming disabled)
839
+ const output = renderHistoryContent([
840
+ { type: "thinking", thinking: "reasoning", signature: "sig" },
841
+ ]);
842
+
843
+ // THEN the rendered block has no startedAt/completedAt and the client hides
844
+ // the duration, exactly as a tool call with no timing
845
+ expect(output.contentBlocks).toEqual([
846
+ { type: "thinking", thinking: "reasoning" },
847
+ ]);
848
+ });
849
+
811
850
  const pdfBlock = {
812
851
  type: "file",
813
852
  source: {
@@ -222,6 +222,19 @@ mock.module("../util/logger.js", () => ({
222
222
  }),
223
223
  }));
224
224
 
225
+ // Mock the skill_loaded telemetry dependencies of conversation-skill-tools so
226
+ // their heavy transitive imports (catalog-install → CLI program, sqlite) stay
227
+ // out of this import-light test.
228
+ mock.module("../skills/catalog-cache.js", () => ({
229
+ getCachedCatalogSync: () => [],
230
+ }));
231
+ mock.module("../skills/install-meta.js", () => ({
232
+ readInstallMeta: () => null,
233
+ }));
234
+ mock.module("../memory/skill-loaded-events-store.js", () => ({
235
+ recordSkillLoadedEvent: () => {},
236
+ }));
237
+
225
238
  // ---------------------------------------------------------------------------
226
239
  // Import module under test (after mocks)
227
240
  // ---------------------------------------------------------------------------
@@ -96,6 +96,19 @@ mock.module("../skills/version-hash.js", () => ({
96
96
  computeSkillVersionHash: () => "v1:deadbeef",
97
97
  }));
98
98
 
99
+ // Mock the skill_loaded telemetry dependencies of conversation-skill-tools so
100
+ // their heavy transitive imports (catalog-install → CLI program, sqlite) stay
101
+ // out of this import-light test.
102
+ mock.module("../skills/catalog-cache.js", () => ({
103
+ getCachedCatalogSync: () => [],
104
+ }));
105
+ mock.module("../skills/install-meta.js", () => ({
106
+ readInstallMeta: () => null,
107
+ }));
108
+ mock.module("../memory/skill-loaded-events-store.js", () => ({
109
+ recordSkillLoadedEvent: () => {},
110
+ }));
111
+
99
112
  // Mock createSkillToolsFromManifest to return lightweight Tool-like objects
100
113
  mock.module("../tools/skills/skill-tool-factory.js", () => ({
101
114
  createSkillToolsFromManifest: (
@@ -153,22 +166,27 @@ mock.module("node:fs", () => ({
153
166
  Stats: class {},
154
167
  }));
155
168
 
156
- const benchmarkRegistry = new Map<string, unknown>();
169
+ // Mirrors the current registry contract: ownership is recorded from the
170
+ // `registerSkillTools(skillId, tools)` call and reported via `getToolOwner`.
171
+ const benchmarkRegistry = new Map<string, { tool: unknown; skillId: string }>();
157
172
  mock.module("../tools/registry.js", () => ({
158
173
  registerSkillTools: (
174
+ skillId: string,
159
175
  tools: Array<{ name: string; [k: string]: unknown }>,
160
176
  ) => {
161
- for (const t of tools) benchmarkRegistry.set(t.name, t);
177
+ for (const t of tools) benchmarkRegistry.set(t.name, { tool: t, skillId });
162
178
  return tools;
163
179
  },
164
180
  unregisterSkillTools: (skillId: string) => {
165
- for (const [name, t] of benchmarkRegistry) {
166
- const owner = (t as { owner?: { kind: string; id: string } }).owner;
167
- if (owner?.kind === "skill" && owner.id === skillId)
168
- benchmarkRegistry.delete(name);
181
+ for (const [name, entry] of benchmarkRegistry) {
182
+ if (entry.skillId === skillId) benchmarkRegistry.delete(name);
169
183
  }
170
184
  },
171
- getTool: (name: string) => benchmarkRegistry.get(name),
185
+ getTool: (name: string) => benchmarkRegistry.get(name)?.tool,
186
+ getToolOwner: (name: string) => {
187
+ const entry = benchmarkRegistry.get(name);
188
+ return entry ? { kind: "skill" as const, id: entry.skillId } : undefined;
189
+ },
172
190
  }));
173
191
 
174
192
  // ---------------------------------------------------------------------------