clawdbot 2026.1.4-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (550) hide show
  1. package/CHANGELOG.md +120 -0
  2. package/LICENSE +21 -0
  3. package/README-header.png +0 -0
  4. package/README.md +297 -0
  5. package/dist/agents/agent-paths.js +17 -0
  6. package/dist/agents/bash-process-registry.js +126 -0
  7. package/dist/agents/bash-tools.js +837 -0
  8. package/dist/agents/clawdbot-tools.js +30 -0
  9. package/dist/agents/clawdis-tools.js +27 -0
  10. package/dist/agents/context.js +34 -0
  11. package/dist/agents/defaults.js +6 -0
  12. package/dist/agents/model-auth.js +112 -0
  13. package/dist/agents/model-catalog.js +55 -0
  14. package/dist/agents/model-fallback.js +191 -0
  15. package/dist/agents/model-scan.js +263 -0
  16. package/dist/agents/model-selection.js +116 -0
  17. package/dist/agents/models-config.js +49 -0
  18. package/dist/agents/pi-embedded-helpers.js +74 -0
  19. package/dist/agents/pi-embedded-runner.js +407 -0
  20. package/dist/agents/pi-embedded-subscribe.js +568 -0
  21. package/dist/agents/pi-embedded-utils.js +20 -0
  22. package/dist/agents/pi-embedded.js +1 -0
  23. package/dist/agents/pi-oauth.js +88 -0
  24. package/dist/agents/pi-tools.js +433 -0
  25. package/dist/agents/sandbox-paths.js +68 -0
  26. package/dist/agents/sandbox.js +644 -0
  27. package/dist/agents/shell-utils.js +53 -0
  28. package/dist/agents/skills-install.js +244 -0
  29. package/dist/agents/skills-status.js +157 -0
  30. package/dist/agents/skills.js +470 -0
  31. package/dist/agents/steerable-agent-loop.js +338 -0
  32. package/dist/agents/steerable-provider-transport.js +48 -0
  33. package/dist/agents/system-prompt.js +104 -0
  34. package/dist/agents/tool-display.js +162 -0
  35. package/dist/agents/tool-images.js +138 -0
  36. package/dist/agents/tools/browser-tool.js +339 -0
  37. package/dist/agents/tools/canvas-tool.js +193 -0
  38. package/dist/agents/tools/common.js +88 -0
  39. package/dist/agents/tools/cron-tool.js +124 -0
  40. package/dist/agents/tools/discord-actions-guild.js +186 -0
  41. package/dist/agents/tools/discord-actions-messaging.js +285 -0
  42. package/dist/agents/tools/discord-actions-moderation.js +70 -0
  43. package/dist/agents/tools/discord-actions.js +56 -0
  44. package/dist/agents/tools/discord-schema.js +199 -0
  45. package/dist/agents/tools/discord-tool.js +16 -0
  46. package/dist/agents/tools/gateway-tool.js +46 -0
  47. package/dist/agents/tools/gateway.js +27 -0
  48. package/dist/agents/tools/image-tool.js +132 -0
  49. package/dist/agents/tools/nodes-tool.js +413 -0
  50. package/dist/agents/tools/nodes-utils.js +92 -0
  51. package/dist/agents/tools/sessions-helpers.js +88 -0
  52. package/dist/agents/tools/sessions-history-tool.js +53 -0
  53. package/dist/agents/tools/sessions-list-tool.js +143 -0
  54. package/dist/agents/tools/sessions-send-helpers.js +100 -0
  55. package/dist/agents/tools/sessions-send-tool.js +347 -0
  56. package/dist/agents/tools/slack-actions.js +129 -0
  57. package/dist/agents/tools/slack-schema.js +59 -0
  58. package/dist/agents/tools/slack-tool.js +16 -0
  59. package/dist/agents/usage.js +39 -0
  60. package/dist/agents/workspace.js +241 -0
  61. package/dist/auto-reply/chunk.js +76 -0
  62. package/dist/auto-reply/envelope.js +38 -0
  63. package/dist/auto-reply/group-activation.js +20 -0
  64. package/dist/auto-reply/heartbeat.js +57 -0
  65. package/dist/auto-reply/model.js +14 -0
  66. package/dist/auto-reply/reply/abort.js +14 -0
  67. package/dist/auto-reply/reply/agent-runner.js +371 -0
  68. package/dist/auto-reply/reply/block-streaming.js +34 -0
  69. package/dist/auto-reply/reply/body.js +29 -0
  70. package/dist/auto-reply/reply/commands.js +207 -0
  71. package/dist/auto-reply/reply/directive-handling.js +361 -0
  72. package/dist/auto-reply/reply/directives.js +47 -0
  73. package/dist/auto-reply/reply/followup-runner.js +149 -0
  74. package/dist/auto-reply/reply/groups.js +91 -0
  75. package/dist/auto-reply/reply/mentions.js +38 -0
  76. package/dist/auto-reply/reply/model-selection.js +114 -0
  77. package/dist/auto-reply/reply/queue.js +399 -0
  78. package/dist/auto-reply/reply/reply-tags.js +26 -0
  79. package/dist/auto-reply/reply/session-updates.js +87 -0
  80. package/dist/auto-reply/reply/session.js +160 -0
  81. package/dist/auto-reply/reply/typing.js +75 -0
  82. package/dist/auto-reply/reply.js +535 -0
  83. package/dist/auto-reply/send-policy.js +28 -0
  84. package/dist/auto-reply/status.js +158 -0
  85. package/dist/auto-reply/templating.js +9 -0
  86. package/dist/auto-reply/thinking.js +49 -0
  87. package/dist/auto-reply/tokens.js +2 -0
  88. package/dist/auto-reply/tool-meta.js +74 -0
  89. package/dist/auto-reply/transcription.js +57 -0
  90. package/dist/auto-reply/types.js +1 -0
  91. package/dist/browser/bridge-server.js +37 -0
  92. package/dist/browser/cdp.js +382 -0
  93. package/dist/browser/chrome.js +432 -0
  94. package/dist/browser/client-actions-core.js +67 -0
  95. package/dist/browser/client-actions-observe.js +24 -0
  96. package/dist/browser/client-actions-types.js +1 -0
  97. package/dist/browser/client-actions.js +3 -0
  98. package/dist/browser/client-fetch.js +43 -0
  99. package/dist/browser/client.js +105 -0
  100. package/dist/browser/config.js +140 -0
  101. package/dist/browser/constants.js +4 -0
  102. package/dist/browser/profiles-service.js +122 -0
  103. package/dist/browser/profiles.js +85 -0
  104. package/dist/browser/pw-ai.js +2 -0
  105. package/dist/browser/pw-session.js +144 -0
  106. package/dist/browser/pw-tools-core.js +363 -0
  107. package/dist/browser/routes/agent.js +535 -0
  108. package/dist/browser/routes/basic.js +155 -0
  109. package/dist/browser/routes/index.js +8 -0
  110. package/dist/browser/routes/tabs.js +105 -0
  111. package/dist/browser/routes/utils.js +62 -0
  112. package/dist/browser/screenshot.js +40 -0
  113. package/dist/browser/server-context.js +377 -0
  114. package/dist/browser/server.js +81 -0
  115. package/dist/browser/target-id.js +18 -0
  116. package/dist/browser/trash.js +21 -0
  117. package/dist/canvas-host/a2ui/.bundle.hash +1 -0
  118. package/dist/canvas-host/a2ui/a2ui.bundle.js +17768 -0
  119. package/dist/canvas-host/a2ui/index.html +246 -0
  120. package/dist/canvas-host/a2ui.js +187 -0
  121. package/dist/canvas-host/server.js +382 -0
  122. package/dist/cli/browser-cli-actions-input.js +459 -0
  123. package/dist/cli/browser-cli-actions-observe.js +56 -0
  124. package/dist/cli/browser-cli-examples.js +31 -0
  125. package/dist/cli/browser-cli-inspect.js +97 -0
  126. package/dist/cli/browser-cli-manage.js +286 -0
  127. package/dist/cli/browser-cli-shared.js +1 -0
  128. package/dist/cli/browser-cli.js +26 -0
  129. package/dist/cli/canvas-cli.js +416 -0
  130. package/dist/cli/cron-cli.js +454 -0
  131. package/dist/cli/deps.js +17 -0
  132. package/dist/cli/dns-cli.js +180 -0
  133. package/dist/cli/gateway-cli.js +489 -0
  134. package/dist/cli/gateway-rpc.js +20 -0
  135. package/dist/cli/hooks-cli.js +135 -0
  136. package/dist/cli/models-cli.js +248 -0
  137. package/dist/cli/nodes-camera.js +57 -0
  138. package/dist/cli/nodes-canvas.js +26 -0
  139. package/dist/cli/nodes-cli.js +946 -0
  140. package/dist/cli/nodes-screen.js +37 -0
  141. package/dist/cli/parse-duration.js +20 -0
  142. package/dist/cli/ports.js +97 -0
  143. package/dist/cli/program.js +406 -0
  144. package/dist/cli/prompt.js +19 -0
  145. package/dist/cli/tui-cli.js +35 -0
  146. package/dist/cli/wait.js +8 -0
  147. package/dist/commands/agent.js +645 -0
  148. package/dist/commands/antigravity-oauth.js +327 -0
  149. package/dist/commands/configure.js +480 -0
  150. package/dist/commands/doctor.js +484 -0
  151. package/dist/commands/health.js +108 -0
  152. package/dist/commands/models/aliases.js +64 -0
  153. package/dist/commands/models/fallbacks.js +99 -0
  154. package/dist/commands/models/image-fallbacks.js +99 -0
  155. package/dist/commands/models/list.js +323 -0
  156. package/dist/commands/models/scan.js +266 -0
  157. package/dist/commands/models/set-image.js +23 -0
  158. package/dist/commands/models/set.js +23 -0
  159. package/dist/commands/models/shared.js +72 -0
  160. package/dist/commands/models.js +7 -0
  161. package/dist/commands/onboard-auth.js +70 -0
  162. package/dist/commands/onboard-helpers.js +295 -0
  163. package/dist/commands/onboard-interactive.js +17 -0
  164. package/dist/commands/onboard-non-interactive.js +202 -0
  165. package/dist/commands/onboard-providers.js +634 -0
  166. package/dist/commands/onboard-remote.js +120 -0
  167. package/dist/commands/onboard-skills.js +148 -0
  168. package/dist/commands/onboard-types.js +1 -0
  169. package/dist/commands/onboard.js +12 -0
  170. package/dist/commands/send.js +124 -0
  171. package/dist/commands/sessions.js +212 -0
  172. package/dist/commands/setup.js +58 -0
  173. package/dist/commands/signal-install.js +135 -0
  174. package/dist/commands/status.js +207 -0
  175. package/dist/commands/update.js +16 -0
  176. package/dist/config/config.js +6 -0
  177. package/dist/config/defaults.js +61 -0
  178. package/dist/config/io.js +147 -0
  179. package/dist/config/legacy-migrate.js +13 -0
  180. package/dist/config/legacy.js +159 -0
  181. package/dist/config/paths.js +71 -0
  182. package/dist/config/schema.js +150 -0
  183. package/dist/config/sessions.js +282 -0
  184. package/dist/config/talk.js +31 -0
  185. package/dist/config/types.js +1 -0
  186. package/dist/config/validation.js +29 -0
  187. package/dist/config/zod-schema.js +831 -0
  188. package/dist/control-ui/assets/index-BFID3yAA.css +1 -0
  189. package/dist/control-ui/assets/index-CE_axlTS.js +2235 -0
  190. package/dist/control-ui/assets/index-CE_axlTS.js.map +1 -0
  191. package/dist/control-ui/index.html +15 -0
  192. package/dist/cron/isolated-agent.js +499 -0
  193. package/dist/cron/run-log.js +72 -0
  194. package/dist/cron/schedule.js +24 -0
  195. package/dist/cron/service.js +471 -0
  196. package/dist/cron/store.js +43 -0
  197. package/dist/cron/types.js +1 -0
  198. package/dist/daemon/constants.js +10 -0
  199. package/dist/daemon/launchd.js +276 -0
  200. package/dist/daemon/legacy.js +63 -0
  201. package/dist/daemon/program-args.js +76 -0
  202. package/dist/daemon/schtasks.js +257 -0
  203. package/dist/daemon/service.js +60 -0
  204. package/dist/daemon/systemd.js +266 -0
  205. package/dist/discord/index.js +2 -0
  206. package/dist/discord/monitor.js +1188 -0
  207. package/dist/discord/probe.js +54 -0
  208. package/dist/discord/send.js +577 -0
  209. package/dist/discord/token.js +8 -0
  210. package/dist/gateway/auth.js +121 -0
  211. package/dist/gateway/call.js +94 -0
  212. package/dist/gateway/chat-attachments.js +41 -0
  213. package/dist/gateway/client.js +180 -0
  214. package/dist/gateway/config-reload.js +274 -0
  215. package/dist/gateway/control-ui.js +184 -0
  216. package/dist/gateway/hooks-mapping.js +282 -0
  217. package/dist/gateway/hooks.js +168 -0
  218. package/dist/gateway/net.js +29 -0
  219. package/dist/gateway/protocol/index.js +61 -0
  220. package/dist/gateway/protocol/schema.js +560 -0
  221. package/dist/gateway/server-bridge-subscriptions.js +93 -0
  222. package/dist/gateway/server-bridge.js +1013 -0
  223. package/dist/gateway/server-browser.js +12 -0
  224. package/dist/gateway/server-chat.js +159 -0
  225. package/dist/gateway/server-constants.js +8 -0
  226. package/dist/gateway/server-discovery.js +62 -0
  227. package/dist/gateway/server-http.js +165 -0
  228. package/dist/gateway/server-methods/agent-job.js +125 -0
  229. package/dist/gateway/server-methods/agent.js +250 -0
  230. package/dist/gateway/server-methods/chat.js +200 -0
  231. package/dist/gateway/server-methods/config.js +50 -0
  232. package/dist/gateway/server-methods/connect.js +6 -0
  233. package/dist/gateway/server-methods/cron.js +83 -0
  234. package/dist/gateway/server-methods/health.js +28 -0
  235. package/dist/gateway/server-methods/models.js +16 -0
  236. package/dist/gateway/server-methods/nodes.js +294 -0
  237. package/dist/gateway/server-methods/providers.js +217 -0
  238. package/dist/gateway/server-methods/send.js +166 -0
  239. package/dist/gateway/server-methods/sessions.js +305 -0
  240. package/dist/gateway/server-methods/skills.js +83 -0
  241. package/dist/gateway/server-methods/system.js +118 -0
  242. package/dist/gateway/server-methods/talk.js +22 -0
  243. package/dist/gateway/server-methods/types.js +1 -0
  244. package/dist/gateway/server-methods/voicewake.js +30 -0
  245. package/dist/gateway/server-methods/web.js +58 -0
  246. package/dist/gateway/server-methods/wizard.js +100 -0
  247. package/dist/gateway/server-methods.js +53 -0
  248. package/dist/gateway/server-providers.js +644 -0
  249. package/dist/gateway/server-shared.js +1 -0
  250. package/dist/gateway/server-utils.js +35 -0
  251. package/dist/gateway/server.js +1437 -0
  252. package/dist/gateway/session-utils.js +216 -0
  253. package/dist/gateway/ws-log.js +349 -0
  254. package/dist/gateway/ws-logging.js +8 -0
  255. package/dist/globals.js +41 -0
  256. package/dist/hooks/gmail-ops.js +236 -0
  257. package/dist/hooks/gmail-setup-utils.js +278 -0
  258. package/dist/hooks/gmail-watcher.js +175 -0
  259. package/dist/hooks/gmail.js +177 -0
  260. package/dist/imessage/client.js +165 -0
  261. package/dist/imessage/index.js +3 -0
  262. package/dist/imessage/monitor.js +272 -0
  263. package/dist/imessage/probe.js +26 -0
  264. package/dist/imessage/send.js +83 -0
  265. package/dist/imessage/targets.js +176 -0
  266. package/dist/index.js +50 -0
  267. package/dist/infra/agent-events.js +46 -0
  268. package/dist/infra/binaries.js +9 -0
  269. package/dist/infra/bonjour-discovery.js +163 -0
  270. package/dist/infra/bonjour.js +200 -0
  271. package/dist/infra/bridge/server.js +562 -0
  272. package/dist/infra/canvas-host-url.js +54 -0
  273. package/dist/infra/env.js +8 -0
  274. package/dist/infra/errors.js +28 -0
  275. package/dist/infra/gateway-lock.js +8 -0
  276. package/dist/infra/heartbeat-events.js +21 -0
  277. package/dist/infra/heartbeat-runner.js +453 -0
  278. package/dist/infra/heartbeat-wake.js +61 -0
  279. package/dist/infra/is-main.js +37 -0
  280. package/dist/infra/machine-name.js +40 -0
  281. package/dist/infra/node-pairing.js +211 -0
  282. package/dist/infra/pam.js +42 -0
  283. package/dist/infra/path-env.js +92 -0
  284. package/dist/infra/ports.js +87 -0
  285. package/dist/infra/provider-summary.js +80 -0
  286. package/dist/infra/restart.js +29 -0
  287. package/dist/infra/retry.js +16 -0
  288. package/dist/infra/runtime-guard.js +59 -0
  289. package/dist/infra/system-events.js +44 -0
  290. package/dist/infra/system-presence.js +216 -0
  291. package/dist/infra/tailnet.js +46 -0
  292. package/dist/infra/tailscale.js +149 -0
  293. package/dist/infra/voicewake.js +77 -0
  294. package/dist/infra/widearea-dns.js +123 -0
  295. package/dist/infra/ws.js +13 -0
  296. package/dist/logger.js +52 -0
  297. package/dist/logging.js +490 -0
  298. package/dist/macos/gateway-daemon.js +141 -0
  299. package/dist/macos/relay.js +46 -0
  300. package/dist/media/constants.js +33 -0
  301. package/dist/media/host.js +42 -0
  302. package/dist/media/image-ops.js +121 -0
  303. package/dist/media/mime.js +115 -0
  304. package/dist/media/parse.js +81 -0
  305. package/dist/media/server.js +64 -0
  306. package/dist/media/store.js +139 -0
  307. package/dist/process/command-queue.js +97 -0
  308. package/dist/process/exec.js +75 -0
  309. package/dist/protocol.schema.json +2918 -0
  310. package/dist/provider-web.js +8 -0
  311. package/dist/providers/web/index.js +2 -0
  312. package/dist/runtime.js +8 -0
  313. package/dist/sessions/send-policy.js +68 -0
  314. package/dist/signal/client.js +134 -0
  315. package/dist/signal/daemon.js +69 -0
  316. package/dist/signal/index.js +3 -0
  317. package/dist/signal/monitor.js +336 -0
  318. package/dist/signal/probe.js +46 -0
  319. package/dist/signal/send.js +91 -0
  320. package/dist/slack/actions.js +97 -0
  321. package/dist/slack/index.js +5 -0
  322. package/dist/slack/monitor.js +1029 -0
  323. package/dist/slack/probe.js +47 -0
  324. package/dist/slack/send.js +131 -0
  325. package/dist/slack/token.js +10 -0
  326. package/dist/telegram/bot.js +394 -0
  327. package/dist/telegram/download.js +34 -0
  328. package/dist/telegram/index.js +4 -0
  329. package/dist/telegram/monitor.js +47 -0
  330. package/dist/telegram/probe.js +63 -0
  331. package/dist/telegram/proxy.js +9 -0
  332. package/dist/telegram/send.js +138 -0
  333. package/dist/telegram/token.js +30 -0
  334. package/dist/telegram/webhook-set.js +12 -0
  335. package/dist/telegram/webhook.js +56 -0
  336. package/dist/tui/commands.js +74 -0
  337. package/dist/tui/components/assistant-message.js +16 -0
  338. package/dist/tui/components/chat-log.js +92 -0
  339. package/dist/tui/components/custom-editor.js +53 -0
  340. package/dist/tui/components/selectors.js +8 -0
  341. package/dist/tui/components/tool-execution.js +111 -0
  342. package/dist/tui/components/user-message.js +17 -0
  343. package/dist/tui/gateway-chat.js +140 -0
  344. package/dist/tui/layout.js +41 -0
  345. package/dist/tui/message-list.js +57 -0
  346. package/dist/tui/theme/theme.js +80 -0
  347. package/dist/tui/theme.js +25 -0
  348. package/dist/tui/tui.js +708 -0
  349. package/dist/utils.js +133 -0
  350. package/dist/version.js +18 -0
  351. package/dist/web/active-listener.js +7 -0
  352. package/dist/web/auto-reply.js +1203 -0
  353. package/dist/web/inbound.js +481 -0
  354. package/dist/web/login-qr.js +204 -0
  355. package/dist/web/login.js +59 -0
  356. package/dist/web/media.js +148 -0
  357. package/dist/web/outbound.js +67 -0
  358. package/dist/web/qr-image.js +97 -0
  359. package/dist/web/reconnect.js +60 -0
  360. package/dist/web/reply-heartbeat-wake.js +61 -0
  361. package/dist/web/session.js +346 -0
  362. package/dist/wizard/clack-prompter.js +56 -0
  363. package/dist/wizard/onboarding.js +452 -0
  364. package/dist/wizard/prompts.js +6 -0
  365. package/dist/wizard/session.js +203 -0
  366. package/docs/AGENTS.default.md +116 -0
  367. package/docs/CNAME +1 -0
  368. package/docs/RELEASING.md +64 -0
  369. package/docs/_config.yml +51 -0
  370. package/docs/_layouts/default.html +145 -0
  371. package/docs/agent-send.md +21 -0
  372. package/docs/agent.md +104 -0
  373. package/docs/android/connect.md +131 -0
  374. package/docs/architecture.md +89 -0
  375. package/docs/assets/markdown.css +130 -0
  376. package/docs/assets/pixel-lobster.svg +60 -0
  377. package/docs/assets/terminal.css +497 -0
  378. package/docs/assets/theme.js +55 -0
  379. package/docs/audio.md +50 -0
  380. package/docs/background-process.md +74 -0
  381. package/docs/bash.md +32 -0
  382. package/docs/bonjour.md +159 -0
  383. package/docs/browser.md +289 -0
  384. package/docs/camera.md +152 -0
  385. package/docs/clawd.md +199 -0
  386. package/docs/clawdbot-mac.md +104 -0
  387. package/docs/configuration.md +1177 -0
  388. package/docs/control-api.md +49 -0
  389. package/docs/control-ui.md +83 -0
  390. package/docs/cron.md +374 -0
  391. package/docs/dashboard.md +17 -0
  392. package/docs/device-models.md +46 -0
  393. package/docs/discord.md +293 -0
  394. package/docs/discovery.md +112 -0
  395. package/docs/docker.md +251 -0
  396. package/docs/docs.json +86 -0
  397. package/docs/doctor.md +47 -0
  398. package/docs/elevated.md +31 -0
  399. package/docs/faq.md +640 -0
  400. package/docs/gateway/pairing.md +109 -0
  401. package/docs/gateway-lock.md +28 -0
  402. package/docs/gateway.md +174 -0
  403. package/docs/gmail-pubsub.md +191 -0
  404. package/docs/grammy.md +27 -0
  405. package/docs/group-messages.md +71 -0
  406. package/docs/groups.md +78 -0
  407. package/docs/health.md +28 -0
  408. package/docs/heartbeat.md +64 -0
  409. package/docs/images.md +52 -0
  410. package/docs/imessage.md +63 -0
  411. package/docs/index.md +182 -0
  412. package/docs/ios/connect.md +177 -0
  413. package/docs/ios/spec.md +236 -0
  414. package/docs/location-command.md +95 -0
  415. package/docs/logging.md +99 -0
  416. package/docs/lore.md +131 -0
  417. package/docs/mac/bun.md +133 -0
  418. package/docs/mac/canvas.md +161 -0
  419. package/docs/mac/child-process.md +72 -0
  420. package/docs/mac/dev-setup.md +81 -0
  421. package/docs/mac/health.md +28 -0
  422. package/docs/mac/icon.md +26 -0
  423. package/docs/mac/logging.md +51 -0
  424. package/docs/mac/menu-bar.md +69 -0
  425. package/docs/mac/peekaboo.md +170 -0
  426. package/docs/mac/permissions.md +40 -0
  427. package/docs/mac/release.md +76 -0
  428. package/docs/mac/remote.md +57 -0
  429. package/docs/mac/signing.md +41 -0
  430. package/docs/mac/skills.md +27 -0
  431. package/docs/mac/voice-overlay.md +52 -0
  432. package/docs/mac/voicewake.md +56 -0
  433. package/docs/mac/webchat.md +27 -0
  434. package/docs/mac/xpc.md +40 -0
  435. package/docs/models.md +90 -0
  436. package/docs/nix.md +49 -0
  437. package/docs/nodes.md +157 -0
  438. package/docs/onboarding-config-protocol.md +29 -0
  439. package/docs/onboarding.md +185 -0
  440. package/docs/presence.md +133 -0
  441. package/docs/queue.md +78 -0
  442. package/docs/refactor/browser-control-simplification.md +58 -0
  443. package/docs/refactor/canvas-a2ui.md +93 -0
  444. package/docs/refactor/cli-unification.md +64 -0
  445. package/docs/refactor/gateway-client.md +31 -0
  446. package/docs/refactor/gateway.md +99 -0
  447. package/docs/refactor/new-arch.md +171 -0
  448. package/docs/refactor/tui.md +26 -0
  449. package/docs/refactor/web-gateway-troubleshooting.md +37 -0
  450. package/docs/refactor/webagent-session.md +46 -0
  451. package/docs/remote-gateway-readme.md +148 -0
  452. package/docs/remote.md +66 -0
  453. package/docs/research/memory.md +227 -0
  454. package/docs/rpc.md +35 -0
  455. package/docs/security.md +168 -0
  456. package/docs/session-tool.md +119 -0
  457. package/docs/session.md +84 -0
  458. package/docs/sessions.md +8 -0
  459. package/docs/setup.md +118 -0
  460. package/docs/signal.md +113 -0
  461. package/docs/skills-config.md +58 -0
  462. package/docs/skills.md +149 -0
  463. package/docs/slack.md +158 -0
  464. package/docs/surface.md +20 -0
  465. package/docs/tailscale.md +71 -0
  466. package/docs/talk.md +79 -0
  467. package/docs/telegram.md +90 -0
  468. package/docs/templates/AGENTS.md +126 -0
  469. package/docs/templates/BOOTSTRAP.md +53 -0
  470. package/docs/templates/IDENTITY.md +17 -0
  471. package/docs/templates/SOUL.md +41 -0
  472. package/docs/templates/TOOLS.md +41 -0
  473. package/docs/templates/USER.md +22 -0
  474. package/docs/test.md +35 -0
  475. package/docs/thinking.md +46 -0
  476. package/docs/tools.md +248 -0
  477. package/docs/troubleshooting.md +227 -0
  478. package/docs/tui.md +69 -0
  479. package/docs/typebox.md +42 -0
  480. package/docs/voicewake.md +61 -0
  481. package/docs/web.md +115 -0
  482. package/docs/webchat.md +34 -0
  483. package/docs/webhook.md +132 -0
  484. package/docs/whatsapp-clawd.jpg +0 -0
  485. package/docs/whatsapp.md +142 -0
  486. package/docs/wizard.md +158 -0
  487. package/package.json +186 -0
  488. package/skills/apple-notes/SKILL.md +50 -0
  489. package/skills/apple-reminders/SKILL.md +67 -0
  490. package/skills/bear-notes/SKILL.md +79 -0
  491. package/skills/bird/SKILL.md +25 -0
  492. package/skills/blogwatcher/SKILL.md +46 -0
  493. package/skills/blucli/SKILL.md +27 -0
  494. package/skills/brave-search/SKILL.md +30 -0
  495. package/skills/brave-search/scripts/content.mjs +53 -0
  496. package/skills/brave-search/scripts/search.mjs +79 -0
  497. package/skills/camsnap/SKILL.md +25 -0
  498. package/skills/clawdhub/SKILL.md +53 -0
  499. package/skills/coding-agent/SKILL.md +275 -0
  500. package/skills/discord/SKILL.md +369 -0
  501. package/skills/eightctl/SKILL.md +29 -0
  502. package/skills/food-order/SKILL.md +41 -0
  503. package/skills/gemini/SKILL.md +23 -0
  504. package/skills/gifgrep/SKILL.md +47 -0
  505. package/skills/github/SKILL.md +47 -0
  506. package/skills/gog/SKILL.md +36 -0
  507. package/skills/goplaces/SKILL.md +30 -0
  508. package/skills/imsg/SKILL.md +25 -0
  509. package/skills/local-places/SERVER_README.md +101 -0
  510. package/skills/local-places/SKILL.md +91 -0
  511. package/skills/local-places/pyproject.toml +27 -0
  512. package/skills/local-places/src/local_places/__init__.py +2 -0
  513. package/skills/local-places/src/local_places/__pycache__/__init__.cpython-314.pyc +0 -0
  514. package/skills/local-places/src/local_places/__pycache__/google_places.cpython-314.pyc +0 -0
  515. package/skills/local-places/src/local_places/__pycache__/main.cpython-314.pyc +0 -0
  516. package/skills/local-places/src/local_places/__pycache__/schemas.cpython-314.pyc +0 -0
  517. package/skills/local-places/src/local_places/google_places.py +314 -0
  518. package/skills/local-places/src/local_places/main.py +65 -0
  519. package/skills/local-places/src/local_places/schemas.py +107 -0
  520. package/skills/mcporter/SKILL.md +38 -0
  521. package/skills/nano-banana-pro/SKILL.md +29 -0
  522. package/skills/nano-banana-pro/scripts/generate_image.py +167 -0
  523. package/skills/nano-pdf/SKILL.md +20 -0
  524. package/skills/notion/SKILL.md +156 -0
  525. package/skills/obsidian/SKILL.md +55 -0
  526. package/skills/openai-image-gen/SKILL.md +31 -0
  527. package/skills/openai-image-gen/scripts/gen.py +173 -0
  528. package/skills/openai-whisper/SKILL.md +19 -0
  529. package/skills/openai-whisper-api/SKILL.md +43 -0
  530. package/skills/openai-whisper-api/scripts/transcribe.sh +85 -0
  531. package/skills/openhue/SKILL.md +30 -0
  532. package/skills/oracle/SKILL.md +105 -0
  533. package/skills/ordercli/SKILL.md +47 -0
  534. package/skills/peekaboo/SKILL.md +153 -0
  535. package/skills/qmd/SKILL.md +26 -0
  536. package/skills/sag/SKILL.md +62 -0
  537. package/skills/slack/SKILL.md +143 -0
  538. package/skills/songsee/SKILL.md +29 -0
  539. package/skills/sonoscli/SKILL.md +26 -0
  540. package/skills/spotify-player/SKILL.md +34 -0
  541. package/skills/summarize/SKILL.md +49 -0
  542. package/skills/things-mac/SKILL.md +61 -0
  543. package/skills/tmux/SKILL.md +121 -0
  544. package/skills/tmux/scripts/find-sessions.sh +112 -0
  545. package/skills/tmux/scripts/wait-for-text.sh +83 -0
  546. package/skills/trello/SKILL.md +84 -0
  547. package/skills/video-frames/SKILL.md +29 -0
  548. package/skills/video-frames/scripts/frame.sh +81 -0
  549. package/skills/wacli/SKILL.md +42 -0
  550. package/skills/weather/SKILL.md +49 -0
