@poolzin/pool-bot 2026.2.17 → 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 (469) hide show
  1. package/CHANGELOG.md +17 -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.resolve-auth-profile-order.fixtures.js +23 -0
  5. package/dist/agents/bash-tools.exec-runtime.js +438 -0
  6. package/dist/agents/bash-tools.shared.js +6 -0
  7. package/dist/agents/cli-runner/reliability.js +61 -0
  8. package/dist/agents/cli-watchdog-defaults.js +11 -0
  9. package/dist/agents/command-poll-backoff.js +63 -0
  10. package/dist/agents/current-time.js +16 -0
  11. package/dist/agents/model-alias-lines.js +18 -0
  12. package/dist/agents/model-auth-label.js +61 -0
  13. package/dist/agents/models-config.e2e-harness.js +115 -0
  14. package/dist/agents/ollama-stream.js +11 -3
  15. package/dist/agents/openclaw-tools.js +135 -0
  16. package/dist/agents/pi-auth-json.js +118 -0
  17. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +147 -0
  18. package/dist/agents/pi-embedded-subscribe.e2e-harness.js +90 -0
  19. package/dist/agents/pi-embedded-subscribe.handlers.compaction.js +63 -0
  20. package/dist/agents/pi-embedded-subscribe.handlers.tools.media.test-helpers.js +30 -0
  21. package/dist/agents/pi-extensions/session-manager-runtime-registry.js +23 -0
  22. package/dist/agents/pi-tools.js +2 -0
  23. package/dist/agents/queued-file-writer.js +22 -0
  24. package/dist/agents/sandbox/docker.js +133 -40
  25. package/dist/agents/sandbox/fs-bridge.js +146 -0
  26. package/dist/agents/sandbox/fs-paths.js +205 -0
  27. package/dist/agents/sandbox/hash.js +4 -0
  28. package/dist/agents/sandbox-paths.js +3 -0
  29. package/dist/agents/session-dirs.js +20 -0
  30. package/dist/agents/skills/filter.js +24 -0
  31. package/dist/agents/skills/tools-dir.js +9 -0
  32. package/dist/agents/skills-install-download.js +290 -0
  33. package/dist/agents/skills-install-output.js +30 -0
  34. package/dist/agents/skills-install.download-test-utils.js +36 -0
  35. package/dist/agents/skills.e2e-test-helpers.js +13 -0
  36. package/dist/agents/subagent-announce-queue.js +59 -15
  37. package/dist/agents/subagent-depth.js +137 -0
  38. package/dist/agents/subagent-registry.js +448 -96
  39. package/dist/agents/subagent-spawn.js +262 -0
  40. package/dist/agents/test-helpers/fast-tool-stubs.js +18 -0
  41. package/dist/agents/test-helpers/host-sandbox-fs-bridge.js +74 -0
  42. package/dist/agents/tool-display-common.js +782 -0
  43. package/dist/agents/tools/image-tool.js +1 -1
  44. package/dist/agents/tools/sessions-access.js +178 -0
  45. package/dist/agents/tools/sessions-resolution.js +206 -0
  46. package/dist/agents/tools/subagents-tool.js +616 -0
  47. package/dist/agents/workspace-dir.js +18 -0
  48. package/dist/agents/workspace-dirs.js +14 -0
  49. package/dist/agents/workspace.js +70 -0
  50. package/dist/auto-reply/heartbeat-reply-payload.js +18 -0
  51. package/dist/auto-reply/reply/commands-export-session.js +163 -0
  52. package/dist/auto-reply/reply/commands-mesh.js +245 -0
  53. package/dist/auto-reply/reply/commands-setunset.js +28 -0
  54. package/dist/auto-reply/reply/commands-slash-parse.js +31 -0
  55. package/dist/auto-reply/reply/commands-system-prompt.js +117 -0
  56. package/dist/auto-reply/reply/directive-handling.levels.js +17 -0
  57. package/dist/auto-reply/reply/directive-handling.params.js +1 -0
  58. package/dist/auto-reply/reply/directive-parsing.js +36 -0
  59. package/dist/auto-reply/reply/dispatcher-registry.js +43 -0
  60. package/dist/auto-reply/reply/elevated-unavailable.js +20 -0
  61. package/dist/auto-reply/reply/reply-delivery.js +92 -0
  62. package/dist/auto-reply/reply/session-reset-prompt.js +1 -0
  63. package/dist/auto-reply/reply/session-run-accounting.js +33 -0
  64. package/dist/auto-reply/reply.directive.directive-behavior.e2e-harness.js +115 -0
  65. package/dist/auto-reply/reply.directive.directive-behavior.e2e-mocks.js +12 -0
  66. package/dist/browser/bridge-auth-registry.js +26 -0
  67. package/dist/browser/client-actions-url.js +10 -0
  68. package/dist/browser/control-auth.js +73 -0
  69. package/dist/browser/csrf.js +64 -0
  70. package/dist/browser/http-auth.js +52 -0
  71. package/dist/browser/paths.js +37 -0
  72. package/dist/browser/proxy-files.js +32 -0
  73. package/dist/browser/pw-ai-state.js +7 -0
  74. package/dist/browser/resolved-config-refresh.js +42 -0
  75. package/dist/browser/routes/path-output.js +1 -0
  76. package/dist/browser/server-context.chrome-test-harness.js +20 -0
  77. package/dist/browser/server-middleware.js +31 -0
  78. package/dist/browser/test-port.js +16 -0
  79. package/dist/build-info.json +3 -3
  80. package/dist/canvas-host/file-resolver.js +43 -0
  81. package/dist/channels/account-summary.js +19 -0
  82. package/dist/channels/draft-stream-loop.js +77 -0
  83. package/dist/channels/plugins/account-helpers.js +26 -0
  84. package/dist/channels/telegram/allow-from.js +10 -0
  85. package/dist/cli/browser-cli-resize.js +22 -0
  86. package/dist/cli/browser-cli-shared.js +8 -0
  87. package/dist/cli/clawbot-cli.js +5 -0
  88. package/dist/cli/completion-cli.js +566 -0
  89. package/dist/cli/config-cli.js +63 -5
  90. package/dist/cli/daemon-cli/lifecycle-core.js +256 -0
  91. package/dist/cli/daemon-cli/register-service-commands.js +60 -0
  92. package/dist/cli/daemon-cli-compat.js +80 -0
  93. package/dist/cli/nodes-cli/pairing-render.js +26 -0
  94. package/dist/cli/program/action-reparse.js +17 -0
  95. package/dist/cli/program/command-registry.js +17 -0
  96. package/dist/cli/program/program-context.js +8 -0
  97. package/dist/cli/program/register.subclis.js +7 -0
  98. package/dist/cli/program/routes.js +233 -0
  99. package/dist/cli/qr-cli.js +132 -0
  100. package/dist/cli/requirements-test-fixtures.js +17 -0
  101. package/dist/cli/respawn-policy.js +4 -0
  102. package/dist/cli/shared/parse-port.js +18 -0
  103. package/dist/cli/skills-cli.format.js +241 -0
  104. package/dist/cli/update-cli/progress.js +121 -0
  105. package/dist/cli/update-cli/restart-helper.js +108 -0
  106. package/dist/cli/update-cli/shared.js +196 -0
  107. package/dist/cli/update-cli/status.js +97 -0
  108. package/dist/cli/update-cli/suppress-deprecations.js +17 -0
  109. package/dist/cli/update-cli/update-command.js +506 -0
  110. package/dist/cli/update-cli/wizard.js +130 -0
  111. package/dist/cli/update-cli.js +3 -9
  112. package/dist/cli/windows-argv.js +69 -0
  113. package/dist/commands/auth-choice-legacy.js +20 -0
  114. package/dist/commands/auth-choice.apply-helpers.js +8 -0
  115. package/dist/commands/channel-test-helpers.js +19 -0
  116. package/dist/commands/cleanup-plan.js +10 -0
  117. package/dist/commands/cleanup-utils.js +7 -0
  118. package/dist/commands/config-validation.js +15 -0
  119. package/dist/commands/doctor-completion.js +112 -0
  120. package/dist/commands/doctor-memory-search.js +119 -0
  121. package/dist/commands/doctor-session-locks.js +73 -0
  122. package/dist/commands/doctor.e2e-harness.js +364 -0
  123. package/dist/commands/gateway-presence.js +19 -0
  124. package/dist/commands/model-default.js +35 -0
  125. package/dist/commands/models/fallbacks-shared.js +102 -0
  126. package/dist/commands/models/shared.js +24 -0
  127. package/dist/commands/onboard-auth.config-gateways.js +64 -0
  128. package/dist/commands/onboard-auth.config-litellm.js +45 -0
  129. package/dist/commands/onboard-auth.config-shared.js +116 -0
  130. package/dist/commands/onboard-config.js +16 -0
  131. package/dist/commands/onboard-non-interactive.test-helpers.js +31 -0
  132. package/dist/commands/onboard-provider-auth-flags.js +136 -0
  133. package/dist/commands/openai-codex-oauth.js +40 -0
  134. package/dist/commands/test-runtime-config-helpers.js +21 -0
  135. package/dist/commands/test-wizard-helpers.js +68 -0
  136. package/dist/commands/vllm-setup.js +66 -0
  137. package/dist/compat/legacy-names.js +2 -0
  138. package/dist/config/backup-rotation.js +19 -0
  139. package/dist/config/env-preserve.js +122 -0
  140. package/dist/config/includes-scan.js +78 -0
  141. package/dist/config/plugins-allowlist.js +13 -0
  142. package/dist/config/schema.help.js +256 -0
  143. package/dist/config/schema.hints.js +189 -0
  144. package/dist/config/schema.irc.js +20 -0
  145. package/dist/config/schema.labels.js +317 -0
  146. package/dist/config/sessions/delivery-info.js +40 -0
  147. package/dist/config/types.irc.js +1 -0
  148. package/dist/config/zod-schema.agent-model.js +10 -0
  149. package/dist/config/zod-schema.allowdeny.js +35 -0
  150. package/dist/config/zod-schema.sensitive.js +4 -0
  151. package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
  152. package/dist/cron/isolated-agent/skills-snapshot.js +26 -0
  153. package/dist/cron/isolated-agent/subagent-followup.js +127 -0
  154. package/dist/cron/isolated-agent.mocks.js +12 -0
  155. package/dist/cron/isolated-agent.test-setup.js +22 -0
  156. package/dist/cron/legacy-delivery.js +43 -0
  157. package/dist/cron/webhook-url.js +22 -0
  158. package/dist/daemon/arg-split.js +40 -0
  159. package/dist/daemon/exec-file.js +23 -0
  160. package/dist/daemon/output.js +6 -0
  161. package/dist/daemon/runtime-format.js +31 -0
  162. package/dist/daemon/schtasks-exec.js +4 -0
  163. package/dist/daemon/service-audit.js +22 -0
  164. package/dist/discord/client.js +41 -0
  165. package/dist/discord/components-registry.js +57 -0
  166. package/dist/discord/components.js +816 -0
  167. package/dist/discord/guilds.js +12 -0
  168. package/dist/discord/monitor/gateway-plugin.js +48 -0
  169. package/dist/discord/monitor/presence.js +30 -0
  170. package/dist/discord/send.components.js +115 -0
  171. package/dist/discord/send.shared.js +4 -0
  172. package/dist/discord/ui.js +26 -0
  173. package/dist/discord/voice-message.js +254 -0
  174. package/dist/gateway/agent-event-assistant-text.js +5 -0
  175. package/dist/gateway/agent-prompt.js +33 -0
  176. package/dist/gateway/auth-rate-limit.js +136 -0
  177. package/dist/gateway/channel-health-monitor.js +114 -0
  178. package/dist/gateway/control-ui-contract.js +1 -0
  179. package/dist/gateway/control-ui-csp.js +15 -0
  180. package/dist/gateway/gateway-config-prompts.shared.js +25 -0
  181. package/dist/gateway/http-auth-helpers.js +18 -0
  182. package/dist/gateway/http-common.js +18 -0
  183. package/dist/gateway/http-endpoint-helpers.js +27 -0
  184. package/dist/gateway/node-invoke-sanitize.js +11 -0
  185. package/dist/gateway/node-invoke-system-run-approval.js +205 -0
  186. package/dist/gateway/probe-auth.js +21 -0
  187. package/dist/gateway/protocol/index.js +7 -2
  188. package/dist/gateway/protocol/schema/mesh.js +54 -0
  189. package/dist/gateway/protocol/schema/protocol-schemas.js +7 -0
  190. package/dist/gateway/protocol/schema.js +1 -0
  191. package/dist/gateway/server/ws-connection/auth-messages.js +54 -0
  192. package/dist/gateway/server-channels.js +11 -0
  193. package/dist/gateway/server-methods/attachment-normalize.js +16 -0
  194. package/dist/gateway/server-methods/base-hash.js +8 -0
  195. package/dist/gateway/server-methods/mesh.js +700 -0
  196. package/dist/gateway/server-methods/nodes.handlers.invoke-result.js +55 -0
  197. package/dist/gateway/server-methods/restart-request.js +13 -0
  198. package/dist/gateway/server-methods/validation.js +8 -0
  199. package/dist/gateway/server.agent.gateway-server-agent.mocks.js +35 -0
  200. package/dist/gateway/server.e2e-registry-helpers.js +1 -0
  201. package/dist/gateway/server.e2e-ws-harness.js +20 -0
  202. package/dist/gateway/test-helpers.js +2 -0
  203. package/dist/gateway/test-helpers.server.js +3 -1
  204. package/dist/gateway/test-http-response.js +12 -0
  205. package/dist/gateway/test-openai-responses-model.js +20 -0
  206. package/dist/gateway/test-temp-config.js +30 -0
  207. package/dist/gateway/test-with-server.js +32 -0
  208. package/dist/hooks/bundled/bootstrap-extra-files/handler.js +46 -0
  209. package/dist/imessage/monitor/abort-handler.js +23 -0
  210. package/dist/imessage/monitor/inbound-processing.js +346 -0
  211. package/dist/imessage/monitor/parse-notification.js +64 -0
  212. package/dist/imessage/target-parsing-helpers.js +92 -0
  213. package/dist/infra/archive.js +244 -20
  214. package/dist/infra/detect-package-manager.js +26 -0
  215. package/dist/infra/exec-approvals-allowlist.js +257 -0
  216. package/dist/infra/exec-approvals-analysis.js +770 -0
  217. package/dist/infra/exec-approvals.js +13 -0
  218. package/dist/infra/file-lock.js +1 -0
  219. package/dist/infra/gemini-auth.js +39 -0
  220. package/dist/infra/heartbeat-active-hours.js +85 -0
  221. package/dist/infra/heartbeat-events-filter.js +50 -0
  222. package/dist/infra/heartbeat-runner.test-utils.js +39 -0
  223. package/dist/infra/http-body.js +265 -0
  224. package/dist/infra/install-package-dir.js +50 -0
  225. package/dist/infra/install-safe-path.js +49 -0
  226. package/dist/infra/json-files.js +49 -0
  227. package/dist/infra/jsonl-socket.js +52 -0
  228. package/dist/infra/map-size.js +14 -0
  229. package/dist/infra/net/hostname.js +7 -0
  230. package/dist/infra/npm-registry-spec.js +39 -0
  231. package/dist/infra/openclaw-root.js +109 -0
  232. package/dist/infra/outbound/delivery-queue.js +214 -0
  233. package/dist/infra/outbound/identity.js +23 -0
  234. package/dist/infra/outbound/message-action-params.js +307 -0
  235. package/dist/infra/outbound/tool-payload.js +21 -0
  236. package/dist/infra/package-json.js +23 -0
  237. package/dist/infra/pairing-files.js +19 -0
  238. package/dist/infra/pairing-token.js +9 -0
  239. package/dist/infra/path-prepend.js +51 -0
  240. package/dist/infra/process-respawn.js +49 -0
  241. package/dist/infra/runtime-status.js +16 -0
  242. package/dist/infra/session-cost-usage.types.js +1 -0
  243. package/dist/infra/session-maintenance-warning.js +89 -0
  244. package/dist/infra/system-run-command.js +78 -0
  245. package/dist/infra/tmp-openclaw-dir.js +81 -0
  246. package/dist/infra/tmp-poolbot-dir.js +2 -0
  247. package/dist/infra/update-channels.js +19 -0
  248. package/dist/line/actions.js +45 -0
  249. package/dist/line/channel-access-token.js +9 -0
  250. package/dist/line/flex-templates/basic-cards.js +332 -0
  251. package/dist/line/flex-templates/common.js +18 -0
  252. package/dist/line/flex-templates/media-control-cards.js +453 -0
  253. package/dist/line/flex-templates/message.js +10 -0
  254. package/dist/line/flex-templates/schedule-cards.js +399 -0
  255. package/dist/line/flex-templates/types.js +1 -0
  256. package/dist/line/webhook-node.js +100 -0
  257. package/dist/line/webhook-utils.js +11 -0
  258. package/dist/logging/timestamps.js +14 -0
  259. package/dist/markdown/whatsapp.js +62 -0
  260. package/dist/media/base64.js +34 -0
  261. package/dist/media/local-roots.js +32 -0
  262. package/dist/media/outbound-attachment.js +10 -0
  263. package/dist/media/read-response-with-limit.js +41 -0
  264. package/dist/media/sniff-mime-from-base64.js +19 -0
  265. package/dist/media-understanding/audio-preflight.js +67 -0
  266. package/dist/media-understanding/fs.js +13 -0
  267. package/dist/media-understanding/output-extract.js +26 -0
  268. package/dist/media-understanding/providers/audio.test-helpers.js +34 -0
  269. package/dist/media-understanding/providers/google/inline-data.js +64 -0
  270. package/dist/media-understanding/providers/shared.js +7 -0
  271. package/dist/media-understanding/runner.entries.js +459 -0
  272. package/dist/memory/batch-error-utils.js +11 -0
  273. package/dist/memory/batch-http.js +27 -0
  274. package/dist/memory/batch-output.js +29 -0
  275. package/dist/memory/batch-runner.js +22 -0
  276. package/dist/memory/batch-upload.js +23 -0
  277. package/dist/memory/batch-utils.js +26 -0
  278. package/dist/memory/embeddings-debug.js +11 -0
  279. package/dist/memory/embeddings-remote-client.js +22 -0
  280. package/dist/memory/embeddings-remote-fetch.js +14 -0
  281. package/dist/memory/manager-embedding-ops.js +616 -0
  282. package/dist/memory/manager-sync-ops.js +953 -0
  283. package/dist/memory/qmd-manager.js +1061 -0
  284. package/dist/memory/qmd-query-parser.js +107 -0
  285. package/dist/memory/qmd-scope.js +93 -0
  286. package/dist/memory/search-manager.js +0 -1
  287. package/dist/memory/sync-index.js +21 -0
  288. package/dist/memory/sync-progress.js +22 -0
  289. package/dist/memory/sync-stale.js +30 -0
  290. package/dist/memory/test-embeddings-mock.js +16 -0
  291. package/dist/memory/test-manager-helpers.js +14 -0
  292. package/dist/memory/test-runtime-mocks.js +11 -0
  293. package/dist/node-host/invoke-browser.js +177 -0
  294. package/dist/node-host/invoke.js +685 -0
  295. package/dist/pairing/setup-code.js +285 -0
  296. package/dist/plugin-sdk/account-id.js +1 -0
  297. package/dist/plugin-sdk/agent-media-payload.js +13 -0
  298. package/dist/plugin-sdk/allow-from.js +47 -0
  299. package/dist/plugin-sdk/command-auth.js +23 -0
  300. package/dist/plugin-sdk/config-paths.js +9 -0
  301. package/dist/plugin-sdk/file-lock.js +116 -0
  302. package/dist/plugin-sdk/json-store.js +31 -0
  303. package/dist/plugin-sdk/onboarding.js +28 -0
  304. package/dist/plugin-sdk/provider-auth-result.js +29 -0
  305. package/dist/plugin-sdk/slack-message-actions.js +133 -0
  306. package/dist/plugin-sdk/status-helpers.js +35 -0
  307. package/dist/plugin-sdk/text-chunking.js +31 -0
  308. package/dist/plugin-sdk/tool-send.js +12 -0
  309. package/dist/plugin-sdk/webhook-path.js +27 -0
  310. package/dist/plugin-sdk/webhook-targets.js +34 -0
  311. package/dist/plugins/hooks.test-helpers.js +21 -0
  312. package/dist/plugins/uninstall.js +171 -0
  313. package/dist/process/supervisor/adapters/child.js +143 -0
  314. package/dist/process/supervisor/adapters/env.js +13 -0
  315. package/dist/process/supervisor/adapters/pty.js +148 -0
  316. package/dist/process/supervisor/index.js +10 -0
  317. package/dist/process/supervisor/registry.js +117 -0
  318. package/dist/process/supervisor/supervisor.js +244 -0
  319. package/dist/process/supervisor/types.js +1 -0
  320. package/dist/providers/google-shared.test-helpers.js +75 -0
  321. package/dist/security/audit-channel.js +419 -0
  322. package/dist/security/audit-tool-policy.js +1 -0
  323. package/dist/security/scan-paths.js +12 -0
  324. package/dist/sessions/input-provenance.js +55 -0
  325. package/dist/sessions/session-key-utils.js +7 -0
  326. package/dist/shared/chat-content.js +31 -0
  327. package/dist/shared/chat-envelope.js +45 -0
  328. package/dist/shared/config-eval.js +117 -0
  329. package/dist/shared/device-auth.js +16 -0
  330. package/dist/shared/entry-metadata.js +9 -0
  331. package/dist/shared/entry-status.js +25 -0
  332. package/dist/shared/frontmatter.js +98 -0
  333. package/dist/shared/model-param-b.js +19 -0
  334. package/dist/shared/net/ipv4.js +17 -0
  335. package/dist/shared/node-match.js +53 -0
  336. package/dist/shared/requirements.js +128 -0
  337. package/dist/shared/subagents-format.js +84 -0
  338. package/dist/shared/usage-aggregates.js +28 -0
  339. package/dist/signal/monitor/mentions.js +45 -0
  340. package/dist/signal/rpc-context.js +19 -0
  341. package/dist/slack/blocks-fallback.js +76 -0
  342. package/dist/slack/blocks-input.js +40 -0
  343. package/dist/slack/draft-stream.js +106 -0
  344. package/dist/slack/message-actions.js +51 -0
  345. package/dist/slack/modal-metadata.js +32 -0
  346. package/dist/slack/monitor/events/interactions.js +462 -0
  347. package/dist/slack/monitor/room-context.js +17 -0
  348. package/dist/slack/stream-mode.js +41 -0
  349. package/dist/telegram/bot-native-command-menu.js +64 -0
  350. package/dist/telegram/bot.media.e2e-harness.js +81 -0
  351. package/dist/telegram/button-types.js +1 -0
  352. package/dist/telegram/group-access.js +65 -0
  353. package/dist/telegram/outbound-params.js +21 -0
  354. package/dist/telegram/poll-vote-cache.js +21 -0
  355. package/dist/terminal/health-style.js +36 -0
  356. package/dist/test-utils/chunk-test-helpers.js +21 -0
  357. package/dist/test-utils/env.js +72 -0
  358. package/dist/test-utils/exec-assertions.js +12 -0
  359. package/dist/test-utils/imessage-test-plugin.js +54 -0
  360. package/dist/test-utils/mock-http-response.js +17 -0
  361. package/dist/test-utils/vitest-mock-fn.js +1 -0
  362. package/dist/tts/tts-core.js +550 -0
  363. package/dist/utils/chunk-items.js +10 -0
  364. package/dist/utils/reaction-level.js +52 -0
  365. package/dist/utils/safe-json.js +22 -0
  366. package/dist/utils/with-timeout.js +14 -0
  367. package/dist/web/media.js +17 -5
  368. package/dist/whatsapp/resolve-outbound-target.js +42 -0
  369. package/dist/wizard/onboarding.completion.js +74 -0
  370. package/extensions/bluebubbles/src/account-resolve.ts +29 -0
  371. package/extensions/bluebubbles/src/monitor-normalize.ts +796 -0
  372. package/extensions/bluebubbles/src/monitor-processing.ts +1007 -0
  373. package/extensions/bluebubbles/src/monitor-reply-cache.ts +185 -0
  374. package/extensions/bluebubbles/src/monitor-shared.ts +51 -0
  375. package/extensions/bluebubbles/src/multipart.ts +32 -0
  376. package/extensions/bluebubbles/src/send-helpers.ts +53 -0
  377. package/extensions/bluebubbles/src/test-harness.ts +50 -0
  378. package/extensions/bluebubbles/src/test-mocks.ts +11 -0
  379. package/extensions/device-pair/index.ts +554 -0
  380. package/extensions/discord/src/channel.js +366 -0
  381. package/extensions/discord/src/runtime.js +10 -0
  382. package/extensions/feishu/index.ts +63 -0
  383. package/extensions/feishu/src/accounts.ts +114 -0
  384. package/extensions/feishu/src/bitable.ts +739 -0
  385. package/extensions/feishu/src/bot.ts +965 -0
  386. package/extensions/feishu/src/channel.ts +351 -0
  387. package/extensions/feishu/src/client.ts +118 -0
  388. package/extensions/feishu/src/config-schema.ts +206 -0
  389. package/extensions/feishu/src/dedup.ts +33 -0
  390. package/extensions/feishu/src/directory.ts +177 -0
  391. package/extensions/feishu/src/doc-schema.ts +47 -0
  392. package/extensions/feishu/src/docx.ts +536 -0
  393. package/extensions/feishu/src/drive-schema.ts +46 -0
  394. package/extensions/feishu/src/drive.ts +227 -0
  395. package/extensions/feishu/src/dynamic-agent.ts +131 -0
  396. package/extensions/feishu/src/media.ts +449 -0
  397. package/extensions/feishu/src/mention.ts +126 -0
  398. package/extensions/feishu/src/monitor.ts +330 -0
  399. package/extensions/feishu/src/onboarding.ts +359 -0
  400. package/extensions/feishu/src/outbound.ts +55 -0
  401. package/extensions/feishu/src/perm-schema.ts +52 -0
  402. package/extensions/feishu/src/perm.ts +173 -0
  403. package/extensions/feishu/src/policy.ts +84 -0
  404. package/extensions/feishu/src/probe.ts +44 -0
  405. package/extensions/feishu/src/reactions.ts +160 -0
  406. package/extensions/feishu/src/reply-dispatcher.ts +239 -0
  407. package/extensions/feishu/src/runtime.ts +14 -0
  408. package/extensions/feishu/src/send-result.ts +29 -0
  409. package/extensions/feishu/src/send.ts +335 -0
  410. package/extensions/feishu/src/streaming-card.ts +223 -0
  411. package/extensions/feishu/src/targets.ts +78 -0
  412. package/extensions/feishu/src/tools-config.ts +21 -0
  413. package/extensions/feishu/src/types.ts +81 -0
  414. package/extensions/feishu/src/typing.ts +80 -0
  415. package/extensions/feishu/src/wiki-schema.ts +55 -0
  416. package/extensions/feishu/src/wiki.ts +232 -0
  417. package/extensions/imessage/src/channel.js +253 -0
  418. package/extensions/imessage/src/runtime.js +10 -0
  419. package/extensions/irc/index.ts +17 -0
  420. package/extensions/irc/src/accounts.ts +268 -0
  421. package/extensions/irc/src/channel.ts +367 -0
  422. package/extensions/irc/src/client.ts +439 -0
  423. package/extensions/irc/src/config-schema.ts +97 -0
  424. package/extensions/irc/src/connect-options.ts +30 -0
  425. package/extensions/irc/src/control-chars.ts +22 -0
  426. package/extensions/irc/src/inbound.ts +334 -0
  427. package/extensions/irc/src/monitor.ts +147 -0
  428. package/extensions/irc/src/normalize.ts +117 -0
  429. package/extensions/irc/src/onboarding.ts +479 -0
  430. package/extensions/irc/src/policy.ts +157 -0
  431. package/extensions/irc/src/probe.ts +53 -0
  432. package/extensions/irc/src/protocol.ts +169 -0
  433. package/extensions/irc/src/runtime.ts +14 -0
  434. package/extensions/irc/src/send.ts +88 -0
  435. package/extensions/irc/src/types.ts +93 -0
  436. package/extensions/matrix/src/matrix/client-bootstrap.ts +39 -0
  437. package/extensions/mattermost/src/mattermost/monitor-onchar.ts +25 -0
  438. package/extensions/mattermost/src/mattermost/monitor-websocket.ts +221 -0
  439. package/extensions/mattermost/src/mattermost/reactions.ts +130 -0
  440. package/extensions/mattermost/src/mattermost/reconnect.ts +103 -0
  441. package/extensions/minimax-portal-auth/index.ts +161 -0
  442. package/extensions/minimax-portal-auth/oauth.ts +247 -0
  443. package/extensions/msteams/src/file-lock.ts +1 -0
  444. package/extensions/msteams/src/graph.ts +92 -0
  445. package/extensions/msteams/src/mentions.ts +114 -0
  446. package/extensions/msteams/src/test-runtime.ts +16 -0
  447. package/extensions/openai-codex-auth/index.ts +177 -0
  448. package/extensions/phone-control/index.ts +421 -0
  449. package/extensions/shared/resolve-target-test-helpers.ts +66 -0
  450. package/extensions/signal/src/channel.js +273 -0
  451. package/extensions/signal/src/runtime.js +10 -0
  452. package/extensions/slack/src/channel.js +489 -0
  453. package/extensions/slack/src/runtime.js +10 -0
  454. package/extensions/talk-voice/index.ts +150 -0
  455. package/extensions/telegram/src/channel.js +424 -0
  456. package/extensions/telegram/src/runtime.js +10 -0
  457. package/extensions/thread-ownership/index.ts +133 -0
  458. package/extensions/tlon/src/account-fields.ts +25 -0
  459. package/extensions/tlon/src/urbit/base-url.ts +57 -0
  460. package/extensions/tlon/src/urbit/channel-client.ts +157 -0
  461. package/extensions/tlon/src/urbit/channel-ops.ts +164 -0
  462. package/extensions/tlon/src/urbit/context.ts +47 -0
  463. package/extensions/tlon/src/urbit/errors.ts +51 -0
  464. package/extensions/tlon/src/urbit/fetch.ts +39 -0
  465. package/extensions/twitch/src/test-fixtures.ts +30 -0
  466. package/extensions/voice-call/src/allowlist.ts +19 -0
  467. package/extensions/whatsapp/src/channel.js +429 -0
  468. package/extensions/whatsapp/src/runtime.js +10 -0
  469. package/package.json +1 -1
