@vellumai/assistant 0.4.48 → 0.4.50

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 (423) hide show
  1. package/ARCHITECTURE.md +26 -35
  2. package/README.md +5 -26
  3. package/docs/architecture/integrations.md +45 -41
  4. package/docs/architecture/keychain-broker.md +3 -3
  5. package/docs/architecture/memory.md +180 -119
  6. package/docs/runbook-trusted-contacts.md +3 -8
  7. package/hook-templates/debug-prompt-logger/hook.json +1 -1
  8. package/hook-templates/debug-prompt-logger/run.sh +1 -3
  9. package/package.json +2 -2
  10. package/src/__tests__/actor-token-service.test.ts +0 -1
  11. package/src/__tests__/agent-loop.test.ts +3 -1
  12. package/src/__tests__/anthropic-provider.test.ts +249 -2
  13. package/src/__tests__/approval-cascade.test.ts +796 -0
  14. package/src/__tests__/approval-primitive.test.ts +0 -1
  15. package/src/__tests__/approval-routes-http.test.ts +4 -0
  16. package/src/__tests__/assistant-attachments.test.ts +12 -34
  17. package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
  18. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +76 -0
  19. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -1
  20. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
  21. package/src/__tests__/canonical-guardian-store.test.ts +95 -0
  22. package/src/__tests__/channel-guardian.test.ts +0 -2
  23. package/src/__tests__/channel-readiness-routes.test.ts +15 -6
  24. package/src/__tests__/channel-readiness-service.test.ts +10 -9
  25. package/src/__tests__/checker.test.ts +13 -20
  26. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
  27. package/src/__tests__/computer-use-tools.test.ts +2 -19
  28. package/src/__tests__/config-schema.test.ts +1 -68
  29. package/src/__tests__/config-watcher.test.ts +0 -1
  30. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  31. package/src/__tests__/context-image-dimensions.test.ts +332 -0
  32. package/src/__tests__/context-memory-e2e.test.ts +11 -100
  33. package/src/__tests__/context-token-estimator.test.ts +196 -13
  34. package/src/__tests__/conversation-attention-store.test.ts +0 -1
  35. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  36. package/src/__tests__/conversation-routes-guardian-reply.test.ts +152 -0
  37. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
  38. package/src/__tests__/credential-metadata-store.test.ts +64 -73
  39. package/src/__tests__/credential-security-e2e.test.ts +1 -0
  40. package/src/__tests__/credential-security-invariants.test.ts +13 -7
  41. package/src/__tests__/credential-vault-unit.test.ts +284 -49
  42. package/src/__tests__/credential-vault.test.ts +150 -16
  43. package/src/__tests__/credentials-cli.test.ts +71 -0
  44. package/src/__tests__/cu-unified-flow.test.ts +532 -0
  45. package/src/__tests__/date-context.test.ts +93 -77
  46. package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
  47. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  48. package/src/__tests__/ephemeral-permissions.test.ts +3 -3
  49. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  50. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
  51. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
  52. package/src/__tests__/guardian-routing-invariants.test.ts +93 -1
  53. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
  54. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -39
  55. package/src/__tests__/heartbeat-service.test.ts +0 -1
  56. package/src/__tests__/history-repair.test.ts +245 -0
  57. package/src/__tests__/host-cu-proxy.test.ts +791 -0
  58. package/src/__tests__/host-shell-tool.test.ts +27 -15
  59. package/src/__tests__/http-user-message-parity.test.ts +2 -0
  60. package/src/__tests__/ingress-url-consistency.test.ts +14 -21
  61. package/src/__tests__/integration-status.test.ts +32 -51
  62. package/src/__tests__/intent-routing.test.ts +0 -1
  63. package/src/__tests__/invite-redemption-service.test.ts +65 -1
  64. package/src/__tests__/invite-routes-http.test.ts +10 -9
  65. package/src/__tests__/keychain-broker-client.test.ts +14 -46
  66. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
  67. package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
  68. package/src/__tests__/memory-recall-quality.test.ts +244 -407
  69. package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
  70. package/src/__tests__/memory-regressions.test.ts +477 -2841
  71. package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
  72. package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
  73. package/src/__tests__/mime-builder.test.ts +28 -0
  74. package/src/__tests__/native-web-search.test.ts +1 -0
  75. package/src/__tests__/notification-routing-intent.test.ts +0 -1
  76. package/src/__tests__/oauth-cli.test.ts +941 -15
  77. package/src/__tests__/oauth-provider-profiles.test.ts +9 -9
  78. package/src/__tests__/oauth-scope-policy.test.ts +4 -6
  79. package/src/__tests__/oauth-store.test.ts +870 -0
  80. package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
  81. package/src/__tests__/provider-error-scenarios.test.ts +0 -1
  82. package/src/__tests__/provider-streaming.benchmark.test.ts +0 -1
  83. package/src/__tests__/public-ingress-urls.test.ts +15 -21
  84. package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
  85. package/src/__tests__/recording-handler.test.ts +3 -4
  86. package/src/__tests__/registry.test.ts +2 -3
  87. package/src/__tests__/relay-server.test.ts +46 -1
  88. package/src/__tests__/runtime-events-sse.test.ts +55 -7
  89. package/src/__tests__/schedule-store.test.ts +0 -1
  90. package/src/__tests__/schedule-tools.test.ts +32 -0
  91. package/src/__tests__/scheduler-recurrence.test.ts +0 -1
  92. package/src/__tests__/scoped-approval-grants.test.ts +0 -1
  93. package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
  94. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  95. package/src/__tests__/secret-ingress-handler.test.ts +0 -1
  96. package/src/__tests__/secret-onetime-send.test.ts +1 -0
  97. package/src/__tests__/secure-keys.test.ts +7 -2
  98. package/src/__tests__/send-endpoint-busy.test.ts +24 -6
  99. package/src/__tests__/sequence-store.test.ts +0 -1
  100. package/src/__tests__/session-abort-tool-results.test.ts +1 -14
  101. package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
  102. package/src/__tests__/session-agent-loop.test.ts +19 -15
  103. package/src/__tests__/session-confirmation-signals.test.ts +1 -15
  104. package/src/__tests__/session-error.test.ts +124 -2
  105. package/src/__tests__/session-history-web-search.test.ts +918 -0
  106. package/src/__tests__/session-init.benchmark.test.ts +4 -5
  107. package/src/__tests__/session-pre-run-repair.test.ts +1 -14
  108. package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
  109. package/src/__tests__/session-queue.test.ts +37 -27
  110. package/src/__tests__/session-runtime-assembly.test.ts +54 -0
  111. package/src/__tests__/session-slash-known.test.ts +1 -15
  112. package/src/__tests__/session-slash-queue.test.ts +1 -15
  113. package/src/__tests__/session-slash-unknown.test.ts +1 -15
  114. package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
  115. package/src/__tests__/session-workspace-injection.test.ts +3 -37
  116. package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
  117. package/src/__tests__/skill-include-graph.test.ts +66 -0
  118. package/src/__tests__/skill-load-feature-flag.test.ts +0 -1
  119. package/src/__tests__/skill-load-tool.test.ts +149 -1
  120. package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
  121. package/src/__tests__/skills-install-extract.test.ts +93 -0
  122. package/src/__tests__/skills-uninstall.test.ts +1 -1
  123. package/src/__tests__/skills.test.ts +3 -3
  124. package/src/__tests__/skillssh-registry.test.ts +451 -0
  125. package/src/__tests__/slack-channel-config.test.ts +67 -3
  126. package/src/__tests__/slack-share-routes.test.ts +17 -19
  127. package/src/__tests__/system-prompt.test.ts +0 -1
  128. package/src/__tests__/telegram-invite-adapter.test.ts +18 -22
  129. package/src/__tests__/terminal-tools.test.ts +4 -3
  130. package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
  131. package/src/__tests__/tool-approval-handler.test.ts +0 -1
  132. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
  133. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  134. package/src/__tests__/tool-executor-shell-integration.test.ts +0 -1
  135. package/src/__tests__/tool-executor.test.ts +0 -1
  136. package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
  137. package/src/__tests__/trust-store-pattern-matches.test.ts +29 -0
  138. package/src/__tests__/trust-store.test.ts +7 -13
  139. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  140. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
  141. package/src/__tests__/twilio-routes.test.ts +0 -16
  142. package/src/__tests__/verification-control-plane-policy.test.ts +0 -1
  143. package/src/__tests__/voice-invite-redemption.test.ts +32 -1
  144. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
  145. package/src/agent/ax-tree-compaction.test.ts +286 -0
  146. package/src/agent/loop.ts +104 -131
  147. package/src/approvals/AGENTS.md +1 -1
  148. package/src/approvals/guardian-request-resolvers.ts +14 -2
  149. package/src/bundler/compiler-tools.ts +66 -2
  150. package/src/calls/call-domain.ts +133 -6
  151. package/src/calls/call-store.ts +6 -0
  152. package/src/calls/relay-server.ts +52 -18
  153. package/src/calls/relay-setup-router.ts +17 -1
  154. package/src/calls/twilio-config.ts +3 -8
  155. package/src/calls/twilio-routes.ts +1 -2
  156. package/src/calls/types.ts +3 -1
  157. package/src/calls/voice-ingress-preflight.ts +1 -1
  158. package/src/cli/commands/browser-relay.ts +18 -12
  159. package/src/cli/commands/completions.ts +0 -3
  160. package/src/cli/commands/credentials.ts +101 -15
  161. package/src/cli/commands/doctor.ts +4 -3
  162. package/src/cli/commands/mcp.ts +46 -59
  163. package/src/cli/commands/memory.ts +16 -165
  164. package/src/cli/commands/oauth/apps.ts +284 -0
  165. package/src/cli/commands/oauth/connections.ts +633 -0
  166. package/src/cli/commands/oauth/index.ts +52 -0
  167. package/src/cli/commands/oauth/providers.ts +256 -0
  168. package/src/cli/commands/sessions.ts +5 -2
  169. package/src/cli/commands/skills.ts +177 -339
  170. package/src/cli/http-client.ts +0 -20
  171. package/src/cli/main-screen.tsx +2 -2
  172. package/src/cli/program.ts +6 -11
  173. package/src/cli/reference.ts +1 -3
  174. package/src/cli.ts +4 -10
  175. package/src/config/assistant-feature-flags.ts +0 -3
  176. package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
  177. package/src/config/bundled-skills/computer-use/SKILL.md +3 -6
  178. package/src/config/bundled-skills/computer-use/TOOLS.json +23 -5
  179. package/src/config/bundled-skills/computer-use/tools/{computer-use-request-control.ts → computer-use-observe.ts} +1 -5
  180. package/src/config/bundled-skills/google-calendar/calendar-client.ts +21 -16
  181. package/src/config/bundled-skills/messaging/tools/shared.ts +1 -4
  182. package/src/config/bundled-skills/settings/SKILL.md +1 -1
  183. package/src/config/bundled-skills/settings/TOOLS.json +2 -8
  184. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +5 -33
  185. package/src/config/bundled-tool-registry.ts +2 -5
  186. package/src/config/env-registry.ts +14 -83
  187. package/src/config/env.ts +11 -50
  188. package/src/config/feature-flag-registry.json +16 -16
  189. package/src/config/loader.ts +0 -6
  190. package/src/config/schema.ts +4 -13
  191. package/src/config/schemas/memory-lifecycle.ts +0 -9
  192. package/src/config/schemas/memory-processing.ts +0 -180
  193. package/src/config/schemas/memory-retrieval.ts +32 -104
  194. package/src/config/schemas/memory.ts +0 -10
  195. package/src/config/skills.ts +21 -2
  196. package/src/config/types.ts +0 -4
  197. package/src/context/image-dimensions.ts +229 -0
  198. package/src/context/token-estimator.ts +75 -12
  199. package/src/context/window-manager.ts +53 -11
  200. package/src/daemon/assistant-attachments.ts +1 -13
  201. package/src/daemon/config-watcher.ts +61 -3
  202. package/src/daemon/daemon-control.ts +1 -1
  203. package/src/daemon/date-context.ts +114 -31
  204. package/src/daemon/handlers/config-ingress.ts +8 -33
  205. package/src/daemon/handlers/config-slack-channel.ts +49 -46
  206. package/src/daemon/handlers/config-telegram.ts +32 -16
  207. package/src/daemon/handlers/sessions.ts +27 -36
  208. package/src/daemon/handlers/shared.ts +0 -130
  209. package/src/daemon/handlers/skills.ts +20 -1
  210. package/src/daemon/history-repair.ts +72 -8
  211. package/src/daemon/host-cu-proxy.ts +430 -0
  212. package/src/daemon/lifecycle.ts +67 -71
  213. package/src/daemon/mcp-reload-service.ts +2 -2
  214. package/src/daemon/message-protocol.ts +3 -0
  215. package/src/daemon/message-types/computer-use.ts +1 -129
  216. package/src/daemon/message-types/host-cu.ts +19 -0
  217. package/src/daemon/message-types/memory.ts +4 -16
  218. package/src/daemon/message-types/messages.ts +4 -0
  219. package/src/daemon/message-types/sessions.ts +4 -0
  220. package/src/daemon/server.ts +25 -21
  221. package/src/daemon/session-agent-loop-handlers.ts +40 -0
  222. package/src/daemon/session-agent-loop.ts +334 -48
  223. package/src/daemon/session-attachments.ts +1 -2
  224. package/src/daemon/session-error.ts +89 -6
  225. package/src/daemon/session-history.ts +17 -7
  226. package/src/daemon/session-media-retry.ts +6 -2
  227. package/src/daemon/session-memory.ts +69 -149
  228. package/src/daemon/session-process.ts +10 -1
  229. package/src/daemon/session-runtime-assembly.ts +49 -19
  230. package/src/daemon/session-slash.ts +1 -1
  231. package/src/daemon/session-surfaces.ts +43 -28
  232. package/src/daemon/session-tool-setup.ts +9 -10
  233. package/src/daemon/session.ts +150 -17
  234. package/src/daemon/tool-side-effects.ts +2 -8
  235. package/src/daemon/watch-handler.ts +2 -2
  236. package/src/events/tool-metrics-listener.ts +2 -2
  237. package/src/hooks/manager.ts +1 -4
  238. package/src/inbound/public-ingress-urls.ts +7 -7
  239. package/src/instrument.ts +61 -1
  240. package/src/logfire.ts +16 -5
  241. package/src/memory/admin.ts +2 -191
  242. package/src/memory/canonical-guardian-store.ts +38 -2
  243. package/src/memory/conversation-crud.ts +0 -33
  244. package/src/memory/conversation-key-store.ts +21 -0
  245. package/src/memory/conversation-queries.ts +22 -3
  246. package/src/memory/db-init.ts +32 -0
  247. package/src/memory/embedding-backend.ts +84 -8
  248. package/src/memory/embedding-types.ts +9 -1
  249. package/src/memory/indexer.ts +7 -46
  250. package/src/memory/items-extractor.ts +274 -76
  251. package/src/memory/job-handlers/backfill.ts +2 -127
  252. package/src/memory/job-handlers/cleanup.ts +2 -16
  253. package/src/memory/job-handlers/extraction.ts +2 -138
  254. package/src/memory/job-handlers/index-maintenance.ts +1 -6
  255. package/src/memory/job-handlers/summarization.ts +3 -148
  256. package/src/memory/job-utils.ts +21 -59
  257. package/src/memory/jobs-store.ts +1 -159
  258. package/src/memory/jobs-worker.ts +9 -52
  259. package/src/memory/migrations/104-core-indexes.ts +3 -3
  260. package/src/memory/migrations/149-oauth-tables.ts +62 -0
  261. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
  262. package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
  263. package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
  264. package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
  265. package/src/memory/migrations/154-drop-fts.ts +20 -0
  266. package/src/memory/migrations/155-drop-conflicts.ts +7 -0
  267. package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
  268. package/src/memory/migrations/index.ts +8 -0
  269. package/src/memory/qdrant-client.ts +148 -51
  270. package/src/memory/raw-query.ts +1 -1
  271. package/src/memory/retriever.test.ts +294 -273
  272. package/src/memory/retriever.ts +421 -645
  273. package/src/memory/schema/calls.ts +2 -0
  274. package/src/memory/schema/index.ts +1 -0
  275. package/src/memory/schema/memory-core.ts +3 -48
  276. package/src/memory/schema/oauth.ts +67 -0
  277. package/src/memory/search/formatting.ts +263 -176
  278. package/src/memory/search/lexical.ts +1 -254
  279. package/src/memory/search/ranking.ts +0 -455
  280. package/src/memory/search/semantic.ts +100 -14
  281. package/src/memory/search/staleness.ts +47 -0
  282. package/src/memory/search/tier-classifier.ts +21 -0
  283. package/src/memory/search/types.ts +15 -77
  284. package/src/memory/task-memory-cleanup.ts +4 -6
  285. package/src/messaging/provider.ts +4 -4
  286. package/src/messaging/providers/gmail/client.ts +82 -2
  287. package/src/messaging/providers/gmail/mime-builder.ts +17 -7
  288. package/src/messaging/providers/gmail/people-client.ts +10 -10
  289. package/src/messaging/providers/telegram-bot/adapter.ts +17 -17
  290. package/src/messaging/providers/whatsapp/adapter.ts +11 -8
  291. package/src/messaging/registry.ts +2 -32
  292. package/src/notifications/copy-composer.ts +0 -5
  293. package/src/notifications/signal.ts +4 -5
  294. package/src/oauth/byo-connection.test.ts +133 -25
  295. package/src/oauth/byo-connection.ts +22 -6
  296. package/src/oauth/connect-orchestrator.ts +113 -57
  297. package/src/oauth/connect-types.ts +17 -23
  298. package/src/oauth/connection-resolver.ts +35 -11
  299. package/src/oauth/connection.ts +1 -1
  300. package/src/oauth/manual-token-connection.ts +104 -0
  301. package/src/oauth/oauth-store.ts +582 -0
  302. package/src/oauth/platform-connection.test.ts +29 -0
  303. package/src/oauth/platform-connection.ts +6 -5
  304. package/src/oauth/provider-behaviors.ts +124 -0
  305. package/src/oauth/scope-policy.ts +9 -2
  306. package/src/oauth/seed-providers.ts +167 -0
  307. package/src/oauth/token-persistence.ts +81 -77
  308. package/src/permissions/checker.ts +3 -3
  309. package/src/permissions/defaults.ts +1 -1
  310. package/src/permissions/prompter.ts +10 -1
  311. package/src/permissions/trust-store.ts +36 -1
  312. package/src/playbooks/playbook-compiler.ts +1 -1
  313. package/src/prompts/__tests__/build-cli-reference-section.test.ts +3 -1
  314. package/src/prompts/system-prompt.ts +46 -42
  315. package/src/providers/anthropic/client.ts +59 -20
  316. package/src/providers/retry.ts +1 -27
  317. package/src/providers/types.ts +7 -1
  318. package/src/runtime/AGENTS.md +9 -0
  319. package/src/runtime/auth/route-policy.ts +6 -6
  320. package/src/runtime/channel-reply-delivery.ts +0 -40
  321. package/src/runtime/gateway-client.ts +0 -7
  322. package/src/runtime/guardian-reply-router.ts +24 -22
  323. package/src/runtime/http-server.ts +10 -8
  324. package/src/runtime/http-types.ts +2 -2
  325. package/src/runtime/invite-redemption-service.ts +19 -1
  326. package/src/runtime/invite-service.ts +25 -0
  327. package/src/runtime/middleware/twilio-validation.ts +1 -11
  328. package/src/runtime/pending-interactions.ts +14 -12
  329. package/src/runtime/routes/brain-graph-routes.ts +10 -90
  330. package/src/runtime/routes/channel-delivery-routes.ts +0 -1
  331. package/src/runtime/routes/conversation-routes.ts +81 -19
  332. package/src/runtime/routes/events-routes.ts +21 -11
  333. package/src/runtime/routes/host-cu-routes.ts +97 -0
  334. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
  335. package/src/runtime/routes/inbound-stages/background-dispatch.ts +12 -111
  336. package/src/runtime/routes/integrations/slack/share.ts +6 -7
  337. package/src/runtime/routes/log-export-routes.ts +126 -8
  338. package/src/runtime/routes/memory-item-routes.test.ts +754 -0
  339. package/src/runtime/routes/memory-item-routes.ts +503 -0
  340. package/src/runtime/routes/session-management-routes.ts +3 -3
  341. package/src/runtime/routes/settings-routes.ts +55 -48
  342. package/src/runtime/routes/surface-action-routes.ts +1 -1
  343. package/src/runtime/routes/trust-rules-routes.ts +14 -0
  344. package/src/runtime/routes/watch-routes.ts +128 -0
  345. package/src/runtime/routes/workspace-routes.ts +2 -1
  346. package/src/schedule/integration-status.ts +10 -9
  347. package/src/security/credential-key.ts +0 -156
  348. package/src/security/keychain-broker-client.ts +22 -10
  349. package/src/security/oauth2.ts +1 -1
  350. package/src/security/secure-keys.ts +25 -3
  351. package/src/security/token-manager.ts +137 -64
  352. package/src/skills/catalog-install.ts +414 -0
  353. package/src/skills/include-graph.ts +32 -0
  354. package/src/skills/skillssh-registry.ts +503 -0
  355. package/src/telegram/bot-username.ts +2 -3
  356. package/src/tools/assets/search.ts +5 -1
  357. package/src/tools/browser/network-recorder.ts +1 -1
  358. package/src/tools/browser/network-recording-types.ts +1 -1
  359. package/src/tools/computer-use/definitions.ts +36 -11
  360. package/src/tools/computer-use/registry.ts +5 -6
  361. package/src/tools/credentials/broker.ts +1 -2
  362. package/src/tools/credentials/metadata-store.ts +17 -121
  363. package/src/tools/credentials/vault.ts +92 -167
  364. package/src/tools/memory/definitions.ts +4 -13
  365. package/src/tools/memory/handlers.test.ts +83 -103
  366. package/src/tools/memory/handlers.ts +50 -85
  367. package/src/tools/registry.ts +2 -7
  368. package/src/tools/schedule/create.ts +8 -1
  369. package/src/tools/schedule/update.ts +8 -1
  370. package/src/tools/skills/load.ts +85 -3
  371. package/src/tools/watch/watch-state.ts +0 -12
  372. package/src/util/logger.ts +7 -41
  373. package/src/util/platform.ts +9 -28
  374. package/src/watcher/providers/google-calendar.ts +2 -1
  375. package/src/__tests__/clarification-resolver.test.ts +0 -193
  376. package/src/__tests__/computer-use-session-compaction.test.ts +0 -143
  377. package/src/__tests__/computer-use-session-lifecycle.test.ts +0 -322
  378. package/src/__tests__/computer-use-session-working-dir.test.ts +0 -166
  379. package/src/__tests__/computer-use-skill-baseline.test.ts +0 -78
  380. package/src/__tests__/computer-use-skill-endstate.test.ts +0 -105
  381. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +0 -249
  382. package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
  383. package/src/__tests__/conflict-policy.test.ts +0 -269
  384. package/src/__tests__/conflict-store.test.ts +0 -372
  385. package/src/__tests__/contradiction-checker.test.ts +0 -361
  386. package/src/__tests__/entity-extractor.test.ts +0 -211
  387. package/src/__tests__/entity-search.test.ts +0 -1117
  388. package/src/__tests__/profile-compiler.test.ts +0 -392
  389. package/src/__tests__/ride-shotgun-handler.test.ts +0 -452
  390. package/src/__tests__/session-conflict-gate.test.ts +0 -1228
  391. package/src/__tests__/session-profile-injection.test.ts +0 -557
  392. package/src/cli/commands/dev.ts +0 -129
  393. package/src/cli/commands/map.ts +0 -391
  394. package/src/cli/commands/oauth.ts +0 -77
  395. package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
  396. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
  397. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
  398. package/src/daemon/computer-use-session.ts +0 -1026
  399. package/src/daemon/ride-shotgun-handler.ts +0 -569
  400. package/src/daemon/session-conflict-gate.ts +0 -167
  401. package/src/daemon/session-dynamic-profile.ts +0 -77
  402. package/src/memory/clarification-resolver.ts +0 -417
  403. package/src/memory/conflict-intent.ts +0 -205
  404. package/src/memory/conflict-policy.ts +0 -127
  405. package/src/memory/conflict-store.ts +0 -410
  406. package/src/memory/contradiction-checker.ts +0 -508
  407. package/src/memory/entity-extractor.ts +0 -535
  408. package/src/memory/format-recall.ts +0 -47
  409. package/src/memory/fts-reconciler.ts +0 -165
  410. package/src/memory/job-handlers/conflict.ts +0 -200
  411. package/src/memory/profile-compiler.ts +0 -195
  412. package/src/memory/recall-cache.ts +0 -117
  413. package/src/memory/search/entity.ts +0 -535
  414. package/src/memory/search/query-expansion.test.ts +0 -70
  415. package/src/memory/search/query-expansion.ts +0 -118
  416. package/src/oauth/provider-base-urls.ts +0 -21
  417. package/src/oauth/provider-profiles.ts +0 -192
  418. package/src/prompts/computer-use-prompt.ts +0 -98
  419. package/src/runtime/routes/computer-use-routes.ts +0 -641
  420. package/src/runtime/routes/mcp-routes.ts +0 -20
  421. package/src/runtime/telegram-streaming-delivery.test.ts +0 -729
  422. package/src/runtime/telegram-streaming-delivery.ts +0 -393
  423. package/src/tools/computer-use/request-computer-control.ts +0 -56
