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,433 @@
1
+ import { codingTools, createEditTool, createReadTool, createWriteTool, readTool, } from "@mariozechner/pi-coding-agent";
2
+ import { Type } from "@sinclair/typebox";
3
+ import { detectMime } from "../media/mime.js";
4
+ import { startWebLoginWithQr, waitForWebLogin } from "../web/login-qr.js";
5
+ import { createBashTool, createProcessTool, } from "./bash-tools.js";
6
+ import { createClawdbotTools } from "./clawdbot-tools.js";
7
+ import { assertSandboxPath } from "./sandbox-paths.js";
8
+ import { sanitizeToolResultImages } from "./tool-images.js";
9
+ async function sniffMimeFromBase64(base64) {
10
+ const trimmed = base64.trim();
11
+ if (!trimmed)
12
+ return undefined;
13
+ const take = Math.min(256, trimmed.length);
14
+ const sliceLen = take - (take % 4);
15
+ if (sliceLen < 8)
16
+ return undefined;
17
+ try {
18
+ const head = Buffer.from(trimmed.slice(0, sliceLen), "base64");
19
+ return await detectMime({ buffer: head });
20
+ }
21
+ catch {
22
+ return undefined;
23
+ }
24
+ }
25
+ function rewriteReadImageHeader(text, mimeType) {
26
+ // pi-coding-agent uses: "Read image file [image/png]"
27
+ if (text.startsWith("Read image file [") && text.endsWith("]")) {
28
+ return `Read image file [${mimeType}]`;
29
+ }
30
+ return text;
31
+ }
32
+ async function normalizeReadImageResult(result, filePath) {
33
+ const content = Array.isArray(result.content) ? result.content : [];
34
+ const image = content.find((b) => !!b &&
35
+ typeof b === "object" &&
36
+ b.type === "image" &&
37
+ typeof b.data === "string" &&
38
+ typeof b.mimeType === "string");
39
+ if (!image)
40
+ return result;
41
+ if (!image.data.trim()) {
42
+ throw new Error(`read: image payload is empty (${filePath})`);
43
+ }
44
+ const sniffed = await sniffMimeFromBase64(image.data);
45
+ if (!sniffed)
46
+ return result;
47
+ if (!sniffed.startsWith("image/")) {
48
+ throw new Error(`read: file looks like ${sniffed} but was treated as ${image.mimeType} (${filePath})`);
49
+ }
50
+ if (sniffed === image.mimeType)
51
+ return result;
52
+ const nextContent = content.map((block) => {
53
+ if (block &&
54
+ typeof block === "object" &&
55
+ block.type === "image") {
56
+ const b = block;
57
+ return { ...b, mimeType: sniffed };
58
+ }
59
+ if (block &&
60
+ typeof block === "object" &&
61
+ block.type === "text" &&
62
+ typeof block.text === "string") {
63
+ const b = block;
64
+ return {
65
+ ...b,
66
+ text: rewriteReadImageHeader(b.text, sniffed),
67
+ };
68
+ }
69
+ return block;
70
+ });
71
+ return { ...result, content: nextContent };
72
+ }
73
+ function extractEnumValues(schema) {
74
+ if (!schema || typeof schema !== "object")
75
+ return undefined;
76
+ const record = schema;
77
+ if (Array.isArray(record.enum))
78
+ return record.enum;
79
+ if ("const" in record)
80
+ return [record.const];
81
+ return undefined;
82
+ }
83
+ function mergePropertySchemas(existing, incoming) {
84
+ if (!existing)
85
+ return incoming;
86
+ if (!incoming)
87
+ return existing;
88
+ const existingEnum = extractEnumValues(existing);
89
+ const incomingEnum = extractEnumValues(incoming);
90
+ if (existingEnum || incomingEnum) {
91
+ const values = Array.from(new Set([...(existingEnum ?? []), ...(incomingEnum ?? [])]));
92
+ const merged = {};
93
+ for (const source of [existing, incoming]) {
94
+ if (!source || typeof source !== "object")
95
+ continue;
96
+ const record = source;
97
+ for (const key of ["title", "description", "default"]) {
98
+ if (!(key in merged) && key in record)
99
+ merged[key] = record[key];
100
+ }
101
+ }
102
+ const types = new Set(values.map((value) => typeof value));
103
+ if (types.size === 1)
104
+ merged.type = Array.from(types)[0];
105
+ merged.enum = values;
106
+ return merged;
107
+ }
108
+ return existing;
109
+ }
110
+ function cleanSchemaForGemini(schema) {
111
+ if (!schema || typeof schema !== "object")
112
+ return schema;
113
+ if (Array.isArray(schema))
114
+ return schema.map(cleanSchemaForGemini);
115
+ const obj = schema;
116
+ const hasAnyOf = "anyOf" in obj && Array.isArray(obj.anyOf);
117
+ const cleaned = {};
118
+ for (const [key, value] of Object.entries(obj)) {
119
+ // Skip unsupported schema features for Gemini:
120
+ // - patternProperties: not in OpenAPI 3.0 subset
121
+ // - const: convert to enum with single value instead
122
+ if (key === "patternProperties") {
123
+ // Gemini doesn't support patternProperties - skip it
124
+ continue;
125
+ }
126
+ // Convert const to enum (Gemini doesn't support const)
127
+ if (key === "const") {
128
+ cleaned.enum = [value];
129
+ continue;
130
+ }
131
+ // Skip 'type' if we have 'anyOf' — Gemini doesn't allow both
132
+ if (key === "type" && hasAnyOf) {
133
+ continue;
134
+ }
135
+ if (key === "properties" && value && typeof value === "object") {
136
+ // Recursively clean nested properties
137
+ const props = value;
138
+ cleaned[key] = Object.fromEntries(Object.entries(props).map(([k, v]) => [k, cleanSchemaForGemini(v)]));
139
+ }
140
+ else if (key === "items" && value && typeof value === "object") {
141
+ // Recursively clean array items schema
142
+ cleaned[key] = cleanSchemaForGemini(value);
143
+ }
144
+ else if (key === "anyOf" && Array.isArray(value)) {
145
+ // Clean each anyOf variant
146
+ cleaned[key] = value.map((variant) => cleanSchemaForGemini(variant));
147
+ }
148
+ else if (key === "oneOf" && Array.isArray(value)) {
149
+ // Clean each oneOf variant
150
+ cleaned[key] = value.map((variant) => cleanSchemaForGemini(variant));
151
+ }
152
+ else if (key === "allOf" && Array.isArray(value)) {
153
+ // Clean each allOf variant
154
+ cleaned[key] = value.map((variant) => cleanSchemaForGemini(variant));
155
+ }
156
+ else if (key === "additionalProperties" &&
157
+ value &&
158
+ typeof value === "object") {
159
+ // Recursively clean additionalProperties schema
160
+ cleaned[key] = cleanSchemaForGemini(value);
161
+ }
162
+ else {
163
+ cleaned[key] = value;
164
+ }
165
+ }
166
+ return cleaned;
167
+ }
168
+ function normalizeToolParameters(tool) {
169
+ const schema = tool.parameters && typeof tool.parameters === "object"
170
+ ? tool.parameters
171
+ : undefined;
172
+ if (!schema)
173
+ return tool;
174
+ // If schema already has type + properties (no top-level anyOf to merge),
175
+ // still clean it for Gemini compatibility
176
+ if ("type" in schema &&
177
+ "properties" in schema &&
178
+ !Array.isArray(schema.anyOf)) {
179
+ return {
180
+ ...tool,
181
+ parameters: cleanSchemaForGemini(schema),
182
+ };
183
+ }
184
+ if (!Array.isArray(schema.anyOf))
185
+ return tool;
186
+ const mergedProperties = {};
187
+ const requiredCounts = new Map();
188
+ let objectVariants = 0;
189
+ for (const entry of schema.anyOf) {
190
+ if (!entry || typeof entry !== "object")
191
+ continue;
192
+ const props = entry.properties;
193
+ if (!props || typeof props !== "object")
194
+ continue;
195
+ objectVariants += 1;
196
+ for (const [key, value] of Object.entries(props)) {
197
+ if (!(key in mergedProperties)) {
198
+ mergedProperties[key] = value;
199
+ continue;
200
+ }
201
+ mergedProperties[key] = mergePropertySchemas(mergedProperties[key], value);
202
+ }
203
+ const required = Array.isArray(entry.required)
204
+ ? entry.required
205
+ : [];
206
+ for (const key of required) {
207
+ if (typeof key !== "string")
208
+ continue;
209
+ requiredCounts.set(key, (requiredCounts.get(key) ?? 0) + 1);
210
+ }
211
+ }
212
+ const baseRequired = Array.isArray(schema.required)
213
+ ? schema.required.filter((key) => typeof key === "string")
214
+ : undefined;
215
+ const mergedRequired = baseRequired && baseRequired.length > 0
216
+ ? baseRequired
217
+ : objectVariants > 0
218
+ ? Array.from(requiredCounts.entries())
219
+ .filter(([, count]) => count === objectVariants)
220
+ .map(([key]) => key)
221
+ : undefined;
222
+ const nextSchema = { ...schema };
223
+ return {
224
+ ...tool,
225
+ parameters: cleanSchemaForGemini({
226
+ ...nextSchema,
227
+ type: nextSchema.type ?? "object",
228
+ properties: Object.keys(mergedProperties).length > 0
229
+ ? mergedProperties
230
+ : (schema.properties ?? {}),
231
+ ...(mergedRequired && mergedRequired.length > 0
232
+ ? { required: mergedRequired }
233
+ : {}),
234
+ additionalProperties: "additionalProperties" in schema ? schema.additionalProperties : true,
235
+ }),
236
+ };
237
+ }
238
+ function normalizeToolNames(list) {
239
+ if (!list)
240
+ return [];
241
+ return list.map((entry) => entry.trim().toLowerCase()).filter(Boolean);
242
+ }
243
+ function filterToolsByPolicy(tools, policy) {
244
+ if (!policy)
245
+ return tools;
246
+ const deny = new Set(normalizeToolNames(policy.deny));
247
+ const allowRaw = normalizeToolNames(policy.allow);
248
+ const allow = allowRaw.length > 0 ? new Set(allowRaw) : null;
249
+ return tools.filter((tool) => {
250
+ const name = tool.name.toLowerCase();
251
+ if (deny.has(name))
252
+ return false;
253
+ if (allow)
254
+ return allow.has(name);
255
+ return true;
256
+ });
257
+ }
258
+ function wrapSandboxPathGuard(tool, root) {
259
+ return {
260
+ ...tool,
261
+ execute: async (toolCallId, args, signal, onUpdate) => {
262
+ const record = args && typeof args === "object"
263
+ ? args
264
+ : undefined;
265
+ const filePath = record?.path;
266
+ if (typeof filePath === "string" && filePath.trim()) {
267
+ await assertSandboxPath({ filePath, cwd: root, root });
268
+ }
269
+ return tool.execute(toolCallId, args, signal, onUpdate);
270
+ },
271
+ };
272
+ }
273
+ function createSandboxedReadTool(root) {
274
+ const base = createReadTool(root);
275
+ return wrapSandboxPathGuard(createClawdbotReadTool(base), root);
276
+ }
277
+ function createSandboxedWriteTool(root) {
278
+ const base = createWriteTool(root);
279
+ return wrapSandboxPathGuard(base, root);
280
+ }
281
+ function createSandboxedEditTool(root) {
282
+ const base = createEditTool(root);
283
+ return wrapSandboxPathGuard(base, root);
284
+ }
285
+ function createWhatsAppLoginTool() {
286
+ return {
287
+ label: "WhatsApp Login",
288
+ name: "whatsapp_login",
289
+ description: "Generate a WhatsApp QR code for linking, or wait for the scan to complete.",
290
+ parameters: Type.Object({
291
+ action: Type.Union([Type.Literal("start"), Type.Literal("wait")]),
292
+ timeoutMs: Type.Optional(Type.Number()),
293
+ force: Type.Optional(Type.Boolean()),
294
+ }),
295
+ execute: async (_toolCallId, args) => {
296
+ const action = args?.action ?? "start";
297
+ if (action === "wait") {
298
+ const result = await waitForWebLogin({
299
+ timeoutMs: typeof args.timeoutMs === "number"
300
+ ? args.timeoutMs
301
+ : undefined,
302
+ });
303
+ return {
304
+ content: [{ type: "text", text: result.message }],
305
+ details: { connected: result.connected },
306
+ };
307
+ }
308
+ const result = await startWebLoginWithQr({
309
+ timeoutMs: typeof args.timeoutMs === "number"
310
+ ? args.timeoutMs
311
+ : undefined,
312
+ force: typeof args.force === "boolean"
313
+ ? args.force
314
+ : false,
315
+ });
316
+ if (!result.qrDataUrl) {
317
+ return {
318
+ content: [
319
+ {
320
+ type: "text",
321
+ text: result.message,
322
+ },
323
+ ],
324
+ details: { qr: false },
325
+ };
326
+ }
327
+ const text = [
328
+ result.message,
329
+ "",
330
+ "Open WhatsApp → Linked Devices and scan:",
331
+ "",
332
+ `![whatsapp-qr](${result.qrDataUrl})`,
333
+ ].join("\n");
334
+ return {
335
+ content: [{ type: "text", text }],
336
+ details: { qr: true },
337
+ };
338
+ },
339
+ };
340
+ }
341
+ function createClawdbotReadTool(base) {
342
+ return {
343
+ ...base,
344
+ execute: async (toolCallId, params, signal) => {
345
+ const result = (await base.execute(toolCallId, params, signal));
346
+ const record = params && typeof params === "object"
347
+ ? params
348
+ : undefined;
349
+ const filePath = typeof record?.path === "string" ? String(record.path) : "<unknown>";
350
+ const normalized = await normalizeReadImageResult(result, filePath);
351
+ return sanitizeToolResultImages(normalized, `read:${filePath}`);
352
+ },
353
+ };
354
+ }
355
+ function normalizeSurface(surface) {
356
+ const trimmed = surface?.trim().toLowerCase();
357
+ return trimmed ? trimmed : undefined;
358
+ }
359
+ function shouldIncludeDiscordTool(surface) {
360
+ const normalized = normalizeSurface(surface);
361
+ if (!normalized)
362
+ return false;
363
+ return normalized === "discord" || normalized.startsWith("discord:");
364
+ }
365
+ function shouldIncludeSlackTool(surface) {
366
+ const normalized = normalizeSurface(surface);
367
+ if (!normalized)
368
+ return false;
369
+ return normalized === "slack" || normalized.startsWith("slack:");
370
+ }
371
+ export function createClawdbotCodingTools(options) {
372
+ const bashToolName = "bash";
373
+ const sandbox = options?.sandbox?.enabled ? options.sandbox : undefined;
374
+ const sandboxRoot = sandbox?.workspaceDir;
375
+ const base = codingTools.flatMap((tool) => {
376
+ if (tool.name === readTool.name) {
377
+ return sandboxRoot
378
+ ? [createSandboxedReadTool(sandboxRoot)]
379
+ : [createClawdbotReadTool(tool)];
380
+ }
381
+ if (tool.name === bashToolName)
382
+ return [];
383
+ if (sandboxRoot && (tool.name === "write" || tool.name === "edit")) {
384
+ return [];
385
+ }
386
+ return [tool];
387
+ });
388
+ const bashTool = createBashTool({
389
+ ...options?.bash,
390
+ sandbox: sandbox
391
+ ? {
392
+ containerName: sandbox.containerName,
393
+ workspaceDir: sandbox.workspaceDir,
394
+ containerWorkdir: sandbox.containerWorkdir,
395
+ env: sandbox.docker.env,
396
+ }
397
+ : undefined,
398
+ });
399
+ const processTool = createProcessTool({
400
+ cleanupMs: options?.bash?.cleanupMs,
401
+ });
402
+ const tools = [
403
+ ...base,
404
+ ...(sandboxRoot
405
+ ? [
406
+ createSandboxedEditTool(sandboxRoot),
407
+ createSandboxedWriteTool(sandboxRoot),
408
+ ]
409
+ : []),
410
+ bashTool,
411
+ processTool,
412
+ createWhatsAppLoginTool(),
413
+ ...createClawdbotTools({
414
+ browserControlUrl: sandbox?.browser?.controlUrl,
415
+ agentSessionKey: options?.sessionKey,
416
+ agentSurface: options?.surface,
417
+ config: options?.config,
418
+ }),
419
+ ];
420
+ const allowDiscord = shouldIncludeDiscordTool(options?.surface);
421
+ const allowSlack = shouldIncludeSlackTool(options?.surface);
422
+ const filtered = tools.filter((tool) => {
423
+ if (tool.name === "discord")
424
+ return allowDiscord;
425
+ if (tool.name === "slack")
426
+ return allowSlack;
427
+ return true;
428
+ });
429
+ const sandboxed = sandbox
430
+ ? filterToolsByPolicy(filtered, sandbox.tools)
431
+ : filtered;
432
+ return sandboxed.map(normalizeToolParameters);
433
+ }
@@ -0,0 +1,68 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ const UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
5
+ function normalizeUnicodeSpaces(str) {
6
+ return str.replace(UNICODE_SPACES, " ");
7
+ }
8
+ function expandPath(filePath) {
9
+ const normalized = normalizeUnicodeSpaces(filePath);
10
+ if (normalized === "~") {
11
+ return os.homedir();
12
+ }
13
+ if (normalized.startsWith("~/")) {
14
+ return os.homedir() + normalized.slice(1);
15
+ }
16
+ return normalized;
17
+ }
18
+ function resolveToCwd(filePath, cwd) {
19
+ const expanded = expandPath(filePath);
20
+ if (path.isAbsolute(expanded))
21
+ return expanded;
22
+ return path.resolve(cwd, expanded);
23
+ }
24
+ export function resolveSandboxPath(params) {
25
+ const resolved = resolveToCwd(params.filePath, params.cwd);
26
+ const rootResolved = path.resolve(params.root);
27
+ const relative = path.relative(rootResolved, resolved);
28
+ if (!relative || relative === "") {
29
+ return { resolved, relative: "" };
30
+ }
31
+ if (relative.startsWith("..") || path.isAbsolute(relative)) {
32
+ throw new Error(`Path escapes sandbox root (${shortPath(rootResolved)}): ${params.filePath}`);
33
+ }
34
+ return { resolved, relative };
35
+ }
36
+ export async function assertSandboxPath(params) {
37
+ const resolved = resolveSandboxPath(params);
38
+ await assertNoSymlink(resolved.relative, path.resolve(params.root));
39
+ return resolved;
40
+ }
41
+ async function assertNoSymlink(relative, root) {
42
+ if (!relative)
43
+ return;
44
+ const parts = relative.split(path.sep).filter(Boolean);
45
+ let current = root;
46
+ for (const part of parts) {
47
+ current = path.join(current, part);
48
+ try {
49
+ const stat = await fs.lstat(current);
50
+ if (stat.isSymbolicLink()) {
51
+ throw new Error(`Symlink not allowed in sandbox path: ${current}`);
52
+ }
53
+ }
54
+ catch (err) {
55
+ const anyErr = err;
56
+ if (anyErr.code === "ENOENT") {
57
+ return;
58
+ }
59
+ throw err;
60
+ }
61
+ }
62
+ }
63
+ function shortPath(value) {
64
+ if (value.startsWith(os.homedir())) {
65
+ return `~${value.slice(os.homedir().length)}`;
66
+ }
67
+ return value;
68
+ }