vellum 0.0.16 → 0.2.0

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 (838) hide show
  1. package/.dockerignore +27 -0
  2. package/.env.example +22 -0
  3. package/Dockerfile +99 -0
  4. package/Dockerfile.sandbox +5 -0
  5. package/README.md +150 -3
  6. package/bun.lock +1768 -0
  7. package/bunfig.toml +2 -0
  8. package/docs/skills.md +158 -0
  9. package/drizzle/0000_dizzy_maggott.sql +301 -0
  10. package/drizzle/meta/0000_snapshot.json +1999 -0
  11. package/drizzle/meta/_journal.json +13 -0
  12. package/drizzle.config.ts +7 -0
  13. package/eslint.config.mjs +17 -0
  14. package/hook-templates/debug-prompt-logger/hook.json +7 -0
  15. package/hook-templates/debug-prompt-logger/run.sh +68 -0
  16. package/knip.json +9 -0
  17. package/package.json +60 -10
  18. package/scripts/ipc/check-contract-inventory.ts +104 -0
  19. package/scripts/ipc/check-swift-decoder-drift.ts +163 -0
  20. package/scripts/ipc/generate-swift.ts +492 -0
  21. package/scripts/test-filesystem-tools.sh +48 -0
  22. package/scripts/test.sh +122 -0
  23. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +2079 -0
  24. package/src/__tests__/account-registry.test.ts +244 -0
  25. package/src/__tests__/active-skill-tools.test.ts +378 -0
  26. package/src/__tests__/agent-loop-thinking.test.ts +81 -0
  27. package/src/__tests__/agent-loop.test.ts +1135 -0
  28. package/src/__tests__/anthropic-provider.test.ts +778 -0
  29. package/src/__tests__/app-builder-tool-scripts.test.ts +290 -0
  30. package/src/__tests__/app-bundler.test.ts +313 -0
  31. package/src/__tests__/app-executors.test.ts +613 -0
  32. package/src/__tests__/app-open-proxy.test.ts +62 -0
  33. package/src/__tests__/asset-materialize-tool.test.ts +451 -0
  34. package/src/__tests__/asset-search-tool.test.ts +476 -0
  35. package/src/__tests__/assistant-attachment-directive.test.ts +401 -0
  36. package/src/__tests__/assistant-attachments.test.ts +437 -0
  37. package/src/__tests__/assistant-event-hub.test.ts +226 -0
  38. package/src/__tests__/assistant-event.test.ts +123 -0
  39. package/src/__tests__/attachments-store.test.ts +547 -0
  40. package/src/__tests__/attachments.test.ts +134 -0
  41. package/src/__tests__/audit-log-rotation.test.ts +154 -0
  42. package/src/__tests__/browser-fill-credential.test.ts +309 -0
  43. package/src/__tests__/browser-manager.test.ts +203 -0
  44. package/src/__tests__/browser-runtime-check.test.ts +55 -0
  45. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +67 -0
  46. package/src/__tests__/browser-skill-endstate.test.ts +198 -0
  47. package/src/__tests__/bundle-scanner.test.ts +313 -0
  48. package/src/__tests__/checker.test.ts +3856 -0
  49. package/src/__tests__/clarification-resolver.test.ts +159 -0
  50. package/src/__tests__/classifier.test.ts +67 -0
  51. package/src/__tests__/claude-code-skill-regression.test.ts +127 -0
  52. package/src/__tests__/claude-code-tool-profiles.test.ts +88 -0
  53. package/src/__tests__/cli-discover.test.ts +85 -0
  54. package/src/__tests__/cli.test.ts +81 -0
  55. package/src/__tests__/clipboard.test.ts +80 -0
  56. package/src/__tests__/commit-guarantee.test.ts +335 -0
  57. package/src/__tests__/computer-use-session-compaction.test.ts +132 -0
  58. package/src/__tests__/computer-use-session-lifecycle.test.ts +293 -0
  59. package/src/__tests__/computer-use-session-working-dir.test.ts +117 -0
  60. package/src/__tests__/computer-use-skill-baseline.test.ts +74 -0
  61. package/src/__tests__/computer-use-skill-endstate.test.ts +89 -0
  62. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +217 -0
  63. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +107 -0
  64. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +54 -0
  65. package/src/__tests__/config-schema.test.ts +720 -0
  66. package/src/__tests__/conflict-store.test.ts +329 -0
  67. package/src/__tests__/connection-policy.test.ts +102 -0
  68. package/src/__tests__/context-memory-e2e.test.ts +434 -0
  69. package/src/__tests__/context-token-estimator.test.ts +135 -0
  70. package/src/__tests__/context-window-manager.test.ts +376 -0
  71. package/src/__tests__/contradiction-checker.test.ts +216 -0
  72. package/src/__tests__/conversation-store.test.ts +614 -0
  73. package/src/__tests__/credential-broker-browser-fill.test.ts +517 -0
  74. package/src/__tests__/credential-broker-server-use.test.ts +554 -0
  75. package/src/__tests__/credential-broker.test.ts +167 -0
  76. package/src/__tests__/credential-host-pattern-match.test.ts +104 -0
  77. package/src/__tests__/credential-metadata-store.test.ts +779 -0
  78. package/src/__tests__/credential-policy-validate.test.ts +121 -0
  79. package/src/__tests__/credential-resolve.test.ts +328 -0
  80. package/src/__tests__/credential-security-e2e.test.ts +352 -0
  81. package/src/__tests__/credential-security-invariants.test.ts +563 -0
  82. package/src/__tests__/credential-selection.test.ts +354 -0
  83. package/src/__tests__/credential-vault.test.ts +852 -0
  84. package/src/__tests__/daemon-assistant-events.test.ts +164 -0
  85. package/src/__tests__/daemon-server-session-init.test.ts +522 -0
  86. package/src/__tests__/delete-managed-skill-tool.test.ts +97 -0
  87. package/src/__tests__/diff.test.ts +121 -0
  88. package/src/__tests__/domain-normalize.test.ts +112 -0
  89. package/src/__tests__/domain-policy.test.ts +124 -0
  90. package/src/__tests__/doordash-client.test.ts +186 -0
  91. package/src/__tests__/doordash-session.test.ts +143 -0
  92. package/src/__tests__/dynamic-page-surface.test.ts +91 -0
  93. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +132 -0
  94. package/src/__tests__/edit-engine.test.ts +180 -0
  95. package/src/__tests__/email-cli.test.ts +283 -0
  96. package/src/__tests__/encrypted-store.test.ts +332 -0
  97. package/src/__tests__/entity-extractor.test.ts +190 -0
  98. package/src/__tests__/ephemeral-permissions.test.ts +312 -0
  99. package/src/__tests__/evaluate-typescript-tool.test.ts +286 -0
  100. package/src/__tests__/event-bus.test.ts +222 -0
  101. package/src/__tests__/file-edit-tool.test.ts +122 -0
  102. package/src/__tests__/file-ops-service.test.ts +330 -0
  103. package/src/__tests__/file-read-tool.test.ts +75 -0
  104. package/src/__tests__/file-write-tool.test.ts +113 -0
  105. package/src/__tests__/fixtures/credential-security-fixtures.ts +181 -0
  106. package/src/__tests__/fixtures/media-reuse-fixtures.ts +126 -0
  107. package/src/__tests__/fixtures/mock-signup-server.ts +387 -0
  108. package/src/__tests__/fixtures/proxy-fixtures.ts +147 -0
  109. package/src/__tests__/fuzzy-match-property.test.ts +216 -0
  110. package/src/__tests__/fuzzy-match.test.ts +138 -0
  111. package/src/__tests__/gemini-image-service.test.ts +261 -0
  112. package/src/__tests__/gemini-provider.test.ts +651 -0
  113. package/src/__tests__/get-weather.test.ts +318 -0
  114. package/src/__tests__/gmail-integration.test.ts +73 -0
  115. package/src/__tests__/handlers-cu-observation-blob.test.ts +351 -0
  116. package/src/__tests__/handlers-ipc-blob-probe.test.ts +190 -0
  117. package/src/__tests__/handlers-slack-config.test.ts +199 -0
  118. package/src/__tests__/handlers-task-submit-slash.test.ts +38 -0
  119. package/src/__tests__/headless-browser-interactions.test.ts +536 -0
  120. package/src/__tests__/headless-browser-navigate.test.ts +211 -0
  121. package/src/__tests__/headless-browser-read-tools.test.ts +261 -0
  122. package/src/__tests__/headless-browser-snapshot.test.ts +185 -0
  123. package/src/__tests__/history-repair-observability.test.ts +56 -0
  124. package/src/__tests__/history-repair.test.ts +510 -0
  125. package/src/__tests__/home-base-bootstrap.test.ts +77 -0
  126. package/src/__tests__/hooks-blocking.test.ts +128 -0
  127. package/src/__tests__/hooks-cli.test.ts +144 -0
  128. package/src/__tests__/hooks-config.test.ts +93 -0
  129. package/src/__tests__/hooks-discovery.test.ts +199 -0
  130. package/src/__tests__/hooks-integration.test.ts +189 -0
  131. package/src/__tests__/hooks-manager.test.ts +187 -0
  132. package/src/__tests__/hooks-runner.test.ts +178 -0
  133. package/src/__tests__/hooks-settings.test.ts +154 -0
  134. package/src/__tests__/hooks-templates.test.ts +137 -0
  135. package/src/__tests__/hooks-ts-runner.test.ts +125 -0
  136. package/src/__tests__/hooks-watch.test.ts +100 -0
  137. package/src/__tests__/host-file-edit-tool.test.ts +104 -0
  138. package/src/__tests__/host-file-read-tool.test.ts +61 -0
  139. package/src/__tests__/host-file-write-tool.test.ts +77 -0
  140. package/src/__tests__/host-shell-tool.test.ts +311 -0
  141. package/src/__tests__/intent-routing.test.ts +255 -0
  142. package/src/__tests__/ipc-blob-store.test.ts +315 -0
  143. package/src/__tests__/ipc-contract-inventory.test.ts +54 -0
  144. package/src/__tests__/ipc-contract.test.ts +74 -0
  145. package/src/__tests__/ipc-protocol.test.ts +113 -0
  146. package/src/__tests__/ipc-snapshot.test.ts +1560 -0
  147. package/src/__tests__/ipc-validate.test.ts +357 -0
  148. package/src/__tests__/key-migration.test.ts +183 -0
  149. package/src/__tests__/keychain.test.ts +258 -0
  150. package/src/__tests__/llm-usage-store.test.ts +226 -0
  151. package/src/__tests__/managed-skill-lifecycle.test.ts +257 -0
  152. package/src/__tests__/managed-store.test.ts +608 -0
  153. package/src/__tests__/media-generate-image.test.ts +238 -0
  154. package/src/__tests__/media-reuse-story.e2e.test.ts +676 -0
  155. package/src/__tests__/media-visibility-policy.test.ts +141 -0
  156. package/src/__tests__/memory-context-benchmark.test.ts +235 -0
  157. package/src/__tests__/memory-lifecycle-e2e.test.ts +481 -0
  158. package/src/__tests__/memory-query-builder.test.ts +59 -0
  159. package/src/__tests__/memory-recall-quality.test.ts +846 -0
  160. package/src/__tests__/memory-regressions.experimental.test.ts +538 -0
  161. package/src/__tests__/memory-regressions.test.ts +4238 -0
  162. package/src/__tests__/memory-retrieval-budget.test.ts +49 -0
  163. package/src/__tests__/migration-cli-flows.test.ts +169 -0
  164. package/src/__tests__/migration-ordering.test.ts +249 -0
  165. package/src/__tests__/mock-signup-server.test.ts +528 -0
  166. package/src/__tests__/onboarding-starter-tasks.test.ts +166 -0
  167. package/src/__tests__/onboarding-template-contract.test.ts +58 -0
  168. package/src/__tests__/openai-provider.test.ts +753 -0
  169. package/src/__tests__/parser.test.ts +472 -0
  170. package/src/__tests__/path-classifier.test.ts +73 -0
  171. package/src/__tests__/path-policy.test.ts +435 -0
  172. package/src/__tests__/platform-move-helper.test.ts +99 -0
  173. package/src/__tests__/platform-socket-path.test.ts +52 -0
  174. package/src/__tests__/platform-workspace-migration.test.ts +1000 -0
  175. package/src/__tests__/platform.test.ts +131 -0
  176. package/src/__tests__/prebuilt-home-base-seed.test.ts +71 -0
  177. package/src/__tests__/pricing.test.ts +256 -0
  178. package/src/__tests__/profile-compiler.test.ts +373 -0
  179. package/src/__tests__/provider-registry-ollama.test.ts +16 -0
  180. package/src/__tests__/proxy-approval-callback.test.ts +601 -0
  181. package/src/__tests__/ratelimit.test.ts +297 -0
  182. package/src/__tests__/registry.test.ts +487 -0
  183. package/src/__tests__/reminder-store.test.ts +220 -0
  184. package/src/__tests__/reminder.test.ts +263 -0
  185. package/src/__tests__/request-file-tool.test.ts +158 -0
  186. package/src/__tests__/run-orchestrator.test.ts +200 -0
  187. package/src/__tests__/runtime-attachment-metadata.test.ts +190 -0
  188. package/src/__tests__/runtime-runs-http.test.ts +451 -0
  189. package/src/__tests__/runtime-runs.test.ts +273 -0
  190. package/src/__tests__/sandbox-diagnostics.test.ts +408 -0
  191. package/src/__tests__/sandbox-host-parity.test.ts +950 -0
  192. package/src/__tests__/scaffold-managed-skill-tool.test.ts +253 -0
  193. package/src/__tests__/script-proxy-certs.test.ts +90 -0
  194. package/src/__tests__/script-proxy-connect-tunnel.test.ts +177 -0
  195. package/src/__tests__/script-proxy-decision-trace.test.ts +156 -0
  196. package/src/__tests__/script-proxy-http-forwarder.test.ts +281 -0
  197. package/src/__tests__/script-proxy-injection-runtime.test.ts +401 -0
  198. package/src/__tests__/script-proxy-mitm-handler.test.ts +407 -0
  199. package/src/__tests__/script-proxy-policy-runtime.test.ts +287 -0
  200. package/src/__tests__/script-proxy-policy.test.ts +310 -0
  201. package/src/__tests__/script-proxy-rewrite-specificity.test.ts +135 -0
  202. package/src/__tests__/script-proxy-router.test.ts +180 -0
  203. package/src/__tests__/script-proxy-session-manager.test.ts +382 -0
  204. package/src/__tests__/script-proxy-session-runtime.test.ts +113 -0
  205. package/src/__tests__/secret-allowlist.test.ts +229 -0
  206. package/src/__tests__/secret-ingress-handler.test.ts +99 -0
  207. package/src/__tests__/secret-onetime-send.test.ts +130 -0
  208. package/src/__tests__/secret-prompt-log-hygiene.test.ts +106 -0
  209. package/src/__tests__/secret-response-routing.test.ts +93 -0
  210. package/src/__tests__/secret-scanner-executor.test.ts +348 -0
  211. package/src/__tests__/secret-scanner.test.ts +857 -0
  212. package/src/__tests__/secure-keys.test.ts +323 -0
  213. package/src/__tests__/server-history-render.test.ts +430 -0
  214. package/src/__tests__/session-abort-tool-results.test.ts +240 -0
  215. package/src/__tests__/session-conflict-gate.test.ts +697 -0
  216. package/src/__tests__/session-error.test.ts +341 -0
  217. package/src/__tests__/session-evictor.test.ts +188 -0
  218. package/src/__tests__/session-load-history-repair.test.ts +222 -0
  219. package/src/__tests__/session-pre-run-repair.test.ts +213 -0
  220. package/src/__tests__/session-profile-injection.test.ts +444 -0
  221. package/src/__tests__/session-provider-retry-repair.test.ts +306 -0
  222. package/src/__tests__/session-queue.test.ts +1462 -0
  223. package/src/__tests__/session-runtime-assembly.test.ts +315 -0
  224. package/src/__tests__/session-runtime-workspace.test.ts +183 -0
  225. package/src/__tests__/session-skill-tools.test.ts +2431 -0
  226. package/src/__tests__/session-slash-known.test.ts +368 -0
  227. package/src/__tests__/session-slash-queue.test.ts +288 -0
  228. package/src/__tests__/session-slash-unknown.test.ts +271 -0
  229. package/src/__tests__/session-tool-setup-app-refresh.test.ts +473 -0
  230. package/src/__tests__/session-tool-setup-memory-scope.test.ts +140 -0
  231. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +140 -0
  232. package/src/__tests__/session-undo.test.ts +75 -0
  233. package/src/__tests__/session-workspace-cache-state.test.ts +246 -0
  234. package/src/__tests__/session-workspace-injection.test.ts +327 -0
  235. package/src/__tests__/session-workspace-tool-tracking.test.ts +240 -0
  236. package/src/__tests__/shared-filesystem-errors.test.ts +78 -0
  237. package/src/__tests__/shell-credential-ref.test.ts +187 -0
  238. package/src/__tests__/shell-parser-fuzz.test.ts +544 -0
  239. package/src/__tests__/shell-parser-property.test.ts +433 -0
  240. package/src/__tests__/shell-tool-proxy-mode.test.ts +272 -0
  241. package/src/__tests__/signup-e2e.test.ts +352 -0
  242. package/src/__tests__/size-guard.test.ts +117 -0
  243. package/src/__tests__/skill-include-graph.test.ts +303 -0
  244. package/src/__tests__/skill-load-tool.test.ts +409 -0
  245. package/src/__tests__/skill-script-runner-host.test.ts +489 -0
  246. package/src/__tests__/skill-script-runner-sandbox.test.ts +349 -0
  247. package/src/__tests__/skill-tool-factory.test.ts +252 -0
  248. package/src/__tests__/skill-tool-manifest.test.ts +658 -0
  249. package/src/__tests__/skill-version-hash.test.ts +182 -0
  250. package/src/__tests__/skills.test.ts +597 -0
  251. package/src/__tests__/slash-commands-catalog.test.ts +86 -0
  252. package/src/__tests__/slash-commands-parser.test.ts +119 -0
  253. package/src/__tests__/slash-commands-resolver.test.ts +193 -0
  254. package/src/__tests__/slash-commands-rewrite.test.ts +39 -0
  255. package/src/__tests__/starter-bundle.test.ts +136 -0
  256. package/src/__tests__/starter-task-flow.test.ts +143 -0
  257. package/src/__tests__/subagent-manager-notify.test.ts +372 -0
  258. package/src/__tests__/subagent-tools.test.ts +118 -0
  259. package/src/__tests__/subagent-types.test.ts +78 -0
  260. package/src/__tests__/swarm-orchestrator.test.ts +428 -0
  261. package/src/__tests__/swarm-plan-validator.test.ts +330 -0
  262. package/src/__tests__/swarm-recursion.test.ts +165 -0
  263. package/src/__tests__/swarm-router-planner.test.ts +208 -0
  264. package/src/__tests__/swarm-session-integration.test.ts +274 -0
  265. package/src/__tests__/swarm-tool.test.ts +145 -0
  266. package/src/__tests__/swarm-worker-backend.test.ts +129 -0
  267. package/src/__tests__/swarm-worker-runner.test.ts +272 -0
  268. package/src/__tests__/system-prompt.test.ts +461 -0
  269. package/src/__tests__/task-compiler.test.ts +283 -0
  270. package/src/__tests__/task-runner.test.ts +215 -0
  271. package/src/__tests__/task-scheduler.test.ts +216 -0
  272. package/src/__tests__/task-tools.test.ts +602 -0
  273. package/src/__tests__/terminal-sandbox-docker.test.ts +1064 -0
  274. package/src/__tests__/terminal-sandbox.integration.test.ts +178 -0
  275. package/src/__tests__/terminal-sandbox.test.ts +202 -0
  276. package/src/__tests__/test-support/browser-skill-harness.ts +90 -0
  277. package/src/__tests__/test-support/computer-use-skill-harness.ts +45 -0
  278. package/src/__tests__/tool-audit-listener.test.ts +112 -0
  279. package/src/__tests__/tool-domain-event-publisher.test.ts +251 -0
  280. package/src/__tests__/tool-executor-lifecycle-events.test.ts +516 -0
  281. package/src/__tests__/tool-executor-redaction.test.ts +289 -0
  282. package/src/__tests__/tool-executor.test.ts +1971 -0
  283. package/src/__tests__/tool-metrics-listener.test.ts +225 -0
  284. package/src/__tests__/tool-notification-listener.test.ts +49 -0
  285. package/src/__tests__/tool-policy.test.ts +54 -0
  286. package/src/__tests__/tool-profiling-listener.test.ts +268 -0
  287. package/src/__tests__/tool-result-truncation.test.ts +217 -0
  288. package/src/__tests__/tool-trace-listener.test.ts +226 -0
  289. package/src/__tests__/top-level-renderer.test.ts +121 -0
  290. package/src/__tests__/top-level-scanner.test.ts +141 -0
  291. package/src/__tests__/trace-emitter.test.ts +173 -0
  292. package/src/__tests__/trust-store.test.ts +2030 -0
  293. package/src/__tests__/turn-commit.test.ts +219 -0
  294. package/src/__tests__/url-safety.test.ts +418 -0
  295. package/src/__tests__/weather-skill-regression.test.ts +225 -0
  296. package/src/__tests__/web-fetch.test.ts +869 -0
  297. package/src/__tests__/web-search.test.ts +584 -0
  298. package/src/__tests__/workspace-git-service.test.ts +750 -0
  299. package/src/__tests__/workspace-heartbeat-service.test.ts +347 -0
  300. package/src/__tests__/workspace-lifecycle.test.ts +292 -0
  301. package/src/agent/attachments.ts +35 -0
  302. package/src/agent/loop.ts +500 -0
  303. package/src/agent/message-types.ts +17 -0
  304. package/src/autonomy/autonomy-resolver.ts +60 -0
  305. package/src/autonomy/autonomy-store.ts +122 -0
  306. package/src/autonomy/disposition-mapper.ts +31 -0
  307. package/src/autonomy/index.ts +11 -0
  308. package/src/autonomy/types.ts +39 -0
  309. package/src/bundler/app-bundler.ts +274 -0
  310. package/src/bundler/bundle-scanner.ts +535 -0
  311. package/src/bundler/bundle-signer.ts +124 -0
  312. package/src/bundler/manifest.ts +21 -0
  313. package/src/bundler/signature-verifier.ts +184 -0
  314. package/src/cli/autonomy.ts +188 -0
  315. package/src/cli/contacts.ts +149 -0
  316. package/src/cli/doordash.ts +824 -0
  317. package/src/cli/email-guardrails.ts +200 -0
  318. package/src/cli/email.ts +405 -0
  319. package/src/cli/main-screen.tsx +155 -0
  320. package/src/cli.ts +935 -0
  321. package/src/config/bundled-skills/.gitkeep +0 -0
  322. package/src/config/bundled-skills/agentmail/SKILL.md +128 -0
  323. package/src/config/bundled-skills/agentmail/icon.svg +21 -0
  324. package/src/config/bundled-skills/app-builder/SKILL.md +1348 -0
  325. package/src/config/bundled-skills/app-builder/TOOLS.json +279 -0
  326. package/src/config/bundled-skills/app-builder/icon.svg +9 -0
  327. package/src/config/bundled-skills/app-builder/tools/app-create.ts +15 -0
  328. package/src/config/bundled-skills/app-builder/tools/app-delete.ts +10 -0
  329. package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +11 -0
  330. package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +10 -0
  331. package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +18 -0
  332. package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +11 -0
  333. package/src/config/bundled-skills/app-builder/tools/app-list.ts +10 -0
  334. package/src/config/bundled-skills/app-builder/tools/app-query.ts +10 -0
  335. package/src/config/bundled-skills/app-builder/tools/app-update.ts +20 -0
  336. package/src/config/bundled-skills/browser/SKILL.md +28 -0
  337. package/src/config/bundled-skills/browser/TOOLS.json +234 -0
  338. package/src/config/bundled-skills/browser/tools/browser-click.ts +9 -0
  339. package/src/config/bundled-skills/browser/tools/browser-close.ts +9 -0
  340. package/src/config/bundled-skills/browser/tools/browser-extract.ts +9 -0
  341. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +9 -0
  342. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +9 -0
  343. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +9 -0
  344. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +9 -0
  345. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +9 -0
  346. package/src/config/bundled-skills/browser/tools/browser-type.ts +9 -0
  347. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +9 -0
  348. package/src/config/bundled-skills/claude-code/SKILL.md +50 -0
  349. package/src/config/bundled-skills/claude-code/TOOLS.json +40 -0
  350. package/src/config/bundled-skills/claude-code/tools/claude-code.ts +9 -0
  351. package/src/config/bundled-skills/computer-use/SKILL.md +17 -0
  352. package/src/config/bundled-skills/computer-use/TOOLS.json +326 -0
  353. package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +9 -0
  354. package/src/config/bundled-skills/computer-use/tools/computer-use-done.ts +9 -0
  355. package/src/config/bundled-skills/computer-use/tools/computer-use-double-click.ts +9 -0
  356. package/src/config/bundled-skills/computer-use/tools/computer-use-drag.ts +9 -0
  357. package/src/config/bundled-skills/computer-use/tools/computer-use-key.ts +9 -0
  358. package/src/config/bundled-skills/computer-use/tools/computer-use-open-app.ts +9 -0
  359. package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +9 -0
  360. package/src/config/bundled-skills/computer-use/tools/computer-use-respond.ts +9 -0
  361. package/src/config/bundled-skills/computer-use/tools/computer-use-right-click.ts +9 -0
  362. package/src/config/bundled-skills/computer-use/tools/computer-use-run-applescript.ts +9 -0
  363. package/src/config/bundled-skills/computer-use/tools/computer-use-scroll.ts +9 -0
  364. package/src/config/bundled-skills/computer-use/tools/computer-use-type-text.ts +9 -0
  365. package/src/config/bundled-skills/computer-use/tools/computer-use-wait.ts +9 -0
  366. package/src/config/bundled-skills/google-calendar/SKILL.md +51 -0
  367. package/src/config/bundled-skills/google-calendar/TOOLS.json +108 -0
  368. package/src/config/bundled-skills/google-calendar/calendar-client.ts +165 -0
  369. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +21 -0
  370. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +42 -0
  371. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +13 -0
  372. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +30 -0
  373. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +41 -0
  374. package/src/config/bundled-skills/google-calendar/tools/shared.ts +18 -0
  375. package/src/config/bundled-skills/google-calendar/types.ts +97 -0
  376. package/src/config/bundled-skills/image-studio/SKILL.md +32 -0
  377. package/src/config/bundled-skills/image-studio/TOOLS.json +42 -0
  378. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +137 -0
  379. package/src/config/bundled-skills/messaging/SKILL.md +126 -0
  380. package/src/config/bundled-skills/messaging/TOOLS.json +357 -0
  381. package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +23 -0
  382. package/src/config/bundled-skills/messaging/tools/gmail-batch-archive.ts +23 -0
  383. package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +25 -0
  384. package/src/config/bundled-skills/messaging/tools/gmail-draft.ts +26 -0
  385. package/src/config/bundled-skills/messaging/tools/gmail-label.ts +25 -0
  386. package/src/config/bundled-skills/messaging/tools/gmail-trash.ts +23 -0
  387. package/src/config/bundled-skills/messaging/tools/gmail-unsubscribe.ts +84 -0
  388. package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +18 -0
  389. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +124 -0
  390. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +16 -0
  391. package/src/config/bundled-skills/messaging/tools/messaging-draft.ts +49 -0
  392. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +21 -0
  393. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +25 -0
  394. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +28 -0
  395. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +29 -0
  396. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +22 -0
  397. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +27 -0
  398. package/src/config/bundled-skills/messaging/tools/shared.ts +71 -0
  399. package/src/config/bundled-skills/messaging/tools/slack-add-reaction.ts +25 -0
  400. package/src/config/bundled-skills/messaging/tools/slack-leave-channel.ts +23 -0
  401. package/src/config/bundled-skills/self-upgrade/SKILL.md +74 -0
  402. package/src/config/bundled-skills/start-the-day/SKILL.md +70 -0
  403. package/src/config/bundled-skills/start-the-day/icon.svg +13 -0
  404. package/src/config/bundled-skills/weather/SKILL.md +37 -0
  405. package/src/config/bundled-skills/weather/TOOLS.json +32 -0
  406. package/src/config/bundled-skills/weather/icon.svg +24 -0
  407. package/src/config/bundled-skills/weather/tools/get-weather.ts +9 -0
  408. package/src/config/computer-use-prompt.ts +97 -0
  409. package/src/config/defaults.ts +186 -0
  410. package/src/config/loader.ts +336 -0
  411. package/src/config/schema.ts +1004 -0
  412. package/src/config/skill-state.ts +95 -0
  413. package/src/config/skills.ts +972 -0
  414. package/src/config/system-prompt.ts +927 -0
  415. package/src/config/templates/BOOTSTRAP.md +70 -0
  416. package/src/config/templates/IDENTITY.md +18 -0
  417. package/src/config/templates/LOOKS.md +25 -0
  418. package/src/config/templates/SOUL.md +37 -0
  419. package/src/config/templates/USER.md +19 -0
  420. package/src/config/types.ts +32 -0
  421. package/src/config/vellum-skills/deploy-fullstack-vercel/SKILL.md +179 -0
  422. package/src/config/vellum-skills/document-writer/SKILL.md +195 -0
  423. package/src/config/vellum-skills/google-oauth-setup/SKILL.md +194 -0
  424. package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +147 -0
  425. package/src/config/vellum-skills/telegram-setup/SKILL.md +105 -0
  426. package/src/contacts/contact-store.ts +410 -0
  427. package/src/contacts/index.ts +11 -0
  428. package/src/contacts/types.ts +28 -0
  429. package/src/context/token-estimator.ts +108 -0
  430. package/src/context/tool-result-truncation.ts +128 -0
  431. package/src/context/window-manager.ts +531 -0
  432. package/src/daemon/assistant-attachments.ts +679 -0
  433. package/src/daemon/classifier.ts +108 -0
  434. package/src/daemon/computer-use-session.ts +900 -0
  435. package/src/daemon/connection-policy.ts +41 -0
  436. package/src/daemon/handlers/apps.ts +446 -0
  437. package/src/daemon/handlers/computer-use.ts +181 -0
  438. package/src/daemon/handlers/config.ts +434 -0
  439. package/src/daemon/handlers/diagnostics.ts +334 -0
  440. package/src/daemon/handlers/documents.ts +184 -0
  441. package/src/daemon/handlers/home-base.ts +73 -0
  442. package/src/daemon/handlers/index.ts +355 -0
  443. package/src/daemon/handlers/misc.ts +323 -0
  444. package/src/daemon/handlers/open-bundle-handler.ts +80 -0
  445. package/src/daemon/handlers/publish.ts +182 -0
  446. package/src/daemon/handlers/sessions.ts +486 -0
  447. package/src/daemon/handlers/shared.ts +533 -0
  448. package/src/daemon/handlers/skills.ts +487 -0
  449. package/src/daemon/handlers/subagents.ts +122 -0
  450. package/src/daemon/handlers/work-items.ts +176 -0
  451. package/src/daemon/handlers.ts +17 -0
  452. package/src/daemon/history-repair.ts +214 -0
  453. package/src/daemon/ipc-blob-store.ts +231 -0
  454. package/src/daemon/ipc-contract-inventory.json +407 -0
  455. package/src/daemon/ipc-contract-inventory.ts +126 -0
  456. package/src/daemon/ipc-contract.ts +2102 -0
  457. package/src/daemon/ipc-protocol.ts +70 -0
  458. package/src/daemon/ipc-validate.ts +171 -0
  459. package/src/daemon/lifecycle.ts +503 -0
  460. package/src/daemon/main.ts +15 -0
  461. package/src/daemon/media-visibility-policy.ts +57 -0
  462. package/src/daemon/ride-shotgun-handler.ts +244 -0
  463. package/src/daemon/server.ts +1085 -0
  464. package/src/daemon/session-attachments.ts +173 -0
  465. package/src/daemon/session-conflict-gate.ts +219 -0
  466. package/src/daemon/session-dynamic-profile.ts +63 -0
  467. package/src/daemon/session-error.ts +269 -0
  468. package/src/daemon/session-evictor.ts +196 -0
  469. package/src/daemon/session-history.ts +437 -0
  470. package/src/daemon/session-memory.ts +212 -0
  471. package/src/daemon/session-process.ts +264 -0
  472. package/src/daemon/session-queue-manager.ts +81 -0
  473. package/src/daemon/session-runtime-assembly.ts +395 -0
  474. package/src/daemon/session-skill-tools.ts +237 -0
  475. package/src/daemon/session-slash.ts +302 -0
  476. package/src/daemon/session-surfaces.ts +624 -0
  477. package/src/daemon/session-tool-setup.ts +286 -0
  478. package/src/daemon/session-usage.ts +74 -0
  479. package/src/daemon/session-workspace.ts +19 -0
  480. package/src/daemon/session.ts +1651 -0
  481. package/src/daemon/trace-emitter.ts +82 -0
  482. package/src/daemon/watch-handler.ts +274 -0
  483. package/src/doordash/client.ts +905 -0
  484. package/src/doordash/queries.ts +1312 -0
  485. package/src/doordash/query-extractor.ts +93 -0
  486. package/src/doordash/session.ts +82 -0
  487. package/src/email/provider.ts +117 -0
  488. package/src/email/providers/agentmail.ts +317 -0
  489. package/src/email/providers/index.ts +58 -0
  490. package/src/email/service.ts +303 -0
  491. package/src/email/types.ts +126 -0
  492. package/src/events/bus.ts +157 -0
  493. package/src/events/domain-events.ts +83 -0
  494. package/src/events/index.ts +18 -0
  495. package/src/events/tool-audit-listener.ts +80 -0
  496. package/src/events/tool-domain-event-publisher.ts +111 -0
  497. package/src/events/tool-metrics-listener.ts +159 -0
  498. package/src/events/tool-notification-listener.ts +17 -0
  499. package/src/events/tool-profiling-listener.ts +158 -0
  500. package/src/events/tool-trace-listener.ts +75 -0
  501. package/src/export/formatter.ts +96 -0
  502. package/src/followups/followup-store.ts +166 -0
  503. package/src/followups/index.ts +10 -0
  504. package/src/followups/types.ts +23 -0
  505. package/src/gallery/default-gallery.ts +795 -0
  506. package/src/gallery/gallery-manifest.ts +24 -0
  507. package/src/home-base/app-link-store.ts +82 -0
  508. package/src/home-base/bootstrap.ts +66 -0
  509. package/src/home-base/prebuilt/index.html +662 -0
  510. package/src/home-base/prebuilt/seed-metadata.json +21 -0
  511. package/src/home-base/prebuilt/seed.ts +101 -0
  512. package/src/home-base/prebuilt-home-base-updater.ts +30 -0
  513. package/src/hooks/cli.ts +163 -0
  514. package/src/hooks/config.ts +88 -0
  515. package/src/hooks/discovery.ts +110 -0
  516. package/src/hooks/manager.ts +128 -0
  517. package/src/hooks/runner.ts +123 -0
  518. package/src/hooks/templates.ts +52 -0
  519. package/src/hooks/types.ts +72 -0
  520. package/src/index.ts +1194 -0
  521. package/src/instrument.ts +60 -0
  522. package/src/logfire.ts +99 -0
  523. package/src/media/gemini-image-service.ts +136 -0
  524. package/src/memory/account-store.ts +108 -0
  525. package/src/memory/admin.ts +211 -0
  526. package/src/memory/app-store.ts +556 -0
  527. package/src/memory/attachments-store.ts +453 -0
  528. package/src/memory/channel-delivery-store.ts +368 -0
  529. package/src/memory/checkpoints.ts +52 -0
  530. package/src/memory/clarification-resolver.ts +297 -0
  531. package/src/memory/conflict-store.ts +342 -0
  532. package/src/memory/contradiction-checker.ts +329 -0
  533. package/src/memory/conversation-key-store.ts +127 -0
  534. package/src/memory/conversation-store.ts +469 -0
  535. package/src/memory/db.ts +1105 -0
  536. package/src/memory/embedding-backend.ts +229 -0
  537. package/src/memory/embedding-gemini.ts +52 -0
  538. package/src/memory/embedding-local.ts +75 -0
  539. package/src/memory/embedding-ollama.ts +55 -0
  540. package/src/memory/embedding-openai.ts +25 -0
  541. package/src/memory/entity-extractor.ts +471 -0
  542. package/src/memory/fingerprint.ts +20 -0
  543. package/src/memory/indexer.ts +156 -0
  544. package/src/memory/items-extractor.ts +460 -0
  545. package/src/memory/job-handlers/backfill.ts +139 -0
  546. package/src/memory/job-handlers/cleanup.ts +58 -0
  547. package/src/memory/job-handlers/conflict.ts +99 -0
  548. package/src/memory/job-handlers/embedding.ts +61 -0
  549. package/src/memory/job-handlers/extraction.ts +123 -0
  550. package/src/memory/job-handlers/index-maintenance.ts +54 -0
  551. package/src/memory/job-handlers/summarization.ts +286 -0
  552. package/src/memory/job-utils.ts +170 -0
  553. package/src/memory/jobs-store.ts +400 -0
  554. package/src/memory/jobs-worker.ts +274 -0
  555. package/src/memory/llm-request-log-store.ts +45 -0
  556. package/src/memory/llm-usage-store.ts +62 -0
  557. package/src/memory/message-content.ts +54 -0
  558. package/src/memory/profile-compiler.ts +160 -0
  559. package/src/memory/published-pages-store.ts +137 -0
  560. package/src/memory/qdrant-client.ts +366 -0
  561. package/src/memory/qdrant-manager.ts +242 -0
  562. package/src/memory/query-builder.ts +45 -0
  563. package/src/memory/retrieval-budget.ts +30 -0
  564. package/src/memory/retriever.ts +653 -0
  565. package/src/memory/runs-store.ts +211 -0
  566. package/src/memory/schema.ts +529 -0
  567. package/src/memory/search/entity.ts +298 -0
  568. package/src/memory/search/formatting.ts +207 -0
  569. package/src/memory/search/lexical.ts +227 -0
  570. package/src/memory/search/ranking.ts +401 -0
  571. package/src/memory/search/semantic.ts +121 -0
  572. package/src/memory/search/types.ts +137 -0
  573. package/src/memory/segmenter.ts +68 -0
  574. package/src/memory/shared-app-links-store.ts +138 -0
  575. package/src/memory/tool-usage-store.ts +62 -0
  576. package/src/messaging/activity-analyzer.ts +76 -0
  577. package/src/messaging/draft-store.ts +88 -0
  578. package/src/messaging/index.ts +3 -0
  579. package/src/messaging/provider-types.ts +80 -0
  580. package/src/messaging/provider.ts +43 -0
  581. package/src/messaging/providers/gmail/adapter.ts +193 -0
  582. package/src/messaging/providers/gmail/client.ts +204 -0
  583. package/src/messaging/providers/gmail/types.ts +90 -0
  584. package/src/messaging/providers/slack/adapter.ts +202 -0
  585. package/src/messaging/providers/slack/client.ts +198 -0
  586. package/src/messaging/providers/slack/types.ts +119 -0
  587. package/src/messaging/registry.ts +34 -0
  588. package/src/messaging/style-analyzer.ts +158 -0
  589. package/src/messaging/thread-summarizer.ts +310 -0
  590. package/src/messaging/triage-engine.ts +321 -0
  591. package/src/messaging/types.ts +55 -0
  592. package/src/permissions/checker.ts +636 -0
  593. package/src/permissions/defaults.ts +243 -0
  594. package/src/permissions/prompter.ts +102 -0
  595. package/src/permissions/secret-prompter.ts +114 -0
  596. package/src/permissions/trust-store.ts +584 -0
  597. package/src/permissions/types.ts +62 -0
  598. package/src/playbooks/index.ts +2 -0
  599. package/src/playbooks/playbook-compiler.ts +90 -0
  600. package/src/playbooks/types.ts +55 -0
  601. package/src/providers/anthropic/client.ts +751 -0
  602. package/src/providers/failover.ts +129 -0
  603. package/src/providers/fireworks/client.ts +20 -0
  604. package/src/providers/gemini/client.ts +285 -0
  605. package/src/providers/ollama/client.ts +30 -0
  606. package/src/providers/openai/client.ts +337 -0
  607. package/src/providers/ratelimit.ts +93 -0
  608. package/src/providers/registry.ts +138 -0
  609. package/src/providers/retry.ts +106 -0
  610. package/src/providers/stream-timeout.ts +38 -0
  611. package/src/providers/types.ts +109 -0
  612. package/src/runtime/assistant-event-hub.ts +120 -0
  613. package/src/runtime/assistant-event.ts +82 -0
  614. package/src/runtime/http-server.ts +478 -0
  615. package/src/runtime/http-types.ts +68 -0
  616. package/src/runtime/routes/app-routes.ts +174 -0
  617. package/src/runtime/routes/attachment-routes.ts +134 -0
  618. package/src/runtime/routes/channel-routes.ts +342 -0
  619. package/src/runtime/routes/conversation-routes.ts +349 -0
  620. package/src/runtime/routes/run-routes.ts +223 -0
  621. package/src/runtime/routes/secret-routes.ts +76 -0
  622. package/src/runtime/run-orchestrator.ts +206 -0
  623. package/src/schedule/schedule-store.ts +452 -0
  624. package/src/schedule/scheduler.ts +168 -0
  625. package/src/security/encrypted-store.ts +238 -0
  626. package/src/security/keychain.ts +252 -0
  627. package/src/security/oauth2.ts +241 -0
  628. package/src/security/redaction.ts +89 -0
  629. package/src/security/secret-allowlist.ts +118 -0
  630. package/src/security/secret-ingress.ts +57 -0
  631. package/src/security/secret-scanner.ts +543 -0
  632. package/src/security/secure-keys.ts +180 -0
  633. package/src/security/token-manager.ts +141 -0
  634. package/src/services/published-app-updater.ts +69 -0
  635. package/src/services/vercel-deploy.ts +73 -0
  636. package/src/skills/active-skill-tools.ts +81 -0
  637. package/src/skills/clawhub.ts +414 -0
  638. package/src/skills/include-graph.ts +146 -0
  639. package/src/skills/managed-store.ts +233 -0
  640. package/src/skills/path-classifier.ts +128 -0
  641. package/src/skills/slash-commands.ts +174 -0
  642. package/src/skills/tool-manifest.ts +165 -0
  643. package/src/skills/version-hash.ts +110 -0
  644. package/src/slack/slack-webhook.ts +61 -0
  645. package/src/subagent/index.ts +19 -0
  646. package/src/subagent/manager.ts +477 -0
  647. package/src/subagent/types.ts +69 -0
  648. package/src/swarm/backend-claude-code.ts +90 -0
  649. package/src/swarm/index.ts +44 -0
  650. package/src/swarm/limits.ts +37 -0
  651. package/src/swarm/orchestrator.ts +279 -0
  652. package/src/swarm/plan-validator.ts +151 -0
  653. package/src/swarm/router-planner.ts +100 -0
  654. package/src/swarm/router-prompts.ts +36 -0
  655. package/src/swarm/synthesizer.ts +62 -0
  656. package/src/swarm/types.ts +62 -0
  657. package/src/swarm/worker-backend.ts +121 -0
  658. package/src/swarm/worker-prompts.ts +78 -0
  659. package/src/swarm/worker-runner.ts +164 -0
  660. package/src/tasks/SPEC.md +133 -0
  661. package/src/tasks/candidate-store.ts +86 -0
  662. package/src/tasks/ephemeral-permissions.ts +41 -0
  663. package/src/tasks/task-compiler.ts +198 -0
  664. package/src/tasks/task-runner.ts +85 -0
  665. package/src/tasks/task-scheduler.ts +20 -0
  666. package/src/tasks/task-store.ts +127 -0
  667. package/src/tools/apps/definitions.ts +59 -0
  668. package/src/tools/apps/executors.ts +313 -0
  669. package/src/tools/apps/open-proxy.ts +43 -0
  670. package/src/tools/apps/registry.ts +16 -0
  671. package/src/tools/assets/materialize.ts +218 -0
  672. package/src/tools/assets/search.ts +396 -0
  673. package/src/tools/browser/__tests__/auth-cache.test.ts +219 -0
  674. package/src/tools/browser/__tests__/auth-detector.test.ts +362 -0
  675. package/src/tools/browser/__tests__/jit-auth.test.ts +189 -0
  676. package/src/tools/browser/auth-cache.ts +149 -0
  677. package/src/tools/browser/auth-detector.ts +347 -0
  678. package/src/tools/browser/browser-execution.ts +979 -0
  679. package/src/tools/browser/browser-handoff.ts +79 -0
  680. package/src/tools/browser/browser-manager.ts +715 -0
  681. package/src/tools/browser/browser-screencast.ts +217 -0
  682. package/src/tools/browser/headless-browser.ts +450 -0
  683. package/src/tools/browser/jit-auth.ts +51 -0
  684. package/src/tools/browser/network-recorder.ts +348 -0
  685. package/src/tools/browser/network-recording-types.ts +49 -0
  686. package/src/tools/browser/recording-store.ts +49 -0
  687. package/src/tools/browser/runtime-check.ts +43 -0
  688. package/src/tools/claude-code/claude-code.ts +232 -0
  689. package/src/tools/computer-use/definitions.ts +443 -0
  690. package/src/tools/computer-use/registry.ts +22 -0
  691. package/src/tools/computer-use/request-computer-control.ts +53 -0
  692. package/src/tools/computer-use/skill-proxy-bridge.ts +28 -0
  693. package/src/tools/contacts/contact-merge.ts +87 -0
  694. package/src/tools/contacts/contact-search.ts +102 -0
  695. package/src/tools/contacts/contact-upsert.ts +137 -0
  696. package/src/tools/contacts/index.ts +4 -0
  697. package/src/tools/credentials/account-registry.ts +127 -0
  698. package/src/tools/credentials/broker-types.ts +107 -0
  699. package/src/tools/credentials/broker.ts +372 -0
  700. package/src/tools/credentials/domain-policy.ts +51 -0
  701. package/src/tools/credentials/host-pattern-match.ts +60 -0
  702. package/src/tools/credentials/metadata-store.ts +335 -0
  703. package/src/tools/credentials/policy-types.ts +52 -0
  704. package/src/tools/credentials/policy-validate.ts +80 -0
  705. package/src/tools/credentials/resolve.ts +122 -0
  706. package/src/tools/credentials/selection.ts +159 -0
  707. package/src/tools/credentials/tool-policy.ts +25 -0
  708. package/src/tools/credentials/vault.ts +641 -0
  709. package/src/tools/document/document-tool.ts +165 -0
  710. package/src/tools/document/editor-template.ts +237 -0
  711. package/src/tools/document/index.ts +5 -0
  712. package/src/tools/executor.ts +825 -0
  713. package/src/tools/filesystem/edit.ts +127 -0
  714. package/src/tools/filesystem/fuzzy-match.ts +202 -0
  715. package/src/tools/filesystem/read.ts +71 -0
  716. package/src/tools/filesystem/view-image.ts +199 -0
  717. package/src/tools/filesystem/write.ts +79 -0
  718. package/src/tools/followups/followup_create.ts +118 -0
  719. package/src/tools/followups/followup_list.ts +100 -0
  720. package/src/tools/followups/followup_resolve.ts +91 -0
  721. package/src/tools/followups/index.ts +3 -0
  722. package/src/tools/host-filesystem/edit.ts +125 -0
  723. package/src/tools/host-filesystem/read.ts +80 -0
  724. package/src/tools/host-filesystem/write.ts +76 -0
  725. package/src/tools/host-terminal/cli-discover.ts +179 -0
  726. package/src/tools/host-terminal/host-shell.ts +181 -0
  727. package/src/tools/memory/definitions.ts +69 -0
  728. package/src/tools/memory/handlers.ts +245 -0
  729. package/src/tools/memory/register.ts +66 -0
  730. package/src/tools/network/domain-normalize.ts +85 -0
  731. package/src/tools/network/script-proxy/certs.ts +237 -0
  732. package/src/tools/network/script-proxy/connect-tunnel.ts +82 -0
  733. package/src/tools/network/script-proxy/http-forwarder.ts +151 -0
  734. package/src/tools/network/script-proxy/index.ts +28 -0
  735. package/src/tools/network/script-proxy/logging.ts +196 -0
  736. package/src/tools/network/script-proxy/mitm-handler.ts +269 -0
  737. package/src/tools/network/script-proxy/policy.ts +152 -0
  738. package/src/tools/network/script-proxy/router.ts +60 -0
  739. package/src/tools/network/script-proxy/server.ts +136 -0
  740. package/src/tools/network/script-proxy/session-manager.ts +534 -0
  741. package/src/tools/network/script-proxy/types.ts +125 -0
  742. package/src/tools/network/url-safety.ts +227 -0
  743. package/src/tools/network/web-fetch.ts +701 -0
  744. package/src/tools/network/web-search.ts +319 -0
  745. package/src/tools/playbooks/index.ts +5 -0
  746. package/src/tools/playbooks/playbook-create.ts +140 -0
  747. package/src/tools/playbooks/playbook-delete.ts +76 -0
  748. package/src/tools/playbooks/playbook-list.ts +101 -0
  749. package/src/tools/playbooks/playbook-update.ts +159 -0
  750. package/src/tools/registry.ts +297 -0
  751. package/src/tools/reminder/reminder-store.ts +148 -0
  752. package/src/tools/reminder/reminder.ts +153 -0
  753. package/src/tools/schedule/create.ts +86 -0
  754. package/src/tools/schedule/delete.ts +54 -0
  755. package/src/tools/schedule/list.ts +88 -0
  756. package/src/tools/schedule/update.ts +97 -0
  757. package/src/tools/shared/filesystem/edit-engine.ts +56 -0
  758. package/src/tools/shared/filesystem/errors.ts +85 -0
  759. package/src/tools/shared/filesystem/file-ops-service.ts +215 -0
  760. package/src/tools/shared/filesystem/format-diff.ts +35 -0
  761. package/src/tools/shared/filesystem/path-policy.ts +125 -0
  762. package/src/tools/shared/filesystem/size-guard.ts +41 -0
  763. package/src/tools/shared/filesystem/types.ts +80 -0
  764. package/src/tools/shared/shell-output.ts +52 -0
  765. package/src/tools/skills/delete-managed.ts +60 -0
  766. package/src/tools/skills/load.ts +139 -0
  767. package/src/tools/skills/sandbox-runner.ts +279 -0
  768. package/src/tools/skills/scaffold-managed.ts +150 -0
  769. package/src/tools/skills/script-contract.ts +6 -0
  770. package/src/tools/skills/skill-script-runner.ts +86 -0
  771. package/src/tools/skills/skill-tool-factory.ts +64 -0
  772. package/src/tools/skills/vellum-catalog.ts +217 -0
  773. package/src/tools/subagent/abort.ts +62 -0
  774. package/src/tools/subagent/index.ts +5 -0
  775. package/src/tools/subagent/message.ts +72 -0
  776. package/src/tools/subagent/read.ts +98 -0
  777. package/src/tools/subagent/spawn.ts +85 -0
  778. package/src/tools/subagent/status.ts +74 -0
  779. package/src/tools/swarm/delegate.ts +182 -0
  780. package/src/tools/system/request-permission.ts +98 -0
  781. package/src/tools/tasks/index.ts +25 -0
  782. package/src/tools/tasks/task-delete.ts +69 -0
  783. package/src/tools/tasks/task-list.ts +65 -0
  784. package/src/tools/tasks/task-run.ts +125 -0
  785. package/src/tools/tasks/task-save.ts +79 -0
  786. package/src/tools/tasks/work-item-enqueue.ts +176 -0
  787. package/src/tools/tasks/work-item-list.ts +86 -0
  788. package/src/tools/terminal/backends/docker.ts +372 -0
  789. package/src/tools/terminal/backends/native.ts +188 -0
  790. package/src/tools/terminal/backends/types.ts +26 -0
  791. package/src/tools/terminal/evaluate-typescript.ts +275 -0
  792. package/src/tools/terminal/parser.ts +393 -0
  793. package/src/tools/terminal/safe-env.ts +37 -0
  794. package/src/tools/terminal/sandbox-diagnostics.ts +149 -0
  795. package/src/tools/terminal/sandbox.ts +44 -0
  796. package/src/tools/terminal/shell.ts +257 -0
  797. package/src/tools/tool-manifest.ts +250 -0
  798. package/src/tools/types.ts +177 -0
  799. package/src/tools/ui-surface/definitions.ts +232 -0
  800. package/src/tools/ui-surface/registry.ts +14 -0
  801. package/src/tools/watch/screen-watch.ts +128 -0
  802. package/src/tools/watch/watch-state.ts +119 -0
  803. package/src/tools/watcher/create.ts +110 -0
  804. package/src/tools/watcher/delete.ts +53 -0
  805. package/src/tools/watcher/digest.ts +84 -0
  806. package/src/tools/watcher/list.ts +90 -0
  807. package/src/tools/watcher/update.ts +102 -0
  808. package/src/tools/weather/service.ts +551 -0
  809. package/src/usage/actors.ts +24 -0
  810. package/src/usage/types.ts +38 -0
  811. package/src/util/clipboard.ts +33 -0
  812. package/src/util/content-id.ts +16 -0
  813. package/src/util/diff.ts +181 -0
  814. package/src/util/errors.ts +129 -0
  815. package/src/util/logger.ts +243 -0
  816. package/src/util/platform.ts +607 -0
  817. package/src/util/pricing.ts +150 -0
  818. package/src/util/spinner.ts +51 -0
  819. package/src/util/time.ts +16 -0
  820. package/src/util/xml.ts +4 -0
  821. package/src/version.ts +3 -0
  822. package/src/watcher/constants.ts +11 -0
  823. package/src/watcher/engine.ts +199 -0
  824. package/src/watcher/provider-registry.ts +15 -0
  825. package/src/watcher/provider-types.ts +48 -0
  826. package/src/watcher/providers/gmail.ts +198 -0
  827. package/src/watcher/providers/google-calendar.ts +228 -0
  828. package/src/watcher/providers/slack.ts +128 -0
  829. package/src/watcher/watcher-store.ts +418 -0
  830. package/src/work-items/work-item-store.ts +91 -0
  831. package/src/workspace/git-service.ts +620 -0
  832. package/src/workspace/heartbeat-service.ts +288 -0
  833. package/src/workspace/top-level-renderer.ts +19 -0
  834. package/src/workspace/top-level-scanner.ts +41 -0
  835. package/src/workspace/turn-commit.ts +122 -0
  836. package/tsconfig.json +21 -0
  837. package/LICENSE +0 -674
  838. package/dist/cli.js +0 -569