@@ -43,8 +43,9 @@ mock.module("../config/loader.js", () => ({
43
43
  contextWindow: {
44
44
  enabled: true,
45
45
  maxInputTokens: 100000,
46
- targetBudgetRatio: 0.30,
47
- compactThreshold: 0.8, summaryBudgetRatio: 0.05,
46
+ targetBudgetRatio: 0.3,
47
+ compactThreshold: 0.8,
48
+ summaryBudgetRatio: 0.05,
48
49
  overflowRecovery: {
49
50
  enabled: true,
50
51
  safetyMarginRatio: 0.05,
@@ -138,23 +139,14 @@ mock.module("../memory/retriever.js", () => ({
138
139
  provider: "mock",
139
140
  model: "mock",
140
141
  injectedText: "",
141
- lexicalHits: 0,
142
142
  semanticHits: 0,
143
143
  recencyHits: 0,
144
- entityHits: 0,
145
- relationSeedEntityCount: 0,
146
- relationTraversedEdgeCount: 0,
147
- relationNeighborEntityCount: 0,
148
- relationExpandedItemCount: 0,
149
- earlyTerminated: false,
150
144
  mergedCount: 0,
151
145
  selectedCount: 0,
152
- rerankApplied: false,
153
146
  injectedTokens: 0,
154
147
  latencyMs: 0,
155
148
  topCandidates: [],
156
149
  }),
157
- injectMemoryRecallIntoUserMessage: (msg: Message) => msg,
158
150
  injectMemoryRecallAsSeparateMessage: (msgs: Message[]) => msgs,
159
151
  stripMemoryRecallMessages: (msgs: Message[]) => msgs,
160
152
  }));
@@ -179,32 +171,6 @@ mock.module("../context/window-manager.js", () => ({
179
171
  }),
180
172
  getSummaryFromContextMessage: () => null,
181
173
  }));
182
- mock.module("../memory/conflict-store.js", () => ({
183
- listPendingConflictDetails: () => [],
184
- applyConflictResolution: () => true,
185
- }));
186
- mock.module("../memory/clarification-resolver.js", () => ({
187
- resolveConflictClarification: async () => ({
188
- resolution: "still_unclear",
189
- strategy: "heuristic",
190
- resolvedStatement: null,
191
- explanation: "",
192
- }),
193
- }));
194
- mock.module("../memory/admin.js", () => ({
195
- getMemoryConflictAndCleanupStats: () => ({
196
- conflicts: { pending: 0, resolved: 0, oldestPendingAgeMs: null },
197
- cleanup: {
198
- resolvedBacklog: 0,
199
- supersededBacklog: 0,
200
- resolvedCompleted24h: 0,
201
- supersededCompleted24h: 0,
202
- },
203
- }),
204
- }));
205
- mock.module("../memory/profile-compiler.js", () => ({
206
- compileDynamicProfile: () => null,
207
- }));
208
174
  mock.module("../memory/llm-usage-store.js", () => ({
209
175
  recordUsageEvent: () => ({ id: "usage-1", createdAt: Date.now() }),
210
176
  }));
@@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test";
2
2
 
3
3
  import type { SkillSummary } from "../config/skills.js";
4
4
  import {
5
+ collectAllMissing,
5
6
  getImmediateChildren,
6
7
  indexCatalogById,
7
8
  traverseIncludes,
@@ -298,3 +299,68 @@ describe("validateIncludes — cycle detection", () => {
298
299
  }
299
300
  });
300
301
  });
