@poolzin/pool-bot 2026.2.11 → 2026.2.18

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 (535) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/agents/agent-scope.js +4 -0
  3. package/dist/agents/announce-idempotency.js +14 -0
  4. package/dist/agents/auth-profiles/usage.js +22 -0
  5. package/dist/agents/auth-profiles.js +1 -1
  6. package/dist/agents/auth-profiles.resolve-auth-profile-order.fixtures.js +23 -0
  7. package/dist/agents/bash-tools.exec-runtime.js +438 -0
  8. package/dist/agents/bash-tools.shared.js +6 -0
  9. package/dist/agents/cli-runner/reliability.js +61 -0
  10. package/dist/agents/cli-watchdog-defaults.js +11 -0
  11. package/dist/agents/command-poll-backoff.js +63 -0
  12. package/dist/agents/current-time.js +16 -0
  13. package/dist/agents/glob-pattern.js +42 -0
  14. package/dist/agents/memory-search.js +33 -0
  15. package/dist/agents/model-alias-lines.js +18 -0
  16. package/dist/agents/model-auth-label.js +61 -0
  17. package/dist/agents/model-fallback.js +59 -8
  18. package/dist/agents/models-config.e2e-harness.js +115 -0
  19. package/dist/agents/ollama-stream.js +11 -3
  20. package/dist/agents/openclaw-tools.js +135 -0
  21. package/dist/agents/pi-auth-json.js +118 -0
  22. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +147 -0
  23. package/dist/agents/pi-embedded-subscribe.e2e-harness.js +90 -0
  24. package/dist/agents/pi-embedded-subscribe.handlers.compaction.js +63 -0
  25. package/dist/agents/pi-embedded-subscribe.handlers.tools.media.test-helpers.js +30 -0
  26. package/dist/agents/pi-extensions/session-manager-runtime-registry.js +23 -0
  27. package/dist/agents/pi-tools.before-tool-call.js +145 -4
  28. package/dist/agents/pi-tools.js +29 -9
  29. package/dist/agents/pi-tools.policy.js +85 -92
  30. package/dist/agents/pi-tools.schema.js +54 -27
  31. package/dist/agents/queued-file-writer.js +22 -0
  32. package/dist/agents/sandbox/docker.js +133 -40
  33. package/dist/agents/sandbox/fs-bridge.js +146 -0
  34. package/dist/agents/sandbox/fs-paths.js +205 -0
  35. package/dist/agents/sandbox/hash.js +4 -0
  36. package/dist/agents/sandbox/validate-sandbox-security.js +157 -0
  37. package/dist/agents/sandbox-paths.js +3 -0
  38. package/dist/agents/sandbox-tool-policy.js +26 -0
  39. package/dist/agents/sanitize-for-prompt.js +18 -0
  40. package/dist/agents/session-dirs.js +20 -0
  41. package/dist/agents/session-write-lock.js +203 -39
  42. package/dist/agents/skills/filter.js +24 -0
  43. package/dist/agents/skills/tools-dir.js +9 -0
  44. package/dist/agents/skills-install-download.js +290 -0
  45. package/dist/agents/skills-install-output.js +30 -0
  46. package/dist/agents/skills-install.download-test-utils.js +36 -0
  47. package/dist/agents/skills.e2e-test-helpers.js +13 -0
  48. package/dist/agents/subagent-announce-queue.js +59 -15
  49. package/dist/agents/subagent-depth.js +137 -0
  50. package/dist/agents/subagent-registry.js +448 -96
  51. package/dist/agents/subagent-spawn.js +262 -0
  52. package/dist/agents/system-prompt.js +52 -10
  53. package/dist/agents/test-helpers/fast-tool-stubs.js +18 -0
  54. package/dist/agents/test-helpers/host-sandbox-fs-bridge.js +74 -0
  55. package/dist/agents/tool-display-common.js +782 -0
  56. package/dist/agents/tool-loop-detection.js +466 -0
  57. package/dist/agents/tool-policy.js +6 -0
  58. package/dist/agents/tools/image-tool.js +1 -1
  59. package/dist/agents/tools/sessions-access.js +178 -0
  60. package/dist/agents/tools/sessions-resolution.js +206 -0
  61. package/dist/agents/tools/subagents-tool.js +616 -0
  62. package/dist/agents/workspace-dir.js +18 -0
  63. package/dist/agents/workspace-dirs.js +14 -0
  64. package/dist/agents/workspace.js +70 -0
  65. package/dist/auto-reply/heartbeat-reply-payload.js +18 -0
  66. package/dist/auto-reply/reply/commands-export-session.js +163 -0
  67. package/dist/auto-reply/reply/commands-mesh.js +245 -0
  68. package/dist/auto-reply/reply/commands-setunset.js +28 -0
  69. package/dist/auto-reply/reply/commands-slash-parse.js +31 -0
  70. package/dist/auto-reply/reply/commands-system-prompt.js +117 -0
  71. package/dist/auto-reply/reply/directive-handling.levels.js +17 -0
  72. package/dist/auto-reply/reply/directive-handling.params.js +1 -0
  73. package/dist/auto-reply/reply/directive-parsing.js +36 -0
  74. package/dist/auto-reply/reply/dispatcher-registry.js +43 -0
  75. package/dist/auto-reply/reply/elevated-unavailable.js +20 -0
  76. package/dist/auto-reply/reply/post-compaction-audit.js +96 -0
  77. package/dist/auto-reply/reply/post-compaction-context.js +98 -0
  78. package/dist/auto-reply/reply/reply-delivery.js +92 -0
  79. package/dist/auto-reply/reply/session-reset-prompt.js +1 -0
  80. package/dist/auto-reply/reply/session-run-accounting.js +33 -0
  81. package/dist/auto-reply/reply.directive.directive-behavior.e2e-harness.js +115 -0
  82. package/dist/auto-reply/reply.directive.directive-behavior.e2e-mocks.js +12 -0
  83. package/dist/browser/bridge-auth-registry.js +26 -0
  84. package/dist/browser/client-actions-url.js +10 -0
  85. package/dist/browser/control-auth.js +73 -0
  86. package/dist/browser/csrf.js +64 -0
  87. package/dist/browser/http-auth.js +52 -0
  88. package/dist/browser/paths.js +37 -0
  89. package/dist/browser/proxy-files.js +32 -0
  90. package/dist/browser/pw-ai-state.js +7 -0
  91. package/dist/browser/resolved-config-refresh.js +42 -0
  92. package/dist/browser/routes/path-output.js +1 -0
  93. package/dist/browser/server-context.chrome-test-harness.js +20 -0
  94. package/dist/browser/server-middleware.js +31 -0
  95. package/dist/browser/test-port.js +16 -0
  96. package/dist/build-info.json +3 -3
  97. package/dist/canvas-host/file-resolver.js +43 -0
  98. package/dist/channels/account-summary.js +19 -0
  99. package/dist/channels/draft-stream-loop.js +77 -0
  100. package/dist/channels/plugins/account-helpers.js +26 -0
  101. package/dist/channels/telegram/allow-from.js +10 -0
  102. package/dist/cli/browser-cli-resize.js +22 -0
  103. package/dist/cli/browser-cli-shared.js +8 -0
  104. package/dist/cli/clawbot-cli.js +5 -0
  105. package/dist/cli/completion-cli.js +566 -0
  106. package/dist/cli/config-cli.js +63 -5
  107. package/dist/cli/daemon-cli/lifecycle-core.js +256 -0
  108. package/dist/cli/daemon-cli/register-service-commands.js +60 -0
  109. package/dist/cli/daemon-cli-compat.js +80 -0
  110. package/dist/cli/nodes-cli/pairing-render.js +26 -0
  111. package/dist/cli/program/action-reparse.js +17 -0
  112. package/dist/cli/program/command-registry.js +17 -0
  113. package/dist/cli/program/program-context.js +8 -0
  114. package/dist/cli/program/register.subclis.js +7 -0
  115. package/dist/cli/program/routes.js +233 -0
  116. package/dist/cli/qr-cli.js +132 -0
  117. package/dist/cli/requirements-test-fixtures.js +17 -0
  118. package/dist/cli/respawn-policy.js +4 -0
  119. package/dist/cli/shared/parse-port.js +18 -0
  120. package/dist/cli/skills-cli.format.js +241 -0
  121. package/dist/cli/update-cli/progress.js +121 -0
  122. package/dist/cli/update-cli/restart-helper.js +108 -0
  123. package/dist/cli/update-cli/shared.js +196 -0
  124. package/dist/cli/update-cli/status.js +97 -0
  125. package/dist/cli/update-cli/suppress-deprecations.js +17 -0
  126. package/dist/cli/update-cli/update-command.js +506 -0
  127. package/dist/cli/update-cli/wizard.js +130 -0
  128. package/dist/cli/update-cli.js +3 -9
  129. package/dist/cli/windows-argv.js +69 -0
  130. package/dist/commands/auth-choice-legacy.js +20 -0
  131. package/dist/commands/auth-choice.apply-helpers.js +8 -0
  132. package/dist/commands/channel-test-helpers.js +19 -0
  133. package/dist/commands/cleanup-plan.js +10 -0
  134. package/dist/commands/cleanup-utils.js +7 -0
  135. package/dist/commands/config-validation.js +15 -0
  136. package/dist/commands/doctor-completion.js +112 -0
  137. package/dist/commands/doctor-memory-search.js +119 -0
  138. package/dist/commands/doctor-session-locks.js +73 -0
  139. package/dist/commands/doctor.e2e-harness.js +364 -0
  140. package/dist/commands/gateway-presence.js +19 -0
  141. package/dist/commands/model-default.js +35 -0
  142. package/dist/commands/models/fallbacks-shared.js +102 -0
  143. package/dist/commands/models/shared.js +24 -0
  144. package/dist/commands/onboard-auth.config-gateways.js +64 -0
  145. package/dist/commands/onboard-auth.config-litellm.js +45 -0
  146. package/dist/commands/onboard-auth.config-shared.js +116 -0
  147. package/dist/commands/onboard-config.js +16 -0
  148. package/dist/commands/onboard-non-interactive.test-helpers.js +31 -0
  149. package/dist/commands/onboard-provider-auth-flags.js +136 -0
  150. package/dist/commands/openai-codex-oauth.js +40 -0
  151. package/dist/commands/test-runtime-config-helpers.js +21 -0
  152. package/dist/commands/test-wizard-helpers.js +68 -0
  153. package/dist/commands/vllm-setup.js +66 -0
  154. package/dist/compat/legacy-names.js +2 -0
  155. package/dist/config/backup-rotation.js +19 -0
  156. package/dist/config/env-preserve.js +122 -0
  157. package/dist/config/includes-scan.js +78 -0
  158. package/dist/config/plugins-allowlist.js +13 -0
  159. package/dist/config/schema.help.js +256 -0
  160. package/dist/config/schema.hints.js +189 -0
  161. package/dist/config/schema.irc.js +20 -0
  162. package/dist/config/schema.labels.js +317 -0
  163. package/dist/config/sessions/delivery-info.js +40 -0
  164. package/dist/config/types.irc.js +1 -0
  165. package/dist/config/zod-schema.agent-defaults.js +14 -0
  166. package/dist/config/zod-schema.agent-model.js +10 -0
  167. package/dist/config/zod-schema.agent-runtime.js +14 -0
  168. package/dist/config/zod-schema.allowdeny.js +35 -0
  169. package/dist/config/zod-schema.sensitive.js +4 -0
  170. package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
  171. package/dist/cron/isolated-agent/skills-snapshot.js +26 -0
  172. package/dist/cron/isolated-agent/subagent-followup.js +127 -0
  173. package/dist/cron/isolated-agent.mocks.js +12 -0
  174. package/dist/cron/isolated-agent.test-setup.js +22 -0
  175. package/dist/cron/legacy-delivery.js +43 -0
  176. package/dist/cron/webhook-url.js +22 -0
  177. package/dist/daemon/arg-split.js +40 -0
  178. package/dist/daemon/exec-file.js +23 -0
  179. package/dist/daemon/output.js +6 -0
  180. package/dist/daemon/runtime-format.js +31 -0
  181. package/dist/daemon/schtasks-exec.js +4 -0
  182. package/dist/daemon/service-audit.js +22 -0
  183. package/dist/discord/client.js +41 -0
  184. package/dist/discord/components-registry.js +57 -0
  185. package/dist/discord/components.js +816 -0
  186. package/dist/discord/guilds.js +12 -0
  187. package/dist/discord/monitor/gateway-plugin.js +48 -0
  188. package/dist/discord/monitor/presence.js +30 -0
  189. package/dist/discord/send.components.js +115 -0
  190. package/dist/discord/send.shared.js +4 -0
  191. package/dist/discord/ui.js +26 -0
  192. package/dist/discord/voice-message.js +254 -0
  193. package/dist/gateway/agent-event-assistant-text.js +5 -0
  194. package/dist/gateway/agent-prompt.js +33 -0
  195. package/dist/gateway/auth-rate-limit.js +136 -0
  196. package/dist/gateway/channel-health-monitor.js +114 -0
  197. package/dist/gateway/control-ui-contract.js +1 -0
  198. package/dist/gateway/control-ui-csp.js +15 -0
  199. package/dist/gateway/gateway-config-prompts.shared.js +25 -0
  200. package/dist/gateway/http-auth-helpers.js +18 -0
  201. package/dist/gateway/http-common.js +18 -0
  202. package/dist/gateway/http-endpoint-helpers.js +27 -0
  203. package/dist/gateway/node-invoke-sanitize.js +11 -0
  204. package/dist/gateway/node-invoke-system-run-approval.js +205 -0
  205. package/dist/gateway/probe-auth.js +21 -0
  206. package/dist/gateway/protocol/index.js +7 -2
  207. package/dist/gateway/protocol/schema/mesh.js +54 -0
  208. package/dist/gateway/protocol/schema/protocol-schemas.js +7 -0
  209. package/dist/gateway/protocol/schema.js +1 -0
  210. package/dist/gateway/server/ws-connection/auth-messages.js +54 -0
  211. package/dist/gateway/server-channels.js +11 -0
  212. package/dist/gateway/server-methods/attachment-normalize.js +16 -0
  213. package/dist/gateway/server-methods/base-hash.js +8 -0
  214. package/dist/gateway/server-methods/mesh.js +700 -0
  215. package/dist/gateway/server-methods/nodes.handlers.invoke-result.js +55 -0
  216. package/dist/gateway/server-methods/restart-request.js +13 -0
  217. package/dist/gateway/server-methods/validation.js +8 -0
  218. package/dist/gateway/server.agent.gateway-server-agent.mocks.js +35 -0
  219. package/dist/gateway/server.e2e-registry-helpers.js +1 -0
  220. package/dist/gateway/server.e2e-ws-harness.js +20 -0
  221. package/dist/gateway/test-helpers.js +2 -0
  222. package/dist/gateway/test-helpers.server.js +3 -1
  223. package/dist/gateway/test-http-response.js +12 -0
  224. package/dist/gateway/test-openai-responses-model.js +20 -0
  225. package/dist/gateway/test-temp-config.js +30 -0
  226. package/dist/gateway/test-with-server.js +32 -0
  227. package/dist/hooks/bundled/bootstrap-extra-files/handler.js +46 -0
  228. package/dist/imessage/monitor/abort-handler.js +23 -0
  229. package/dist/imessage/monitor/inbound-processing.js +346 -0
  230. package/dist/imessage/monitor/parse-notification.js +64 -0
  231. package/dist/imessage/target-parsing-helpers.js +92 -0
  232. package/dist/infra/archive.js +244 -20
  233. package/dist/infra/detect-package-manager.js +26 -0
  234. package/dist/infra/exec-approvals-allowlist.js +257 -0
  235. package/dist/infra/exec-approvals-analysis.js +770 -0
  236. package/dist/infra/exec-approvals.js +13 -0
  237. package/dist/infra/file-lock.js +1 -0
  238. package/dist/infra/gemini-auth.js +39 -0
  239. package/dist/infra/heartbeat-active-hours.js +85 -0
  240. package/dist/infra/heartbeat-events-filter.js +50 -0
  241. package/dist/infra/heartbeat-runner.test-utils.js +39 -0
  242. package/dist/infra/http-body.js +265 -0
  243. package/dist/infra/install-package-dir.js +50 -0
  244. package/dist/infra/install-safe-path.js +49 -0
  245. package/dist/infra/json-files.js +49 -0
  246. package/dist/infra/jsonl-socket.js +52 -0
  247. package/dist/infra/map-size.js +14 -0
  248. package/dist/infra/net/hostname.js +7 -0
  249. package/dist/infra/npm-registry-spec.js +39 -0
  250. package/dist/infra/openclaw-root.js +109 -0
  251. package/dist/infra/outbound/delivery-queue.js +214 -0
  252. package/dist/infra/outbound/identity.js +23 -0
  253. package/dist/infra/outbound/message-action-params.js +307 -0
  254. package/dist/infra/outbound/tool-payload.js +21 -0
  255. package/dist/infra/package-json.js +23 -0
  256. package/dist/infra/pairing-files.js +19 -0
  257. package/dist/infra/pairing-token.js +9 -0
  258. package/dist/infra/path-prepend.js +51 -0
  259. package/dist/infra/path-safety.js +16 -0
  260. package/dist/infra/process-respawn.js +49 -0
  261. package/dist/infra/runtime-status.js +16 -0
  262. package/dist/infra/session-cost-usage.types.js +1 -0
  263. package/dist/infra/session-maintenance-warning.js +89 -0
  264. package/dist/infra/system-run-command.js +78 -0
  265. package/dist/infra/tmp-openclaw-dir.js +81 -0
  266. package/dist/infra/tmp-poolbot-dir.js +2 -0
  267. package/dist/infra/update-channels.js +19 -0
  268. package/dist/line/actions.js +45 -0
  269. package/dist/line/channel-access-token.js +9 -0
  270. package/dist/line/flex-templates/basic-cards.js +332 -0
  271. package/dist/line/flex-templates/common.js +18 -0
  272. package/dist/line/flex-templates/media-control-cards.js +453 -0
  273. package/dist/line/flex-templates/message.js +10 -0
  274. package/dist/line/flex-templates/schedule-cards.js +399 -0
  275. package/dist/line/flex-templates/types.js +1 -0
  276. package/dist/line/webhook-node.js +100 -0
  277. package/dist/line/webhook-utils.js +11 -0
  278. package/dist/logging/diagnostic-session-state.js +73 -0
  279. package/dist/logging/diagnostic.js +22 -0
  280. package/dist/logging/timestamps.js +14 -0
  281. package/dist/markdown/whatsapp.js +62 -0
  282. package/dist/media/base64.js +34 -0
  283. package/dist/media/local-roots.js +32 -0
  284. package/dist/media/outbound-attachment.js +10 -0
  285. package/dist/media/read-response-with-limit.js +41 -0
  286. package/dist/media/sniff-mime-from-base64.js +19 -0
  287. package/dist/media-understanding/audio-preflight.js +67 -0
  288. package/dist/media-understanding/fs.js +13 -0
  289. package/dist/media-understanding/output-extract.js +26 -0
  290. package/dist/media-understanding/providers/audio.test-helpers.js +34 -0
  291. package/dist/media-understanding/providers/google/inline-data.js +64 -0
  292. package/dist/media-understanding/providers/shared.js +7 -0
  293. package/dist/media-understanding/runner.entries.js +459 -0
  294. package/dist/memory/batch-error-utils.js +11 -0
  295. package/dist/memory/batch-http.js +27 -0
  296. package/dist/memory/batch-output.js +29 -0
  297. package/dist/memory/batch-runner.js +22 -0
  298. package/dist/memory/batch-upload.js +23 -0
  299. package/dist/memory/batch-utils.js +26 -0
  300. package/dist/memory/embeddings-debug.js +11 -0
  301. package/dist/memory/embeddings-remote-client.js +22 -0
  302. package/dist/memory/embeddings-remote-fetch.js +14 -0
  303. package/dist/memory/embeddings.js +36 -9
  304. package/dist/memory/hybrid.js +24 -5
  305. package/dist/memory/manager-embedding-ops.js +616 -0
  306. package/dist/memory/manager-sync-ops.js +953 -0
  307. package/dist/memory/manager.js +76 -28
  308. package/dist/memory/mmr.js +164 -0
  309. package/dist/memory/qmd-manager.js +1061 -0
  310. package/dist/memory/qmd-query-parser.js +107 -0
  311. package/dist/memory/qmd-scope.js +93 -0
  312. package/dist/memory/query-expansion.js +331 -0
  313. package/dist/memory/search-manager.js +0 -1
  314. package/dist/memory/sync-index.js +21 -0
  315. package/dist/memory/sync-progress.js +22 -0
  316. package/dist/memory/sync-stale.js +30 -0
  317. package/dist/memory/temporal-decay.js +119 -0
  318. package/dist/memory/test-embeddings-mock.js +16 -0
  319. package/dist/memory/test-manager-helpers.js +14 -0
  320. package/dist/memory/test-runtime-mocks.js +11 -0
  321. package/dist/node-host/invoke-browser.js +177 -0
  322. package/dist/node-host/invoke.js +685 -0
  323. package/dist/pairing/setup-code.js +285 -0
  324. package/dist/plugin-sdk/account-id.js +1 -0
  325. package/dist/plugin-sdk/agent-media-payload.js +13 -0
  326. package/dist/plugin-sdk/allow-from.js +47 -0
  327. package/dist/plugin-sdk/command-auth.js +23 -0
  328. package/dist/plugin-sdk/config-paths.js +9 -0
  329. package/dist/plugin-sdk/file-lock.js +116 -0
  330. package/dist/plugin-sdk/json-store.js +31 -0
  331. package/dist/plugin-sdk/onboarding.js +28 -0
  332. package/dist/plugin-sdk/provider-auth-result.js +29 -0
  333. package/dist/plugin-sdk/slack-message-actions.js +133 -0
  334. package/dist/plugin-sdk/status-helpers.js +35 -0
  335. package/dist/plugin-sdk/text-chunking.js +31 -0
  336. package/dist/plugin-sdk/tool-send.js +12 -0
  337. package/dist/plugin-sdk/webhook-path.js +27 -0
  338. package/dist/plugin-sdk/webhook-targets.js +34 -0
  339. package/dist/plugins/hooks.test-helpers.js +21 -0
  340. package/dist/plugins/uninstall.js +171 -0
  341. package/dist/process/kill-tree.js +98 -0
  342. package/dist/process/supervisor/adapters/child.js +143 -0
  343. package/dist/process/supervisor/adapters/env.js +13 -0
  344. package/dist/process/supervisor/adapters/pty.js +148 -0
  345. package/dist/process/supervisor/index.js +10 -0
  346. package/dist/process/supervisor/registry.js +117 -0
  347. package/dist/process/supervisor/supervisor.js +244 -0
  348. package/dist/process/supervisor/types.js +1 -0
  349. package/dist/providers/google-shared.test-helpers.js +75 -0
  350. package/dist/security/audit-channel.js +419 -0
  351. package/dist/security/audit-tool-policy.js +1 -0
  352. package/dist/security/scan-paths.js +12 -0
  353. package/dist/sessions/input-provenance.js +55 -0
  354. package/dist/sessions/session-key-utils.js +7 -0
  355. package/dist/shared/chat-content.js +31 -0
  356. package/dist/shared/chat-envelope.js +45 -0
  357. package/dist/shared/config-eval.js +117 -0
  358. package/dist/shared/device-auth.js +16 -0
  359. package/dist/shared/entry-metadata.js +9 -0
  360. package/dist/shared/entry-status.js +25 -0
  361. package/dist/shared/frontmatter.js +98 -0
  362. package/dist/shared/model-param-b.js +19 -0
  363. package/dist/shared/net/ipv4.js +17 -0
  364. package/dist/shared/node-match.js +53 -0
  365. package/dist/shared/pid-alive.js +12 -0
  366. package/dist/shared/process-scoped-map.js +10 -0
  367. package/dist/shared/requirements.js +128 -0
  368. package/dist/shared/subagents-format.js +84 -0
  369. package/dist/shared/usage-aggregates.js +28 -0
  370. package/dist/signal/monitor/mentions.js +45 -0
  371. package/dist/signal/rpc-context.js +19 -0
  372. package/dist/slack/blocks-fallback.js +76 -0
  373. package/dist/slack/blocks-input.js +40 -0
  374. package/dist/slack/draft-stream.js +106 -0
  375. package/dist/slack/message-actions.js +51 -0
  376. package/dist/slack/modal-metadata.js +32 -0
  377. package/dist/slack/monitor/events/interactions.js +462 -0
  378. package/dist/slack/monitor/room-context.js +17 -0
  379. package/dist/slack/stream-mode.js +41 -0
  380. package/dist/telegram/bot-native-command-menu.js +64 -0
  381. package/dist/telegram/bot.media.e2e-harness.js +81 -0
  382. package/dist/telegram/button-types.js +1 -0
  383. package/dist/telegram/group-access.js +65 -0
  384. package/dist/telegram/outbound-params.js +21 -0
  385. package/dist/telegram/poll-vote-cache.js +21 -0
  386. package/dist/terminal/health-style.js +36 -0
  387. package/dist/test-utils/chunk-test-helpers.js +21 -0
  388. package/dist/test-utils/env.js +72 -0
  389. package/dist/test-utils/exec-assertions.js +12 -0
  390. package/dist/test-utils/imessage-test-plugin.js +54 -0
  391. package/dist/test-utils/mock-http-response.js +17 -0
  392. package/dist/test-utils/vitest-mock-fn.js +1 -0
  393. package/dist/tts/tts-core.js +550 -0
  394. package/dist/utils/chunk-items.js +10 -0
  395. package/dist/utils/reaction-level.js +52 -0
  396. package/dist/utils/safe-json.js +22 -0
  397. package/dist/utils/with-timeout.js +14 -0
  398. package/dist/web/media.js +17 -5
  399. package/dist/whatsapp/resolve-outbound-target.js +42 -0
  400. package/dist/wizard/onboarding.completion.js +74 -0
  401. package/extensions/bluebubbles/package.json +1 -1
  402. package/extensions/bluebubbles/src/account-resolve.ts +29 -0
  403. package/extensions/bluebubbles/src/monitor-normalize.ts +796 -0
  404. package/extensions/bluebubbles/src/monitor-processing.ts +1007 -0
  405. package/extensions/bluebubbles/src/monitor-reply-cache.ts +185 -0
  406. package/extensions/bluebubbles/src/monitor-shared.ts +51 -0
  407. package/extensions/bluebubbles/src/multipart.ts +32 -0
  408. package/extensions/bluebubbles/src/send-helpers.ts +53 -0
  409. package/extensions/bluebubbles/src/test-harness.ts +50 -0
  410. package/extensions/bluebubbles/src/test-mocks.ts +11 -0
  411. package/extensions/copilot-proxy/package.json +1 -1
  412. package/extensions/device-pair/index.ts +554 -0
  413. package/extensions/diagnostics-otel/package.json +1 -1
  414. package/extensions/discord/package.json +1 -1
  415. package/extensions/discord/src/channel.js +366 -0
  416. package/extensions/discord/src/runtime.js +10 -0
  417. package/extensions/feishu/index.ts +63 -0
  418. package/extensions/feishu/src/accounts.ts +114 -0
  419. package/extensions/feishu/src/bitable.ts +739 -0
  420. package/extensions/feishu/src/bot.ts +965 -0
  421. package/extensions/feishu/src/channel.ts +351 -0
  422. package/extensions/feishu/src/client.ts +118 -0
  423. package/extensions/feishu/src/config-schema.ts +206 -0
  424. package/extensions/feishu/src/dedup.ts +33 -0
  425. package/extensions/feishu/src/directory.ts +177 -0
  426. package/extensions/feishu/src/doc-schema.ts +47 -0
  427. package/extensions/feishu/src/docx.ts +536 -0
  428. package/extensions/feishu/src/drive-schema.ts +46 -0
  429. package/extensions/feishu/src/drive.ts +227 -0
  430. package/extensions/feishu/src/dynamic-agent.ts +131 -0
  431. package/extensions/feishu/src/media.ts +449 -0
  432. package/extensions/feishu/src/mention.ts +126 -0
  433. package/extensions/feishu/src/monitor.ts +330 -0
  434. package/extensions/feishu/src/onboarding.ts +359 -0
  435. package/extensions/feishu/src/outbound.ts +55 -0
  436. package/extensions/feishu/src/perm-schema.ts +52 -0
  437. package/extensions/feishu/src/perm.ts +173 -0
  438. package/extensions/feishu/src/policy.ts +84 -0
  439. package/extensions/feishu/src/probe.ts +44 -0
  440. package/extensions/feishu/src/reactions.ts +160 -0
  441. package/extensions/feishu/src/reply-dispatcher.ts +239 -0
  442. package/extensions/feishu/src/runtime.ts +14 -0
  443. package/extensions/feishu/src/send-result.ts +29 -0
  444. package/extensions/feishu/src/send.ts +335 -0
  445. package/extensions/feishu/src/streaming-card.ts +223 -0
  446. package/extensions/feishu/src/targets.ts +78 -0
  447. package/extensions/feishu/src/tools-config.ts +21 -0
  448. package/extensions/feishu/src/types.ts +81 -0
  449. package/extensions/feishu/src/typing.ts +80 -0
  450. package/extensions/feishu/src/wiki-schema.ts +55 -0
  451. package/extensions/feishu/src/wiki.ts +232 -0
  452. package/extensions/google-antigravity-auth/package.json +1 -1
  453. package/extensions/google-gemini-cli-auth/package.json +1 -1
  454. package/extensions/googlechat/package.json +1 -1
  455. package/extensions/imessage/package.json +1 -1
  456. package/extensions/imessage/src/channel.js +253 -0
  457. package/extensions/imessage/src/runtime.js +10 -0
  458. package/extensions/irc/index.ts +17 -0
  459. package/extensions/irc/src/accounts.ts +268 -0
  460. package/extensions/irc/src/channel.ts +367 -0
  461. package/extensions/irc/src/client.ts +439 -0
  462. package/extensions/irc/src/config-schema.ts +97 -0
  463. package/extensions/irc/src/connect-options.ts +30 -0
  464. package/extensions/irc/src/control-chars.ts +22 -0
  465. package/extensions/irc/src/inbound.ts +334 -0
  466. package/extensions/irc/src/monitor.ts +147 -0
  467. package/extensions/irc/src/normalize.ts +117 -0
  468. package/extensions/irc/src/onboarding.ts +479 -0
  469. package/extensions/irc/src/policy.ts +157 -0
  470. package/extensions/irc/src/probe.ts +53 -0
  471. package/extensions/irc/src/protocol.ts +169 -0
  472. package/extensions/irc/src/runtime.ts +14 -0
  473. package/extensions/irc/src/send.ts +88 -0
  474. package/extensions/irc/src/types.ts +93 -0
  475. package/extensions/line/package.json +1 -1
  476. package/extensions/llm-task/package.json +1 -1
  477. package/extensions/lobster/package.json +1 -1
  478. package/extensions/matrix/CHANGELOG.md +5 -0
  479. package/extensions/matrix/package.json +1 -1
  480. package/extensions/matrix/src/matrix/client-bootstrap.ts +39 -0
  481. package/extensions/mattermost/package.json +1 -1
  482. package/extensions/mattermost/src/mattermost/monitor-onchar.ts +25 -0
  483. package/extensions/mattermost/src/mattermost/monitor-websocket.ts +221 -0
  484. package/extensions/mattermost/src/mattermost/reactions.ts +130 -0
  485. package/extensions/mattermost/src/mattermost/reconnect.ts +103 -0
  486. package/extensions/memory-core/package.json +1 -1
  487. package/extensions/memory-lancedb/package.json +1 -1
  488. package/extensions/minimax-portal-auth/index.ts +161 -0
  489. package/extensions/minimax-portal-auth/oauth.ts +247 -0
  490. package/extensions/msteams/CHANGELOG.md +5 -0
  491. package/extensions/msteams/package.json +1 -1
  492. package/extensions/msteams/src/file-lock.ts +1 -0
  493. package/extensions/msteams/src/graph.ts +92 -0
  494. package/extensions/msteams/src/mentions.ts +114 -0
  495. package/extensions/msteams/src/test-runtime.ts +16 -0
  496. package/extensions/nextcloud-talk/package.json +1 -1
  497. package/extensions/nostr/CHANGELOG.md +5 -0
  498. package/extensions/nostr/package.json +1 -1
  499. package/extensions/open-prose/package.json +1 -1
  500. package/extensions/openai-codex-auth/index.ts +177 -0
  501. package/extensions/phone-control/index.ts +421 -0
  502. package/extensions/shared/resolve-target-test-helpers.ts +66 -0
  503. package/extensions/signal/package.json +1 -1
  504. package/extensions/signal/src/channel.js +273 -0
  505. package/extensions/signal/src/runtime.js +10 -0
  506. package/extensions/slack/package.json +1 -1
  507. package/extensions/slack/src/channel.js +489 -0
  508. package/extensions/slack/src/runtime.js +10 -0
  509. package/extensions/talk-voice/index.ts +150 -0
  510. package/extensions/telegram/package.json +1 -1
  511. package/extensions/telegram/src/channel.js +424 -0
  512. package/extensions/telegram/src/runtime.js +10 -0
  513. package/extensions/thread-ownership/index.ts +133 -0
  514. package/extensions/tlon/package.json +1 -1
  515. package/extensions/tlon/src/account-fields.ts +25 -0
  516. package/extensions/tlon/src/urbit/base-url.ts +57 -0
  517. package/extensions/tlon/src/urbit/channel-client.ts +157 -0
  518. package/extensions/tlon/src/urbit/channel-ops.ts +164 -0
  519. package/extensions/tlon/src/urbit/context.ts +47 -0
  520. package/extensions/tlon/src/urbit/errors.ts +51 -0
  521. package/extensions/tlon/src/urbit/fetch.ts +39 -0
  522. package/extensions/twitch/CHANGELOG.md +5 -0
  523. package/extensions/twitch/package.json +1 -1
  524. package/extensions/twitch/src/test-fixtures.ts +30 -0
  525. package/extensions/voice-call/CHANGELOG.md +5 -0
  526. package/extensions/voice-call/package.json +1 -1
  527. package/extensions/voice-call/src/allowlist.ts +19 -0
  528. package/extensions/whatsapp/package.json +1 -1
  529. package/extensions/whatsapp/src/channel.js +429 -0
  530. package/extensions/whatsapp/src/runtime.js +10 -0
  531. package/extensions/zalo/CHANGELOG.md +5 -0
  532. package/extensions/zalo/package.json +1 -1
  533. package/extensions/zalouser/CHANGELOG.md +5 -0
  534. package/extensions/zalouser/package.json +1 -1
  535. package/package.json +1 -1