@@ -0,0 +1,900 @@
1
+ /**
2
+ * Computer-use session orchestrator.
3
+ *
4
+ * Manages the observation -> infer -> action loop for computer-use tasks,
5
+ * bridging the macOS client (which captures screen state and executes actions)
6
+ * with the AgentLoop (which runs inference via the Anthropic API with CU tools).
7
+ */
8
+
9
+ import { v4 as uuid } from 'uuid';
10
+ import type { Provider, Message, ContentBlock, ToolDefinition } from '../providers/types.js';
11
+ import { INTERACTIVE_SURFACE_TYPES } from './ipc-protocol.js';
12
+ import type { ServerMessage, CuObservation, SurfaceType, SurfaceData, FileUploadSurfaceData, UiSurfaceShow } from './ipc-protocol.js';
13
+ import type { Tool, ToolExecutionResult } from '../tools/types.js';
14
+ import { AgentLoop } from '../agent/loop.js';
15
+ import { ToolExecutor } from '../tools/executor.js';
16
+ import { PermissionPrompter } from '../permissions/prompter.js';
17
+ import { SecretPrompter } from '../permissions/secret-prompter.js';
18
+ import { allUiSurfaceTools } from '../tools/ui-surface/definitions.js';
19
+ import { allComputerUseTools } from '../tools/computer-use/definitions.js';
20
+ import { registerSkillTools } from '../tools/registry.js';
21
+ import { buildComputerUseSystemPrompt } from '../config/computer-use-prompt.js';
22
+ import { getSandboxWorkingDir } from '../util/platform.js';
23
+ import { getConfig } from '../config/loader.js';
24
+ import { projectSkillTools, resetSkillToolProjection } from './session-skill-tools.js';
25
+ import { getLogger } from '../util/logger.js';
26
+
27
+ const log = getLogger('computer-use-session');
28
+
29
+ const MAX_STEPS = 50;
30
+ const SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
31
+ const MAX_HISTORY_ENTRIES = 10;
32
+ const LOOP_DETECTION_WINDOW = 3;
33
+ const CONSECUTIVE_UNCHANGED_WARNING_THRESHOLD = 2;
34
+
35
+ /** Number of most-recent AX tree snapshots to keep in conversation history. */
36
+ const MAX_AX_TREES_IN_HISTORY = 2;
37
+
38
+ /** Regex that matches the `<ax-tree>…</ax-tree>` markers injected by buildObservationResultContent. */
39
+ const AX_TREE_PATTERN = /<ax-tree>[\s\S]*?<\/ax-tree>/g;
40
+ const AX_TREE_PLACEHOLDER = '<ax_tree_omitted />';
41
+
42
+ type SessionState = 'idle' | 'awaiting_observation' | 'inferring' | 'complete' | 'error';
43
+
44
+ interface ActionRecord {
45
+ step: number;
46
+ toolName: string;
47
+ input: Record<string, unknown>;
48
+ reasoning?: string;
49
+ result?: string;
50
+ }
51
+
52
+ export class ComputerUseSession {
53
+ private readonly sessionId: string;
54
+ private readonly task: string;
55
+ private readonly screenWidth: number;
56
+ private readonly screenHeight: number;
57
+ private readonly provider: Provider;
58
+ private sendToClient: (msg: ServerMessage) => void;
59
+ private readonly interactionType: 'computer_use' | 'text_qa';
60
+ private readonly onTerminal?: (sessionId: string) => void;
61
+ private readonly preactivatedSkillIds: string[];
62
+ private readonly skillProjectionState = new Map<string, string>();
63
+
64
+ private state: SessionState = 'idle';
65
+ private stepCount = 0;
66
+ private actionHistory: ActionRecord[] = [];
67
+ private previousAXTree: string | undefined;
68
+ private consecutiveUnchangedSteps = 0;
69
+ private abortController: AbortController | null = null;
70
+ private sessionTimer: ReturnType<typeof setTimeout> | null = null;
71
+
72
+ private pendingObservation: {
73
+ resolve: (result: ToolExecutionResult) => void;
74
+ } | null = null;
75
+
76
+ private pendingSurfaceActions = new Map<string, {
77
+ resolve: (result: ToolExecutionResult) => void;
78
+ }>();
79
+ private surfaceState = new Map<string, { surfaceType: SurfaceType; data: SurfaceData }>();
80
+ private terminalNotified = false;
81
+ private prompter: PermissionPrompter | null = null;
82
+
83
+ // Tracks the agent loop promise so callers can await session completion
84
+ private loopPromise: Promise<void> | null = null;
85
+
86
+ constructor(
87
+ sessionId: string,
88
+ task: string,
89
+ screenWidth: number,
90
+ screenHeight: number,
91
+ provider: Provider,
92
+ sendToClient: (msg: ServerMessage) => void,
93
+ interactionType?: 'computer_use' | 'text_qa',
94
+ onTerminal?: (sessionId: string) => void,
95
+ preactivatedSkillIds?: string[],
96
+ ) {
97
+ this.sessionId = sessionId;
98
+ this.task = task;
99
+ this.screenWidth = screenWidth;
100
+ this.screenHeight = screenHeight;
101
+ this.provider = provider;
102
+ this.sendToClient = sendToClient;
103
+ this.interactionType = interactionType ?? 'computer_use';
104
+ this.onTerminal = onTerminal;
105
+ this.preactivatedSkillIds = preactivatedSkillIds ?? ['computer-use'];
106
+ }
107
+
108
+ // ---------------------------------------------------------------------------
109
+ // Public API
110
+ // ---------------------------------------------------------------------------
111
+
112
+ async handleObservation(obs: CuObservation): Promise<void> {
113
+ if (this.state === 'complete' || this.state === 'error') {
114
+ log.warn({ sessionId: this.sessionId, state: this.state }, 'Observation received after session ended');
115
+ return;
116
+ }
117
+
118
+ // Track consecutive unchanged steps
119
+ const hadPreviousAXTree = this.previousAXTree != null;
120
+ if (this.stepCount > 0) {
121
+ if (obs.axDiff == null && hadPreviousAXTree && obs.axTree != null) {
122
+ this.consecutiveUnchangedSteps++;
123
+ } else if (obs.axDiff != null) {
124
+ this.consecutiveUnchangedSteps = 0;
125
+ }
126
+ }
127
+
128
+ // Capture previous AX tree for next turn
129
+ if (obs.axTree != null) {
130
+ this.previousAXTree = obs.axTree;
131
+ }
132
+
133
+ if (this.state === 'awaiting_observation' && this.pendingObservation) {
134
+ // Resolve the pending proxy tool result with updated screen context
135
+ const content = this.buildObservationResultContent(obs, hadPreviousAXTree);
136
+ const result: ToolExecutionResult = obs.executionError
137
+ ? { content: `Action failed: ${obs.executionError}\n\n${content}`, isError: true }
138
+ : { content, isError: false };
139
+ this.state = 'inferring';
140
+ this.pendingObservation.resolve(result);
141
+ this.pendingObservation = null;
142
+ // The agent loop continues automatically after resolution
143
+ return;
144
+ }
145
+
146
+ // First observation — start the agent loop
147
+ this.state = 'inferring';
148
+ this.abortController = new AbortController();
149
+
150
+ // Safety net: abort the session if it runs longer than SESSION_TIMEOUT_MS
151
+ this.sessionTimer = setTimeout(() => {
152
+ log.warn({ sessionId: this.sessionId, timeoutMs: SESSION_TIMEOUT_MS }, 'Session timeout reached, aborting');
153
+ this.abort();
154
+ }, SESSION_TIMEOUT_MS);
155
+
156
+ const messages = this.buildMessages(obs, hadPreviousAXTree);
157
+ this.loopPromise = this.runAgentLoop(messages).catch((err) => {
158
+ // Catches errors from setup code (e.g. skill projection failures) that
159
+ // occur before runAgentLoop's internal try-catch takes over.
160
+ const message = err instanceof Error ? err.message : String(err);
161
+ log.error({ err, sessionId: this.sessionId }, 'Agent loop startup failed');
162
+ if (this.sessionTimer) {
163
+ clearTimeout(this.sessionTimer);
164
+ this.sessionTimer = null;
165
+ }
166
+ if (this.state !== 'complete' && this.state !== 'error') {
167
+ this.state = 'error';
168
+ this.sendToClient({
169
+ type: 'cu_error',
170
+ sessionId: this.sessionId,
171
+ message,
172
+ });
173
+ this.notifyTerminal();
174
+ }
175
+ });
176
+
177
+ await this.loopPromise;
178
+ }
179
+
180
+ abort(): void {
181
+ if (this.state === 'complete' || this.state === 'error') return;
182
+
183
+ log.info({ sessionId: this.sessionId }, 'Aborting computer-use session');
184
+ if (this.sessionTimer) {
185
+ clearTimeout(this.sessionTimer);
186
+ this.sessionTimer = null;
187
+ }
188
+ this.abortController?.abort();
189
+
190
+ // If waiting for an observation, resolve it as cancelled
191
+ if (this.pendingObservation) {
192
+ this.pendingObservation.resolve({ content: 'Session aborted', isError: true });
193
+ this.pendingObservation = null;
194
+ }
195
+
196
+ // Dispose prompter to clear pending permission timers and reject promises
197
+ this.prompter?.dispose();
198
+
199
+ // Resolve any pending surface actions
200
+ for (const [, pending] of this.pendingSurfaceActions) {
201
+ pending.resolve({ content: 'Session aborted', isError: true });
202
+ }
203
+ this.pendingSurfaceActions.clear();
204
+ this.surfaceState.clear();
205
+
206
+ this.state = 'error';
207
+ this.sendToClient({
208
+ type: 'cu_error',
209
+ sessionId: this.sessionId,
210
+ message: 'Session aborted by user',
211
+ });
212
+ this.notifyTerminal();
213
+ }
214
+
215
+ isComplete(): boolean {
216
+ return this.state === 'complete';
217
+ }
218
+
219
+ getState(): string {
220
+ return this.state;
221
+ }
222
+
223
+ /**
224
+ * Compute CU tool definitions from the bundled computer-use skill via
225
+ * skill projection. Returns null if projection fails so the caller can
226
+ * fall back to legacy hardcoded tool definitions.
227
+ */
228
+ private getProjectedCuToolDefinitions(): ToolDefinition[] | null {
229
+ if (this.preactivatedSkillIds.length === 0) {
230
+ log.warn('No preactivatedSkillIds configured, falling back to legacy CU tools');
231
+ return null;
232
+ }
233
+
234
+ try {
235
+ const projection = projectSkillTools([], {
236
+ preactivatedSkillIds: this.preactivatedSkillIds,
237
+ previouslyActiveSkillIds: this.skillProjectionState,
238
+ });
239
+
240
+ if (projection.toolDefinitions.length === 0) {
241
+ log.warn(
242
+ { preactivatedSkillIds: this.preactivatedSkillIds },
243
+ 'Skill projection produced no tool definitions, falling back to legacy CU tools',
244
+ );
245
+ return null;
246
+ }
247
+
248
+ return projection.toolDefinitions;
249
+ } catch (err) {
250
+ log.warn({ err }, 'Skill projection failed, falling back to legacy CU tools');
251
+ return null;
252
+ }
253
+ }
254
+
255
+ handleSurfaceAction(surfaceId: string, actionId: string, data?: Record<string, unknown>): void {
256
+ const pending = this.pendingSurfaceActions.get(surfaceId);
257
+ if (!pending) {
258
+ log.warn({ surfaceId, actionId }, 'No pending surface action found');
259
+ return;
260
+ }
261
+ // selection_changed is a non-terminal state update — don't consume the
262
+ // pending entry. The selection state will be in the action button payload.
263
+ if (actionId === 'selection_changed') {
264
+ return;
265
+ }
266
+ this.pendingSurfaceActions.delete(surfaceId);
267
+ pending.resolve({
268
+ content: JSON.stringify({ actionId, data: data ?? {} }),
269
+ isError: false,
270
+ });
271
+ }
272
+
273
+ // ---------------------------------------------------------------------------
274
+ // Agent loop execution
275
+ // ---------------------------------------------------------------------------
276
+
277
+ private async runAgentLoop(messages: Message[]): Promise<void> {
278
+ const systemPrompt = buildComputerUseSystemPrompt(this.screenWidth, this.screenHeight);
279
+
280
+ let cuToolDefs = this.getProjectedCuToolDefinitions();
281
+ if (!cuToolDefs) {
282
+ // Fallback: register the legacy CU tools as skill-origin tools so
283
+ // ToolExecutor can resolve them via getTool(), but using the same
284
+ // ownerSkillId as the bundled computer-use skill. This avoids
285
+ // core-vs-skill collisions that would permanently block skill
286
+ // projection recovery on subsequent sessions.
287
+ const fallbackSkillId = this.preactivatedSkillIds[0] ?? 'computer-use';
288
+ const fallbackTools: Tool[] = allComputerUseTools.map((t) => ({
289
+ ...t,
290
+ origin: 'skill' as const,
291
+ ownerSkillId: fallbackSkillId,
292
+ ownerSkillBundled: true,
293
+ }));
294
+ registerSkillTools(fallbackTools);
295
+ // Track in the session map so resetSkillToolProjection cleans up
296
+ this.skillProjectionState.set(fallbackSkillId, 'fallback');
297
+ cuToolDefs = allComputerUseTools.map((t) => t.getDefinition());
298
+ }
299
+
300
+ const toolDefs: ToolDefinition[] = [
301
+ ...cuToolDefs,
302
+ ...allUiSurfaceTools
303
+ .filter((t) => t.name !== 'request_file')
304
+ .map((t) => t.getDefinition()),
305
+ ];
306
+
307
+ this.prompter = new PermissionPrompter(this.sendToClient);
308
+ const prompter = this.prompter;
309
+ const secretPrompter = new SecretPrompter(this.sendToClient);
310
+ const executor = new ToolExecutor(prompter);
311
+
312
+ const proxyResolver = async (
313
+ toolName: string,
314
+ input: Record<string, unknown>,
315
+ ): Promise<ToolExecutionResult> => {
316
+ // ── Surface tool proxying ──────────────────────────────────────
317
+ if (toolName === 'ui_show') {
318
+ const surfaceId = uuid();
319
+ const surfaceType = input.surface_type as SurfaceType;
320
+ const title = typeof input.title === 'string' ? input.title : undefined;
321
+ const data = input.data as SurfaceData;
322
+ const actions = input.actions as Array<{ id: string; label: string; style?: string }> | undefined;
323
+ // Interactive surfaces default to awaiting user action.
324
+ // Tables and lists only block when explicit action buttons are provided;
325
+ // selectionMode alone should not gate blocking because selection_changed
326
+ // fires on every click and would immediately resolve multi-select surfaces.
327
+ const hasActions = Array.isArray(actions) && actions.length > 0;
328
+ const isInteractive = surfaceType === 'list'
329
+ ? hasActions
330
+ : surfaceType === 'table'
331
+ ? hasActions
332
+ : INTERACTIVE_SURFACE_TYPES.includes(surfaceType);
333
+ const awaitAction = (input.await_action as boolean) ?? isInteractive;
334
+
335
+ // Track surface state for ui_update merging
336
+ this.surfaceState.set(surfaceId, { surfaceType, data });
337
+
338
+ this.sendToClient({
339
+ type: 'ui_surface_show',
340
+ sessionId: this.sessionId,
341
+ surfaceId,
342
+ surfaceType,
343
+ title,
344
+ data,
345
+ actions: actions?.map(a => ({ id: a.id, label: a.label, style: (a.style ?? 'secondary') as 'primary' | 'secondary' | 'destructive' })),
346
+ } as unknown as UiSurfaceShow);
347
+
348
+ if (awaitAction) {
349
+ return new Promise<ToolExecutionResult>((resolve) => {
350
+ this.pendingSurfaceActions.set(surfaceId, { resolve });
351
+ });
352
+ }
353
+ return { content: JSON.stringify({ surfaceId }), isError: false };
354
+ }
355
+
356
+ if (toolName === 'ui_update') {
357
+ const surfaceId = input.surface_id as string;
358
+ const patch = input.data as Record<string, unknown>;
359
+
360
+ // Merge the partial patch into the stored full surface data
361
+ const stored = this.surfaceState.get(surfaceId);
362
+ let mergedData: SurfaceData;
363
+ if (stored) {
364
+ mergedData = { ...stored.data, ...patch } as SurfaceData;
365
+ stored.data = mergedData;
366
+ } else {
367
+ mergedData = patch as unknown as SurfaceData;
368
+ }
369
+
370
+ this.sendToClient({
371
+ type: 'ui_surface_update',
372
+ sessionId: this.sessionId,
373
+ surfaceId,
374
+ data: mergedData,
375
+ });
376
+ return { content: 'Surface updated', isError: false };
377
+ }
378
+
379
+ if (toolName === 'ui_dismiss') {
380
+ const surfaceId = input.surface_id as string;
381
+ this.sendToClient({
382
+ type: 'ui_surface_dismiss',
383
+ sessionId: this.sessionId,
384
+ surfaceId,
385
+ });
386
+ this.pendingSurfaceActions.delete(surfaceId);
387
+ this.surfaceState.delete(surfaceId);
388
+ return { content: 'Surface dismissed', isError: false };
389
+ }
390
+
391
+ // ── File request proxying ──────────────────────────────────────
392
+ if (toolName === 'request_file') {
393
+ const surfaceId = uuid();
394
+ const prompt = typeof input.prompt === 'string' ? input.prompt : 'Please share a file';
395
+ const acceptedTypes = Array.isArray(input.accepted_types) ? input.accepted_types as string[] : undefined;
396
+ const maxFiles = typeof input.max_files === 'number' ? input.max_files : 1;
397
+
398
+ const data: FileUploadSurfaceData = {
399
+ prompt,
400
+ acceptedTypes,
401
+ maxFiles,
402
+ };
403
+
404
+ this.surfaceState.set(surfaceId, { surfaceType: 'file_upload', data });
405
+
406
+ this.sendToClient({
407
+ type: 'ui_surface_show',
408
+ sessionId: this.sessionId,
409
+ surfaceId,
410
+ surfaceType: 'file_upload',
411
+ title: 'File Request',
412
+ data,
413
+ } as UiSurfaceShow);
414
+
415
+ // Always await — file upload is interactive
416
+ return new Promise<ToolExecutionResult>((resolve) => {
417
+ this.pendingSurfaceActions.set(surfaceId, { resolve });
418
+ });
419
+ }
420
+
421
+ // ── Computer-use tool proxying ─────────────────────────────────
422
+ const reasoning = typeof input.reasoning === 'string' ? input.reasoning : undefined;
423
+
424
+ // Record action in history
425
+ this.actionHistory.push({
426
+ step: this.stepCount + 1,
427
+ toolName,
428
+ input,
429
+ reasoning,
430
+ });
431
+
432
+ // Check for terminal tools
433
+ if (toolName === 'computer_use_done' || toolName === 'computer_use_respond') {
434
+ const summary =
435
+ toolName === 'computer_use_done'
436
+ ? (typeof input.summary === 'string' ? input.summary : 'Task completed')
437
+ : (typeof input.answer === 'string' ? input.answer : 'No answer provided');
438
+
439
+ this.sendToClient({
440
+ type: 'cu_complete',
441
+ sessionId: this.sessionId,
442
+ summary,
443
+ stepCount: this.stepCount,
444
+ isResponse: toolName === 'computer_use_respond' ? true : undefined,
445
+ });
446
+ this.state = 'complete';
447
+ // Stop AgentLoop immediately so terminal tools cannot trigger extra provider calls.
448
+ this.abortController?.abort();
449
+ this.notifyTerminal();
450
+ return { content: 'Session complete', isError: false };
451
+ }
452
+
453
+ this.stepCount++;
454
+
455
+ // Enforce step limit — abort the loop so toolChoice:'any' can't force another turn
456
+ if (this.stepCount > MAX_STEPS) {
457
+ this.state = 'error';
458
+ this.sendToClient({
459
+ type: 'cu_error',
460
+ sessionId: this.sessionId,
461
+ message: `Step limit (${MAX_STEPS}) exceeded`,
462
+ });
463
+ this.abortController?.abort();
464
+ this.notifyTerminal();
465
+ return { content: `Step limit (${MAX_STEPS}) exceeded`, isError: true };
466
+ }
467
+
468
+ // Send action to client for execution
469
+ this.sendToClient({
470
+ type: 'cu_action',
471
+ sessionId: this.sessionId,
472
+ toolName,
473
+ input,
474
+ reasoning,
475
+ stepNumber: this.stepCount,
476
+ });
477
+
478
+ // Wait for next observation from client
479
+ this.state = 'awaiting_observation';
480
+ return new Promise<ToolExecutionResult>((resolve) => {
481
+ this.pendingObservation = { resolve };
482
+ });
483
+ };
484
+
485
+ // Build a set of tool names the CU session is allowed to execute.
486
+ // This prevents tools registered globally (e.g. computer_use_request_control)
487
+ // but not advertised to the CU model from executing during CU sessions.
488
+ const allowedToolNames = new Set(toolDefs.map((td) => td.name));
489
+
490
+ const toolExecutor = async (
491
+ name: string,
492
+ input: Record<string, unknown>,
493
+ ): Promise<ToolExecutionResult> => {
494
+ return executor.execute(name, input, {
495
+ workingDir: getSandboxWorkingDir(),
496
+ sessionId: this.sessionId,
497
+ conversationId: this.sessionId,
498
+ proxyToolResolver: proxyResolver,
499
+ allowedToolNames,
500
+ requestSecret: async (params) => {
501
+ return secretPrompter.prompt(
502
+ params.service, params.field, params.label,
503
+ params.description, params.placeholder,
504
+ this.sessionId,
505
+ params.purpose, params.allowedTools, params.allowedDomains,
506
+ );
507
+ },
508
+ });
509
+ };
510
+
511
+ // Wrap the provider so that old AX tree snapshots are stripped from
512
+ // conversation history before each API call, keeping only the most recent
513
+ // MAX_AX_TREES_IN_HISTORY entries. This prevents TTFT from growing
514
+ // linearly with step count.
515
+ const compactingProvider: Provider = {
516
+ name: this.provider.name,
517
+ sendMessage: (msgs, tools, sys, opts) => {
518
+ const compacted = ComputerUseSession.compactHistory(msgs);
519
+ return this.provider.sendMessage(compacted, tools, sys, opts);
520
+ },
521
+ };
522
+
523
+ const cuConfig = getConfig();
524
+ const agentLoop = new AgentLoop(
525
+ compactingProvider,
526
+ systemPrompt,
527
+ {
528
+ maxTokens: 4096,
529
+ maxInputTokens: cuConfig.contextWindow.maxInputTokens,
530
+ toolChoice: { type: 'any' },
531
+ // Allow MAX_STEPS non-terminal actions plus one terminal turn
532
+ // (computer_use_done/computer_use_respond), since AgentLoop caps tool turns globally.
533
+ maxToolUseTurns: MAX_STEPS + 1,
534
+ },
535
+ toolDefs,
536
+ toolExecutor,
537
+ );
538
+
539
+ try {
540
+ await agentLoop.run(
541
+ messages,
542
+ (event) => {
543
+ switch (event.type) {
544
+ case 'error':
545
+ log.error({ err: event.error, sessionId: this.sessionId }, 'Agent loop error');
546
+ if (this.state !== 'complete') {
547
+ this.state = 'error';
548
+ this.sendToClient({
549
+ type: 'cu_error',
550
+ sessionId: this.sessionId,
551
+ message: event.error.message,
552
+ });
553
+ this.notifyTerminal();
554
+ }
555
+ break;
556
+ case 'usage':
557
+ log.info({
558
+ sessionId: this.sessionId,
559
+ inputTokens: event.inputTokens,
560
+ outputTokens: event.outputTokens,
561
+ model: event.model,
562
+ }, 'Usage');
563
+ break;
564
+ // Other events (text_delta, thinking_delta, etc.) are not surfaced to the CU client
565
+ }
566
+ },
567
+ this.abortController?.signal,
568
+ );
569
+
570
+ // If the loop exits without completing, treat as error
571
+ if (this.state !== 'complete' && this.state !== 'error') {
572
+ this.state = 'error';
573
+ this.sendToClient({
574
+ type: 'cu_error',
575
+ sessionId: this.sessionId,
576
+ message: 'Agent loop ended unexpectedly',
577
+ });
578
+ this.notifyTerminal();
579
+ }
580
+ } catch (err) {
581
+ if (this.abortController?.signal.aborted) {
582
+ log.info({ sessionId: this.sessionId }, 'Agent loop aborted');
583
+ return;
584
+ }
585
+ const message = err instanceof Error ? err.message : String(err);
586
+ log.error({ err, sessionId: this.sessionId }, 'Agent loop failed');
587
+ if (this.state !== 'complete') {
588
+ this.state = 'error';
589
+ this.sendToClient({
590
+ type: 'cu_error',
591
+ sessionId: this.sessionId,
592
+ message,
593
+ });
594
+ this.notifyTerminal();
595
+ }
596
+ } finally {
597
+ // Always clean up skill projection state and session timer
598
+ resetSkillToolProjection(this.skillProjectionState);
599
+ if (this.sessionTimer) {
600
+ clearTimeout(this.sessionTimer);
601
+ this.sessionTimer = null;
602
+ }
603
+ }
604
+ }
605
+
606
+ private notifyTerminal(): void {
607
+ if (this.terminalNotified) return;
608
+ this.terminalNotified = true;
609
+ resetSkillToolProjection(this.skillProjectionState);
610
+ this.onTerminal?.(this.sessionId);
611
+ }
612
+
613
+ // ---------------------------------------------------------------------------
614
+ // History compaction — strip old AX tree snapshots from tool results
615
+ // ---------------------------------------------------------------------------
616
+
617
+ /**
618
+ * Returns a shallow copy of `messages` where all but the most recent
619
+ * `MAX_AX_TREES_IN_HISTORY` `<ax-tree>` blocks have been replaced with a
620
+ * short placeholder. This keeps the conversation context small so that
621
+ * TTFT does not grow linearly with step count.
622
+ */
623
+ static compactHistory(messages: Message[]): Message[] {
624
+ // Collect indices of user messages that contain an <ax-tree> block
625
+ const indicesWithAxTree: number[] = [];
626
+ for (let i = 0; i < messages.length; i++) {
627
+ const msg = messages[i];
628
+ if (msg.role !== 'user') continue;
629
+ for (const block of msg.content) {
630
+ if (
631
+ block.type === 'tool_result' &&
632
+ typeof block.content === 'string' &&
633
+ block.content.includes('<ax-tree>')
634
+ ) {
635
+ indicesWithAxTree.push(i);
636
+ break;
637
+ }
638
+ }
639
+ }
640
+
641
+ if (indicesWithAxTree.length <= MAX_AX_TREES_IN_HISTORY) {
642
+ return messages;
643
+ }
644
+
645
+ const toStrip = new Set(indicesWithAxTree.slice(0, -MAX_AX_TREES_IN_HISTORY));
646
+
647
+ return messages.map((msg, idx) => {
648
+ if (!toStrip.has(idx)) return msg;
649
+ return {
650
+ ...msg,
651
+ content: msg.content.map((block) => {
652
+ if (
653
+ block.type === 'tool_result' &&
654
+ typeof block.content === 'string' &&
655
+ block.content.includes('<ax-tree>')
656
+ ) {
657
+ return {
658
+ ...block,
659
+ content: block.content.replace(AX_TREE_PATTERN, AX_TREE_PLACEHOLDER),
660
+ };
661
+ }
662
+ return block;
663
+ }),
664
+ };
665
+ });
666
+ }
667
+
668
+ /**
669
+ * Escapes any literal `</ax-tree>` occurrences inside AX tree content so
670
+ * that the non-greedy compaction regex (`AX_TREE_PATTERN`) does not stop
671
+ * prematurely when the user happens to be viewing XML/HTML source that
672
+ * contains the closing tag. The escaped content does not need to be
673
+ * unescaped because compaction replaces the entire block with a placeholder.
674
+ */
675
+ static escapeAxTreeContent(content: string): string {
676
+ return content.replace(/<\/ax-tree>/gi, '&lt;/ax-tree&gt;');
677
+ }
678
+
679
+ // ---------------------------------------------------------------------------
680
+ // Build rich tool-result content from an observation so the model sees
681
+ // updated screen state on each turn (not just "Action executed").
682
+ // ---------------------------------------------------------------------------
683
+
684
+ private buildObservationResultContent(obs: CuObservation, hadPreviousAXTree: boolean): string {
685
+ const parts: string[] = [];
686
+
687
+ if (obs.executionResult) {
688
+ parts.push(obs.executionResult);
689
+ parts.push('');
690
+ }
691
+
692
+ // AX tree diff
693
+ if (obs.axDiff) {
694
+ parts.push(obs.axDiff);
695
+ parts.push('');
696
+ } else if (hadPreviousAXTree && obs.axTree != null) {
697
+ const lastAction = this.actionHistory[this.actionHistory.length - 1];
698
+ const wasWait = lastAction?.toolName === 'computer_use_wait';
699
+ if (this.consecutiveUnchangedSteps >= CONSECUTIVE_UNCHANGED_WARNING_THRESHOLD) {
700
+ parts.push(
701
+ `WARNING: ${this.consecutiveUnchangedSteps} consecutive actions had NO VISIBLE EFFECT on the UI. You MUST try a completely different approach.`,
702
+ );
703
+ } else if (!wasWait) {
704
+ parts.push('Your last action had NO VISIBLE EFFECT on the UI. Try something different.');
705
+ }
706
+ parts.push('');
707
+ }
708
+
709
+ // Current screen state — wrapped in markers so compactHistory can strip old snapshots
710
+ if (obs.axTree) {
711
+ parts.push('<ax-tree>');
712
+ parts.push('CURRENT SCREEN STATE:');
713
+ parts.push(ComputerUseSession.escapeAxTreeContent(obs.axTree));
714
+ parts.push('</ax-tree>');
715
+ }
716
+
717
+ const screenshotMetadata = this.formatScreenshotMetadata(obs);
718
+ if (screenshotMetadata.length > 0) {
719
+ parts.push('');
720
+ parts.push(...screenshotMetadata);
721
+ }
722
+
723
+ return parts.join('\n').trim() || 'Action executed';
724
+ }
725
+
726
+ // ---------------------------------------------------------------------------
727
+ // Message building (replicates AnthropicProvider.buildMessages from Swift)
728
+ // ---------------------------------------------------------------------------
729
+
730
+ private buildMessages(obs: CuObservation, hadPreviousAXTree: boolean): Message[] {
731
+ const contentBlocks: ContentBlock[] = [];
732
+
733
+ // Screenshot image block
734
+ if (obs.screenshot) {
735
+ contentBlocks.push({
736
+ type: 'image',
737
+ source: {
738
+ type: 'base64',
739
+ media_type: 'image/jpeg',
740
+ data: obs.screenshot,
741
+ },
742
+ });
743
+ }
744
+
745
+ // Text block
746
+ const textParts: string[] = [];
747
+ const trimmedTask = this.task.trim();
748
+ if (trimmedTask) {
749
+ textParts.push(`TASK: ${trimmedTask}`);
750
+ } else {
751
+ textParts.push('TASK: No explicit task provided.');
752
+ }
753
+ textParts.push('');
754
+
755
+ // AX tree diff (compact summary of what changed)
756
+ if (obs.axDiff && this.actionHistory.length > 0) {
757
+ textParts.push(obs.axDiff);
758
+ textParts.push('');
759
+ } else if (hadPreviousAXTree && obs.axTree != null && this.actionHistory.length > 0) {
760
+ // AX tree unchanged — tell the model its action had no effect
761
+ const lastAction = this.actionHistory[this.actionHistory.length - 1];
762
+ const wasWait = lastAction?.toolName === 'computer_use_wait';
763
+ textParts.push('CHANGES SINCE LAST ACTION:');
764
+ if (this.consecutiveUnchangedSteps >= CONSECUTIVE_UNCHANGED_WARNING_THRESHOLD) {
765
+ textParts.push(
766
+ `WARNING: ${this.consecutiveUnchangedSteps} consecutive actions had NO VISIBLE EFFECT on the UI. You MUST try a completely different approach — do not repeat any of your recent actions.`,
767
+ );
768
+ } else if (!wasWait) {
769
+ const actionDesc = `${lastAction?.toolName ?? 'unknown'}`;
770
+ textParts.push(
771
+ `Your last action (${actionDesc}) had NO VISIBLE EFFECT on the UI. The screen is identical to the previous step. Do NOT repeat the same action — try something different.`,
772
+ );
773
+ } else {
774
+ textParts.push('No visible changes detected — the UI is identical to the previous step.');
775
+ }
776
+ textParts.push('');
777
+ }
778
+
779
+ // Current screen state
780
+ if (obs.axTree) {
781
+ textParts.push('CURRENT SCREEN STATE (accessibility tree of the focused window):');
782
+ textParts.push(obs.axTree);
783
+ textParts.push('');
784
+ textParts.push('Use element_id with the [ID] numbers shown above to target elements.');
785
+
786
+ // Secondary windows for cross-app awareness
787
+ if (obs.secondaryWindows) {
788
+ textParts.push('');
789
+ textParts.push(obs.secondaryWindows);
790
+ textParts.push('');
791
+ textParts.push(
792
+ "Note: The element [ID]s above are from other windows — you can reference them for context but can only interact with the focused window's elements.",
793
+ );
794
+ }
795
+
796
+ if (obs.screenshot) {
797
+ textParts.push('');
798
+ textParts.push(
799
+ 'A screenshot of the FULL SCREEN is also attached above. Use it to see content outside the focused window (e.g., reference documents, PDFs, other apps visible behind the current window).',
800
+ );
801
+ const screenshotMetadata = this.formatScreenshotMetadata(obs);
802
+ if (screenshotMetadata.length > 0) {
803
+ textParts.push(...screenshotMetadata);
804
+ }
805
+ }
806
+ } else if (obs.screenshot) {
807
+ textParts.push('CURRENT SCREEN STATE:');
808
+ textParts.push('See the screenshot above. No accessibility tree available — estimate coordinates from the image.');
809
+ const screenshotMetadata = this.formatScreenshotMetadata(obs);
810
+ if (screenshotMetadata.length > 0) {
811
+ textParts.push(...screenshotMetadata);
812
+ }
813
+ } else {
814
+ textParts.push('CURRENT SCREEN STATE:');
815
+ textParts.push('No screen data available.');
816
+ }
817
+
818
+ // Action history
819
+ if (this.actionHistory.length > 0) {
820
+ textParts.push('');
821
+ textParts.push('ACTIONS TAKEN SO FAR:');
822
+ let windowedHistory: ActionRecord[];
823
+ if (this.actionHistory.length > MAX_HISTORY_ENTRIES) {
824
+ textParts.push(
825
+ ` [... ${this.actionHistory.length - MAX_HISTORY_ENTRIES} earlier actions omitted]`,
826
+ );
827
+ windowedHistory = this.actionHistory.slice(-MAX_HISTORY_ENTRIES);
828
+ } else {
829
+ windowedHistory = this.actionHistory;
830
+ }
831
+ for (const record of windowedHistory) {
832
+ const result = record.result ?? 'executed';
833
+ textParts.push(` ${record.step}. ${record.toolName} → ${result}`);
834
+ }
835
+ }
836
+
837
+ // Loop detection warning
838
+ if (this.actionHistory.length >= LOOP_DETECTION_WINDOW) {
839
+ const recent = this.actionHistory.slice(-LOOP_DETECTION_WINDOW);
840
+ const allIdentical = recent.every(
841
+ (r) =>
842
+ r.toolName === recent[0].toolName &&
843
+ JSON.stringify(r.input) === JSON.stringify(recent[0].input),
844
+ );
845
+ if (allIdentical) {
846
+ textParts.push('');
847
+ textParts.push(
848
+ `WARNING: You have repeated the exact same action (${recent[0].toolName}) ${LOOP_DETECTION_WINDOW} times in a row. You MUST try a completely different approach or call computer_use_done with an explanation of why you are stuck.`,
849
+ );
850
+ }
851
+ }
852
+
853
+ // Prompt for next action
854
+ textParts.push('');
855
+ if (this.actionHistory.length === 0) {
856
+ textParts.push('This is the first action. Examine the screen state and decide what to do first.');
857
+ } else {
858
+ textParts.push('Decide the next action to take.');
859
+ }
860
+
861
+ contentBlocks.push({
862
+ type: 'text',
863
+ text: textParts.join('\n'),
864
+ });
865
+
866
+ return [{ role: 'user', content: contentBlocks }];
867
+ }
868
+
869
+ private formatScreenshotMetadata(obs: CuObservation): string[] {
870
+ if (!obs.screenshot) return [];
871
+
872
+ const lines: string[] = [];
873
+ if (obs.screenshotWidthPx != null && obs.screenshotHeightPx != null) {
874
+ lines.push(`Screenshot metadata: ${obs.screenshotWidthPx}x${obs.screenshotHeightPx} px`);
875
+ }
876
+ if (obs.screenWidthPt != null && obs.screenHeightPt != null) {
877
+ lines.push(`Screen metadata: ${obs.screenWidthPt}x${obs.screenHeightPt} pt`);
878
+ }
879
+ if (obs.coordinateOrigin) {
880
+ lines.push(`Coordinate origin: ${obs.coordinateOrigin}`);
881
+ }
882
+ if (obs.captureDisplayId != null) {
883
+ lines.push(`Capture display ID: ${obs.captureDisplayId}`);
884
+ }
885
+ return lines;
886
+ }
887
+
888
+ hasPendingConfirmation(requestId: string): boolean {
889
+ return this.prompter?.hasPendingRequest(requestId) ?? false;
890
+ }
891
+
892
+ handleConfirmationResponse(
893
+ requestId: string,
894
+ decision: 'allow' | 'always_allow' | 'deny',
895
+ selectedPattern?: string,
896
+ selectedScope?: string,
897
+ ): void {
898
+ this.prompter?.resolveConfirmation(requestId, decision, selectedPattern, selectedScope);
899
+ }
900
+ }