@@ -1,22 +1,41 @@
1
+ import { createWriteStream } from "node:fs";
1
2
  import fs from "node:fs/promises";
2
3
  import path from "node:path";
3
- import * as tar from "tar";
4
+ import { Readable, Transform } from "node:stream";
5
+ import { pipeline } from "node:stream/promises";
4
6
  import JSZip from "jszip";
7
+ import * as tar from "tar";
8
+ import { resolveSafeBaseDir } from "./path-safety.js";
9
+ /** @internal */
10
+ export const DEFAULT_MAX_ARCHIVE_BYTES_ZIP = 256 * 1024 * 1024;
11
+ /** @internal */
12
+ export const DEFAULT_MAX_ENTRIES = 50_000;
13
+ /** @internal */
14
+ export const DEFAULT_MAX_EXTRACTED_BYTES = 512 * 1024 * 1024;
15
+ /** @internal */
16
+ export const DEFAULT_MAX_ENTRY_BYTES = 256 * 1024 * 1024;
17
+ const ERROR_ARCHIVE_SIZE_EXCEEDS_LIMIT = "archive size exceeds limit";
18
+ const ERROR_ARCHIVE_ENTRY_COUNT_EXCEEDS_LIMIT = "archive entry count exceeds limit";
19
+ const ERROR_ARCHIVE_ENTRY_EXTRACTED_SIZE_EXCEEDS_LIMIT = "archive entry extracted size exceeds limit";
20
+ const ERROR_ARCHIVE_EXTRACTED_SIZE_EXCEEDS_LIMIT = "archive extracted size exceeds limit";
5
21
  const TAR_SUFFIXES = [".tgz", ".tar.gz", ".tar"];