@@ -0,0 +1,535 @@
1
+ import path from "node:path";
2
+ import { ensureMediaDir, saveMediaBuffer } from "../../media/store.js";
3
+ import { captureScreenshot, snapshotAria } from "../cdp.js";
4
+ import { DEFAULT_BROWSER_SCREENSHOT_MAX_BYTES, DEFAULT_BROWSER_SCREENSHOT_MAX_SIDE, normalizeBrowserScreenshot, } from "../screenshot.js";
5
+ import { getProfileContext, jsonError, toBoolean, toNumber, toStringArray, toStringOrEmpty, } from "./utils.js";
6
+ const SELECTOR_UNSUPPORTED_MESSAGE = [
7
+ "Error: 'selector' is not supported. Use 'ref' from snapshot instead.",
8
+ "",
9
+ "Example workflow:",
10
+ "1. snapshot action to get page state with refs",
11
+ '2. act with ref: "e123" to interact with element',
12
+ "",
13
+ "This is more reliable for modern SPAs.",
14
+ ].join("\n");
15
+ function readBody(req) {
16
+ const body = req.body;
17
+ if (!body || typeof body !== "object" || Array.isArray(body))
18
+ return {};
19
+ return body;
20
+ }
21
+ function handleRouteError(ctx, res, err) {
22
+ const mapped = ctx.mapTabError(err);
23
+ if (mapped)
24
+ return jsonError(res, mapped.status, mapped.message);
25
+ jsonError(res, 500, String(err));
26
+ }
27
+ function resolveProfileContext(req, res, ctx) {
28
+ const profileCtx = getProfileContext(req, ctx);
29
+ if ("error" in profileCtx) {
30
+ jsonError(res, profileCtx.status, profileCtx.error);
31
+ return null;
32
+ }
33
+ return profileCtx;
34
+ }
35
+ function parseClickButton(raw) {
36
+ if (raw === "left" || raw === "right" || raw === "middle")
37
+ return raw;
38
+ return undefined;
39
+ }
40
+ let pwAiModule = null;
41
+ async function getPwAiModule() {
42
+ if (pwAiModule)
43
+ return pwAiModule;
44
+ pwAiModule = (async () => {
45
+ try {
46
+ return await import("../pw-ai.js");
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ })();
52
+ return pwAiModule;
53
+ }
54
+ async function requirePwAi(res, feature) {
55
+ const mod = await getPwAiModule();
56
+ if (mod)
57
+ return mod;
58
+ jsonError(res, 501, `Playwright is not available in this gateway build; '${feature}' is unsupported.`);
59
+ return null;
60
+ }
61
+ export function registerBrowserAgentRoutes(app, ctx) {
62
+ app.post("/navigate", async (req, res) => {
63
+ const profileCtx = resolveProfileContext(req, res, ctx);
64
+ if (!profileCtx)
65
+ return;
66
+ const body = readBody(req);
67
+ const url = toStringOrEmpty(body.url);
68
+ const targetId = toStringOrEmpty(body.targetId) || undefined;
69
+ if (!url)
70
+ return jsonError(res, 400, "url is required");
71
+ try {
72
+ const tab = await profileCtx.ensureTabAvailable(targetId);
73
+ const pw = await requirePwAi(res, "navigate");
74
+ if (!pw)
75
+ return;
76
+ const result = await pw.navigateViaPlaywright({
77
+ cdpUrl: profileCtx.profile.cdpUrl,
78
+ targetId: tab.targetId,
79
+ url,
80
+ });
81
+ res.json({ ok: true, targetId: tab.targetId, ...result });
82
+ }
83
+ catch (err) {
84
+ handleRouteError(ctx, res, err);
85
+ }
86
+ });
87
+ app.post("/act", async (req, res) => {
88
+ const profileCtx = resolveProfileContext(req, res, ctx);
89
+ if (!profileCtx)
90
+ return;
91
+ const body = readBody(req);
92
+ const kind = toStringOrEmpty(body.kind);
93
+ const targetId = toStringOrEmpty(body.targetId) || undefined;
94
+ if (Object.hasOwn(body, "selector")) {
95
+ return jsonError(res, 400, SELECTOR_UNSUPPORTED_MESSAGE);
96
+ }
97
+ if (kind !== "click" &&
98
+ kind !== "close" &&
99
+ kind !== "drag" &&
100
+ kind !== "evaluate" &&
101
+ kind !== "fill" &&
102
+ kind !== "hover" &&
103
+ kind !== "press" &&
104
+ kind !== "resize" &&
105
+ kind !== "select" &&
106
+ kind !== "type" &&
107
+ kind !== "wait") {
108
+ return jsonError(res, 400, "kind is required");
109
+ }
110
+ try {
111
+ const tab = await profileCtx.ensureTabAvailable(targetId);
112
+ const cdpUrl = profileCtx.profile.cdpUrl;
113
+ const pw = await requirePwAi(res, `act:${kind}`);
114
+ if (!pw)
115
+ return;
116
+ switch (kind) {
117
+ case "click": {
118
+ const ref = toStringOrEmpty(body.ref);
119
+ if (!ref)
120
+ return jsonError(res, 400, "ref is required");
121
+ const doubleClick = toBoolean(body.doubleClick) ?? false;
122
+ const buttonRaw = toStringOrEmpty(body.button) || "";
123
+ const button = buttonRaw ? parseClickButton(buttonRaw) : undefined;
124
+ if (buttonRaw && !button)
125
+ return jsonError(res, 400, "button must be left|right|middle");
126
+ const modifiersRaw = toStringArray(body.modifiers) ?? [];
127
+ const allowedModifiers = new Set([
128
+ "Alt",
129
+ "Control",
130
+ "ControlOrMeta",
131
+ "Meta",
132
+ "Shift",
133
+ ]);
134
+ const invalidModifiers = modifiersRaw.filter((m) => !allowedModifiers.has(m));
135
+ if (invalidModifiers.length)
136
+ return jsonError(res, 400, "modifiers must be Alt|Control|ControlOrMeta|Meta|Shift");
137
+ const modifiers = modifiersRaw.length
138
+ ? modifiersRaw
139
+ : undefined;
140
+ const clickRequest = {
141
+ cdpUrl,
142
+ targetId: tab.targetId,
143
+ ref,
144
+ doubleClick,
145
+ };
146
+ if (button)
147
+ clickRequest.button = button;
148
+ if (modifiers)
149
+ clickRequest.modifiers = modifiers;
150
+ await pw.clickViaPlaywright(clickRequest);
151
+ return res.json({ ok: true, targetId: tab.targetId, url: tab.url });
152
+ }
153
+ case "type": {
154
+ const ref = toStringOrEmpty(body.ref);
155
+ if (!ref)
156
+ return jsonError(res, 400, "ref is required");
157
+ if (typeof body.text !== "string")
158
+ return jsonError(res, 400, "text is required");
159
+ const text = body.text;
160
+ const submit = toBoolean(body.submit) ?? false;
161
+ const slowly = toBoolean(body.slowly) ?? false;
162
+ const typeRequest = {
163
+ cdpUrl,
164
+ targetId: tab.targetId,
165
+ ref,
166
+ text,
167
+ submit,
168
+ slowly,
169
+ };
170
+ await pw.typeViaPlaywright(typeRequest);
171
+ return res.json({ ok: true, targetId: tab.targetId });
172
+ }
173
+ case "press": {
174
+ const key = toStringOrEmpty(body.key);
175
+ if (!key)
176
+ return jsonError(res, 400, "key is required");
177
+ await pw.pressKeyViaPlaywright({
178
+ cdpUrl,
179
+ targetId: tab.targetId,
180
+ key,
181
+ });
182
+ return res.json({ ok: true, targetId: tab.targetId });
183
+ }
184
+ case "hover": {
185
+ const ref = toStringOrEmpty(body.ref);
186
+ if (!ref)
187
+ return jsonError(res, 400, "ref is required");
188
+ await pw.hoverViaPlaywright({ cdpUrl, targetId: tab.targetId, ref });
189
+ return res.json({ ok: true, targetId: tab.targetId });
190
+ }
191
+ case "drag": {
192
+ const startRef = toStringOrEmpty(body.startRef);
193
+ const endRef = toStringOrEmpty(body.endRef);
194
+ if (!startRef || !endRef)
195
+ return jsonError(res, 400, "startRef and endRef are required");
196
+ await pw.dragViaPlaywright({
197
+ cdpUrl,
198
+ targetId: tab.targetId,
199
+ startRef,
200
+ endRef,
201
+ });
202
+ return res.json({ ok: true, targetId: tab.targetId });
203
+ }
204
+ case "select": {
205
+ const ref = toStringOrEmpty(body.ref);
206
+ const values = toStringArray(body.values);
207
+ if (!ref || !values?.length)
208
+ return jsonError(res, 400, "ref and values are required");
209
+ await pw.selectOptionViaPlaywright({
210
+ cdpUrl,
211
+ targetId: tab.targetId,
212
+ ref,
213
+ values,
214
+ });
215
+ return res.json({ ok: true, targetId: tab.targetId });
216
+ }
217
+ case "fill": {
218
+ const rawFields = Array.isArray(body.fields) ? body.fields : [];
219
+ const fields = rawFields
220
+ .map((field) => {
221
+ if (!field || typeof field !== "object")
222
+ return null;
223
+ const rec = field;
224
+ const ref = toStringOrEmpty(rec.ref);
225
+ const type = toStringOrEmpty(rec.type);
226
+ if (!ref || !type)
227
+ return null;
228
+ const value = typeof rec.value === "string" ||
229
+ typeof rec.value === "number" ||
230
+ typeof rec.value === "boolean"
231
+ ? rec.value
232
+ : undefined;
233
+ const parsed = value === undefined ? { ref, type } : { ref, type, value };
234
+ return parsed;
235
+ })
236
+ .filter((field) => field !== null);
237
+ if (!fields.length)
238
+ return jsonError(res, 400, "fields are required");
239
+ await pw.fillFormViaPlaywright({
240
+ cdpUrl,
241
+ targetId: tab.targetId,
242
+ fields,
243
+ });
244
+ return res.json({ ok: true, targetId: tab.targetId });
245
+ }
246
+ case "resize": {
247
+ const width = toNumber(body.width);
248
+ const height = toNumber(body.height);
249
+ if (!width || !height)
250
+ return jsonError(res, 400, "width and height are required");
251
+ await pw.resizeViewportViaPlaywright({
252
+ cdpUrl,
253
+ targetId: tab.targetId,
254
+ width,
255
+ height,
256
+ });
257
+ return res.json({ ok: true, targetId: tab.targetId, url: tab.url });
258
+ }
259
+ case "wait": {
260
+ const timeMs = toNumber(body.timeMs);
261
+ const text = toStringOrEmpty(body.text) || undefined;
262
+ const textGone = toStringOrEmpty(body.textGone) || undefined;
263
+ await pw.waitForViaPlaywright({
264
+ cdpUrl,
265
+ targetId: tab.targetId,
266
+ timeMs,
267
+ text,
268
+ textGone,
269
+ });
270
+ return res.json({ ok: true, targetId: tab.targetId });
271
+ }
272
+ case "evaluate": {
273
+ const fn = toStringOrEmpty(body.fn);
274
+ if (!fn)
275
+ return jsonError(res, 400, "fn is required");
276
+ const ref = toStringOrEmpty(body.ref) || undefined;
277
+ const result = await pw.evaluateViaPlaywright({
278
+ cdpUrl,
279
+ targetId: tab.targetId,
280
+ fn,
281
+ ref,
282
+ });
283
+ return res.json({
284
+ ok: true,
285
+ targetId: tab.targetId,
286
+ url: tab.url,
287
+ result,
288
+ });
289
+ }
290
+ case "close": {
291
+ await pw.closePageViaPlaywright({ cdpUrl, targetId: tab.targetId });
292
+ return res.json({ ok: true, targetId: tab.targetId });
293
+ }
294
+ default: {
295
+ return jsonError(res, 400, "unsupported kind");
296
+ }
297
+ }
298
+ }
299
+ catch (err) {
300
+ handleRouteError(ctx, res, err);
301
+ }
302
+ });
303
+ app.post("/hooks/file-chooser", async (req, res) => {
304
+ const profileCtx = resolveProfileContext(req, res, ctx);
305
+ if (!profileCtx)
306
+ return;
307
+ const body = readBody(req);
308
+ const targetId = toStringOrEmpty(body.targetId) || undefined;
309
+ const ref = toStringOrEmpty(body.ref) || undefined;
310
+ const inputRef = toStringOrEmpty(body.inputRef) || undefined;
311
+ const element = toStringOrEmpty(body.element) || undefined;
312
+ const paths = toStringArray(body.paths) ?? [];
313
+ const timeoutMs = toNumber(body.timeoutMs);
314
+ if (!paths.length)
315
+ return jsonError(res, 400, "paths are required");
316
+ try {
317
+ const tab = await profileCtx.ensureTabAvailable(targetId);
318
+ const pw = await requirePwAi(res, "file chooser hook");
319
+ if (!pw)
320
+ return;
321
+ if (inputRef || element) {
322
+ if (ref) {
323
+ return jsonError(res, 400, "ref cannot be combined with inputRef/element");
324
+ }
325
+ await pw.setInputFilesViaPlaywright({
326
+ cdpUrl: profileCtx.profile.cdpUrl,
327
+ targetId: tab.targetId,
328
+ inputRef,
329
+ element,
330
+ paths,
331
+ });
332
+ }
333
+ else {
334
+ await pw.armFileUploadViaPlaywright({
335
+ cdpUrl: profileCtx.profile.cdpUrl,
336
+ targetId: tab.targetId,
337
+ paths,
338
+ timeoutMs: timeoutMs ?? undefined,
339
+ });
340
+ if (ref) {
341
+ await pw.clickViaPlaywright({
342
+ cdpUrl: profileCtx.profile.cdpUrl,
343
+ targetId: tab.targetId,
344
+ ref,
345
+ });
346
+ }
347
+ }
348
+ res.json({ ok: true });
349
+ }
350
+ catch (err) {
351
+ handleRouteError(ctx, res, err);
352
+ }
353
+ });
354
+ app.post("/hooks/dialog", async (req, res) => {
355
+ const profileCtx = resolveProfileContext(req, res, ctx);
356
+ if (!profileCtx)
357
+ return;
358
+ const body = readBody(req);
359
+ const targetId = toStringOrEmpty(body.targetId) || undefined;
360
+ const accept = toBoolean(body.accept);
361
+ const promptText = toStringOrEmpty(body.promptText) || undefined;
362
+ const timeoutMs = toNumber(body.timeoutMs);
363
+ if (accept === undefined)
364
+ return jsonError(res, 400, "accept is required");
365
+ try {
366
+ const tab = await profileCtx.ensureTabAvailable(targetId);
367
+ const pw = await requirePwAi(res, "dialog hook");
368
+ if (!pw)
369
+ return;
370
+ await pw.armDialogViaPlaywright({
371
+ cdpUrl: profileCtx.profile.cdpUrl,
372
+ targetId: tab.targetId,
373
+ accept,
374
+ promptText,
375
+ timeoutMs: timeoutMs ?? undefined,
376
+ });
377
+ res.json({ ok: true });
378
+ }
379
+ catch (err) {
380
+ handleRouteError(ctx, res, err);
381
+ }
382
+ });
383
+ app.get("/console", async (req, res) => {
384
+ const profileCtx = resolveProfileContext(req, res, ctx);
385
+ if (!profileCtx)
386
+ return;
387
+ const targetId = typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
388
+ const level = typeof req.query.level === "string" ? req.query.level : "";
389
+ try {
390
+ const tab = await profileCtx.ensureTabAvailable(targetId || undefined);
391
+ const pw = await requirePwAi(res, "console messages");
392
+ if (!pw)
393
+ return;
394
+ const messages = await pw.getConsoleMessagesViaPlaywright({
395
+ cdpUrl: profileCtx.profile.cdpUrl,
396
+ targetId: tab.targetId,
397
+ level: level.trim() || undefined,
398
+ });
399
+ res.json({ ok: true, messages, targetId: tab.targetId });
400
+ }
401
+ catch (err) {
402
+ handleRouteError(ctx, res, err);
403
+ }
404
+ });
405
+ app.post("/pdf", async (req, res) => {
406
+ const profileCtx = resolveProfileContext(req, res, ctx);
407
+ if (!profileCtx)
408
+ return;
409
+ const body = readBody(req);
410
+ const targetId = toStringOrEmpty(body.targetId) || undefined;
411
+ try {
412
+ const tab = await profileCtx.ensureTabAvailable(targetId);
413
+ const pw = await requirePwAi(res, "pdf");
414
+ if (!pw)
415
+ return;
416
+ const pdf = await pw.pdfViaPlaywright({
417
+ cdpUrl: profileCtx.profile.cdpUrl,
418
+ targetId: tab.targetId,
419
+ });
420
+ await ensureMediaDir();
421
+ const saved = await saveMediaBuffer(pdf.buffer, "application/pdf", "browser", pdf.buffer.byteLength);
422
+ res.json({
423
+ ok: true,
424
+ path: path.resolve(saved.path),
425
+ targetId: tab.targetId,
426
+ url: tab.url,
427
+ });
428
+ }
429
+ catch (err) {
430
+ handleRouteError(ctx, res, err);
431
+ }
432
+ });
433
+ app.post("/screenshot", async (req, res) => {
434
+ const profileCtx = resolveProfileContext(req, res, ctx);
435
+ if (!profileCtx)
436
+ return;
437
+ const body = readBody(req);
438
+ const targetId = toStringOrEmpty(body.targetId) || undefined;
439
+ const fullPage = toBoolean(body.fullPage) ?? false;
440
+ const ref = toStringOrEmpty(body.ref) || undefined;
441
+ const element = toStringOrEmpty(body.element) || undefined;
442
+ const type = body.type === "jpeg" ? "jpeg" : "png";
443
+ if (fullPage && (ref || element)) {
444
+ return jsonError(res, 400, "fullPage is not supported for element screenshots");
445
+ }
446
+ try {
447
+ const tab = await profileCtx.ensureTabAvailable(targetId);
448
+ let buffer;
449
+ if (ref || element) {
450
+ const pw = await requirePwAi(res, "element/ref screenshot");
451
+ if (!pw)
452
+ return;
453
+ const snap = await pw.takeScreenshotViaPlaywright({
454
+ cdpUrl: profileCtx.profile.cdpUrl,
455
+ targetId: tab.targetId,
456
+ ref,
457
+ element,
458
+ fullPage,
459
+ type,
460
+ });
461
+ buffer = snap.buffer;
462
+ }
463
+ else {
464
+ buffer = await captureScreenshot({
465
+ wsUrl: tab.wsUrl ?? "",
466
+ fullPage,
467
+ format: type,
468
+ quality: type === "jpeg" ? 85 : undefined,
469
+ });
470
+ }
471
+ const normalized = await normalizeBrowserScreenshot(buffer, {
472
+ maxSide: DEFAULT_BROWSER_SCREENSHOT_MAX_SIDE,
473
+ maxBytes: DEFAULT_BROWSER_SCREENSHOT_MAX_BYTES,
474
+ });
475
+ await ensureMediaDir();
476
+ const saved = await saveMediaBuffer(normalized.buffer, normalized.contentType ?? `image/${type}`, "browser", DEFAULT_BROWSER_SCREENSHOT_MAX_BYTES);
477
+ res.json({
478
+ ok: true,
479
+ path: path.resolve(saved.path),
480
+ targetId: tab.targetId,
481
+ url: tab.url,
482
+ });
483
+ }
484
+ catch (err) {
485
+ handleRouteError(ctx, res, err);
486
+ }
487
+ });
488
+ app.get("/snapshot", async (req, res) => {
489
+ const profileCtx = resolveProfileContext(req, res, ctx);
490
+ if (!profileCtx)
491
+ return;
492
+ const targetId = typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
493
+ const format = req.query.format === "aria"
494
+ ? "aria"
495
+ : req.query.format === "ai"
496
+ ? "ai"
497
+ : (await getPwAiModule())
498
+ ? "ai"
499
+ : "aria";
500
+ const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : undefined;
501
+ try {
502
+ const tab = await profileCtx.ensureTabAvailable(targetId || undefined);
503
+ if (format === "ai") {
504
+ const pw = await requirePwAi(res, "ai snapshot");
505
+ if (!pw)
506
+ return;
507
+ const snap = await pw.snapshotAiViaPlaywright({
508
+ cdpUrl: profileCtx.profile.cdpUrl,
509
+ targetId: tab.targetId,
510
+ });
511
+ return res.json({
512
+ ok: true,
513
+ format,
514
+ targetId: tab.targetId,
515
+ url: tab.url,
516
+ ...snap,
517
+ });
518
+ }
519
+ const snap = await snapshotAria({
520
+ wsUrl: tab.wsUrl ?? "",
521
+ limit,
522
+ });
523
+ return res.json({
524
+ ok: true,
525
+ format,
526
+ targetId: tab.targetId,
527
+ url: tab.url,
528
+ ...snap,
529
+ });
530
+ }
531
+ catch (err) {
532
+ handleRouteError(ctx, res, err);
533
+ }
534
+ });
535
+ }
@@ -0,0 +1,155 @@
1
+ import { createBrowserProfilesService } from "../profiles-service.js";
2
+ import { getProfileContext, jsonError, toStringOrEmpty } from "./utils.js";
3
+ export function registerBrowserBasicRoutes(app, ctx) {
4
+ // List all profiles with their status
5
+ app.get("/profiles", async (_req, res) => {
6
+ try {
7
+ const service = createBrowserProfilesService(ctx);
8
+ const profiles = await service.listProfiles();
9
+ res.json({ profiles });
10
+ }
11
+ catch (err) {
12
+ jsonError(res, 500, String(err));
13
+ }
14
+ });
15
+ // Get status (profile-aware)
16
+ app.get("/", async (req, res) => {
17
+ let current;
18
+ try {
19
+ current = ctx.state();
20
+ }
21
+ catch {
22
+ return jsonError(res, 503, "browser server not started");
23
+ }
24
+ const profileCtx = getProfileContext(req, ctx);
25
+ if ("error" in profileCtx) {
26
+ return jsonError(res, profileCtx.status, profileCtx.error);
27
+ }
28
+ const [cdpHttp, cdpReady] = await Promise.all([
29
+ profileCtx.isHttpReachable(300),
30
+ profileCtx.isReachable(600),
31
+ ]);
32
+ const profileState = current.profiles.get(profileCtx.profile.name);
33
+ res.json({
34
+ enabled: current.resolved.enabled,
35
+ controlUrl: current.resolved.controlUrl,
36
+ profile: profileCtx.profile.name,
37
+ running: cdpReady,
38
+ cdpReady,
39
+ cdpHttp,
40
+ pid: profileState?.running?.pid ?? null,
41
+ cdpPort: profileCtx.profile.cdpPort,
42
+ cdpUrl: profileCtx.profile.cdpUrl,
43
+ chosenBrowser: profileState?.running?.exe.kind ?? null,
44
+ userDataDir: profileState?.running?.userDataDir ?? null,
45
+ color: profileCtx.profile.color,
46
+ headless: current.resolved.headless,
47
+ noSandbox: current.resolved.noSandbox,
48
+ executablePath: current.resolved.executablePath ?? null,
49
+ attachOnly: current.resolved.attachOnly,
50
+ });
51
+ });
52
+ // Start browser (profile-aware)
53
+ app.post("/start", async (req, res) => {
54
+ const profileCtx = getProfileContext(req, ctx);
55
+ if ("error" in profileCtx) {
56
+ return jsonError(res, profileCtx.status, profileCtx.error);
57
+ }
58
+ try {
59
+ await profileCtx.ensureBrowserAvailable();
60
+ res.json({ ok: true, profile: profileCtx.profile.name });
61
+ }
62
+ catch (err) {
63
+ jsonError(res, 500, String(err));
64
+ }
65
+ });
66
+ // Stop browser (profile-aware)
67
+ app.post("/stop", async (req, res) => {
68
+ const profileCtx = getProfileContext(req, ctx);
69
+ if ("error" in profileCtx) {
70
+ return jsonError(res, profileCtx.status, profileCtx.error);
71
+ }
72
+ try {
73
+ const result = await profileCtx.stopRunningBrowser();
74
+ res.json({
75
+ ok: true,
76
+ stopped: result.stopped,
77
+ profile: profileCtx.profile.name,
78
+ });
79
+ }
80
+ catch (err) {
81
+ jsonError(res, 500, String(err));
82
+ }
83
+ });
84
+ // Reset profile (profile-aware)
85
+ app.post("/reset-profile", async (req, res) => {
86
+ const profileCtx = getProfileContext(req, ctx);
87
+ if ("error" in profileCtx) {
88
+ return jsonError(res, profileCtx.status, profileCtx.error);
89
+ }
90
+ try {
91
+ const result = await profileCtx.resetProfile();
92
+ res.json({ ok: true, profile: profileCtx.profile.name, ...result });
93
+ }
94
+ catch (err) {
95
+ jsonError(res, 500, String(err));
96
+ }
97
+ });
98
+ // Create a new profile
99
+ app.post("/profiles/create", async (req, res) => {
100
+ const name = toStringOrEmpty(req.body?.name);
101
+ const color = toStringOrEmpty(req.body?.color);
102
+ const cdpUrl = toStringOrEmpty(req.body?.cdpUrl);
103
+ if (!name)
104
+ return jsonError(res, 400, "name is required");
105
+ try {
106
+ const service = createBrowserProfilesService(ctx);
107
+ const result = await service.createProfile({
108
+ name,
109
+ color: color || undefined,
110
+ cdpUrl: cdpUrl || undefined,
111
+ });
112
+ res.json(result);
113
+ }
114
+ catch (err) {
115
+ const msg = String(err);
116
+ if (msg.includes("already exists")) {
117
+ return jsonError(res, 409, msg);
118
+ }
119
+ if (msg.includes("invalid profile name")) {
120
+ return jsonError(res, 400, msg);
121
+ }
122
+ if (msg.includes("no available CDP ports")) {
123
+ return jsonError(res, 507, msg);
124
+ }
125
+ if (msg.includes("cdpUrl")) {
126
+ return jsonError(res, 400, msg);
127
+ }
128
+ jsonError(res, 500, msg);
129
+ }
130
+ });
131
+ // Delete a profile
132
+ app.delete("/profiles/:name", async (req, res) => {
133
+ const name = toStringOrEmpty(req.params.name);
134
+ if (!name)
135
+ return jsonError(res, 400, "profile name is required");
136
+ try {
137
+ const service = createBrowserProfilesService(ctx);
138
+ const result = await service.deleteProfile(name);
139
+ res.json(result);
140
+ }
141
+ catch (err) {
142
+ const msg = String(err);
143
+ if (msg.includes("invalid profile name")) {
144
+ return jsonError(res, 400, msg);
145
+ }
146
+ if (msg.includes("default profile")) {
147
+ return jsonError(res, 400, msg);
148
+ }
149
+ if (msg.includes("not found")) {
150
+ return jsonError(res, 404, msg);
151
+ }
152
+ jsonError(res, 500, msg);
153
+ }
154
+ });
155
+ }
@@ -0,0 +1,8 @@
1
+ import { registerBrowserAgentRoutes } from "./agent.js";
2
+ import { registerBrowserBasicRoutes } from "./basic.js";
3
+ import { registerBrowserTabRoutes } from "./tabs.js";
4
+ export function registerBrowserRoutes(app, ctx) {
5
+ registerBrowserBasicRoutes(app, ctx);
6
+ registerBrowserTabRoutes(app, ctx);
7
+ registerBrowserAgentRoutes(app, ctx);
8
+ }