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,837 @@
1
+ import { spawn } from "node:child_process";
2
+ import { randomUUID } from "node:crypto";
3
+ import { existsSync, statSync } from "node:fs";
4
+ import fs from "node:fs/promises";
5
+ import { homedir } from "node:os";
6
+ import path from "node:path";
7
+ import { Type } from "@sinclair/typebox";
8
+ import { logInfo } from "../logger.js";
9
+ import { addSession, appendOutput, deleteSession, drainSession, getFinishedSession, getSession, listFinishedSessions, listRunningSessions, markBackgrounded, markExited, setJobTtlMs, } from "./bash-process-registry.js";
10
+ import { assertSandboxPath } from "./sandbox-paths.js";
11
+ import { getShellConfig, killProcessTree, sanitizeBinaryOutput, } from "./shell-utils.js";
12
+ const CHUNK_LIMIT = 8 * 1024;
13
+ const DEFAULT_MAX_OUTPUT = clampNumber(readEnvInt("PI_BASH_MAX_OUTPUT_CHARS"), 30_000, 1_000, 150_000);
14
+ const DEFAULT_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
15
+ const stringEnum = (values, options) => Type.Union(values.map((value) => Type.Literal(value)), options);
16
+ const bashSchema = Type.Object({
17
+ command: Type.String({ description: "Bash command to execute" }),
18
+ workdir: Type.Optional(Type.String({ description: "Working directory (defaults to cwd)" })),
19
+ env: Type.Optional(Type.Record(Type.String(), Type.String())),
20
+ yieldMs: Type.Optional(Type.Number({
21
+ description: "Milliseconds to wait before backgrounding (default 10000)",
22
+ })),
23
+ background: Type.Optional(Type.Boolean({ description: "Run in background immediately" })),
24
+ timeout: Type.Optional(Type.Number({
25
+ description: "Timeout in seconds (optional, kills process on expiry)",
26
+ })),
27
+ elevated: Type.Optional(Type.Boolean({
28
+ description: "Run on the host with elevated permissions (if allowed)",
29
+ })),
30
+ });
31
+ export function createBashTool(defaults) {
32
+ const defaultBackgroundMs = clampNumber(defaults?.backgroundMs ?? readEnvInt("PI_BASH_YIELD_MS"), 10_000, 10, 120_000);
33
+ const defaultTimeoutSec = typeof defaults?.timeoutSec === "number" && defaults.timeoutSec > 0
34
+ ? defaults.timeoutSec
35
+ : 1800;
36
+ return {
37
+ name: "bash",
38
+ label: "bash",
39
+ description: "Execute bash with background continuation. Use yieldMs/background to continue later via process tool. For real TTY mode, use the tmux skill.",
40
+ parameters: bashSchema,
41
+ execute: async (_toolCallId, args, signal, onUpdate) => {
42
+ const params = args;
43
+ if (!params.command) {
44
+ throw new Error("Provide a command to start.");
45
+ }
46
+ const yieldWindow = params.background
47
+ ? 0
48
+ : clampNumber(params.yieldMs ?? defaultBackgroundMs, defaultBackgroundMs, 10, 120_000);
49
+ const maxOutput = DEFAULT_MAX_OUTPUT;
50
+ const startedAt = Date.now();
51
+ const sessionId = randomUUID();
52
+ const warnings = [];
53
+ const elevatedDefaults = defaults?.elevated;
54
+ const elevatedRequested = typeof params.elevated === "boolean"
55
+ ? params.elevated
56
+ : elevatedDefaults?.defaultLevel === "on";
57
+ if (elevatedRequested) {
58
+ if (!elevatedDefaults?.enabled || !elevatedDefaults.allowed) {
59
+ throw new Error("elevated is not available right now.");
60
+ }
61
+ logInfo(`bash: elevated command (${sessionId.slice(0, 8)}) ${truncateMiddle(params.command, 120)}`);
62
+ }
63
+ const sandbox = elevatedRequested ? undefined : defaults?.sandbox;
64
+ const rawWorkdir = params.workdir?.trim() || process.cwd();
65
+ let workdir = rawWorkdir;
66
+ let containerWorkdir = sandbox?.containerWorkdir;
67
+ if (sandbox) {
68
+ const resolved = await resolveSandboxWorkdir({
69
+ workdir: rawWorkdir,
70
+ sandbox,
71
+ warnings,
72
+ });
73
+ workdir = resolved.hostWorkdir;
74
+ containerWorkdir = resolved.containerWorkdir;
75
+ }
76
+ else {
77
+ workdir = resolveWorkdir(rawWorkdir, warnings);
78
+ }
79
+ const { shell, args: shellArgs } = getShellConfig();
80
+ const baseEnv = coerceEnv(process.env);
81
+ const mergedEnv = params.env ? { ...baseEnv, ...params.env } : baseEnv;
82
+ const env = sandbox
83
+ ? buildSandboxEnv({
84
+ paramsEnv: params.env,
85
+ sandboxEnv: sandbox.env,
86
+ containerWorkdir: containerWorkdir ?? sandbox.containerWorkdir,
87
+ })
88
+ : mergedEnv;
89
+ const child = sandbox
90
+ ? spawn("docker", buildDockerExecArgs({
91
+ containerName: sandbox.containerName,
92
+ command: params.command,
93
+ workdir: containerWorkdir ?? sandbox.containerWorkdir,
94
+ env,
95
+ tty: false,
96
+ }), {
97
+ cwd: workdir,
98
+ env: process.env,
99
+ detached: true,
100
+ stdio: ["pipe", "pipe", "pipe"],
101
+ })
102
+ : spawn(shell, [...shellArgs, params.command], {
103
+ cwd: workdir,
104
+ env,
105
+ detached: true,
106
+ stdio: ["pipe", "pipe", "pipe"],
107
+ });
108
+ const session = {
109
+ id: sessionId,
110
+ command: params.command,
111
+ child,
112
+ pid: child?.pid,
113
+ startedAt,
114
+ cwd: workdir,
115
+ maxOutputChars: maxOutput,
116
+ totalOutputChars: 0,
117
+ pendingStdout: [],
118
+ pendingStderr: [],
119
+ aggregated: "",
120
+ tail: "",
121
+ exited: false,
122
+ exitCode: undefined,
123
+ exitSignal: undefined,
124
+ truncated: false,
125
+ backgrounded: false,
126
+ };
127
+ addSession(session);
128
+ let settled = false;
129
+ let yielded = false;
130
+ let yieldTimer = null;
131
+ let timeoutTimer = null;
132
+ let timedOut = false;
133
+ const settle = (fn) => {
134
+ if (settled)
135
+ return;
136
+ settled = true;
137
+ fn();
138
+ };
139
+ const onAbort = () => {
140
+ killSession(session);
141
+ };
142
+ if (signal?.aborted)
143
+ onAbort();
144
+ else if (signal) {
145
+ signal.addEventListener("abort", onAbort, { once: true });
146
+ }
147
+ const effectiveTimeout = typeof params.timeout === "number" ? params.timeout : defaultTimeoutSec;
148
+ if (effectiveTimeout > 0) {
149
+ timeoutTimer = setTimeout(() => {
150
+ timedOut = true;
151
+ onAbort();
152
+ }, effectiveTimeout * 1000);
153
+ }
154
+ const emitUpdate = () => {
155
+ if (!onUpdate)
156
+ return;
157
+ const tailText = session.tail || session.aggregated;
158
+ const warningText = warnings.length ? `${warnings.join("\n")}\n\n` : "";
159
+ onUpdate({
160
+ content: [{ type: "text", text: warningText + (tailText || "") }],
161
+ details: {
162
+ status: "running",
163
+ sessionId,
164
+ pid: session.pid ?? undefined,
165
+ startedAt,
166
+ tail: session.tail,
167
+ },
168
+ });
169
+ };
170
+ child.stdout.on("data", (data) => {
171
+ const str = sanitizeBinaryOutput(data.toString());
172
+ for (const chunk of chunkString(str)) {
173
+ appendOutput(session, "stdout", chunk);
174
+ emitUpdate();
175
+ }
176
+ });
177
+ child.stderr.on("data", (data) => {
178
+ const str = sanitizeBinaryOutput(data.toString());
179
+ for (const chunk of chunkString(str)) {
180
+ appendOutput(session, "stderr", chunk);
181
+ emitUpdate();
182
+ }
183
+ });
184
+ return new Promise((resolve, reject) => {
185
+ const resolveRunning = () => {
186
+ settle(() => resolve({
187
+ content: [
188
+ {
189
+ type: "text",
190
+ text: `${warnings.length ? `${warnings.join("\n")}\n\n` : ""}` +
191
+ `Command still running (session ${sessionId}, pid ${session.pid ?? "n/a"}). ` +
192
+ "Use process (list/poll/log/write/kill/clear/remove) for follow-up.",
193
+ },
194
+ ],
195
+ details: {
196
+ status: "running",
197
+ sessionId,
198
+ pid: session.pid ?? undefined,
199
+ startedAt,
200
+ tail: session.tail,
201
+ },
202
+ }));
203
+ };
204
+ const onYieldNow = () => {
205
+ if (yieldTimer)
206
+ clearTimeout(yieldTimer);
207
+ if (settled)
208
+ return;
209
+ yielded = true;
210
+ markBackgrounded(session);
211
+ resolveRunning();
212
+ };
213
+ if (yieldWindow === 0) {
214
+ onYieldNow();
215
+ }
216
+ else {
217
+ yieldTimer = setTimeout(() => {
218
+ if (settled)
219
+ return;
220
+ yielded = true;
221
+ markBackgrounded(session);
222
+ resolveRunning();
223
+ }, yieldWindow);
224
+ }
225
+ const handleExit = (code, exitSignal) => {
226
+ if (yieldTimer)
227
+ clearTimeout(yieldTimer);
228
+ if (timeoutTimer)
229
+ clearTimeout(timeoutTimer);
230
+ const durationMs = Date.now() - startedAt;
231
+ const wasSignal = exitSignal != null;
232
+ const isSuccess = code === 0 && !wasSignal && !signal?.aborted && !timedOut;
233
+ const status = isSuccess
234
+ ? "completed"
235
+ : "failed";
236
+ markExited(session, code, exitSignal, status);
237
+ if (yielded || session.backgrounded)
238
+ return;
239
+ const aggregated = session.aggregated.trim();
240
+ if (!isSuccess) {
241
+ const reason = timedOut
242
+ ? `Command timed out after ${effectiveTimeout} seconds`
243
+ : wasSignal && exitSignal
244
+ ? `Command aborted by signal ${exitSignal}`
245
+ : code === null
246
+ ? "Command aborted before exit code was captured"
247
+ : `Command exited with code ${code}`;
248
+ const message = aggregated
249
+ ? `${aggregated}\n\n${reason}`
250
+ : reason;
251
+ settle(() => reject(new Error(message)));
252
+ return;
253
+ }
254
+ settle(() => resolve({
255
+ content: [
256
+ {
257
+ type: "text",
258
+ text: `${warnings.length ? `${warnings.join("\n")}\n\n` : ""}` +
259
+ (aggregated || "(no output)"),
260
+ },
261
+ ],
262
+ details: {
263
+ status: "completed",
264
+ exitCode: code ?? 0,
265
+ durationMs,
266
+ aggregated,
267
+ },
268
+ }));
269
+ };
270
+ child.once("exit", (code, exitSignal) => {
271
+ handleExit(code, exitSignal);
272
+ });
273
+ child.once("error", (err) => {
274
+ if (yieldTimer)
275
+ clearTimeout(yieldTimer);
276
+ if (timeoutTimer)
277
+ clearTimeout(timeoutTimer);
278
+ markExited(session, null, null, "failed");
279
+ settle(() => reject(err));
280
+ });
281
+ });
282
+ },
283
+ };
284
+ }
285
+ export const bashTool = createBashTool();
286
+ const processSchema = Type.Object({
287
+ action: stringEnum(["list", "poll", "log", "write", "kill", "clear", "remove"], {
288
+ description: "Process action",
289
+ }),
290
+ sessionId: Type.Optional(Type.String({ description: "Session id for actions other than list" })),
291
+ data: Type.Optional(Type.String({ description: "Data to write for write" })),
292
+ eof: Type.Optional(Type.Boolean({ description: "Close stdin after write" })),
293
+ offset: Type.Optional(Type.Number({ description: "Log offset" })),
294
+ limit: Type.Optional(Type.Number({ description: "Log length" })),
295
+ });
296
+ export function createProcessTool(defaults) {
297
+ if (defaults?.cleanupMs !== undefined) {
298
+ setJobTtlMs(defaults.cleanupMs);
299
+ }
300
+ return {
301
+ name: "process",
302
+ label: "process",
303
+ description: "Manage running bash sessions: list, poll, log, write, kill.",
304
+ parameters: processSchema,
305
+ execute: async (_toolCallId, args) => {
306
+ const params = args;
307
+ if (params.action === "list") {
308
+ const running = listRunningSessions().map((s) => ({
309
+ sessionId: s.id,
310
+ status: "running",
311
+ pid: s.pid ?? undefined,
312
+ startedAt: s.startedAt,
313
+ runtimeMs: Date.now() - s.startedAt,
314
+ cwd: s.cwd,
315
+ command: s.command,
316
+ name: deriveSessionName(s.command),
317
+ tail: s.tail,
318
+ truncated: s.truncated,
319
+ }));
320
+ const finished = listFinishedSessions().map((s) => ({
321
+ sessionId: s.id,
322
+ status: s.status,
323
+ startedAt: s.startedAt,
324
+ endedAt: s.endedAt,
325
+ runtimeMs: s.endedAt - s.startedAt,
326
+ cwd: s.cwd,
327
+ command: s.command,
328
+ name: deriveSessionName(s.command),
329
+ tail: s.tail,
330
+ truncated: s.truncated,
331
+ exitCode: s.exitCode ?? undefined,
332
+ exitSignal: s.exitSignal ?? undefined,
333
+ }));
334
+ const lines = [...running, ...finished]
335
+ .sort((a, b) => b.startedAt - a.startedAt)
336
+ .map((s) => {
337
+ const label = s.name
338
+ ? truncateMiddle(s.name, 80)
339
+ : truncateMiddle(s.command, 120);
340
+ return `${s.sessionId.slice(0, 8)} ${pad(s.status, 9)} ${formatDuration(s.runtimeMs)} :: ${label}`;
341
+ });
342
+ return {
343
+ content: [
344
+ {
345
+ type: "text",
346
+ text: lines.join("\n") || "No running or recent sessions.",
347
+ },
348
+ ],
349
+ details: { status: "completed", sessions: [...running, ...finished] },
350
+ };
351
+ }
352
+ if (!params.sessionId) {
353
+ return {
354
+ content: [
355
+ { type: "text", text: "sessionId is required for this action." },
356
+ ],
357
+ details: { status: "failed" },
358
+ };
359
+ }
360
+ const session = getSession(params.sessionId);
361
+ const finished = getFinishedSession(params.sessionId);
362
+ switch (params.action) {
363
+ case "poll": {
364
+ if (!session) {
365
+ if (finished) {
366
+ return {
367
+ content: [
368
+ {
369
+ type: "text",
370
+ text: (finished.tail ||
371
+ `(no output recorded${finished.truncated ? " — truncated to cap" : ""})`) +
372
+ `\n\nProcess exited with ${finished.exitSignal
373
+ ? `signal ${finished.exitSignal}`
374
+ : `code ${finished.exitCode ?? 0}`}.`,
375
+ },
376
+ ],
377
+ details: {
378
+ status: finished.status === "completed" ? "completed" : "failed",
379
+ sessionId: params.sessionId,
380
+ exitCode: finished.exitCode ?? undefined,
381
+ aggregated: finished.aggregated,
382
+ name: deriveSessionName(finished.command),
383
+ },
384
+ };
385
+ }
386
+ return {
387
+ content: [
388
+ {
389
+ type: "text",
390
+ text: `No session found for ${params.sessionId}`,
391
+ },
392
+ ],
393
+ details: { status: "failed" },
394
+ };
395
+ }
396
+ if (!session.backgrounded) {
397
+ return {
398
+ content: [
399
+ {
400
+ type: "text",
401
+ text: `Session ${params.sessionId} is not backgrounded.`,
402
+ },
403
+ ],
404
+ details: { status: "failed" },
405
+ };
406
+ }
407
+ const { stdout, stderr } = drainSession(session);
408
+ const exited = session.exited;
409
+ const exitCode = session.exitCode ?? 0;
410
+ const exitSignal = session.exitSignal ?? undefined;
411
+ if (exited) {
412
+ const status = exitCode === 0 && exitSignal == null ? "completed" : "failed";
413
+ markExited(session, session.exitCode ?? null, session.exitSignal ?? null, status);
414
+ }
415
+ const status = exited
416
+ ? exitCode === 0 && exitSignal == null
417
+ ? "completed"
418
+ : "failed"
419
+ : "running";
420
+ const output = [stdout.trimEnd(), stderr.trimEnd()]
421
+ .filter(Boolean)
422
+ .join("\n")
423
+ .trim();
424
+ return {
425
+ content: [
426
+ {
427
+ type: "text",
428
+ text: (output || "(no new output)") +
429
+ (exited
430
+ ? `\n\nProcess exited with ${exitSignal ? `signal ${exitSignal}` : `code ${exitCode}`}.`
431
+ : "\n\nProcess still running."),
432
+ },
433
+ ],
434
+ details: {
435
+ status,
436
+ sessionId: params.sessionId,
437
+ exitCode: exited ? exitCode : undefined,
438
+ aggregated: session.aggregated,
439
+ name: deriveSessionName(session.command),
440
+ },
441
+ };
442
+ }
443
+ case "log": {
444
+ if (session) {
445
+ if (!session.backgrounded) {
446
+ return {
447
+ content: [
448
+ {
449
+ type: "text",
450
+ text: `Session ${params.sessionId} is not backgrounded.`,
451
+ },
452
+ ],
453
+ details: { status: "failed" },
454
+ };
455
+ }
456
+ const { slice, totalLines, totalChars } = sliceLogLines(session.aggregated, params.offset, params.limit);
457
+ return {
458
+ content: [{ type: "text", text: slice || "(no output yet)" }],
459
+ details: {
460
+ status: session.exited ? "completed" : "running",
461
+ sessionId: params.sessionId,
462
+ total: totalLines,
463
+ totalLines,
464
+ totalChars,
465
+ truncated: session.truncated,
466
+ name: deriveSessionName(session.command),
467
+ },
468
+ };
469
+ }
470
+ if (finished) {
471
+ const { slice, totalLines, totalChars } = sliceLogLines(finished.aggregated, params.offset, params.limit);
472
+ const status = finished.status === "completed" ? "completed" : "failed";
473
+ return {
474
+ content: [
475
+ { type: "text", text: slice || "(no output recorded)" },
476
+ ],
477
+ details: {
478
+ status,
479
+ sessionId: params.sessionId,
480
+ total: totalLines,
481
+ totalLines,
482
+ totalChars,
483
+ truncated: finished.truncated,
484
+ exitCode: finished.exitCode ?? undefined,
485
+ exitSignal: finished.exitSignal ?? undefined,
486
+ name: deriveSessionName(finished.command),
487
+ },
488
+ };
489
+ }
490
+ return {
491
+ content: [
492
+ {
493
+ type: "text",
494
+ text: `No session found for ${params.sessionId}`,
495
+ },
496
+ ],
497
+ details: { status: "failed" },
498
+ };
499
+ }
500
+ case "write": {
501
+ if (!session) {
502
+ return {
503
+ content: [
504
+ {
505
+ type: "text",
506
+ text: `No active session found for ${params.sessionId}`,
507
+ },
508
+ ],
509
+ details: { status: "failed" },
510
+ };
511
+ }
512
+ if (!session.backgrounded) {
513
+ return {
514
+ content: [
515
+ {
516
+ type: "text",
517
+ text: `Session ${params.sessionId} is not backgrounded.`,
518
+ },
519
+ ],
520
+ details: { status: "failed" },
521
+ };
522
+ }
523
+ if (!session.child?.stdin || session.child.stdin.destroyed) {
524
+ return {
525
+ content: [
526
+ {
527
+ type: "text",
528
+ text: `Session ${params.sessionId} stdin is not writable.`,
529
+ },
530
+ ],
531
+ details: { status: "failed" },
532
+ };
533
+ }
534
+ await new Promise((resolve, reject) => {
535
+ session.child?.stdin.write(params.data ?? "", (err) => {
536
+ if (err)
537
+ reject(err);
538
+ else
539
+ resolve();
540
+ });
541
+ });
542
+ if (params.eof) {
543
+ session.child.stdin.end();
544
+ }
545
+ return {
546
+ content: [
547
+ {
548
+ type: "text",
549
+ text: `Wrote ${(params.data ?? "").length} bytes to session ${params.sessionId}${params.eof ? " (stdin closed)" : ""}.`,
550
+ },
551
+ ],
552
+ details: {
553
+ status: "running",
554
+ sessionId: params.sessionId,
555
+ name: session ? deriveSessionName(session.command) : undefined,
556
+ },
557
+ };
558
+ }
559
+ case "kill": {
560
+ if (!session) {
561
+ return {
562
+ content: [
563
+ {
564
+ type: "text",
565
+ text: `No active session found for ${params.sessionId}`,
566
+ },
567
+ ],
568
+ details: { status: "failed" },
569
+ };
570
+ }
571
+ if (!session.backgrounded) {
572
+ return {
573
+ content: [
574
+ {
575
+ type: "text",
576
+ text: `Session ${params.sessionId} is not backgrounded.`,
577
+ },
578
+ ],
579
+ details: { status: "failed" },
580
+ };
581
+ }
582
+ killSession(session);
583
+ markExited(session, null, "SIGKILL", "failed");
584
+ return {
585
+ content: [
586
+ { type: "text", text: `Killed session ${params.sessionId}.` },
587
+ ],
588
+ details: {
589
+ status: "failed",
590
+ name: session ? deriveSessionName(session.command) : undefined,
591
+ },
592
+ };
593
+ }
594
+ case "clear": {
595
+ if (finished) {
596
+ deleteSession(params.sessionId);
597
+ return {
598
+ content: [
599
+ { type: "text", text: `Cleared session ${params.sessionId}.` },
600
+ ],
601
+ details: { status: "completed" },
602
+ };
603
+ }
604
+ return {
605
+ content: [
606
+ {
607
+ type: "text",
608
+ text: `No finished session found for ${params.sessionId}`,
609
+ },
610
+ ],
611
+ details: { status: "failed" },
612
+ };
613
+ }
614
+ case "remove": {
615
+ if (session) {
616
+ killSession(session);
617
+ markExited(session, null, "SIGKILL", "failed");
618
+ return {
619
+ content: [
620
+ { type: "text", text: `Removed session ${params.sessionId}.` },
621
+ ],
622
+ details: {
623
+ status: "failed",
624
+ name: session ? deriveSessionName(session.command) : undefined,
625
+ },
626
+ };
627
+ }
628
+ if (finished) {
629
+ deleteSession(params.sessionId);
630
+ return {
631
+ content: [
632
+ { type: "text", text: `Removed session ${params.sessionId}.` },
633
+ ],
634
+ details: { status: "completed" },
635
+ };
636
+ }
637
+ return {
638
+ content: [
639
+ {
640
+ type: "text",
641
+ text: `No session found for ${params.sessionId}`,
642
+ },
643
+ ],
644
+ details: { status: "failed" },
645
+ };
646
+ }
647
+ }
648
+ return {
649
+ content: [
650
+ { type: "text", text: `Unknown action ${params.action}` },
651
+ ],
652
+ details: { status: "failed" },
653
+ };
654
+ },
655
+ };
656
+ }
657
+ export const processTool = createProcessTool();
658
+ function buildSandboxEnv(params) {
659
+ const env = {
660
+ PATH: DEFAULT_PATH,
661
+ HOME: params.containerWorkdir,
662
+ };
663
+ for (const [key, value] of Object.entries(params.sandboxEnv ?? {})) {
664
+ env[key] = value;
665
+ }
666
+ for (const [key, value] of Object.entries(params.paramsEnv ?? {})) {
667
+ env[key] = value;
668
+ }
669
+ return env;
670
+ }
671
+ function coerceEnv(env) {
672
+ const record = {};
673
+ if (!env)
674
+ return record;
675
+ for (const [key, value] of Object.entries(env)) {
676
+ if (typeof value === "string")
677
+ record[key] = value;
678
+ }
679
+ return record;
680
+ }
681
+ function buildDockerExecArgs(params) {
682
+ const args = ["exec", "-i"];
683
+ if (params.tty)
684
+ args.push("-t");
685
+ if (params.workdir) {
686
+ args.push("-w", params.workdir);
687
+ }
688
+ for (const [key, value] of Object.entries(params.env)) {
689
+ args.push("-e", `${key}=${value}`);
690
+ }
691
+ args.push(params.containerName, "sh", "-lc", params.command);
692
+ return args;
693
+ }
694
+ async function resolveSandboxWorkdir(params) {
695
+ const fallback = params.sandbox.workspaceDir;
696
+ try {
697
+ const resolved = await assertSandboxPath({
698
+ filePath: params.workdir,
699
+ cwd: process.cwd(),
700
+ root: params.sandbox.workspaceDir,
701
+ });
702
+ const stats = await fs.stat(resolved.resolved);
703
+ if (!stats.isDirectory()) {
704
+ throw new Error("workdir is not a directory");
705
+ }
706
+ const relative = resolved.relative
707
+ ? resolved.relative.split(path.sep).join(path.posix.sep)
708
+ : "";
709
+ const containerWorkdir = relative
710
+ ? path.posix.join(params.sandbox.containerWorkdir, relative)
711
+ : params.sandbox.containerWorkdir;
712
+ return { hostWorkdir: resolved.resolved, containerWorkdir };
713
+ }
714
+ catch {
715
+ params.warnings.push(`Warning: workdir "${params.workdir}" is unavailable; using "${fallback}".`);
716
+ return {
717
+ hostWorkdir: fallback,
718
+ containerWorkdir: params.sandbox.containerWorkdir,
719
+ };
720
+ }
721
+ }
722
+ function killSession(session) {
723
+ const pid = session.pid ?? session.child?.pid;
724
+ if (pid) {
725
+ killProcessTree(pid);
726
+ }
727
+ }
728
+ function resolveWorkdir(workdir, warnings) {
729
+ const current = safeCwd();
730
+ const fallback = current ?? homedir();
731
+ try {
732
+ const stats = statSync(workdir);
733
+ if (stats.isDirectory())
734
+ return workdir;
735
+ }
736
+ catch {
737
+ // ignore, fallback below
738
+ }
739
+ warnings.push(`Warning: workdir "${workdir}" is unavailable; using "${fallback}".`);
740
+ return fallback;
741
+ }
742
+ function safeCwd() {
743
+ try {
744
+ const cwd = process.cwd();
745
+ return existsSync(cwd) ? cwd : null;
746
+ }
747
+ catch {
748
+ return null;
749
+ }
750
+ }
751
+ function clampNumber(value, defaultValue, min, max) {
752
+ if (value === undefined || Number.isNaN(value))
753
+ return defaultValue;
754
+ return Math.min(Math.max(value, min), max);
755
+ }
756
+ function readEnvInt(key) {
757
+ const raw = process.env[key];
758
+ if (!raw)
759
+ return undefined;
760
+ const parsed = Number.parseInt(raw, 10);
761
+ return Number.isFinite(parsed) ? parsed : undefined;
762
+ }
763
+ function chunkString(input, limit = CHUNK_LIMIT) {
764
+ const chunks = [];
765
+ for (let i = 0; i < input.length; i += limit) {
766
+ chunks.push(input.slice(i, i + limit));
767
+ }
768
+ return chunks;
769
+ }
770
+ function truncateMiddle(str, max) {
771
+ if (str.length <= max)
772
+ return str;
773
+ const half = Math.floor((max - 3) / 2);
774
+ return `${str.slice(0, half)}...${str.slice(str.length - half)}`;
775
+ }
776
+ function sliceLogLines(text, offset, limit) {
777
+ if (!text)
778
+ return { slice: "", totalLines: 0, totalChars: 0 };
779
+ const normalized = text.replace(/\r\n/g, "\n");
780
+ const lines = normalized.split("\n");
781
+ if (lines.length > 0 && lines[lines.length - 1] === "") {
782
+ lines.pop();
783
+ }
784
+ const totalLines = lines.length;
785
+ const totalChars = text.length;
786
+ let start = typeof offset === "number" && Number.isFinite(offset)
787
+ ? Math.max(0, Math.floor(offset))
788
+ : 0;
789
+ if (limit !== undefined && offset === undefined) {
790
+ const tailCount = Math.max(0, Math.floor(limit));
791
+ start = Math.max(totalLines - tailCount, 0);
792
+ }
793
+ const end = typeof limit === "number" && Number.isFinite(limit)
794
+ ? start + Math.max(0, Math.floor(limit))
795
+ : undefined;
796
+ return { slice: lines.slice(start, end).join("\n"), totalLines, totalChars };
797
+ }
798
+ function deriveSessionName(command) {
799
+ const tokens = tokenizeCommand(command);
800
+ if (tokens.length === 0)
801
+ return undefined;
802
+ const verb = tokens[0];
803
+ let target = tokens.slice(1).find((t) => !t.startsWith("-"));
804
+ if (!target)
805
+ target = tokens[1];
806
+ if (!target)
807
+ return verb;
808
+ const cleaned = truncateMiddle(stripQuotes(target), 48);
809
+ return `${stripQuotes(verb)} ${cleaned}`;
810
+ }
811
+ function tokenizeCommand(command) {
812
+ const matches = command.match(/(?:[^\s"']+|"(?:\\.|[^"])*"|'(?:\\.|[^'])*')+/g) ?? [];
813
+ return matches.map((token) => stripQuotes(token)).filter(Boolean);
814
+ }
815
+ function stripQuotes(value) {
816
+ const trimmed = value.trim();
817
+ if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
818
+ (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
819
+ return trimmed.slice(1, -1);
820
+ }
821
+ return trimmed;
822
+ }
823
+ function formatDuration(ms) {
824
+ if (ms < 1000)
825
+ return `${ms}ms`;
826
+ const seconds = Math.floor(ms / 1000);
827
+ if (seconds < 60)
828
+ return `${seconds}s`;
829
+ const minutes = Math.floor(seconds / 60);
830
+ const rem = seconds % 60;
831
+ return `${minutes}m${rem.toString().padStart(2, "0")}s`;
832
+ }
833
+ function pad(str, width) {
834
+ if (str.length >= width)
835
+ return str;
836
+ return str + " ".repeat(width - str.length);
837
+ }