@@ -1,44 +1,118 @@
1
1
  import { spawn } from "node:child_process";
2
- import { defaultRuntime } from "../../runtime.js";
3
- import { formatCliCommand } from "../../cli/command-format.js";
4
- import { DEFAULT_SANDBOX_IMAGE, SANDBOX_AGENT_WORKSPACE_MOUNT } from "./constants.js";
5
- import { readRegistry, updateRegistry } from "./registry.js";
6
- import { computeSandboxConfigHash } from "./config-hash.js";
7
- import { resolveSandboxAgentId, resolveSandboxScopeKey, slugifySessionKey } from "./shared.js";
8
- const HOT_CONTAINER_WINDOW_MS = 5 * 60 * 1000;
9
- export function execDocker(args, opts) {
2
+ function createAbortError() {
3
+ const err = new Error("Aborted");
4
+ err.name = "AbortError";
5
+ return err;
6
+ }
7
+ export function execDockerRaw(args, opts) {
10
8
  return new Promise((resolve, reject) => {
11
9
  const child = spawn("docker", args, {
12
- stdio: ["ignore", "pipe", "pipe"],
10
+ stdio: ["pipe", "pipe", "pipe"],
13
11
  });
14
- let stdout = "";
15
- let stderr = "";
12
+ const stdoutChunks = [];
13
+ const stderrChunks = [];
14
+ let aborted = false;
15
+ const signal = opts?.signal;
16
+ const handleAbort = () => {
17
+ if (aborted) {
18
+ return;
19
+ }
20
+ aborted = true;
21
+ child.kill("SIGTERM");
22
+ };
23
+ if (signal) {
24
+ if (signal.aborted) {
25
+ handleAbort();
26
+ }
27
+ else {
28
+ signal.addEventListener("abort", handleAbort);
29
+ }
30
+ }
16
31
  child.stdout?.on("data", (chunk) => {
17
- stdout += chunk.toString();
32
+ stdoutChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
18
33
  });
19
34
  child.stderr?.on("data", (chunk) => {
20
- stderr += chunk.toString();
35
+ stderrChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
36
+ });
37
+ child.on("error", (error) => {
38
+ if (signal) {
39
+ signal.removeEventListener("abort", handleAbort);
40
+ }
41
+ reject(error);
21
42
  });
22
43
  child.on("close", (code) => {
44
+ if (signal) {
45
+ signal.removeEventListener("abort", handleAbort);
46
+ }
47
+ const stdout = Buffer.concat(stdoutChunks);
48
+ const stderr = Buffer.concat(stderrChunks);
49
+ if (aborted || signal?.aborted) {
50
+ reject(createAbortError());
51
+ return;
52
+ }
23
53
  const exitCode = code ?? 0;
24
54
  if (exitCode !== 0 && !opts?.allowFailure) {
25
- reject(new Error(stderr.trim() || `docker ${args.join(" ")} failed`));
55
+ const message = stderr.length > 0 ? stderr.toString("utf8").trim() : "";
56
+ const error = Object.assign(new Error(message || `docker ${args.join(" ")} failed`), {
57
+ code: exitCode,
58
+ stdout,
59
+ stderr,
60
+ });
61
+ reject(error);
26
62
  return;
27
63
  }
28
64
  resolve({ stdout, stderr, code: exitCode });
29
65
  });
66
+ const stdin = child.stdin;
67
+ if (stdin) {
68
+ if (opts?.input !== undefined) {
69
+ stdin.end(opts.input);
70
+ }
71
+ else {
72
+ stdin.end();
73
+ }
74
+ }
30
75
  });
31
76
  }
77
+ import { formatCliCommand } from "../../cli/command-format.js";
78
+ import { defaultRuntime } from "../../runtime.js";
79
+ import { computeSandboxConfigHash } from "./config-hash.js";
80
+ import { DEFAULT_SANDBOX_IMAGE, SANDBOX_AGENT_WORKSPACE_MOUNT } from "./constants.js";
81
+ import { readRegistry, updateRegistry } from "./registry.js";
82
+ import { resolveSandboxAgentId, resolveSandboxScopeKey, slugifySessionKey } from "./shared.js";
83
+ import { validateSandboxSecurity } from "./validate-sandbox-security.js";
84
+ const HOT_CONTAINER_WINDOW_MS = 5 * 60 * 1000;
85
+ export async function execDocker(args, opts) {
86
+ const result = await execDockerRaw(args, opts);
87
+ return {
88
+ stdout: result.stdout.toString("utf8"),
89
+ stderr: result.stderr.toString("utf8"),
90
+ code: result.code,
91
+ };
92
+ }
93
+ export async function readDockerContainerLabel(containerName, label) {
94
+ const result = await execDocker(["inspect", "-f", `{{ index .Config.Labels "${label}" }}`, containerName], { allowFailure: true });
95
+ if (result.code !== 0) {
96
+ return null;
97
+ }
98
+ const raw = result.stdout.trim();
99
+ if (!raw || raw === "<no value>") {
100
+ return null;
101
+ }
102
+ return raw;
103
+ }
32
104
  export async function readDockerPort(containerName, port) {
33
105
  const result = await execDocker(["port", containerName, `${port}/tcp`], {
34
106
  allowFailure: true,
35
107
  });
36
- if (result.code !== 0)
108
+ if (result.code !== 0) {
37
109
  return null;
110
+ }
38
111
  const line = result.stdout.trim().split(/\r?\n/)[0] ?? "";
39
112
  const match = line.match(/:(\d+)\s*$/);
40
- if (!match)
113
+ if (!match) {
41
114
  return null;
115
+ }
42
116
  const mapped = Number.parseInt(match[1] ?? "", 10);
43
117
  return Number.isFinite(mapped) ? mapped : null;
44
118
  }
@@ -46,8 +120,9 @@ async function dockerImageExists(image) {
46
120
  const result = await execDocker(["image", "inspect", image], {
47
121
  allowFailure: true,
48
122
  });
49
- if (result.code === 0)
123
+ if (result.code === 0) {
50
124
  return true;
125
+ }
51
126
  const stderr = result.stderr.trim();
52
127
  if (stderr.includes("No such image")) {
53
128
  return false;
@@ -56,8 +131,9 @@ async function dockerImageExists(image) {
56
131
  }
57
132
  export async function ensureDockerImage(image) {
58
133
  const exists = await dockerImageExists(image);
59
- if (exists)
134
+ if (exists) {
60
135
  return;
136
+ }
61
137
  if (image === DEFAULT_SANDBOX_IMAGE) {
62
138
  await execDocker(["pull", "debian:bookworm-slim"]);
63
139
  await execDocker(["tag", "debian:bookworm-slim", DEFAULT_SANDBOX_IMAGE]);
@@ -69,13 +145,15 @@ export async function dockerContainerState(name) {
69
145
  const result = await execDocker(["inspect", "-f", "{{.State.Running}}", name], {
70
146
  allowFailure: true,
71
147
  });
72
- if (result.code !== 0)
148
+ if (result.code !== 0) {
73
149
  return { exists: false, running: false };
150
+ }
74
151
  return { exists: true, running: result.stdout.trim() === "true" };
75
152
  }
76
153
  function normalizeDockerLimit(value) {
77
- if (value === undefined || value === null)
154
+ if (value === undefined || value === null) {
78
155
  return undefined;
156
+ }
79
157
  if (typeof value === "number") {
80
158
  return Number.isFinite(value) ? String(value) : undefined;
81
159
  }
@@ -83,23 +161,29 @@ function normalizeDockerLimit(value) {
83
161
  return trimmed ? trimmed : undefined;
84
162
  }
85
163
  function formatUlimitValue(name, value) {
86
- if (!name.trim())
164
+ if (!name.trim()) {
87
165
  return null;
166
+ }
88
167
  if (typeof value === "number" || typeof value === "string") {
89
168
  const raw = String(value).trim();
90
169
  return raw ? `${name}=${raw}` : null;
91
170
  }
92
171
  const soft = typeof value.soft === "number" ? Math.max(0, value.soft) : undefined;
93
172
  const hard = typeof value.hard === "number" ? Math.max(0, value.hard) : undefined;
94
- if (soft === undefined && hard === undefined)
173
+ if (soft === undefined && hard === undefined) {
95
174
  return null;
96
- if (soft === undefined)
175
+ }
176
+ if (soft === undefined) {
97
177
  return `${name}=${hard}`;
98
- if (hard === undefined)
178
+ }
179
+ if (hard === undefined) {
99
180
  return `${name}=${soft}`;
181
+ }
100
182
  return `${name}=${soft}:${hard}`;
101
183
  }
102
184
  export function buildSandboxCreateArgs(params) {
185
+ // Runtime security validation: blocks dangerous bind mounts, network modes, and profiles.
186
+ validateSandboxSecurity(params.cfg);
103
187
  const createdAtMs = params.createdAtMs ?? Date.now();
104
188
  const args = ["create", "--name", params.name];
105
189
  args.push("--label", "poolbot.sandbox=1");
@@ -109,18 +193,28 @@ export function buildSandboxCreateArgs(params) {
109
193
  args.push("--label", `poolbot.configHash=${params.configHash}`);
110
194
  }
111
195
  for (const [key, value] of Object.entries(params.labels ?? {})) {
112
- if (key && value)
196
+ if (key && value) {
113
197
  args.push("--label", `${key}=${value}`);
198
+ }
114
199
  }
115
- if (params.cfg.readOnlyRoot)
200
+ if (params.cfg.readOnlyRoot) {
116
201
  args.push("--read-only");
202
+ }
117
203
  for (const entry of params.cfg.tmpfs) {
118
204
  args.push("--tmpfs", entry);
119
205
  }
120
- if (params.cfg.network)
206
+ if (params.cfg.network) {
121
207
  args.push("--network", params.cfg.network);
122
- if (params.cfg.user)
208
+ }
209
+ if (params.cfg.user) {
123
210
  args.push("--user", params.cfg.user);
211
+ }
212
+ for (const [key, value] of Object.entries(params.cfg.env ?? {})) {
213
+ if (!key.trim()) {
214
+ continue;
215
+ }
216
+ args.push("--env", key + "=" + value);
217
+ }
124
218
  for (const cap of params.cfg.capDrop) {
125
219
  args.push("--cap-drop", cap);
126
220
  }
@@ -132,29 +226,34 @@ export function buildSandboxCreateArgs(params) {
132
226
  args.push("--security-opt", `apparmor=${params.cfg.apparmorProfile}`);
133
227
  }
134
228
  for (const entry of params.cfg.dns ?? []) {
135
- if (entry.trim())
229
+ if (entry.trim()) {
136
230
  args.push("--dns", entry);
231
+ }
137
232
  }
138
233
  for (const entry of params.cfg.extraHosts ?? []) {
139
- if (entry.trim())
234
+ if (entry.trim()) {
140
235
  args.push("--add-host", entry);
236
+ }
141
237
  }
142
238
  if (typeof params.cfg.pidsLimit === "number" && params.cfg.pidsLimit > 0) {
143
239
  args.push("--pids-limit", String(params.cfg.pidsLimit));
144
240
  }
145
241
  const memory = normalizeDockerLimit(params.cfg.memory);
146
- if (memory)
242
+ if (memory) {
147
243
  args.push("--memory", memory);
244
+ }
148
245
  const memorySwap = normalizeDockerLimit(params.cfg.memorySwap);
149
- if (memorySwap)
246
+ if (memorySwap) {
150
247
  args.push("--memory-swap", memorySwap);
248
+ }
151
249
  if (typeof params.cfg.cpus === "number" && params.cfg.cpus > 0) {
152
250
  args.push("--cpus", String(params.cfg.cpus));
153
251
  }
154
252
  for (const [name, value] of Object.entries(params.cfg.ulimits ?? {})) {
155
253
  const formatted = formatUlimitValue(name, value);
156
- if (formatted)
254
+ if (formatted) {
157
255
  args.push("--ulimit", formatted);
256
+ }
158
257
  }
159
258
  if (params.cfg.binds?.length) {
160
259
  for (const bind of params.cfg.binds) {
@@ -187,13 +286,7 @@ async function createSandboxContainer(params) {
187
286
  }
188
287
  }
189
288
  async function readContainerConfigHash(containerName) {
190
- const result = await execDocker(["inspect", "-f", '{{ index .Config.Labels "poolbot.configHash" }}', containerName], { allowFailure: true });
191
- if (result.code !== 0)
192
- return null;
193
- const raw = result.stdout.trim();
194
- if (!raw || raw === "<no value>")
195
- return null;
196
- return raw;
289
+ return await readDockerContainerLabel(containerName, "poolbot.configHash");
197
290
  }
198
291
  function formatSandboxRecreateHint(params) {
199
292
  if (params.scope === "session") {
@@ -0,0 +1,146 @@
1
+ import { execDockerRaw } from "./docker.js";
2
+ import { buildSandboxFsMounts, resolveSandboxFsPathWithMounts, } from "./fs-paths.js";
3
+ export function createSandboxFsBridge(params) {
4
+ return new SandboxFsBridgeImpl(params.sandbox);
5
+ }
6
+ class SandboxFsBridgeImpl {
7
+ sandbox;
8
+ mounts;
9
+ constructor(sandbox) {
10
+ this.sandbox = sandbox;
11
+ this.mounts = buildSandboxFsMounts(sandbox);
12
+ }
13
+ resolvePath(params) {
14
+ const target = this.resolveResolvedPath(params);
15
+ return {
16
+ hostPath: target.hostPath,
17
+ relativePath: target.relativePath,
18
+ containerPath: target.containerPath,
19
+ };
20
+ }
21
+ async readFile(params) {
22
+ const target = this.resolveResolvedPath(params);
23
+ const result = await this.runCommand('set -eu; cat -- "$1"', {
24
+ args: [target.containerPath],
25
+ signal: params.signal,
26
+ });
27
+ return result.stdout;
28
+ }
29
+ async writeFile(params) {
30
+ const target = this.resolveResolvedPath(params);
31
+ this.ensureWriteAccess(target, "write files");
32
+ const buffer = Buffer.isBuffer(params.data)
33
+ ? params.data
34
+ : Buffer.from(params.data, params.encoding ?? "utf8");
35
+ const script = params.mkdir === false
36
+ ? 'set -eu; cat >"$1"'
37
+ : 'set -eu; dir=$(dirname -- "$1"); if [ "$dir" != "." ]; then mkdir -p -- "$dir"; fi; cat >"$1"';
38
+ await this.runCommand(script, {
39
+ args: [target.containerPath],
40
+ stdin: buffer,
41
+ signal: params.signal,
42
+ });
43
+ }
44
+ async mkdirp(params) {
45
+ const target = this.resolveResolvedPath(params);
46
+ this.ensureWriteAccess(target, "create directories");
47
+ await this.runCommand('set -eu; mkdir -p -- "$1"', {
48
+ args: [target.containerPath],
49
+ signal: params.signal,
50
+ });
51
+ }
52
+ async remove(params) {
53
+ const target = this.resolveResolvedPath(params);
54
+ this.ensureWriteAccess(target, "remove files");
55
+ const flags = [params.force === false ? "" : "-f", params.recursive ? "-r" : ""].filter(Boolean);
56
+ const rmCommand = flags.length > 0 ? `rm ${flags.join(" ")}` : "rm";
57
+ await this.runCommand(`set -eu; ${rmCommand} -- "$1"`, {
58
+ args: [target.containerPath],
59
+ signal: params.signal,
60
+ });
61
+ }
62
+ async rename(params) {
63
+ const from = this.resolveResolvedPath({ filePath: params.from, cwd: params.cwd });
64
+ const to = this.resolveResolvedPath({ filePath: params.to, cwd: params.cwd });
65
+ this.ensureWriteAccess(from, "rename files");
66
+ this.ensureWriteAccess(to, "rename files");
67
+ await this.runCommand('set -eu; dir=$(dirname -- "$2"); if [ "$dir" != "." ]; then mkdir -p -- "$dir"; fi; mv -- "$1" "$2"', {
68
+ args: [from.containerPath, to.containerPath],
69
+ signal: params.signal,
70
+ });
71
+ }
72
+ async stat(params) {
73
+ const target = this.resolveResolvedPath(params);
74
+ const result = await this.runCommand('set -eu; stat -c "%F|%s|%Y" -- "$1"', {
75
+ args: [target.containerPath],
76
+ signal: params.signal,
77
+ allowFailure: true,
78
+ });
79
+ if (result.code !== 0) {
80
+ const stderr = result.stderr.toString("utf8");
81
+ if (stderr.includes("No such file or directory")) {
82
+ return null;
83
+ }
84
+ const message = stderr.trim() || `stat failed with code ${result.code}`;
85
+ throw new Error(`stat failed for ${target.containerPath}: ${message}`);
86
+ }
87
+ const text = result.stdout.toString("utf8").trim();
88
+ const [typeRaw, sizeRaw, mtimeRaw] = text.split("|");
89
+ const size = Number.parseInt(sizeRaw ?? "0", 10);
90
+ const mtime = Number.parseInt(mtimeRaw ?? "0", 10) * 1000;
91
+ return {
92
+ type: coerceStatType(typeRaw),
93
+ size: Number.isFinite(size) ? size : 0,
94
+ mtimeMs: Number.isFinite(mtime) ? mtime : 0,
95
+ };
96
+ }
97
+ async runCommand(script, options = {}) {
98
+ const dockerArgs = [
99
+ "exec",
100
+ "-i",
101
+ this.sandbox.containerName,
102
+ "sh",
103
+ "-c",
104
+ script,
105
+ "moltbot-sandbox-fs",
106
+ ];
107
+ if (options.args?.length) {
108
+ dockerArgs.push(...options.args);
109
+ }
110
+ return execDockerRaw(dockerArgs, {
111
+ input: options.stdin,
112
+ allowFailure: options.allowFailure,
113
+ signal: options.signal,
114
+ });
115
+ }
116
+ ensureWriteAccess(target, action) {
117
+ if (!allowsWrites(this.sandbox.workspaceAccess) || !target.writable) {
118
+ throw new Error(`Sandbox path is read-only; cannot ${action}: ${target.containerPath}`);
119
+ }
120
+ }
121
+ resolveResolvedPath(params) {
122
+ return resolveSandboxFsPathWithMounts({
123
+ filePath: params.filePath,
124
+ cwd: params.cwd ?? this.sandbox.workspaceDir,
125
+ defaultWorkspaceRoot: this.sandbox.workspaceDir,
126
+ defaultContainerRoot: this.sandbox.containerWorkdir,
127
+ mounts: this.mounts,
128
+ });
129
+ }
130
+ }
131
+ function allowsWrites(access) {
132
+ return access === "rw";
133
+ }
134
+ function coerceStatType(typeRaw) {
135
+ if (!typeRaw) {
136
+ return "other";
137
+ }
138
+ const normalized = typeRaw.trim().toLowerCase();
139
+ if (normalized.includes("directory")) {
140
+ return "directory";
141
+ }
142
+ if (normalized.includes("file")) {
143
+ return "file";
144
+ }
145
+ return "other";
146
+ }
@@ -0,0 +1,205 @@
1
+ import path from "node:path";
2
+ import { resolveSandboxInputPath, resolveSandboxPath } from "../sandbox-paths.js";
3
+ import { SANDBOX_AGENT_WORKSPACE_MOUNT } from "./constants.js";
4
+ export function parseSandboxBindMount(spec) {
5
+ const trimmed = spec.trim();
6
+ if (!trimmed) {
7
+ return null;
8
+ }
9
+ const parsed = splitBindSpec(trimmed);
10
+ if (!parsed) {
11
+ return null;
12
+ }
13
+ const hostToken = parsed.host.trim();
14
+ const containerToken = parsed.container.trim();
15
+ if (!hostToken || !containerToken || !path.posix.isAbsolute(containerToken)) {
16
+ return null;
17
+ }
18
+ const optionsToken = parsed.options.trim().toLowerCase();
19
+ const optionParts = optionsToken
20
+ ? optionsToken
21
+ .split(",")
22
+ .map((entry) => entry.trim())
23
+ .filter(Boolean)
24
+ : [];
25
+ const writable = !optionParts.includes("ro");
26
+ return {
27
+ hostRoot: path.resolve(hostToken),
28
+ containerRoot: normalizeContainerPath(containerToken),
29
+ writable,
30
+ };
31
+ }
32
+ function splitBindSpec(spec) {
33
+ const separator = getHostContainerSeparatorIndex(spec);
34
+ if (separator === -1) {
35
+ return null;
36
+ }
37
+ const host = spec.slice(0, separator);
38
+ const rest = spec.slice(separator + 1);
39
+ const optionsStart = rest.indexOf(":");
40
+ if (optionsStart === -1) {
41
+ return { host, container: rest, options: "" };
42
+ }
43
+ return {
44
+ host,
45
+ container: rest.slice(0, optionsStart),
46
+ options: rest.slice(optionsStart + 1),
47
+ };
48
+ }
49
+ function getHostContainerSeparatorIndex(spec) {
50
+ const hasDriveLetterPrefix = /^[A-Za-z]:[\\/]/.test(spec);
51
+ for (let i = hasDriveLetterPrefix ? 2 : 0; i < spec.length; i += 1) {
52
+ if (spec[i] === ":") {
53
+ return i;
54
+ }
55
+ }
56
+ return -1;
57
+ }
58
+ export function buildSandboxFsMounts(sandbox) {
59
+ const mounts = [
60
+ {
61
+ hostRoot: path.resolve(sandbox.workspaceDir),
62
+ containerRoot: normalizeContainerPath(sandbox.containerWorkdir),
63
+ writable: sandbox.workspaceAccess === "rw",
64
+ source: "workspace",
65
+ },
66
+ ];
67
+ if (sandbox.workspaceAccess !== "none" &&
68
+ path.resolve(sandbox.agentWorkspaceDir) !== path.resolve(sandbox.workspaceDir)) {
69
+ mounts.push({
70
+ hostRoot: path.resolve(sandbox.agentWorkspaceDir),
71
+ containerRoot: SANDBOX_AGENT_WORKSPACE_MOUNT,
72
+ writable: sandbox.workspaceAccess === "rw",
73
+ source: "agent",
74
+ });
75
+ }
76
+ for (const bind of sandbox.docker.binds ?? []) {
77
+ const parsed = parseSandboxBindMount(bind);
78
+ if (!parsed) {
79
+ continue;
80
+ }
81
+ mounts.push({
82
+ hostRoot: parsed.hostRoot,
83
+ containerRoot: parsed.containerRoot,
84
+ writable: parsed.writable,
85
+ source: "bind",
86
+ });
87
+ }
88
+ return dedupeMounts(mounts);
89
+ }
90
+ export function resolveSandboxFsPathWithMounts(params) {
91
+ const mountsByContainer = [...params.mounts].toSorted((a, b) => b.containerRoot.length - a.containerRoot.length);
92
+ const mountsByHost = [...params.mounts].toSorted((a, b) => b.hostRoot.length - a.hostRoot.length);
93
+ const input = params.filePath;
94
+ const inputPosix = normalizePosixInput(input);
95
+ if (path.posix.isAbsolute(inputPosix)) {
96
+ const containerMount = findMountByContainerPath(mountsByContainer, inputPosix);
97
+ if (containerMount) {
98
+ const rel = path.posix.relative(containerMount.containerRoot, inputPosix);
99
+ const hostPath = rel
100
+ ? path.resolve(containerMount.hostRoot, ...toHostSegments(rel))
101
+ : containerMount.hostRoot;
102
+ return {
103
+ hostPath,
104
+ containerPath: rel
105
+ ? path.posix.join(containerMount.containerRoot, rel)
106
+ : containerMount.containerRoot,
107
+ relativePath: toDisplayRelative({
108
+ containerPath: rel
109
+ ? path.posix.join(containerMount.containerRoot, rel)
110
+ : containerMount.containerRoot,
111
+ defaultContainerRoot: params.defaultContainerRoot,
112
+ }),
113
+ writable: containerMount.writable,
114
+ };
115
+ }
116
+ }
117
+ const hostResolved = resolveSandboxInputPath(input, params.cwd);
118
+ const hostMount = findMountByHostPath(mountsByHost, hostResolved);
119
+ if (hostMount) {
120
+ const relHost = path.relative(hostMount.hostRoot, hostResolved);
121
+ const relPosix = relHost ? relHost.split(path.sep).join(path.posix.sep) : "";
122
+ const containerPath = relPosix
123
+ ? path.posix.join(hostMount.containerRoot, relPosix)
124
+ : hostMount.containerRoot;
125
+ return {
126
+ hostPath: hostResolved,
127
+ containerPath,
128
+ relativePath: toDisplayRelative({
129
+ containerPath,
130
+ defaultContainerRoot: params.defaultContainerRoot,
131
+ }),
132
+ writable: hostMount.writable,
133
+ };
134
+ }
135
+ // Preserve legacy error wording for out-of-sandbox paths.
136
+ resolveSandboxPath({
137
+ filePath: input,
138
+ cwd: params.cwd,
139
+ root: params.defaultWorkspaceRoot,
140
+ });
141
+ throw new Error(`Path escapes sandbox root (${params.defaultWorkspaceRoot}): ${input}`);
142
+ }
143
+ function dedupeMounts(mounts) {
144
+ const seen = new Set();
145
+ const deduped = [];
146
+ for (const mount of mounts) {
147
+ const key = `${mount.hostRoot}=>${mount.containerRoot}`;
148
+ if (seen.has(key)) {
149
+ continue;
150
+ }
151
+ seen.add(key);
152
+ deduped.push(mount);
153
+ }
154
+ return deduped;
155
+ }
156
+ function findMountByContainerPath(mounts, target) {
157
+ for (const mount of mounts) {
158
+ if (isPathInsidePosix(mount.containerRoot, target)) {
159
+ return mount;
160
+ }
161
+ }
162
+ return null;
163
+ }
164
+ function findMountByHostPath(mounts, target) {
165
+ for (const mount of mounts) {
166
+ if (isPathInsideHost(mount.hostRoot, target)) {
167
+ return mount;
168
+ }
169
+ }
170
+ return null;
171
+ }
172
+ function isPathInsidePosix(root, target) {
173
+ const rel = path.posix.relative(root, target);
174
+ if (!rel) {
175
+ return true;
176
+ }
177
+ return !(rel.startsWith("..") || path.posix.isAbsolute(rel));
178
+ }
179
+ function isPathInsideHost(root, target) {
180
+ const rel = path.relative(root, target);
181
+ if (!rel) {
182
+ return true;
183
+ }
184
+ return !(rel.startsWith("..") || path.isAbsolute(rel));
185
+ }
186
+ function toHostSegments(relativePosix) {
187
+ return relativePosix.split("/").filter(Boolean);
188
+ }
189
+ function toDisplayRelative(params) {
190
+ const rel = path.posix.relative(params.defaultContainerRoot, params.containerPath);
191
+ if (!rel) {
192
+ return "";
193
+ }
194
+ if (!rel.startsWith("..") && !path.posix.isAbsolute(rel)) {
195
+ return rel;
196
+ }
197
+ return params.containerPath;
198
+ }
199
+ function normalizeContainerPath(value) {
200
+ const normalized = path.posix.normalize(value);
201
+ return normalized === "." ? "/" : normalized;
202
+ }
203
+ function normalizePosixInput(value) {
204
+ return value.replace(/\\/g, "/").trim();
205
+ }
@@ -0,0 +1,4 @@
1
+ import crypto from "node:crypto";
2
+ export function hashTextSha256(value) {
3
+ return crypto.createHash("sha256").update(value).digest("hex");
4
+ }