6
22
  export function resolveArchiveKind(filePath) {
7
23
  const lower = filePath.toLowerCase();
8
- if (lower.endsWith(".zip"))
24
+ if (lower.endsWith(".zip")) {
9
25
  return "zip";
10
- if (TAR_SUFFIXES.some((suffix) => lower.endsWith(suffix)))
26
+ }
27
+ if (TAR_SUFFIXES.some((suffix) => lower.endsWith(suffix))) {
11
28
  return "tar";
29
+ }
12
30
  return null;
13
31
  }
14
32
  export async function resolvePackedRootDir(extractDir) {
15
33
  const direct = path.join(extractDir, "package");
16
34
  try {
17
35
  const stat = await fs.stat(direct);
18
- if (stat.isDirectory())
36
+ if (stat.isDirectory()) {
19
37
  return direct;
38
+ }
20
39
  }
21
40
  catch {
22
41
  // ignore
@@ -43,44 +62,249 @@ export async function withTimeout(promise, timeoutMs, label) {
43
62
  ]);
44
63
  }
45
64
  finally {
46
- if (timeoutId)
65
+ if (timeoutId) {
47
66
  clearTimeout(timeoutId);
67
+ }
68
+ }
69
+ }
70
+ // Path hygiene.
71
+ function normalizeArchivePath(raw) {
72
+ // Archives may contain Windows separators; treat them as separators.
73
+ return raw.replaceAll("\\", "/");
74
+ }
75
+ function isWindowsDrivePath(p) {
76
+ return /^[a-zA-Z]:[\\/]/.test(p);
77
+ }
78
+ function validateArchiveEntryPath(entryPath) {
79
+ if (!entryPath || entryPath === "." || entryPath === "./") {
80
+ return;
81
+ }
82
+ if (isWindowsDrivePath(entryPath)) {
83
+ throw new Error(`archive entry uses a drive path: ${entryPath}`);
84
+ }
85
+ const normalized = path.posix.normalize(normalizeArchivePath(entryPath));
86
+ if (normalized === ".." || normalized.startsWith("../")) {
87
+ throw new Error(`archive entry escapes destination: ${entryPath}`);
88
+ }
89
+ if (path.posix.isAbsolute(normalized) || normalized.startsWith("//")) {
90
+ throw new Error(`archive entry is absolute: ${entryPath}`);
91
+ }
92
+ }
93
+ function stripArchivePath(entryPath, stripComponents) {
94
+ const raw = normalizeArchivePath(entryPath);
95
+ if (!raw || raw === "." || raw === "./") {
96
+ return null;
97
+ }
98
+ // Important: mimic tar --strip-components semantics (raw segments before
99
+ // normalization) so strip-induced escapes like "a/../b" are not hidden.
100
+ const parts = raw.split("/").filter((part) => part.length > 0 && part !== ".");
101
+ const strip = Math.max(0, Math.floor(stripComponents));
102
+ const stripped = strip === 0 ? parts.join("/") : parts.slice(strip).join("/");
103
+ const result = path.posix.normalize(stripped);
104
+ if (!result || result === "." || result === "./") {
105
+ return null;
106
+ }
107
+ return result;
108
+ }
109
+ function resolveCheckedOutPath(destDir, relPath, original) {
110
+ const safeBase = resolveSafeBaseDir(destDir);
111
+ const outPath = path.resolve(destDir, relPath);
112
+ if (!outPath.startsWith(safeBase)) {
113
+ throw new Error(`archive entry escapes destination: ${original}`);
114
+ }
115
+ return outPath;
116
+ }
117
+ function clampLimit(value) {
118
+ if (typeof value !== "number" || !Number.isFinite(value)) {
119
+ return undefined;
48
120
  }
121
+ const v = Math.floor(value);
122
+ return v > 0 ? v : undefined;
123
+ }
124
+ function resolveExtractLimits(limits) {
125
+ // Defaults: defensive, but should not break normal installs.
126
+ return {
127
+ maxArchiveBytes: clampLimit(limits?.maxArchiveBytes) ?? DEFAULT_MAX_ARCHIVE_BYTES_ZIP,
128
+ maxEntries: clampLimit(limits?.maxEntries) ?? DEFAULT_MAX_ENTRIES,
129
+ maxExtractedBytes: clampLimit(limits?.maxExtractedBytes) ?? DEFAULT_MAX_EXTRACTED_BYTES,
130
+ maxEntryBytes: clampLimit(limits?.maxEntryBytes) ?? DEFAULT_MAX_ENTRY_BYTES,
131
+ };
132
+ }
133
+ function assertArchiveEntryCountWithinLimit(entryCount, limits) {
134
+ if (entryCount > limits.maxEntries) {
135
+ throw new Error(ERROR_ARCHIVE_ENTRY_COUNT_EXCEEDS_LIMIT);
136
+ }
137
+ }
138
+ function createByteBudgetTracker(limits) {
139
+ let entryBytes = 0;
140
+ let extractedBytes = 0;
141
+ const addBytes = (bytes) => {
142
+ const b = Math.max(0, Math.floor(bytes));
143
+ if (b === 0) {
144
+ return;
145
+ }
146
+ entryBytes += b;
147
+ if (entryBytes > limits.maxEntryBytes) {
148
+ throw new Error(ERROR_ARCHIVE_ENTRY_EXTRACTED_SIZE_EXCEEDS_LIMIT);
149
+ }
150
+ extractedBytes += b;
151
+ if (extractedBytes > limits.maxExtractedBytes) {
152
+ throw new Error(ERROR_ARCHIVE_EXTRACTED_SIZE_EXCEEDS_LIMIT);
153
+ }
154
+ };
155
+ return {
156
+ startEntry() {
157
+ entryBytes = 0;
158
+ },
159
+ addBytes,
160
+ addEntrySize(size) {
161
+ const s = Math.max(0, Math.floor(size));
162
+ if (s > limits.maxEntryBytes) {
163
+ throw new Error(ERROR_ARCHIVE_ENTRY_EXTRACTED_SIZE_EXCEEDS_LIMIT);
164
+ }
165
+ // Note: tar budgets are based on the header-declared size.
166
+ addBytes(s);
167
+ },
168
+ };
169
+ }
170
+ function createExtractBudgetTransform(params) {
171
+ return new Transform({
172
+ transform(chunk, _encoding, callback) {
173
+ try {
174
+ const buf = chunk instanceof Buffer ? chunk : Buffer.from(chunk);
175
+ params.onChunkBytes(buf.byteLength);
176
+ callback(null, buf);
177
+ }
178
+ catch (err) {
179
+ callback(err instanceof Error ? err : new Error(String(err)));
180
+ }
181
+ },
182
+ });
183
+ }
184
+ async function readZipEntryStream(entry) {
185
+ if (typeof entry.nodeStream === "function") {
186
+ return entry.nodeStream();
187
+ }
188
+ // Old JSZip: fall back to buffering, but still extract via a stream.
189
+ const buf = await entry.async("nodebuffer");
190
+ return Readable.from(buf);
49
191
  }