302
+
303
+ describe("collectAllMissing", () => {
304
+ test("returns empty set when skill has no includes", () => {
305
+ const catalog = [makeSkill("root")];
306
+ const index = indexCatalogById(catalog);
307
+ expect(collectAllMissing("root", index)).toEqual(new Set([]));
308
+ });
309
+
310
+ test("returns empty set when all includes are present", () => {
311
+ const catalog = [makeSkill("A", ["B"]), makeSkill("B")];
312
+ const index = indexCatalogById(catalog);
313
+ expect(collectAllMissing("A", index)).toEqual(new Set([]));
314
+ });
315
+
316
+ test("returns immediate missing children", () => {
317
+ const catalog = [makeSkill("A", ["B", "C"]), makeSkill("C")];
318
+ const index = indexCatalogById(catalog);
319
+ expect(collectAllMissing("A", index)).toEqual(new Set(["B"]));
320
+ });
321
+
322
+ test("returns transitive missing children", () => {
323
+ const catalog = [makeSkill("A", ["B"]), makeSkill("B", ["C"])];
324
+ const index = indexCatalogById(catalog);
325
+ expect(collectAllMissing("A", index)).toEqual(new Set(["C"]));
326
+ });
327
+
328
+ test("returns multiple missing at different levels", () => {
329
+ // A→B→C, B present but C missing
330
+ const catalog1 = [makeSkill("A", ["B"]), makeSkill("B", ["C"])];
331
+ const index1 = indexCatalogById(catalog1);
332
+ expect(collectAllMissing("A", index1)).toEqual(new Set(["C"]));
333
+
334
+ // A includes B and C, both missing
335
+ const catalog2 = [makeSkill("A", ["B", "C"])];
336
+ const index2 = indexCatalogById(catalog2);
337
+ expect(collectAllMissing("A", index2)).toEqual(new Set(["B", "C"]));
338
+ });
339
+
340
+ test("handles diamond with missing leaf", () => {
341
+ const catalog = [
342
+ makeSkill("A", ["B", "C"]),
343
+ makeSkill("B", ["D"]),
344
+ makeSkill("C", ["D"]),
345
+ ];
346
+ const index = indexCatalogById(catalog);
347
+ const result = collectAllMissing("A", index);
348
+ expect(result).toEqual(new Set(["D"]));
349
+ // Verify no duplicates (Set handles this, but confirm size)
350
+ expect(result.size).toBe(1);
351
+ });
352
+
353
+ test("does not loop infinitely on cycles", () => {
354
+ const catalog = [makeSkill("A", ["B"]), makeSkill("B", ["A"])];
355
+ const index = indexCatalogById(catalog);
356
+ expect(collectAllMissing("A", index)).toEqual(new Set([]));
357
+ });
358
+
359
+ test("handles cycle with missing node", () => {
360
+ const catalog = [makeSkill("A", ["B"]), makeSkill("B", ["C"])];
361
+ // C is missing, and if C referenced B it would be a cycle — but C isn't in catalog
362
+ // So A→B→C, C missing
363
+ const index = indexCatalogById(catalog);
364
+ expect(collectAllMissing("A", index)).toEqual(new Set(["C"]));
365
+ });
366
+ });
@@ -61,7 +61,6 @@ mock.module("../util/logger.js", () => ({
61
61
  ...realLogger,
62
62
  getLogger: () => noopLogger,
63
63
  getCliLogger: () => noopLogger,
64
- isDebug: () => false,
65
64
  truncateForLog: (value: string) => value,
66
65
  initLogger: () => {},
67
66
  pruneOldLogFiles: () => 0,
@@ -60,10 +60,16 @@ mock.module("../util/logger.js", () => ({
60
60
  new Proxy({} as Record<string, unknown>, {
61
61
  get: () => () => {},
62
62
  }),
63
- isDebug: () => false,
64
63
  truncateForLog: (s: unknown) => String(s),
65
64
  }));
66
65
 
66
+ // Mock autoInstallFromCatalog — default returns false (not found in catalog).
67
+ // Tests can override via `mockAutoInstall.mockImplementation(...)`.
68
+ const mockAutoInstall = mock((_skillId: string) => Promise.resolve(false));
69
+ mock.module("../skills/catalog-install.js", () => ({
70
+ autoInstallFromCatalog: (skillId: string) => mockAutoInstall(skillId),
71
+ }));
72
+
67
73
  await import("../tools/skills/load.js");
68
74
  const { getTool } = await import("../tools/registry.js");
69
75
 
@@ -145,6 +151,10 @@ async function executeSkillLoad(
145
151
  describe("skill_load tool", () => {
146
152
  beforeEach(() => {
147
153
  mkdirSync(join(TEST_DIR, "skills"), { recursive: true });
154
+ mockAutoInstall.mockReset();
155
+ mockAutoInstall.mockImplementation((_skillId: string) =>
156
+ Promise.resolve(false),
157
+ );
148
158
  });
149
159
 
150
160
  afterEach(() => {
@@ -850,4 +860,142 @@ describe("skill_load tool", () => {
850
860
  "Use `skill_execute` to call these tools.",
851
861
  );
852
862
  });
863
+
864
+ test("auto-installs missing includes from catalog", async () => {
865
+ // Parent includes "dep-a" which is not initially in the catalog
866
+ writeSkillWithIncludes(
867
+ "auto-parent",
868
+ "Auto Parent",
869
+ "Has auto-installable dep",
870
+ "Parent body",
871
+ ["dep-a"],
872
+ );
873
+ writeFileSync(join(TEST_DIR, "skills", "SKILLS.md"), "- auto-parent\n");
874
+
875
+ // Mock autoInstallFromCatalog to succeed and write the skill to disk
876
+ mockAutoInstall.mockImplementation((skillId: string) => {
877
+ if (skillId === "dep-a") {
878
+ writeSkill("dep-a", "Dep A", "A dependency", "Dep A body");
879
+ // Add to SKILLS.md so catalog reload finds it
880
+ writeFileSync(
881
+ join(TEST_DIR, "skills", "SKILLS.md"),
882
+ "- auto-parent\n- dep-a\n",
883
+ );
884
+ return Promise.resolve(true);
885
+ }
886
+ return Promise.resolve(false);
887
+ });
888
+
889
+ const result = await executeSkillLoad({ skill: "auto-parent" });
890
+ expect(result.isError).toBe(false);
891
+ expect(result.content).toContain("Skill: Auto Parent");
892
+ expect(result.content).toContain("<loaded_skill");
893
+ expect(mockAutoInstall).toHaveBeenCalledWith("dep-a");
894
+ });
895
+
896
+ test("auto-installs transitive missing includes across rounds", async () => {
897
+ // Skill A includes B, B includes C. Neither B nor C in initial catalog.
898
+ writeSkillWithIncludes("trans-a", "Trans A", "Top level", "Body A", [
899
+ "trans-b",
900
+ ]);
901
+ writeFileSync(join(TEST_DIR, "skills", "SKILLS.md"), "- trans-a\n");
902
+
903
+ let round = 0;
904
+ mockAutoInstall.mockImplementation((skillId: string) => {
905
+ if (skillId === "trans-b" && round === 0) {
906
+ // First round: install B (which includes C)
907
+ writeSkillWithIncludes("trans-b", "Trans B", "Mid level", "Body B", [
908
+ "trans-c",
909
+ ]);
910
+ writeFileSync(
911
+ join(TEST_DIR, "skills", "SKILLS.md"),
912
+ "- trans-a\n- trans-b\n",
913
+ );
914
+ round++;
915
+ return Promise.resolve(true);
916
+ }
917
+ if (skillId === "trans-c") {
918
+ // Second round: install C
919
+ writeSkill("trans-c", "Trans C", "Leaf", "Body C");
920
+ writeFileSync(
921
+ join(TEST_DIR, "skills", "SKILLS.md"),
922
+ "- trans-a\n- trans-b\n- trans-c\n",
923
+ );
924
+ return Promise.resolve(true);
925
+ }
926
+ return Promise.resolve(false);
927
+ });
928
+
929
+ const result = await executeSkillLoad({ skill: "trans-a" });
930
+ expect(result.isError).toBe(false);
931
+ expect(result.content).toContain("Skill: Trans A");
932
+ expect(result.content).toContain("<loaded_skill");
933
+ expect(mockAutoInstall).toHaveBeenCalledWith("trans-b");
934
+ expect(mockAutoInstall).toHaveBeenCalledWith("trans-c");
935
+ });
936
+
937
+ test("returns error when auto-install of missing include fails", async () => {
938
+ writeSkillWithIncludes(
939
+ "fail-parent",
940
+ "Fail Parent",
941
+ "Has failing dep",
942
+ "Body",
943
+ ["dep-x"],
944
+ );
945
+ writeFileSync(join(TEST_DIR, "skills", "SKILLS.md"), "- fail-parent\n");
946
+
947
+ // autoInstallFromCatalog throws an error
948
+ mockAutoInstall.mockImplementation((skillId: string) => {
949
+ if (skillId === "dep-x") {
950
+ return Promise.reject(new Error("Network error"));
951
+ }
952
+ return Promise.resolve(false);
953
+ });
954
+
955
+ const result = await executeSkillLoad({ skill: "fail-parent" });
956
+ expect(result.isError).toBe(true);
957
+ expect(result.content).toContain("dep-x");
958
+ expect(result.content).toContain("not found");
959
+ expect(result.content).not.toContain("<loaded_skill");
960
+ });
961
+
962
+ test("stops after MAX_INSTALL_ROUNDS", async () => {
963
+ // Pathological case: each install round reveals a new missing dep
964
+ writeSkillWithIncludes("loop-root", "Loop Root", "Infinite deps", "Body", [
965
+ "loop-dep-0",
966
+ ]);
967
+ writeFileSync(join(TEST_DIR, "skills", "SKILLS.md"), "- loop-root\n");
968
+
969
+ let installCount = 0;
970
+ mockAutoInstall.mockImplementation((skillId: string) => {
971
+ const id = skillId;
972
+ if (id.startsWith("loop-dep-")) {
973
+ installCount++;
974
+ const nextDepId = `loop-dep-${installCount}`;
975
+ // Install the requested dep, but it includes yet another missing dep
976
+ writeSkillWithIncludes(
977
+ id,
978
+ `Loop Dep ${installCount}`,
979
+ "Generated dep",
980
+ "Body",
981
+ [nextDepId],
982
+ );
983
+ // Update SKILLS.md to include all installed deps so far
984
+ const entries = ["- loop-root\n"];
985
+ for (let i = 0; i < installCount; i++) {
986
+ entries.push(`- loop-dep-${i}\n`);
987
+ }
988
+ writeFileSync(join(TEST_DIR, "skills", "SKILLS.md"), entries.join(""));
989
+ return Promise.resolve(true);
990
+ }
991
+ return Promise.resolve(false);
992
+ });
993
+
994
+ const result = await executeSkillLoad({ skill: "loop-root" });
995
+ // Should terminate with an error (the final dep is still missing)
996
+ expect(result.isError).toBe(true);
997
+ expect(result.content).toContain("not found");
998
+ // Should have terminated — installCount should be bounded by MAX_INSTALL_ROUNDS (5)
999
+ expect(installCount).toBeLessThanOrEqual(5);
1000
+ });
853
1001
  });
@@ -210,7 +210,6 @@ mock.module("../util/logger.js", () => ({
210
210
  debug: () => {},
211
211
  error: () => {},
212
212
  }),
213
- isDebug: () => false,
214
213
  }));
215
214
 
216
215
  // ---------------------------------------------------------------------------
@@ -0,0 +1,93 @@
1
+ import { existsSync, mkdirSync, readFileSync, rmSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
5
+
6
+ import { extractTarToDir } from "../skills/catalog-install.js";
7
+
8
+ let tempDir: string;
9
+
10
+ function makeTarEntry(name: string, content: string): Buffer {
11
+ const header = Buffer.alloc(512, 0);
12
+ const nameBuffer = Buffer.from(name, "utf-8");
13
+ nameBuffer.copy(header, 0, 0, Math.min(nameBuffer.length, 100));
14
+
15
+ const mode = Buffer.from("0000644\0", "ascii");
16
+ mode.copy(header, 100);
17
+ Buffer.from("0000000\0", "ascii").copy(header, 108); // uid
18
+ Buffer.from("0000000\0", "ascii").copy(header, 116); // gid
19
+
20
+ const sizeOct = content.length.toString(8).padStart(11, "0") + "\0";
21
+ Buffer.from(sizeOct, "ascii").copy(header, 124);
22
+
23
+ Buffer.from("00000000000\0", "ascii").copy(header, 136); // mtime
24
+ Buffer.from(" ", "ascii").copy(header, 148); // checksum placeholder
25
+ header[156] = "0".charCodeAt(0);
26
+ Buffer.from("ustar\0", "ascii").copy(header, 257);
27
+ Buffer.from("00", "ascii").copy(header, 263);
28
+
29
+ let sum = 0;
30
+ for (let i = 0; i < 512; i += 1) sum += header[i] ?? 0;
31
+ const checksum = sum.toString(8).padStart(6, "0");
32
+ Buffer.from(`${checksum}\0 `, "ascii").copy(header, 148);
33
+
34
+ const data = Buffer.from(content, "utf-8");
35
+ const paddedSize = Math.ceil(data.length / 512) * 512;
36
+ const padded = Buffer.alloc(paddedSize, 0);
37
+ data.copy(padded);
38
+
39
+ return Buffer.concat([header, padded]);
40
+ }
41
+
42
+ function makeTar(entries: Array<{ name: string; content: string }>): Buffer {
43
+ const body = entries.map((entry) => makeTarEntry(entry.name, entry.content));
44
+ return Buffer.concat([...body, Buffer.alloc(1024, 0)]);
45
+ }
46
+
47
+ beforeEach(() => {
48
+ tempDir = join(
49
+ tmpdir(),
50
+ `skills-extract-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
51
+ );
52
+ mkdirSync(tempDir, { recursive: true });
53
+ });
54
+
55
+ afterEach(() => {
56
+ rmSync(tempDir, { recursive: true, force: true });
57
+ });
58
+
59
+ describe("extractTarToDir", () => {
60
+ test("extracts valid files and detects SKILL.md", () => {
61
+ const tar = makeTar([
62
+ { name: "SKILL.md", content: "# demo\n" },
63
+ { name: "scripts/run.sh", content: "echo ok\n" },
64
+ ]);
65
+
66
+ const foundSkillMd = extractTarToDir(tar, tempDir);
67
+
68
+ expect(foundSkillMd).toBe(true);
69
+ expect(readFileSync(join(tempDir, "SKILL.md"), "utf-8")).toBe("# demo\n");
70
+ expect(readFileSync(join(tempDir, "scripts", "run.sh"), "utf-8")).toBe(
71
+ "echo ok\n",
72
+ );
73
+ });
74
+
75
+ test("rejects traversal and absolute archive paths", () => {
76
+ const tar = makeTar([
77
+ { name: "SKILL.md", content: "# demo\n" },
78
+ { name: "../../escape.txt", content: "nope\n" },
79
+ { name: "..\\..\\win-escape.txt", content: "nope\n" },
80
+ { name: "/absolute.txt", content: "nope\n" },
81
+ { name: "C:/windows.txt", content: "nope\n" },
82
+ ]);
83
+
84
+ const foundSkillMd = extractTarToDir(tar, tempDir);
85
+
86
+ expect(foundSkillMd).toBe(true);
87
+ expect(existsSync(join(tempDir, "escape.txt"))).toBe(false);
88
+ expect(existsSync(join(tempDir, "win-escape.txt"))).toBe(false);
89
+ expect(existsSync(join(tempDir, "absolute.txt"))).toBe(false);
90
+ expect(existsSync(join(tempDir, "windows.txt"))).toBe(false);
91
+ expect(readFileSync(join(tempDir, "SKILL.md"), "utf-8")).toBe("# demo\n");
92
+ });
93
+ });
@@ -9,7 +9,7 @@ import { tmpdir } from "node:os";
9
9
  import { join } from "node:path";
10
10
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
11
11
 
12
- import { uninstallSkillLocally } from "../cli/commands/skills.js";
12
+ import { uninstallSkillLocally } from "../skills/catalog-install.js";
13
13
 
14
14
  let tempDir: string;
15
15
  let originalBaseDataDir: string | undefined;
@@ -60,7 +60,6 @@ mock.module("../util/logger.js", () => ({
60
60
  ...realLogger,
61
61
  getLogger: () => noopLogger,
62
62
  getCliLogger: () => noopLogger,
63
- isDebug: () => false,
64
63
  truncateForLog: (v: string) => v,
65
64
  initLogger: () => {},
66
65
  pruneOldLogFiles: () => 0,
@@ -719,15 +718,16 @@ describe("bundled computer-use skill", () => {
719
718
  expect(cuSkill!.disableModelInvocation).toBe(true);
720
719
  });
721
720
 
722
- test("computer-use skill has a valid tool manifest with 12 tools", () => {
721
+ test("computer-use skill has a valid tool manifest with 11 tools", () => {
723
722
  const catalog = loadSkillCatalog();
724
723
  const cuSkill = catalog.find((s) => s.id === "computer-use");
725
724
  expect(cuSkill).toBeDefined();
726
725
  expect(cuSkill!.toolManifest).toBeDefined();
727
726
  expect(cuSkill!.toolManifest!.present).toBe(true);
728
727
  expect(cuSkill!.toolManifest!.valid).toBe(true);
729
- expect(cuSkill!.toolManifest!.toolCount).toBe(10);
728
+ expect(cuSkill!.toolManifest!.toolCount).toBe(11);
730
729
  expect(cuSkill!.toolManifest!.toolNames).toEqual([
730
+ "computer_use_observe",
731
731
  "computer_use_click",
732
732
  "computer_use_type_text",
733
733
  "computer_use_key",