50
192
  async function extractZip(params) {
193
+ const limits = resolveExtractLimits(params.limits);
194
+ const stat = await fs.stat(params.archivePath);
195
+ if (stat.size > limits.maxArchiveBytes) {
196
+ throw new Error(ERROR_ARCHIVE_SIZE_EXCEEDS_LIMIT);
197
+ }
51
198
  const buffer = await fs.readFile(params.archivePath);
52
199
  const zip = await JSZip.loadAsync(buffer);
53
200
  const entries = Object.values(zip.files);
201
+ const strip = Math.max(0, Math.floor(params.stripComponents ?? 0));
202
+ assertArchiveEntryCountWithinLimit(entries.length, limits);
203
+ const budget = createByteBudgetTracker(limits);
54
204
  for (const entry of entries) {
55
- const entryPath = entry.name.replaceAll("\\", "/");
56
- if (!entryPath || entryPath.endsWith("/")) {
57
- const dirPath = path.resolve(params.destDir, entryPath);
58
- if (!dirPath.startsWith(params.destDir)) {
59
- throw new Error(`zip entry escapes destination: ${entry.name}`);
60
- }
61
- await fs.mkdir(dirPath, { recursive: true });
205
+ validateArchiveEntryPath(entry.name);
206
+ const relPath = stripArchivePath(entry.name, strip);
207
+ if (!relPath) {
62
208
  continue;
63
209
  }
64
- const outPath = path.resolve(params.destDir, entryPath);
65
- if (!outPath.startsWith(params.destDir)) {
66
- throw new Error(`zip entry escapes destination: ${entry.name}`);
210
+ validateArchiveEntryPath(relPath);
211
+ const outPath = resolveCheckedOutPath(params.destDir, relPath, entry.name);
212
+ if (entry.dir) {
213
+ await fs.mkdir(outPath, { recursive: true });
214
+ continue;
67
215
  }
68
216
  await fs.mkdir(path.dirname(outPath), { recursive: true });
69
- const data = await entry.async("nodebuffer");
70
- await fs.writeFile(outPath, data);
217
+ budget.startEntry();
218
+ const readable = await readZipEntryStream(entry);
219
+ try {
220
+ await pipeline(readable, createExtractBudgetTransform({ onChunkBytes: budget.addBytes }), createWriteStream(outPath));
221
+ }
222
+ catch (err) {
223
+ await fs.unlink(outPath).catch(() => undefined);
224
+ throw err;
225
+ }
226
+ // Best-effort permission restore for zip entries created on unix.
227
+ if (typeof entry.unixPermissions === "number") {
228
+ const mode = entry.unixPermissions & 0o777;
229
+ if (mode !== 0) {
230
+ await fs.chmod(outPath, mode).catch(() => undefined);
231
+ }
232
+ }
71
233
  }
72
234
  }
235
+ function readTarEntryInfo(entry) {
236
+ const p = typeof entry === "object" && entry !== null && "path" in entry
237
+ ? String(entry.path)
238
+ : "";
239
+ const t = typeof entry === "object" && entry !== null && "type" in entry
240
+ ? String(entry.type)
241
+ : "";
242
+ const s = typeof entry === "object" &&
243
+ entry !== null &&
244
+ "size" in entry &&
245
+ typeof entry.size === "number" &&
246
+ Number.isFinite(entry.size)
247
+ ? Math.max(0, Math.floor(entry.size))
248
+ : 0;
249
+ return { path: p, type: t, size: s };
250
+ }
73
251
  export async function extractArchive(params) {
74
- const kind = resolveArchiveKind(params.archivePath);
252
+ const kind = params.kind ?? resolveArchiveKind(params.archivePath);
75
253
  if (!kind) {
76
254
  throw new Error(`unsupported archive: ${params.archivePath}`);
77
255
  }
78
256
  const label = kind === "zip" ? "extract zip" : "extract tar";
79
257
  if (kind === "tar") {
80
- await withTimeout(tar.x({ file: params.archivePath, cwd: params.destDir }), params.timeoutMs, label);
258
+ const strip = Math.max(0, Math.floor(params.stripComponents ?? 0));
259
+ const limits = resolveExtractLimits(params.limits);
260
+ let entryCount = 0;
261
+ const budget = createByteBudgetTracker(limits);
262
+ await withTimeout(tar.x({
263
+ file: params.archivePath,
264
+ cwd: params.destDir,
265
+ strip,
266
+ gzip: params.tarGzip,
267
+ preservePaths: false,
268
+ strict: true,
269
+ onReadEntry(entry) {
270
+ const info = readTarEntryInfo(entry);
271
+ try {
272
+ validateArchiveEntryPath(info.path);
273
+ const relPath = stripArchivePath(info.path, strip);
274
+ if (!relPath) {
275
+ return;
276
+ }
277
+ validateArchiveEntryPath(relPath);
278
+ resolveCheckedOutPath(params.destDir, relPath, info.path);
279
+ if (info.type === "SymbolicLink" ||
280
+ info.type === "Link" ||
281
+ info.type === "BlockDevice" ||
282
+ info.type === "CharacterDevice" ||
283
+ info.type === "FIFO" ||
284
+ info.type === "Socket") {
285
+ throw new Error(`tar entry is a link: ${info.path}`);
286
+ }
287
+ entryCount += 1;
288
+ assertArchiveEntryCountWithinLimit(entryCount, limits);
289
+ budget.addEntrySize(info.size);
290
+ }
291
+ catch (err) {
292
+ const error = err instanceof Error ? err : new Error(String(err));
293
+ // Node's EventEmitter calls listeners with `this` bound to the
294
+ // emitter (tar.Unpack), which exposes Parser.abort().
295
+ const emitter = this;
296
+ emitter.abort?.(error);
297
+ }
298
+ },
299
+ }), params.timeoutMs, label);
81
300
  return;
82
301
  }
83
- await withTimeout(extractZip(params), params.timeoutMs, label);
302
+ await withTimeout(extractZip({
303
+ archivePath: params.archivePath,
304
+ destDir: params.destDir,
305
+ stripComponents: params.stripComponents,
306
+ limits: params.limits,
307
+ }), params.timeoutMs, label);
84
308
  }
85
309
  export async function fileExists(filePath) {
86
310
  try {
@@ -0,0 +1,26 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ export async function detectPackageManager(root) {
4
+ try {
5
+ const raw = await fs.readFile(path.join(root, "package.json"), "utf-8");
6
+ const parsed = JSON.parse(raw);
7
+ const pm = parsed?.packageManager?.split("@")[0]?.trim();
8
+ if (pm === "pnpm" || pm === "bun" || pm === "npm") {
9
+ return pm;
10
+ }
11
+ }
12
+ catch {
13
+ // ignore
14
+ }
15
+ const files = await fs.readdir(root).catch(() => []);
16
+ if (files.includes("pnpm-lock.yaml")) {
17
+ return "pnpm";
18
+ }
19
+ if (files.includes("bun.lockb")) {
20
+ return "bun";
21
+ }
22
+ if (files.includes("package-lock.json")) {
23
+ return "npm";
24
+ }
25
+ return null;
26
+ }
@@ -0,0 +1,257 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { DEFAULT_SAFE_BINS, analyzeShellCommand, isWindowsPlatform, matchAllowlist, resolveAllowlistCandidatePath, splitCommandChain, } from "./exec-approvals-analysis.js";
4
+ function isPathLikeToken(value) {
5
+ const trimmed = value.trim();
6
+ if (!trimmed) {
7
+ return false;
8
+ }
9
+ if (trimmed === "-") {
10
+ return false;
11
+ }
12
+ if (trimmed.startsWith("./") || trimmed.startsWith("../") || trimmed.startsWith("~")) {
13
+ return true;
14
+ }
15
+ if (trimmed.startsWith("/")) {
16
+ return true;
17
+ }
18
+ return /^[A-Za-z]:[\\/]/.test(trimmed);
19
+ }
20
+ function defaultFileExists(filePath) {
21
+ try {
22
+ return fs.existsSync(filePath);
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ }
28
+ export function normalizeSafeBins(entries) {
29
+ if (!Array.isArray(entries)) {
30
+ return new Set();
31
+ }
32
+ const normalized = entries
33
+ .map((entry) => entry.trim().toLowerCase())
34
+ .filter((entry) => entry.length > 0);
35
+ return new Set(normalized);
36
+ }
37
+ export function resolveSafeBins(entries) {
38
+ if (entries === undefined) {
39
+ return normalizeSafeBins(DEFAULT_SAFE_BINS);
40
+ }
41
+ return normalizeSafeBins(entries ?? []);
42
+ }
43
+ function hasGlobToken(value) {
44
+ // Safe bins are stdin-only; globbing is both surprising and a historical bypass vector.
45
+ // Note: we still harden execution-time expansion separately.
46
+ return /[*?[\]]/.test(value);
47
+ }
48
+ export function isSafeBinUsage(params) {
49
+ // Windows host exec uses PowerShell, which has different parsing/expansion rules.
50
+ // Keep safeBins conservative there (require explicit allowlist entries).
51
+ if (isWindowsPlatform(process.platform)) {
52
+ return false;
53
+ }
54
+ if (params.safeBins.size === 0) {
55
+ return false;
56
+ }
57
+ const resolution = params.resolution;
58
+ const execName = resolution?.executableName?.toLowerCase();
59
+ if (!execName) {
60
+ return false;
61
+ }
62
+ const matchesSafeBin = params.safeBins.has(execName) ||
63
+ (process.platform === "win32" && params.safeBins.has(path.parse(execName).name));
64
+ if (!matchesSafeBin) {
65
+ return false;
66
+ }
67
+ if (!resolution?.resolvedPath) {
68
+ return false;
69
+ }
70
+ const cwd = params.cwd ?? process.cwd();
71
+ const exists = params.fileExists ?? defaultFileExists;
72
+ const argv = params.argv.slice(1);
73
+ for (let i = 0; i < argv.length; i += 1) {
74
+ const token = argv[i];
75
+ if (!token) {
76
+ continue;
77
+ }
78
+ if (token === "-") {
79
+ continue;
80
+ }
81
+ if (token.startsWith("-")) {
82
+ const eqIndex = token.indexOf("=");
83
+ if (eqIndex > 0) {
84
+ const value = token.slice(eqIndex + 1);
85
+ if (value && hasGlobToken(value)) {
86
+ return false;
87
+ }
88
+ if (value && (isPathLikeToken(value) || exists(path.resolve(cwd, value)))) {
89
+ return false;
90
+ }
91
+ }
92
+ continue;
93
+ }
94
+ if (hasGlobToken(token)) {
95
+ return false;
96
+ }
97
+ if (isPathLikeToken(token)) {
98
+ return false;
99
+ }
100
+ if (exists(path.resolve(cwd, token))) {
101
+ return false;
102
+ }
103
+ }
104
+ return true;
105
+ }
106
+ function evaluateSegments(segments, params) {
107
+ const matches = [];
108
+ const allowSkills = params.autoAllowSkills === true && (params.skillBins?.size ?? 0) > 0;
109
+ const segmentSatisfiedBy = [];
110
+ const satisfied = segments.every((segment) => {
111
+ const candidatePath = resolveAllowlistCandidatePath(segment.resolution, params.cwd);
112
+ const candidateResolution = candidatePath && segment.resolution
113
+ ? { ...segment.resolution, resolvedPath: candidatePath }
114
+ : segment.resolution;
115
+ const match = matchAllowlist(params.allowlist, candidateResolution);
116
+ if (match) {
117
+ matches.push(match);
118
+ }
119
+ const safe = isSafeBinUsage({
120
+ argv: segment.argv,
121
+ resolution: segment.resolution,
122
+ safeBins: params.safeBins,
123
+ cwd: params.cwd,
124
+ });
125
+ const skillAllow = allowSkills && segment.resolution?.executableName
126
+ ? params.skillBins?.has(segment.resolution.executableName)
127
+ : false;
128
+ const by = match
129
+ ? "allowlist"
130
+ : safe
131
+ ? "safeBins"
132
+ : skillAllow
133
+ ? "skills"
134
+ : null;
135
+ segmentSatisfiedBy.push(by);
136
+ return Boolean(by);
137
+ });
138
+ return { satisfied, matches, segmentSatisfiedBy };
139
+ }
140
+ export function evaluateExecAllowlist(params) {
141
+ const allowlistMatches = [];
142
+ const segmentSatisfiedBy = [];
143
+ if (!params.analysis.ok || params.analysis.segments.length === 0) {
144
+ return { allowlistSatisfied: false, allowlistMatches, segmentSatisfiedBy };
145
+ }
146
+ // If the analysis contains chains, evaluate each chain part separately
147
+ if (params.analysis.chains) {
148
+ for (const chainSegments of params.analysis.chains) {
149
+ const result = evaluateSegments(chainSegments, {
150
+ allowlist: params.allowlist,
151
+ safeBins: params.safeBins,
152
+ cwd: params.cwd,
153
+ skillBins: params.skillBins,
154
+ autoAllowSkills: params.autoAllowSkills,
155
+ });
156
+ if (!result.satisfied) {
157
+ return { allowlistSatisfied: false, allowlistMatches: [], segmentSatisfiedBy: [] };
158
+ }
159
+ allowlistMatches.push(...result.matches);
160
+ segmentSatisfiedBy.push(...result.segmentSatisfiedBy);
161
+ }
162
+ return { allowlistSatisfied: true, allowlistMatches, segmentSatisfiedBy };
163
+ }
164
+ // No chains, evaluate all segments together
165
+ const result = evaluateSegments(params.analysis.segments, {
166
+ allowlist: params.allowlist,
167
+ safeBins: params.safeBins,
168
+ cwd: params.cwd,
169
+ skillBins: params.skillBins,
170
+ autoAllowSkills: params.autoAllowSkills,
171
+ });
172
+ return {
173
+ allowlistSatisfied: result.satisfied,
174
+ allowlistMatches: result.matches,
175
+ segmentSatisfiedBy: result.segmentSatisfiedBy,
176
+ };
177
+ }
178
+ /**
179
+ * Evaluates allowlist for shell commands (including &&, ||, ;) and returns analysis metadata.
180
+ */
181
+ export function evaluateShellAllowlist(params) {
182
+ const analysisFailure = () => ({
183
+ analysisOk: false,
184
+ allowlistSatisfied: false,
185
+ allowlistMatches: [],
186
+ segments: [],
187
+ segmentSatisfiedBy: [],
188
+ });
189
+ const chainParts = isWindowsPlatform(params.platform) ? null : splitCommandChain(params.command);
190
+ if (!chainParts) {
191
+ const analysis = analyzeShellCommand({
192
+ command: params.command,
193
+ cwd: params.cwd,
194
+ env: params.env,
195
+ platform: params.platform,
196
+ });
197
+ if (!analysis.ok) {
198
+ return analysisFailure();
199
+ }
200
+ const evaluation = evaluateExecAllowlist({
201
+ analysis,
202
+ allowlist: params.allowlist,
203
+ safeBins: params.safeBins,
204
+ cwd: params.cwd,
205
+ skillBins: params.skillBins,
206
+ autoAllowSkills: params.autoAllowSkills,
207
+ });
208
+ return {
209
+ analysisOk: true,
210
+ allowlistSatisfied: evaluation.allowlistSatisfied,
211
+ allowlistMatches: evaluation.allowlistMatches,
212
+ segments: analysis.segments,
213
+ segmentSatisfiedBy: evaluation.segmentSatisfiedBy,
214
+ };
215
+ }
216
+ const allowlistMatches = [];
217
+ const segments = [];
218
+ const segmentSatisfiedBy = [];
219
+ for (const part of chainParts) {
220
+ const analysis = analyzeShellCommand({
221
+ command: part,
222
+ cwd: params.cwd,
223
+ env: params.env,
224
+ platform: params.platform,
225
+ });
226
+ if (!analysis.ok) {
227
+ return analysisFailure();
228
+ }
229
+ segments.push(...analysis.segments);
230
+ const evaluation = evaluateExecAllowlist({
231
+ analysis,
232
+ allowlist: params.allowlist,
233
+ safeBins: params.safeBins,
234
+ cwd: params.cwd,
235
+ skillBins: params.skillBins,
236
+ autoAllowSkills: params.autoAllowSkills,
237
+ });
238
+ allowlistMatches.push(...evaluation.allowlistMatches);
239
+ segmentSatisfiedBy.push(...evaluation.segmentSatisfiedBy);
240
+ if (!evaluation.allowlistSatisfied) {
241
+ return {
242
+ analysisOk: true,
243
+ allowlistSatisfied: false,
244
+ allowlistMatches,
245
+ segments,
246
+ segmentSatisfiedBy,
247
+ };
248
+ }
249
+ }
250
+ return {
251
+ analysisOk: true,
252
+ allowlistSatisfied: true,
253
+ allowlistMatches,
254
+ segments,
255
+ segmentSatisfiedBy,
256
+ };
257
+ }