@poolzin/pool-bot 2026.2.24 → 2026.2.26

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 (646) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/acp/client.js +207 -18
  3. package/dist/acp/event-mapper.js +87 -22
  4. package/dist/acp/meta.js +12 -6
  5. package/dist/acp/secret-file.js +22 -0
  6. package/dist/agents/agent-paths.js +8 -9
  7. package/dist/agents/agent-scope.js +17 -5
  8. package/dist/agents/auth-profiles/oauth.js +148 -64
  9. package/dist/agents/auth-profiles/session-override.js +13 -7
  10. package/dist/agents/bash-process-registry.test-helpers.js +29 -0
  11. package/dist/agents/bash-tools.exec-approval-request.js +20 -0
  12. package/dist/agents/bash-tools.exec-host-gateway.js +240 -0
  13. package/dist/agents/bash-tools.exec-host-node.js +235 -0
  14. package/dist/agents/bash-tools.exec-runtime.js +2 -25
  15. package/dist/agents/bash-tools.exec-types.js +1 -0
  16. package/dist/agents/bash-tools.process.js +224 -218
  17. package/dist/agents/bedrock-discovery.js +3 -1
  18. package/dist/agents/byteplus-models.js +97 -0
  19. package/dist/agents/chutes-oauth.js +1 -0
  20. package/dist/agents/cli-runner/helpers.js +4 -0
  21. package/dist/agents/compaction.js +41 -14
  22. package/dist/agents/content-blocks.js +16 -0
  23. package/dist/agents/doubao-models.js +121 -0
  24. package/dist/agents/failover-error.js +2 -0
  25. package/dist/agents/huggingface-models.js +5 -3
  26. package/dist/agents/live-model-filter.js +5 -0
  27. package/dist/agents/minimax-vlm.js +10 -8
  28. package/dist/agents/model-auth.js +6 -0
  29. package/dist/agents/model-catalog.js +3 -1
  30. package/dist/agents/model-fallback.js +96 -101
  31. package/dist/agents/model-selection.js +7 -1
  32. package/dist/agents/models-config.providers.js +364 -165
  33. package/dist/agents/ollama-stream.js +117 -4
  34. package/dist/agents/opencode-zen-models.js +22 -11
  35. package/dist/agents/pi-embedded-helpers/errors.js +55 -33
  36. package/dist/agents/pi-embedded-helpers/messaging-dedupe.js +10 -5
  37. package/dist/agents/pi-embedded-helpers/thinking.js +10 -5
  38. package/dist/agents/pi-embedded-helpers.js +1 -1
  39. package/dist/agents/pi-embedded-payloads.js +1 -0
  40. package/dist/agents/pi-embedded-runner/compact.js +29 -7
  41. package/dist/agents/pi-embedded-runner/extensions.js +28 -26
  42. package/dist/agents/pi-embedded-runner/google.js +20 -8
  43. package/dist/agents/pi-embedded-runner/run/attempt.js +95 -36
  44. package/dist/agents/pi-embedded-runner/run.js +71 -12
  45. package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +34 -0
  46. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +11 -2
  47. package/dist/agents/pi-embedded-runner/session-manager-cache.js +11 -7
  48. package/dist/agents/pi-embedded-runner/system-prompt.js +2 -0
  49. package/dist/agents/pi-embedded-runner/thinking.js +42 -0
  50. package/dist/agents/pi-embedded-runner/tool-name-allowlist.js +19 -0
  51. package/dist/agents/pi-embedded-runner/utils.js +7 -10
  52. package/dist/agents/pi-embedded-subscribe.handlers.lifecycle.js +45 -56
  53. package/dist/agents/pi-embedded-subscribe.handlers.tools.js +2 -2
  54. package/dist/agents/pi-embedded-subscribe.js +9 -4
  55. package/dist/agents/pi-embedded-subscribe.tools.js +68 -14
  56. package/dist/agents/pi-embedded-utils.js +3 -0
  57. package/dist/agents/pi-extensions/compaction-safeguard-runtime.js +4 -20
  58. package/dist/agents/pi-extensions/compaction-safeguard.js +75 -33
  59. package/dist/agents/pi-settings.js +40 -0
  60. package/dist/agents/pi-tools.policy.js +2 -1
  61. package/dist/agents/provider/config-loader.js +1 -1
  62. package/dist/agents/sandbox/browser.js +170 -33
  63. package/dist/agents/sandbox/config-hash.js +14 -27
  64. package/dist/agents/sandbox/config.js +21 -2
  65. package/dist/agents/sandbox/constants.js +2 -0
  66. package/dist/agents/sandbox/docker.js +16 -2
  67. package/dist/agents/sandbox/novnc-auth.js +62 -0
  68. package/dist/agents/sandbox/sanitize-env-vars.js +1 -1
  69. package/dist/agents/sandbox/shared.js +10 -6
  70. package/dist/agents/sandbox-paths.js +24 -11
  71. package/dist/agents/schema/clean-for-gemini.js +132 -85
  72. package/dist/agents/session-slug.js +10 -5
  73. package/dist/agents/session-tool-result-guard-wrapper.js +1 -0
  74. package/dist/agents/session-tool-result-guard.js +3 -1
  75. package/dist/agents/session-transcript-repair.js +40 -6
  76. package/dist/agents/skills/bundled-dir.js +19 -5
  77. package/dist/agents/skills/env-overrides.js +124 -43
  78. package/dist/agents/skills/frontmatter.js +6 -6
  79. package/dist/agents/skills/plugin-skills.js +14 -7
  80. package/dist/agents/skills/workspace.js +1 -0
  81. package/dist/agents/skills.test-helpers.js +13 -0
  82. package/dist/agents/stable-stringify.js +12 -0
  83. package/dist/agents/subagent-announce.js +251 -49
  84. package/dist/agents/subagent-lifecycle-events.js +19 -0
  85. package/dist/agents/subagent-registry-cleanup.js +31 -0
  86. package/dist/agents/subagent-registry-completion.js +68 -0
  87. package/dist/agents/subagent-registry-queries.js +117 -0
  88. package/dist/agents/subagent-registry-state.js +46 -0
  89. package/dist/agents/subagent-registry.js +252 -221
  90. package/dist/agents/subagent-registry.mocks.shared.js +12 -0
  91. package/dist/agents/subagent-registry.store.js +1 -0
  92. package/dist/agents/subagent-registry.types.js +1 -0
  93. package/dist/agents/subagent-spawn.js +195 -7
  94. package/dist/agents/system-prompt.js +22 -6
  95. package/dist/agents/test-helpers/assistant-message-fixtures.js +29 -0
  96. package/dist/agents/test-helpers/fast-coding-tools.js +1 -18
  97. package/dist/agents/test-helpers/fast-core-tools.js +1 -17
  98. package/dist/agents/test-helpers/pi-tools-sandbox-context.js +27 -0
  99. package/dist/agents/timeout.js +18 -6
  100. package/dist/agents/tool-call-id.js +1 -1
  101. package/dist/agents/tool-display-common.js +162 -29
  102. package/dist/agents/tool-images.js +82 -9
  103. package/dist/agents/tool-policy-shared.js +108 -0
  104. package/dist/agents/tool-policy.js +51 -26
  105. package/dist/agents/tools/browser-tool.js +160 -54
  106. package/dist/agents/tools/canvas-tool.js +27 -1
  107. package/dist/agents/tools/common.js +45 -0
  108. package/dist/agents/tools/cron-tool.test-helpers.js +12 -0
  109. package/dist/agents/tools/discord-actions-guild.js +4 -1
  110. package/dist/agents/tools/discord-actions-moderation-shared.js +27 -0
  111. package/dist/agents/tools/gateway-tool.js +3 -1
  112. package/dist/agents/tools/image-tool.js +214 -99
  113. package/dist/agents/tools/nodes-utils.js +1 -10
  114. package/dist/agents/tools/sessions-history-tool.js +140 -108
  115. package/dist/agents/tools/sessions-send-helpers.js +12 -6
  116. package/dist/agents/tools/sessions-spawn-tool.js +8 -2
  117. package/dist/agents/tools/subagents-tool.js +2 -1
  118. package/dist/agents/tools/whatsapp-actions.js +10 -2
  119. package/dist/agents/tools/whatsapp-target-auth.js +18 -0
  120. package/dist/agents/transcript-policy.js +22 -8
  121. package/dist/agents/venice-models.js +11 -3
  122. package/dist/agents/workspace.js +222 -46
  123. package/dist/auto-reply/commands-registry.data.js +51 -0
  124. package/dist/auto-reply/commands-registry.js +19 -21
  125. package/dist/auto-reply/fallback-state.js +114 -0
  126. package/dist/auto-reply/group-activation.js +10 -5
  127. package/dist/auto-reply/inbound-debounce.js +10 -5
  128. package/dist/auto-reply/model-runtime.js +68 -0
  129. package/dist/auto-reply/reply/abort.js +1 -1
  130. package/dist/auto-reply/reply/agent-runner-execution.js +40 -5
  131. package/dist/auto-reply/reply/agent-runner.js +165 -39
  132. package/dist/auto-reply/reply/bash-command.js +41 -39
  133. package/dist/auto-reply/reply/command-gates.js +25 -0
  134. package/dist/auto-reply/reply/commands-allowlist.js +111 -72
  135. package/dist/auto-reply/reply/commands-bash.js +6 -5
  136. package/dist/auto-reply/reply/commands-config.js +30 -28
  137. package/dist/auto-reply/reply/commands-core.js +2 -1
  138. package/dist/auto-reply/reply/commands-info.js +1 -0
  139. package/dist/auto-reply/reply/commands-models.js +65 -14
  140. package/dist/auto-reply/reply/commands-session.js +237 -82
  141. package/dist/auto-reply/reply/commands-setunset-standard.js +13 -0
  142. package/dist/auto-reply/reply/commands-setunset.js +45 -0
  143. package/dist/auto-reply/reply/commands-subagents/action-agents.js +44 -0
  144. package/dist/auto-reply/reply/commands-subagents/action-focus.js +64 -0
  145. package/dist/auto-reply/reply/commands-subagents/action-help.js +4 -0
  146. package/dist/auto-reply/reply/commands-subagents/action-info.js +45 -0
  147. package/dist/auto-reply/reply/commands-subagents/action-kill.js +60 -0
  148. package/dist/auto-reply/reply/commands-subagents/action-list.js +44 -0
  149. package/dist/auto-reply/reply/commands-subagents/action-log.js +29 -0
  150. package/dist/auto-reply/reply/commands-subagents/action-send.js +119 -0
  151. package/dist/auto-reply/reply/commands-subagents/action-spawn.js +52 -0
  152. package/dist/auto-reply/reply/commands-subagents/action-unfocus.js +30 -0
  153. package/dist/auto-reply/reply/commands-subagents/shared.js +303 -0
  154. package/dist/auto-reply/reply/commands-subagents.js +51 -587
  155. package/dist/auto-reply/reply/commands-tts.js +10 -5
  156. package/dist/auto-reply/reply/config-value.js +10 -5
  157. package/dist/auto-reply/reply/directive-handling.model-picker.js +12 -6
  158. package/dist/auto-reply/reply/directive-handling.persist.js +9 -21
  159. package/dist/auto-reply/reply/directive-handling.shared.js +24 -4
  160. package/dist/auto-reply/reply/followup-runner.js +1 -0
  161. package/dist/auto-reply/reply/get-reply-directives-utils.js +23 -14
  162. package/dist/auto-reply/reply/get-reply-directives.js +17 -28
  163. package/dist/auto-reply/reply/get-reply-inline-actions.js +1 -0
  164. package/dist/auto-reply/reply/get-reply.js +71 -12
  165. package/dist/auto-reply/reply/model-selection.js +80 -39
  166. package/dist/auto-reply/reply/queue/enqueue.js +10 -5
  167. package/dist/auto-reply/reply/queue/state.js +13 -12
  168. package/dist/auto-reply/reply/reply-payloads.js +67 -36
  169. package/dist/auto-reply/reply/reply-reference.js +9 -8
  170. package/dist/auto-reply/reply/route-reply.js +15 -8
  171. package/dist/auto-reply/reply/session-reset-prompt.js +1 -1
  172. package/dist/auto-reply/reply/session.js +22 -6
  173. package/dist/auto-reply/reply/strip-inbound-meta.js +147 -0
  174. package/dist/auto-reply/reply/subagents-utils.js +56 -30
  175. package/dist/auto-reply/reply/typing.js +46 -21
  176. package/dist/auto-reply/send-policy.js +14 -7
  177. package/dist/auto-reply/status.js +140 -16
  178. package/dist/auto-reply/templating.js +10 -5
  179. package/dist/auto-reply/thinking.js +7 -16
  180. package/dist/auto-reply/tokens.js +21 -5
  181. package/dist/browser/bridge-server.js +36 -20
  182. package/dist/browser/cdp.helpers.js +7 -14
  183. package/dist/browser/cdp.js +35 -15
  184. package/dist/browser/chrome.profile-decoration.js +7 -4
  185. package/dist/browser/config.js +30 -0
  186. package/dist/browser/extension-relay-auth.js +55 -0
  187. package/dist/browser/extension-relay.js +74 -29
  188. package/dist/browser/navigation-guard.js +39 -0
  189. package/dist/browser/paths.js +77 -0
  190. package/dist/browser/profiles.js +13 -8
  191. package/dist/browser/pw-ai-module.js +10 -5
  192. package/dist/browser/pw-session.js +76 -39
  193. package/dist/browser/pw-tools-core.interactions.js +14 -7
  194. package/dist/browser/pw-tools-core.state.js +12 -6
  195. package/dist/browser/routes/agent.act.js +431 -424
  196. package/dist/browser/routes/agent.shared.js +47 -3
  197. package/dist/browser/routes/agent.snapshot.js +122 -116
  198. package/dist/browser/routes/agent.storage.js +303 -297
  199. package/dist/browser/routes/tabs.js +154 -100
  200. package/dist/browser/server-context.js +7 -0
  201. package/dist/browser/server-lifecycle.js +37 -0
  202. package/dist/build-info.json +3 -3
  203. package/dist/channels/allow-from.js +26 -0
  204. package/dist/channels/allowlists/resolve-utils.js +43 -19
  205. package/dist/channels/channel-config.js +14 -7
  206. package/dist/channels/draft-stream-loop.js +7 -0
  207. package/dist/channels/model-overrides.js +82 -0
  208. package/dist/channels/plugins/account-action-gate.js +13 -0
  209. package/dist/channels/plugins/message-actions.js +10 -0
  210. package/dist/channels/plugins/normalize/imessage.js +14 -7
  211. package/dist/channels/plugins/normalize/slack.js +10 -5
  212. package/dist/channels/plugins/normalize/telegram.js +14 -7
  213. package/dist/channels/plugins/outbound/discord.js +80 -8
  214. package/dist/channels/plugins/outbound/signal.js +11 -11
  215. package/dist/channels/plugins/setup-helpers.js +10 -5
  216. package/dist/channels/sender-label.js +14 -7
  217. package/dist/channels/session.js +4 -2
  218. package/dist/channels/status-reactions.js +297 -0
  219. package/dist/channels/telegram/api.js +18 -0
  220. package/dist/cli/argv.js +84 -21
  221. package/dist/cli/banner.js +3 -2
  222. package/dist/cli/browser-cli-actions-input/register.files-downloads.js +65 -56
  223. package/dist/cli/cli-name.js +11 -11
  224. package/dist/cli/cli-utils.js +13 -3
  225. package/dist/cli/command-format.js +1 -1
  226. package/dist/cli/config-cli.js +1 -1
  227. package/dist/cli/daemon-cli/lifecycle-core.js +31 -19
  228. package/dist/cli/daemon-cli/lifecycle.js +64 -2
  229. package/dist/cli/daemon-cli/restart-health.js +126 -0
  230. package/dist/cli/daemon-cli/status.gather.js +9 -13
  231. package/dist/cli/daemon-cli/status.print.js +2 -10
  232. package/dist/cli/deps.js +27 -22
  233. package/dist/cli/exec-approvals-cli.js +92 -124
  234. package/dist/cli/gateway-cli/run-loop.js +23 -5
  235. package/dist/cli/memory-cli.js +158 -61
  236. package/dist/cli/node-cli/register.js +14 -5
  237. package/dist/cli/nodes-cli/register.push.js +63 -0
  238. package/dist/cli/nodes-media-utils.js +26 -0
  239. package/dist/cli/outbound-send-deps.js +2 -9
  240. package/dist/cli/outbound-send-mapping.js +11 -0
  241. package/dist/cli/pairing-cli.js +40 -14
  242. package/dist/cli/plugins-cli.js +250 -73
  243. package/dist/cli/ports.js +11 -10
  244. package/dist/cli/program/build-program.js +3 -1
  245. package/dist/cli/program/command-registry.js +214 -136
  246. package/dist/cli/program/command-tree.js +16 -0
  247. package/dist/cli/program/help.js +43 -12
  248. package/dist/cli/program/preaction.js +13 -9
  249. package/dist/cli/program/register.configure.js +3 -18
  250. package/dist/cli/program/register.maintenance.js +2 -2
  251. package/dist/cli/program/register.onboard.js +2 -0
  252. package/dist/cli/program/register.status-health-sessions.js +16 -17
  253. package/dist/cli/program/register.subclis.js +93 -52
  254. package/dist/cli/route.js +12 -8
  255. package/dist/cli/system-cli.js +36 -46
  256. package/dist/cli/test-runtime-capture.js +24 -0
  257. package/dist/cli/update-cli/shared.js +22 -9
  258. package/dist/cli/update-cli/update-command.js +89 -14
  259. package/dist/cli/update-cli/wizard.js +6 -12
  260. package/dist/commands/agent/run-context.js +18 -5
  261. package/dist/commands/agent/session-store.js +17 -4
  262. package/dist/commands/agent.js +185 -89
  263. package/dist/commands/agents.bindings.js +14 -7
  264. package/dist/commands/agents.commands.add.js +13 -9
  265. package/dist/commands/agents.commands.identity.js +12 -6
  266. package/dist/commands/agents.commands.list.js +11 -6
  267. package/dist/commands/agents.config.js +8 -10
  268. package/dist/commands/agents.providers.js +12 -6
  269. package/dist/commands/auth-choice-options.js +103 -75
  270. package/dist/commands/auth-choice.apply.byteplus.js +55 -0
  271. package/dist/commands/auth-choice.apply.js +4 -0
  272. package/dist/commands/auth-choice.apply.minimax.js +61 -13
  273. package/dist/commands/auth-choice.apply.openai.js +3 -1
  274. package/dist/commands/auth-choice.apply.volcengine.js +55 -0
  275. package/dist/commands/auth-choice.preferred-provider.js +2 -0
  276. package/dist/commands/channels/remove.js +13 -6
  277. package/dist/commands/channels/shared.js +4 -14
  278. package/dist/commands/channels.mock-harness.js +23 -0
  279. package/dist/commands/configure.commands.js +14 -0
  280. package/dist/commands/configure.gateway.js +2 -4
  281. package/dist/commands/configure.js +1 -1
  282. package/dist/commands/configure.shared.js +11 -0
  283. package/dist/commands/daemon-install-helpers.js +2 -2
  284. package/dist/commands/daemon-install-runtime-warning.js +11 -0
  285. package/dist/commands/dashboard.js +12 -10
  286. package/dist/commands/docs.js +14 -8
  287. package/dist/commands/doctor-config-flow.js +11 -9
  288. package/dist/commands/doctor-legacy-config.js +281 -0
  289. package/dist/commands/doctor-state-integrity.js +99 -23
  290. package/dist/commands/doctor-update.js +12 -9
  291. package/dist/commands/models/list.list-command.js +7 -5
  292. package/dist/commands/models/set-image.js +2 -21
  293. package/dist/commands/node-daemon-install-helpers.js +10 -8
  294. package/dist/commands/onboard-auth.config-minimax.js +54 -80
  295. package/dist/commands/onboard-auth.config-opencode.js +2 -18
  296. package/dist/commands/onboard-auth.credentials.js +90 -13
  297. package/dist/commands/onboard-auth.js +1 -1
  298. package/dist/commands/onboard-auth.models.js +6 -5
  299. package/dist/commands/onboard-hooks.js +1 -1
  300. package/dist/commands/onboard-non-interactive/api-keys.js +14 -7
  301. package/dist/commands/onboard-non-interactive/local/auth-choice.js +64 -49
  302. package/dist/commands/onboard-provider-auth-flags.js +14 -0
  303. package/dist/commands/onboard-remote.js +14 -7
  304. package/dist/commands/onboard.js +11 -13
  305. package/dist/commands/sandbox-display.js +6 -5
  306. package/dist/commands/sessions.test-helpers.js +61 -0
  307. package/dist/commands/status-all/diagnosis.js +14 -10
  308. package/dist/commands/status-all/format.js +1 -0
  309. package/dist/commands/status.gateway-probe.js +1 -16
  310. package/dist/commands/systemd-linger.js +12 -6
  311. package/dist/config/agent-limits.js +2 -0
  312. package/dist/config/commands.js +32 -15
  313. package/dist/config/config-paths.js +9 -11
  314. package/dist/config/config.js +1 -1
  315. package/dist/config/defaults.js +22 -2
  316. package/dist/config/discord-preview-streaming.js +104 -0
  317. package/dist/config/env-substitution.js +62 -34
  318. package/dist/config/env-vars.js +45 -7
  319. package/dist/config/includes.js +4 -0
  320. package/dist/config/io.js +656 -171
  321. package/dist/config/legacy.migrations.part-1.js +189 -78
  322. package/dist/config/legacy.shared.js +3 -1
  323. package/dist/config/merge-patch.js +54 -4
  324. package/dist/config/prototype-keys.js +4 -0
  325. package/dist/config/redact-snapshot.js +404 -76
  326. package/dist/config/schema.help.js +44 -7
  327. package/dist/config/schema.js +58 -570
  328. package/dist/config/schema.labels.js +38 -6
  329. package/dist/config/sessions/delivery-info.js +10 -3
  330. package/dist/config/sessions/main-session.js +10 -5
  331. package/dist/config/sessions/session-file.js +33 -0
  332. package/dist/config/sessions/session-key.js +10 -5
  333. package/dist/config/sessions/store.js +1 -1
  334. package/dist/config/sessions.js +1 -0
  335. package/dist/config/validation.js +140 -85
  336. package/dist/config/zod-schema.agent-runtime.js +11 -0
  337. package/dist/config/zod-schema.hooks.js +40 -11
  338. package/dist/config/zod-schema.installs.js +20 -0
  339. package/dist/config/zod-schema.js +156 -20
  340. package/dist/config/zod-schema.providers-core.js +78 -4
  341. package/dist/config/zod-schema.providers.js +6 -1
  342. package/dist/config/zod-schema.session.js +41 -2
  343. package/dist/cron/run-log.js +3 -0
  344. package/dist/cron/schedule.js +21 -10
  345. package/dist/cron/service/ops.js +35 -21
  346. package/dist/cron/service/timer.js +116 -16
  347. package/dist/cron/stagger.js +3 -1
  348. package/dist/daemon/cmd-argv.js +21 -0
  349. package/dist/daemon/cmd-set.js +58 -0
  350. package/dist/daemon/service-types.js +1 -0
  351. package/dist/discord/api.js +12 -6
  352. package/dist/discord/draft-chunking.js +22 -0
  353. package/dist/discord/draft-stream.js +124 -0
  354. package/dist/discord/monitor/agent-components.js +1 -1
  355. package/dist/discord/monitor/commands.js +5 -0
  356. package/dist/discord/monitor/exec-approvals.js +357 -162
  357. package/dist/discord/monitor/gateway-plugin.js +2 -1
  358. package/dist/discord/monitor/listeners.js +37 -27
  359. package/dist/discord/monitor/message-handler.js +4 -1
  360. package/dist/discord/monitor/message-handler.preflight.js +65 -8
  361. package/dist/discord/monitor/message-handler.process.js +246 -217
  362. package/dist/discord/monitor/message-utils.js +143 -6
  363. package/dist/discord/monitor/model-picker-preferences.js +143 -0
  364. package/dist/discord/monitor/model-picker.js +651 -0
  365. package/dist/discord/monitor/native-command.js +573 -16
  366. package/dist/discord/monitor/provider.allowlist.js +223 -0
  367. package/dist/discord/monitor/provider.js +275 -347
  368. package/dist/discord/monitor/provider.lifecycle.js +100 -0
  369. package/dist/discord/monitor/reply-delivery.js +123 -16
  370. package/dist/discord/monitor/thread-bindings.discord-api.js +215 -0
  371. package/dist/discord/monitor/thread-bindings.js +4 -0
  372. package/dist/discord/monitor/thread-bindings.lifecycle.js +177 -0
  373. package/dist/discord/monitor/thread-bindings.manager.js +423 -0
  374. package/dist/discord/monitor/thread-bindings.messages.js +55 -0
  375. package/dist/discord/monitor/thread-bindings.state.js +358 -0
  376. package/dist/discord/monitor/thread-bindings.types.js +6 -0
  377. package/dist/discord/resolve-users.js +33 -21
  378. package/dist/discord/send.channels.js +15 -0
  379. package/dist/discord/send.js +3 -2
  380. package/dist/discord/send.outbound.js +82 -26
  381. package/dist/discord/send.permissions.js +83 -30
  382. package/dist/discord/send.reactions.js +8 -4
  383. package/dist/discord/token.js +10 -5
  384. package/dist/discord/voice/command.js +263 -0
  385. package/dist/discord/voice/manager.js +531 -0
  386. package/dist/gateway/auth.js +72 -13
  387. package/dist/gateway/call.js +152 -83
  388. package/dist/gateway/canvas-capability.js +75 -0
  389. package/dist/gateway/client.js +28 -4
  390. package/dist/gateway/config-reload.js +3 -4
  391. package/dist/gateway/control-plane-audit.js +28 -0
  392. package/dist/gateway/control-plane-rate-limit.js +53 -0
  393. package/dist/gateway/control-ui.js +219 -96
  394. package/dist/gateway/events.js +1 -0
  395. package/dist/gateway/hooks-mapping.js +88 -38
  396. package/dist/gateway/hooks.js +109 -54
  397. package/dist/gateway/http-auth-helpers.js +3 -2
  398. package/dist/gateway/http-common.js +22 -0
  399. package/dist/gateway/http-endpoint-helpers.js +1 -0
  400. package/dist/gateway/method-scopes.js +169 -0
  401. package/dist/gateway/net.js +74 -9
  402. package/dist/gateway/node-invoke-system-run-approval.js +14 -35
  403. package/dist/gateway/node-registry.js +10 -5
  404. package/dist/gateway/openai-http.js +1 -0
  405. package/dist/gateway/openresponses-http.js +121 -110
  406. package/dist/gateway/origin-check.js +1 -18
  407. package/dist/gateway/probe-auth.js +2 -0
  408. package/dist/gateway/protocol/index.js +4 -2
  409. package/dist/gateway/protocol/schema/cron.js +1 -0
  410. package/dist/gateway/protocol/schema/devices.js +1 -0
  411. package/dist/gateway/protocol/schema/protocol-schemas.js +4 -1
  412. package/dist/gateway/protocol/schema/push.js +18 -0
  413. package/dist/gateway/protocol/schema/sessions.js +6 -0
  414. package/dist/gateway/protocol/schema.js +1 -0
  415. package/dist/gateway/role-policy.js +17 -0
  416. package/dist/gateway/server/ws-connection/connect-policy.js +37 -0
  417. package/dist/gateway/server/ws-connection/message-handler.js +175 -148
  418. package/dist/gateway/server-chat.js +83 -25
  419. package/dist/gateway/server-constants.js +10 -9
  420. package/dist/gateway/server-cron.js +1 -0
  421. package/dist/gateway/server-http.js +247 -54
  422. package/dist/gateway/server-maintenance.js +20 -5
  423. package/dist/gateway/server-methods/agent.js +162 -24
  424. package/dist/gateway/server-methods/chat.js +465 -130
  425. package/dist/gateway/server-methods/config.js +193 -152
  426. package/dist/gateway/server-methods/devices.js +17 -3
  427. package/dist/gateway/server-methods/models.js +11 -1
  428. package/dist/gateway/server-methods/nodes.helpers.js +12 -0
  429. package/dist/gateway/server-methods/nodes.js +251 -69
  430. package/dist/gateway/server-methods/push.js +53 -0
  431. package/dist/gateway/server-methods/sessions.js +64 -8
  432. package/dist/gateway/server-methods/usage.js +162 -75
  433. package/dist/gateway/server-node-events.js +29 -0
  434. package/dist/gateway/server-reload-handlers.js +2 -3
  435. package/dist/gateway/server-runtime-config.js +39 -13
  436. package/dist/gateway/server-runtime-state.js +2 -0
  437. package/dist/gateway/server-startup-memory.js +17 -11
  438. package/dist/gateway/server-ws-runtime.js +1 -0
  439. package/dist/gateway/server.impl.js +296 -139
  440. package/dist/gateway/session-preview.test-helpers.js +11 -0
  441. package/dist/gateway/session-utils.fs.js +32 -34
  442. package/dist/gateway/sessions-resolve.js +17 -5
  443. package/dist/gateway/startup-auth.js +126 -0
  444. package/dist/gateway/test-helpers.agent-results.js +15 -0
  445. package/dist/gateway/test-helpers.mocks.js +37 -14
  446. package/dist/gateway/test-helpers.openai-mock.js +14 -7
  447. package/dist/gateway/test-helpers.server.js +161 -77
  448. package/dist/gateway/tools-invoke-http.js +21 -10
  449. package/dist/hooks/bundled/bootstrap-extra-files/handler.js +3 -1
  450. package/dist/hooks/bundled/command-logger/handler.js +7 -2
  451. package/dist/hooks/bundled/session-memory/handler.js +170 -38
  452. package/dist/hooks/frontmatter.js +6 -6
  453. package/dist/hooks/gmail-watcher-lifecycle.js +23 -0
  454. package/dist/hooks/gmail-watcher.js +11 -6
  455. package/dist/hooks/internal-hooks.js +11 -1
  456. package/dist/hooks/llm-slug-generator.js +4 -1
  457. package/dist/hooks/workspace.js +47 -17
  458. package/dist/imessage/accounts.js +9 -20
  459. package/dist/imessage/monitor/inbound-processing.js +2 -1
  460. package/dist/infra/archive-path.js +49 -0
  461. package/dist/infra/archive.js +174 -73
  462. package/dist/infra/control-ui-assets.js +14 -6
  463. package/dist/infra/device-pairing.js +204 -144
  464. package/dist/infra/env.js +10 -5
  465. package/dist/infra/exec-approvals-allowlist.js +141 -70
  466. package/dist/infra/exec-approvals-analysis.js +78 -20
  467. package/dist/infra/exec-approvals.js +5 -17
  468. package/dist/infra/exec-safe-bin-policy.js +277 -0
  469. package/dist/infra/fixed-window-rate-limit.js +33 -0
  470. package/dist/infra/fs-safe.js +71 -39
  471. package/dist/infra/gateway-lock.js +6 -2
  472. package/dist/infra/git-root.js +61 -0
  473. package/dist/infra/heartbeat-active-hours.js +2 -2
  474. package/dist/infra/heartbeat-reason.js +40 -0
  475. package/dist/infra/heartbeat-runner.js +72 -32
  476. package/dist/infra/heartbeat-wake.js +6 -12
  477. package/dist/infra/host-env-security-policy.json +19 -0
  478. package/dist/infra/host-env-security.js +66 -0
  479. package/dist/infra/install-source-utils.js +91 -7
  480. package/dist/infra/net/ssrf.js +131 -38
  481. package/dist/infra/node-pairing.js +50 -105
  482. package/dist/infra/npm-integrity.js +45 -0
  483. package/dist/infra/npm-pack-install.js +40 -0
  484. package/dist/infra/outbound/bound-delivery-router.js +88 -0
  485. package/dist/infra/outbound/channel-adapters.js +20 -7
  486. package/dist/infra/outbound/channel-selection.js +12 -6
  487. package/dist/infra/outbound/envelope.js +1 -1
  488. package/dist/infra/outbound/format.js +12 -6
  489. package/dist/infra/outbound/message-action-runner.js +107 -327
  490. package/dist/infra/outbound/message.js +59 -36
  491. package/dist/infra/outbound/outbound-policy.js +52 -25
  492. package/dist/infra/outbound/outbound-send-service.js +58 -71
  493. package/dist/infra/outbound/payloads.js +14 -7
  494. package/dist/infra/outbound/session-binding-service.js +123 -0
  495. package/dist/infra/pairing-files.js +10 -0
  496. package/dist/infra/path-guards.js +25 -0
  497. package/dist/infra/plain-object.js +9 -0
  498. package/dist/infra/provider-usage.fetch.codex.js +7 -15
  499. package/dist/infra/provider-usage.fetch.gemini.js +14 -11
  500. package/dist/infra/provider-usage.fetch.shared.js +30 -1
  501. package/dist/infra/provider-usage.fetch.zai.js +10 -9
  502. package/dist/infra/push-apns.js +365 -0
  503. package/dist/infra/restart-sentinel.js +16 -1
  504. package/dist/infra/restart.js +229 -26
  505. package/dist/infra/retry-policy.js +4 -2
  506. package/dist/infra/retry.js +9 -5
  507. package/dist/infra/scp-host.js +54 -0
  508. package/dist/infra/session-cost-usage.js +107 -59
  509. package/dist/infra/session-maintenance-warning.js +3 -1
  510. package/dist/infra/shell-env.js +98 -34
  511. package/dist/infra/ssh-config.js +12 -6
  512. package/dist/infra/system-run-command.js +49 -4
  513. package/dist/infra/update-channels.js +10 -5
  514. package/dist/infra/update-startup.js +86 -9
  515. package/dist/line/accounts.js +5 -7
  516. package/dist/line/bot-access.js +8 -20
  517. package/dist/line/bot-handlers.js +3 -1
  518. package/dist/link-understanding/detect.js +15 -7
  519. package/dist/media/constants.js +15 -6
  520. package/dist/media/image-ops.js +7 -0
  521. package/dist/media/inbound-path-policy.js +114 -0
  522. package/dist/media/input-files.js +16 -0
  523. package/dist/media/local-roots.js +3 -2
  524. package/dist/media-understanding/apply.js +4 -1
  525. package/dist/media-understanding/concurrency.js +8 -20
  526. package/dist/memory/backend-config.js +45 -6
  527. package/dist/memory/embeddings.js +10 -4
  528. package/dist/memory/fs-utils.js +23 -0
  529. package/dist/memory/manager-search.js +12 -6
  530. package/dist/memory/manager-sync-ops.js +12 -2
  531. package/dist/memory/qmd-manager.js +466 -53
  532. package/dist/memory/query-expansion.js +167 -3
  533. package/dist/memory/status-format.js +10 -5
  534. package/dist/memory/sync-memory-files.js +1 -1
  535. package/dist/memory/test-manager.js +8 -0
  536. package/dist/node-host/invoke-system-run.js +281 -0
  537. package/dist/node-host/invoke.js +55 -337
  538. package/dist/pairing/pairing-store.js +22 -0
  539. package/dist/plugin-sdk/allow-from.js +1 -1
  540. package/dist/plugin-sdk/command-auth.js +3 -1
  541. package/dist/plugin-sdk/index.js +6 -3
  542. package/dist/plugin-sdk/temp-path.js +47 -0
  543. package/dist/plugin-sdk/webhook-targets.js +32 -0
  544. package/dist/plugins/bundled-dir.js +9 -6
  545. package/dist/plugins/discovery.js +217 -23
  546. package/dist/plugins/hook-runner-global.js +16 -0
  547. package/dist/plugins/hooks.js +50 -0
  548. package/dist/plugins/install.js +28 -16
  549. package/dist/plugins/loader.js +192 -26
  550. package/dist/plugins/logger.js +8 -0
  551. package/dist/plugins/manifest-registry.js +3 -0
  552. package/dist/plugins/path-safety.js +34 -0
  553. package/dist/plugins/registry.js +5 -2
  554. package/dist/plugins/runtime/index.js +271 -206
  555. package/dist/plugins/runtime.js +3 -17
  556. package/dist/plugins/update.js +78 -12
  557. package/dist/process/spawn-utils.js +14 -7
  558. package/dist/providers/github-copilot-models.js +4 -1
  559. package/dist/providers/github-copilot-token.js +11 -6
  560. package/dist/providers/qwen-portal-oauth.js +14 -6
  561. package/dist/routing/account-id.js +30 -0
  562. package/dist/routing/resolve-route.js +3 -7
  563. package/dist/routing/session-key.js +2 -16
  564. package/dist/security/audit-channel.js +100 -20
  565. package/dist/security/audit-extra.async.js +505 -179
  566. package/dist/security/audit-extra.js +12 -2
  567. package/dist/security/audit-extra.sync.js +421 -35
  568. package/dist/security/audit-fs.js +31 -13
  569. package/dist/security/audit.js +180 -370
  570. package/dist/security/dm-policy-shared.js +68 -0
  571. package/dist/security/external-content.js +46 -14
  572. package/dist/security/fix.js +49 -85
  573. package/dist/security/scan-paths.js +20 -0
  574. package/dist/security/secret-equal.js +3 -7
  575. package/dist/security/windows-acl.js +30 -15
  576. package/dist/shared/entry-status.js +6 -0
  577. package/dist/shared/frontmatter.js +5 -5
  578. package/dist/shared/node-list-parse.js +13 -0
  579. package/dist/shared/node-match.js +11 -4
  580. package/dist/shared/operator-scope-compat.js +42 -0
  581. package/dist/shared/text-chunking.js +29 -0
  582. package/dist/signal/accounts.js +7 -20
  583. package/dist/signal/monitor/event-handler.js +3 -1
  584. package/dist/slack/accounts.js +6 -19
  585. package/dist/slack/actions.js +11 -3
  586. package/dist/slack/blocks.test-helpers.js +31 -0
  587. package/dist/slack/monitor/auth.js +1 -1
  588. package/dist/slack/monitor/message-handler/dispatch.js +50 -29
  589. package/dist/slack/monitor/mrkdwn.js +8 -0
  590. package/dist/slack/monitor/replies.js +15 -7
  591. package/dist/slack/monitor/slash.js +22 -13
  592. package/dist/slack/resolve-channels.js +10 -5
  593. package/dist/slack/send.js +102 -12
  594. package/dist/slack/stream-mode.js +10 -0
  595. package/dist/slack/streaming.js +4 -2
  596. package/dist/telegram/accounts.js +19 -14
  597. package/dist/telegram/bot/helpers.js +3 -5
  598. package/dist/telegram/bot-access.js +35 -36
  599. package/dist/telegram/bot-handlers.js +120 -148
  600. package/dist/telegram/bot-message-context.js +68 -9
  601. package/dist/telegram/bot-message-dispatch.js +477 -210
  602. package/dist/telegram/bot-native-commands.js +16 -0
  603. package/dist/telegram/draft-stream.js +44 -8
  604. package/dist/telegram/inline-buttons.js +5 -15
  605. package/dist/telegram/monitor.js +11 -7
  606. package/dist/telegram/network-config.js +19 -7
  607. package/dist/telegram/reasoning-lane-coordinator.js +128 -0
  608. package/dist/telegram/send.js +3 -2
  609. package/dist/telegram/sent-message-cache.js +5 -6
  610. package/dist/telegram/status-reaction-variants.js +208 -0
  611. package/dist/telegram/sticker-cache.js +11 -9
  612. package/dist/terminal/prompt-select-styled.js +9 -0
  613. package/dist/terminal/theme.js +12 -12
  614. package/dist/test-utils/command-runner.js +6 -0
  615. package/dist/test-utils/internal-hook-event-payload.js +10 -0
  616. package/dist/test-utils/model-auth-mock.js +12 -0
  617. package/dist/test-utils/provider-usage-fetch.js +14 -0
  618. package/dist/test-utils/temp-home.js +33 -0
  619. package/dist/tts/tts.js +80 -567
  620. package/dist/tui/components/chat-log.js +50 -8
  621. package/dist/tui/theme/theme.js +10 -12
  622. package/dist/tui/tui-command-handlers.js +36 -27
  623. package/dist/tui/tui-event-handlers.js +122 -32
  624. package/dist/tui/tui-local-shell.js +16 -6
  625. package/dist/tui/tui.js +236 -48
  626. package/dist/utils/account-id.js +2 -4
  627. package/dist/utils/boolean.js +10 -5
  628. package/dist/utils/directive-tags.js +11 -0
  629. package/dist/utils/mask-api-key.js +10 -0
  630. package/dist/utils/queue-helpers.js +67 -12
  631. package/dist/utils/run-with-concurrency.js +39 -0
  632. package/dist/web/auto-reply/deliver-reply.js +8 -4
  633. package/dist/web/auto-reply/mentions.js +10 -5
  634. package/dist/web/auto-reply/monitor/group-members.js +14 -7
  635. package/dist/web/auto-reply/monitor/process-message.js +45 -24
  636. package/dist/web/inbound/access-control.js +5 -2
  637. package/dist/web/login-qr.js +12 -6
  638. package/dist/web/media.js +126 -15
  639. package/docs/tools/slash-commands.md +5 -1
  640. package/extensions/bluebubbles/src/monitor-processing.ts +580 -139
  641. package/extensions/bluebubbles/src/monitor.ts +208 -1950
  642. package/extensions/feishu/src/external-keys.ts +19 -0
  643. package/extensions/lobster/src/windows-spawn.ts +193 -0
  644. package/extensions/matrix/src/matrix/actions/limits.ts +6 -0
  645. package/extensions/mattermost/src/mattermost/reactions.test-helpers.ts +83 -0
  646. package/package.json +1 -1
@@ -1,2 +1,12 @@
1
- export { collectAttackSurfaceSummaryFindings, collectExposureMatrixFindings, collectHooksHardeningFindings, collectModelHygieneFindings, collectSecretsInConfigFindings, collectSmallModelRiskFindings, collectSyncedFolderFindings, } from "./audit-extra.sync.js";
2
- export { collectIncludeFilePermFindings, collectInstalledSkillsCodeSafetyFindings, collectPluginsCodeSafetyFindings, collectPluginsTrustFindings, collectStateDeepFilesystemFindings, readConfigSnapshotForAudit, } from "./audit-extra.async.js";
1
+ /**
2
+ * Re-export barrel for security audit collector functions.
3
+ *
4
+ * Maintains backward compatibility with existing imports from audit-extra.
5
+ * Implementation split into:
6
+ * - audit-extra.sync.ts: Config-based checks (no I/O)
7
+ * - audit-extra.async.ts: Filesystem/plugin checks (async I/O)
8
+ */
9
+ // Sync collectors
10
+ export { collectAttackSurfaceSummaryFindings, collectExposureMatrixFindings, collectGatewayHttpNoAuthFindings, collectGatewayHttpSessionKeyOverrideFindings, collectHooksHardeningFindings, collectMinimalProfileOverrideFindings, collectModelHygieneFindings, collectNodeDenyCommandPatternFindings, collectSandboxDangerousConfigFindings, collectSandboxDockerNoopFindings, collectSecretsInConfigFindings, collectSmallModelRiskFindings, collectSyncedFolderFindings, } from "./audit-extra.sync.js";
11
+ // Async collectors
12
+ export { collectSandboxBrowserHashLabelFindings, collectIncludeFilePermFindings, collectInstalledSkillsCodeSafetyFindings, collectPluginsCodeSafetyFindings, collectPluginsTrustFindings, collectStateDeepFilesystemFindings, readConfigSnapshotForAudit, } from "./audit-extra.async.js";
@@ -1,9 +1,13 @@
1
1
  import { isToolAllowedByPolicies } from "../agents/pi-tools.policy.js";
2
2
  import { resolveSandboxConfigForAgent, resolveSandboxToolPolicyForAgent, } from "../agents/sandbox.js";
3
+ import { getBlockedBindReason } from "../agents/sandbox/validate-sandbox-security.js";
3
4
  import { resolveToolProfilePolicy } from "../agents/tool-policy.js";
4
5
  import { resolveBrowserConfig } from "../browser/config.js";
5
6
  import { formatCliCommand } from "../cli/command-format.js";
6
7
  import { resolveGatewayAuth } from "../gateway/auth.js";
8
+ import { resolveNodeCommandAllowlist } from "../gateway/node-command-policy.js";
9
+ import { inferParamBFromIdOrName } from "../shared/model-param-b.js";
10
+ import { pickSandboxToolPolicy } from "./audit-tool-policy.js";
7
11
  const SMALL_MODEL_PARAM_B_MAX = 300;
8
12
  // --------------------------------------------------------------------------
9
13
  // Helpers
@@ -46,6 +50,14 @@ function looksLikeEnvRef(value) {
46
50
  const v = value.trim();
47
51
  return v.startsWith("${") && v.endsWith("}");
48
52
  }
53
+ function isGatewayRemotelyExposed(cfg) {
54
+ const bind = typeof cfg.gateway?.bind === "string" ? cfg.gateway.bind : "loopback";
55
+ if (bind !== "loopback") {
56
+ return true;
57
+ }
58
+ const tailscaleMode = cfg.gateway?.tailscale?.mode ?? "off";
59
+ return tailscaleMode === "serve" || tailscaleMode === "funnel";
60
+ }
49
61
  function addModel(models, raw, source) {
50
62
  if (typeof raw !== "string") {
51
63
  return;
@@ -96,25 +108,6 @@ const LEGACY_MODEL_PATTERNS = [
96
108
  const WEAK_TIER_MODEL_PATTERNS = [
97
109
  { id: "anthropic.haiku", re: /\bhaiku\b/i, label: "Haiku tier (smaller model)" },
98
110
  ];
99
- function inferParamBFromIdOrName(text) {
100
- const raw = text.toLowerCase();
101
- const matches = raw.matchAll(/(?:^|[^a-z0-9])[a-z]?(\d+(?:\.\d+)?)b(?:[^a-z0-9]|$)/g);
102
- let best = null;
103
- for (const match of matches) {
104
- const numRaw = match[1];
105
- if (!numRaw) {
106
- continue;
107
- }
108
- const value = Number(numRaw);
109
- if (!Number.isFinite(value) || value <= 0) {
110
- continue;
111
- }
112
- if (best === null || value > best) {
113
- best = value;
114
- }
115
- }
116
- return best;
117
- }
118
111
  function isGptModel(id) {
119
112
  return /\bgpt-/i.test(id);
120
113
  }
@@ -132,16 +125,52 @@ function extractAgentIdFromSource(source) {
132
125
  const match = source.match(/^agents\.list\.([^.]*)\./);
133
126
  return match?.[1] ?? null;
134
127
  }
135
- function pickToolPolicy(config) {
136
- if (!config) {
137
- return null;
128
+ function hasConfiguredDockerConfig(docker) {
129
+ if (!docker || typeof docker !== "object") {
130
+ return false;
138
131
  }
139
- const allow = Array.isArray(config.allow) ? config.allow : undefined;
140
- const deny = Array.isArray(config.deny) ? config.deny : undefined;
141
- if (!allow && !deny) {
142
- return null;
132
+ return Object.values(docker).some((value) => value !== undefined);
133
+ }
134
+ function normalizeNodeCommand(value) {
135
+ return typeof value === "string" ? value.trim() : "";
136
+ }
137
+ function listKnownNodeCommands(cfg) {
138
+ const baseCfg = {
139
+ ...cfg,
140
+ gateway: {
141
+ ...cfg.gateway,
142
+ nodes: {
143
+ ...cfg.gateway?.nodes,
144
+ denyCommands: [],
145
+ },
146
+ },
147
+ };
148
+ const out = new Set();
149
+ for (const platform of ["ios", "android", "macos", "linux", "windows", "unknown"]) {
150
+ const allow = resolveNodeCommandAllowlist(baseCfg, { platform });
151
+ for (const cmd of allow) {
152
+ const normalized = normalizeNodeCommand(cmd);
153
+ if (normalized) {
154
+ out.add(normalized);
155
+ }
156
+ }
143
157
  }
144
- return { allow, deny };
158
+ return out;
159
+ }
160
+ function looksLikeNodeCommandPattern(value) {
161
+ if (!value) {
162
+ return false;
163
+ }
164
+ if (/[?*[\]{}(),|]/.test(value)) {
165
+ return true;
166
+ }
167
+ if (value.startsWith("/") ||
168
+ value.endsWith("/") ||
169
+ value.startsWith("^") ||
170
+ value.endsWith("$")) {
171
+ return true;
172
+ }
173
+ return /\s/.test(value) || value.includes("group:");
145
174
  }
146
175
  function resolveToolPolicies(params) {
147
176
  const policies = [];
@@ -150,11 +179,11 @@ function resolveToolPolicies(params) {
150
179
  if (profilePolicy) {
151
180
  policies.push(profilePolicy);
152
181
  }
153
- const globalPolicy = pickToolPolicy(params.cfg.tools ?? undefined);
182
+ const globalPolicy = pickSandboxToolPolicy(params.cfg.tools ?? undefined);
154
183
  if (globalPolicy) {
155
184
  policies.push(globalPolicy);
156
185
  }
157
- const agentPolicy = pickToolPolicy(params.agentTools);
186
+ const agentPolicy = pickSandboxToolPolicy(params.agentTools);
158
187
  if (agentPolicy) {
159
188
  policies.push(agentPolicy);
160
189
  }
@@ -232,13 +261,16 @@ function listGroupPolicyOpen(cfg) {
232
261
  export function collectAttackSurfaceSummaryFindings(cfg) {
233
262
  const group = summarizeGroupPolicy(cfg);
234
263
  const elevated = cfg.tools?.elevated?.enabled !== false;
235
- const hooksEnabled = cfg.hooks?.enabled === true;
264
+ const webhooksEnabled = cfg.hooks?.enabled === true;
265
+ const internalHooksEnabled = cfg.hooks?.internal?.enabled === true;
236
266
  const browserEnabled = cfg.browser?.enabled ?? true;
237
267
  const detail = `groups: open=${group.open}, allowlist=${group.allowlist}` +
238
268
  `\n` +
239
269
  `tools.elevated: ${elevated ? "enabled" : "disabled"}` +
240
270
  `\n` +
241
- `hooks: ${hooksEnabled ? "enabled" : "disabled"}` +
271
+ `hooks.webhooks: ${webhooksEnabled ? "enabled" : "disabled"}` +
272
+ `\n` +
273
+ `hooks.internal: ${internalHooksEnabled ? "enabled" : "disabled"}` +
242
274
  `\n` +
243
275
  `browser control: ${browserEnabled ? "enabled" : "disabled"}`;
244
276
  return [
@@ -258,7 +290,7 @@ export function collectSyncedFolderFindings(params) {
258
290
  severity: "warn",
259
291
  title: "State/config path looks like a synced folder",
260
292
  detail: `stateDir=${params.stateDir}, configPath=${params.configPath}. Synced folders (iCloud/Dropbox/OneDrive/Google Drive) can leak tokens and transcripts onto other devices.`,
261
- remediation: `Keep CLAWDBOT_STATE_DIR on a local-only volume and re-run "${formatCliCommand("poolbot security audit --fix")}".`,
293
+ remediation: `Keep POOLBOT_STATE_DIR on a local-only volume and re-run "${formatCliCommand("poolbot security audit --fix")}".`,
262
294
  });
263
295
  }
264
296
  return findings;
@@ -286,7 +318,7 @@ export function collectSecretsInConfigFindings(cfg) {
286
318
  }
287
319
  return findings;
288
320
  }
289
- export function collectHooksHardeningFindings(cfg) {
321
+ export function collectHooksHardeningFindings(cfg, env = process.env) {
290
322
  const findings = [];
291
323
  if (cfg.hooks?.enabled !== true) {
292
324
  return findings;
@@ -303,16 +335,22 @@ export function collectHooksHardeningFindings(cfg) {
303
335
  const gatewayAuth = resolveGatewayAuth({
304
336
  authConfig: cfg.gateway?.auth,
305
337
  tailscaleMode: cfg.gateway?.tailscale?.mode ?? "off",
338
+ env,
306
339
  });
340
+ const poolbotGatewayToken = typeof env.POOLBOT_GATEWAY_TOKEN === "string" && env.POOLBOT_GATEWAY_TOKEN.trim()
341
+ ? env.POOLBOT_GATEWAY_TOKEN.trim()
342
+ : null;
307
343
  const gatewayToken = gatewayAuth.mode === "token" &&
308
344
  typeof gatewayAuth.token === "string" &&
309
345
  gatewayAuth.token.trim()
310
346
  ? gatewayAuth.token.trim()
311
- : null;
347
+ : poolbotGatewayToken
348
+ ? poolbotGatewayToken
349
+ : null;
312
350
  if (token && gatewayToken && token === gatewayToken) {
313
351
  findings.push({
314
352
  checkId: "hooks.token_reuse_gateway_token",
315
- severity: "warn",
353
+ severity: "critical",
316
354
  title: "Hooks token reuses the Gateway token",
317
355
  detail: "hooks.token matches gateway.auth token; compromise of hooks expands blast radius to the Gateway API.",
318
356
  remediation: "Use a separate hooks.token dedicated to hook ingress.",
@@ -328,6 +366,309 @@ export function collectHooksHardeningFindings(cfg) {
328
366
  remediation: "Use a dedicated path like '/hooks'.",
329
367
  });
330
368
  }
369
+ const allowRequestSessionKey = cfg.hooks?.allowRequestSessionKey === true;
370
+ const defaultSessionKey = typeof cfg.hooks?.defaultSessionKey === "string" ? cfg.hooks.defaultSessionKey.trim() : "";
371
+ const allowedPrefixes = Array.isArray(cfg.hooks?.allowedSessionKeyPrefixes)
372
+ ? cfg.hooks.allowedSessionKeyPrefixes
373
+ .map((prefix) => prefix.trim())
374
+ .filter((prefix) => prefix.length > 0)
375
+ : [];
376
+ const remoteExposure = isGatewayRemotelyExposed(cfg);
377
+ if (!defaultSessionKey) {
378
+ findings.push({
379
+ checkId: "hooks.default_session_key_unset",
380
+ severity: "warn",
381
+ title: "hooks.defaultSessionKey is not configured",
382
+ detail: "Hook agent runs without explicit sessionKey use generated per-request keys. Set hooks.defaultSessionKey to keep hook ingress scoped to a known session.",
383
+ remediation: 'Set hooks.defaultSessionKey (for example, "hook:ingress").',
384
+ });
385
+ }
386
+ if (allowRequestSessionKey) {
387
+ findings.push({
388
+ checkId: "hooks.request_session_key_enabled",
389
+ severity: remoteExposure ? "critical" : "warn",
390
+ title: "External hook payloads may override sessionKey",
391
+ detail: "hooks.allowRequestSessionKey=true allows `/hooks/agent` callers to choose the session key. Treat hook token holders as full-trust unless you also restrict prefixes.",
392
+ remediation: "Set hooks.allowRequestSessionKey=false (recommended) or constrain hooks.allowedSessionKeyPrefixes.",
393
+ });
394
+ }
395
+ if (allowRequestSessionKey && allowedPrefixes.length === 0) {
396
+ findings.push({
397
+ checkId: "hooks.request_session_key_prefixes_missing",
398
+ severity: remoteExposure ? "critical" : "warn",
399
+ title: "Request sessionKey override is enabled without prefix restrictions",
400
+ detail: "hooks.allowRequestSessionKey=true and hooks.allowedSessionKeyPrefixes is unset/empty, so request payloads can target arbitrary session key shapes.",
401
+ remediation: 'Set hooks.allowedSessionKeyPrefixes (for example, ["hook:"]) or disable request overrides.',
402
+ });
403
+ }
404
+ return findings;
405
+ }
406
+ export function collectGatewayHttpSessionKeyOverrideFindings(cfg) {
407
+ const findings = [];
408
+ const chatCompletionsEnabled = cfg.gateway?.http?.endpoints?.chatCompletions?.enabled === true;
409
+ const responsesEnabled = cfg.gateway?.http?.endpoints?.responses?.enabled === true;
410
+ if (!chatCompletionsEnabled && !responsesEnabled) {
411
+ return findings;
412
+ }
413
+ const enabledEndpoints = [
414
+ chatCompletionsEnabled ? "/v1/chat/completions" : null,
415
+ responsesEnabled ? "/v1/responses" : null,
416
+ ].filter((entry) => Boolean(entry));
417
+ findings.push({
418
+ checkId: "gateway.http.session_key_override_enabled",
419
+ severity: "info",
420
+ title: "HTTP API session-key override is enabled",
421
+ detail: `${enabledEndpoints.join(", ")} accept x-poolbot-session-key for per-request session routing. ` +
422
+ "Treat API credential holders as trusted principals.",
423
+ });
424
+ return findings;
425
+ }
426
+ export function collectGatewayHttpNoAuthFindings(cfg, env) {
427
+ const findings = [];
428
+ const tailscaleMode = cfg.gateway?.tailscale?.mode ?? "off";
429
+ const auth = resolveGatewayAuth({ authConfig: cfg.gateway?.auth, tailscaleMode, env });
430
+ if (auth.mode !== "none") {
431
+ return findings;
432
+ }
433
+ const chatCompletionsEnabled = cfg.gateway?.http?.endpoints?.chatCompletions?.enabled === true;
434
+ const responsesEnabled = cfg.gateway?.http?.endpoints?.responses?.enabled === true;
435
+ const enabledEndpoints = [
436
+ "/tools/invoke",
437
+ chatCompletionsEnabled ? "/v1/chat/completions" : null,
438
+ responsesEnabled ? "/v1/responses" : null,
439
+ ].filter((entry) => Boolean(entry));
440
+ const remoteExposure = isGatewayRemotelyExposed(cfg);
441
+ findings.push({
442
+ checkId: "gateway.http.no_auth",
443
+ severity: remoteExposure ? "critical" : "warn",
444
+ title: "Gateway HTTP APIs are reachable without auth",
445
+ detail: `gateway.auth.mode="none" leaves ${enabledEndpoints.join(", ")} callable without a shared secret. ` +
446
+ "Treat this as trusted-local only and avoid exposing the gateway beyond loopback.",
447
+ remediation: "Set gateway.auth.mode to token/password (recommended). If you intentionally keep mode=none, keep gateway.bind=loopback and disable optional HTTP endpoints.",
448
+ });
449
+ return findings;
450
+ }
451
+ export function collectSandboxDockerNoopFindings(cfg) {
452
+ const findings = [];
453
+ const configuredPaths = [];
454
+ const agents = Array.isArray(cfg.agents?.list) ? cfg.agents.list : [];
455
+ const defaultsSandbox = cfg.agents?.defaults?.sandbox;
456
+ const hasDefaultDocker = hasConfiguredDockerConfig(defaultsSandbox?.docker);
457
+ const defaultMode = defaultsSandbox?.mode ?? "off";
458
+ const hasAnySandboxEnabledAgent = agents.some((entry) => {
459
+ if (!entry || typeof entry !== "object" || typeof entry.id !== "string") {
460
+ return false;
461
+ }
462
+ return resolveSandboxConfigForAgent(cfg, entry.id).mode !== "off";
463
+ });
464
+ if (hasDefaultDocker && defaultMode === "off" && !hasAnySandboxEnabledAgent) {
465
+ configuredPaths.push("agents.defaults.sandbox.docker");
466
+ }
467
+ for (const entry of agents) {
468
+ if (!entry || typeof entry !== "object" || typeof entry.id !== "string") {
469
+ continue;
470
+ }
471
+ if (!hasConfiguredDockerConfig(entry.sandbox?.docker)) {
472
+ continue;
473
+ }
474
+ if (resolveSandboxConfigForAgent(cfg, entry.id).mode === "off") {
475
+ configuredPaths.push(`agents.list.${entry.id}.sandbox.docker`);
476
+ }
477
+ }
478
+ if (configuredPaths.length === 0) {
479
+ return findings;
480
+ }
481
+ findings.push({
482
+ checkId: "sandbox.docker_config_mode_off",
483
+ severity: "warn",
484
+ title: "Sandbox docker settings configured while sandbox mode is off",
485
+ detail: "These docker settings will not take effect until sandbox mode is enabled:\n" +
486
+ configuredPaths.map((entry) => `- ${entry}`).join("\n"),
487
+ remediation: 'Enable sandbox mode (`agents.defaults.sandbox.mode="non-main"` or `"all"`) where needed, or remove unused docker settings.',
488
+ });
489
+ return findings;
490
+ }
491
+ export function collectSandboxDangerousConfigFindings(cfg) {
492
+ const findings = [];
493
+ const agents = Array.isArray(cfg.agents?.list) ? cfg.agents.list : [];
494
+ const configs = [];
495
+ const defaultDocker = cfg.agents?.defaults?.sandbox?.docker;
496
+ if (defaultDocker && typeof defaultDocker === "object") {
497
+ configs.push({
498
+ source: "agents.defaults.sandbox.docker",
499
+ docker: defaultDocker,
500
+ });
501
+ }
502
+ for (const entry of agents) {
503
+ if (!entry || typeof entry !== "object" || typeof entry.id !== "string") {
504
+ continue;
505
+ }
506
+ const agentDocker = entry.sandbox?.docker;
507
+ if (agentDocker && typeof agentDocker === "object") {
508
+ configs.push({
509
+ source: `agents.list.${entry.id}.sandbox.docker`,
510
+ docker: agentDocker,
511
+ });
512
+ }
513
+ }
514
+ for (const { source, docker } of configs) {
515
+ const binds = Array.isArray(docker.binds) ? docker.binds : [];
516
+ for (const bind of binds) {
517
+ if (typeof bind !== "string") {
518
+ continue;
519
+ }
520
+ const blocked = getBlockedBindReason(bind);
521
+ if (!blocked) {
522
+ continue;
523
+ }
524
+ if (blocked.kind === "non_absolute") {
525
+ findings.push({
526
+ checkId: "sandbox.bind_mount_non_absolute",
527
+ severity: "warn",
528
+ title: "Sandbox bind mount uses a non-absolute source path",
529
+ detail: `${source}.binds contains "${bind}" which uses source path "${blocked.sourcePath}". ` +
530
+ "Non-absolute bind sources are hard to validate safely and may resolve unexpectedly.",
531
+ remediation: `Rewrite "${bind}" to use an absolute host path (for example: /home/user/project:/project:ro).`,
532
+ });
533
+ continue;
534
+ }
535
+ const verb = blocked.kind === "covers" ? "covers" : "targets";
536
+ findings.push({
537
+ checkId: "sandbox.dangerous_bind_mount",
538
+ severity: "critical",
539
+ title: "Dangerous bind mount in sandbox config",
540
+ detail: `${source}.binds contains "${bind}" which ${verb} blocked path "${blocked.blockedPath}". ` +
541
+ "This can expose host system directories or the Docker socket to sandbox containers.",
542
+ remediation: `Remove "${bind}" from ${source}.binds. Use project-specific paths instead.`,
543
+ });
544
+ }
545
+ const network = typeof docker.network === "string" ? docker.network : undefined;
546
+ if (network && network.trim().toLowerCase() === "host") {
547
+ findings.push({
548
+ checkId: "sandbox.dangerous_network_mode",
549
+ severity: "critical",
550
+ title: "Network host mode in sandbox config",
551
+ detail: `${source}.network is "host" which bypasses container network isolation entirely.`,
552
+ remediation: `Set ${source}.network to "bridge" or "none".`,
553
+ });
554
+ }
555
+ const seccompProfile = typeof docker.seccompProfile === "string" ? docker.seccompProfile : undefined;
556
+ if (seccompProfile && seccompProfile.trim().toLowerCase() === "unconfined") {
557
+ findings.push({
558
+ checkId: "sandbox.dangerous_seccomp_profile",
559
+ severity: "critical",
560
+ title: "Seccomp unconfined in sandbox config",
561
+ detail: `${source}.seccompProfile is "unconfined" which disables syscall filtering.`,
562
+ remediation: `Remove ${source}.seccompProfile or use a custom seccomp profile file.`,
563
+ });
564
+ }
565
+ const apparmorProfile = typeof docker.apparmorProfile === "string" ? docker.apparmorProfile : undefined;
566
+ if (apparmorProfile && apparmorProfile.trim().toLowerCase() === "unconfined") {
567
+ findings.push({
568
+ checkId: "sandbox.dangerous_apparmor_profile",
569
+ severity: "critical",
570
+ title: "AppArmor unconfined in sandbox config",
571
+ detail: `${source}.apparmorProfile is "unconfined" which disables AppArmor enforcement.`,
572
+ remediation: `Remove ${source}.apparmorProfile or use a named AppArmor profile.`,
573
+ });
574
+ }
575
+ }
576
+ const browserExposurePaths = [];
577
+ const defaultBrowser = resolveSandboxConfigForAgent(cfg).browser;
578
+ if (defaultBrowser.enabled &&
579
+ defaultBrowser.network.trim().toLowerCase() === "bridge" &&
580
+ !defaultBrowser.cdpSourceRange?.trim()) {
581
+ browserExposurePaths.push("agents.defaults.sandbox.browser");
582
+ }
583
+ for (const entry of agents) {
584
+ if (!entry || typeof entry !== "object" || typeof entry.id !== "string") {
585
+ continue;
586
+ }
587
+ const browser = resolveSandboxConfigForAgent(cfg, entry.id).browser;
588
+ if (!browser.enabled) {
589
+ continue;
590
+ }
591
+ if (browser.network.trim().toLowerCase() !== "bridge") {
592
+ continue;
593
+ }
594
+ if (browser.cdpSourceRange?.trim()) {
595
+ continue;
596
+ }
597
+ browserExposurePaths.push(`agents.list.${entry.id}.sandbox.browser`);
598
+ }
599
+ if (browserExposurePaths.length > 0) {
600
+ findings.push({
601
+ checkId: "sandbox.browser_cdp_bridge_unrestricted",
602
+ severity: "warn",
603
+ title: "Sandbox browser CDP may be reachable by peer containers",
604
+ detail: "These sandbox browser configs use Docker bridge networking with no CDP source restriction:\n" +
605
+ browserExposurePaths.map((entry) => `- ${entry}`).join("\n"),
606
+ remediation: "Set sandbox.browser.network to a dedicated bridge network (recommended default: poolbot-sandbox-browser), " +
607
+ "or set sandbox.browser.cdpSourceRange (for example 172.21.0.1/32) to restrict container-edge CDP ingress.",
608
+ });
609
+ }
610
+ return findings;
611
+ }
612
+ export function collectNodeDenyCommandPatternFindings(cfg) {
613
+ const findings = [];
614
+ const denyListRaw = cfg.gateway?.nodes?.denyCommands;
615
+ if (!Array.isArray(denyListRaw) || denyListRaw.length === 0) {
616
+ return findings;
617
+ }
618
+ const denyList = denyListRaw.map(normalizeNodeCommand).filter(Boolean);
619
+ if (denyList.length === 0) {
620
+ return findings;
621
+ }
622
+ const knownCommands = listKnownNodeCommands(cfg);
623
+ const patternLike = denyList.filter((entry) => looksLikeNodeCommandPattern(entry));
624
+ const unknownExact = denyList.filter((entry) => !looksLikeNodeCommandPattern(entry) && !knownCommands.has(entry));
625
+ if (patternLike.length === 0 && unknownExact.length === 0) {
626
+ return findings;
627
+ }
628
+ const detailParts = [];
629
+ if (patternLike.length > 0) {
630
+ detailParts.push(`Pattern-like entries (not supported by exact matching): ${patternLike.join(", ")}`);
631
+ }
632
+ if (unknownExact.length > 0) {
633
+ detailParts.push(`Unknown command names (not in defaults/allowCommands): ${unknownExact.join(", ")}`);
634
+ }
635
+ const examples = Array.from(knownCommands).slice(0, 8);
636
+ findings.push({
637
+ checkId: "gateway.nodes.deny_commands_ineffective",
638
+ severity: "warn",
639
+ title: "Some gateway.nodes.denyCommands entries are ineffective",
640
+ detail: "gateway.nodes.denyCommands uses exact command-name matching only.\n" +
641
+ detailParts.map((entry) => `- ${entry}`).join("\n"),
642
+ remediation: `Use exact command names (for example: ${examples.join(", ")}). ` +
643
+ "If you need broader restrictions, remove risky commands from allowCommands/default workflows.",
644
+ });
645
+ return findings;
646
+ }
647
+ export function collectMinimalProfileOverrideFindings(cfg) {
648
+ const findings = [];
649
+ if (cfg.tools?.profile !== "minimal") {
650
+ return findings;
651
+ }
652
+ const overrides = (cfg.agents?.list ?? [])
653
+ .filter((entry) => {
654
+ return Boolean(entry &&
655
+ typeof entry === "object" &&
656
+ typeof entry.id === "string" &&
657
+ entry.tools?.profile &&
658
+ entry.tools.profile !== "minimal");
659
+ })
660
+ .map((entry) => `${entry.id}=${entry.tools?.profile}`);
661
+ if (overrides.length === 0) {
662
+ return findings;
663
+ }
664
+ findings.push({
665
+ checkId: "tools.profile_minimal_overridden",
666
+ severity: "warn",
667
+ title: "Global tools.profile=minimal is overridden by agent profiles",
668
+ detail: "Global minimal profile is set, but these agent profiles take precedence:\n" +
669
+ overrides.map((entry) => `- agents.list.${entry}`).join("\n"),
670
+ remediation: 'Set those agents to `tools.profile="minimal"` (or remove the agent override) if you want minimal tools enforced globally.',
671
+ });
331
672
  return findings;
332
673
  }
333
674
  export function collectModelHygieneFindings(cfg) {
@@ -501,5 +842,50 @@ export function collectExposureMatrixFindings(cfg) {
501
842
  remediation: `Set groupPolicy="allowlist" and keep elevated allowlists extremely tight.`,
502
843
  });
503
844
  }
845
+ const contexts = [{ label: "agents.defaults" }];
846
+ for (const agent of cfg.agents?.list ?? []) {
847
+ if (!agent || typeof agent !== "object" || typeof agent.id !== "string") {
848
+ continue;
849
+ }
850
+ contexts.push({
851
+ label: `agents.list.${agent.id}`,
852
+ agentId: agent.id,
853
+ tools: agent.tools,
854
+ });
855
+ }
856
+ const riskyContexts = [];
857
+ let hasRuntimeRisk = false;
858
+ for (const context of contexts) {
859
+ const sandboxMode = resolveSandboxConfigForAgent(cfg, context.agentId).mode;
860
+ const policies = resolveToolPolicies({
861
+ cfg,
862
+ agentTools: context.tools,
863
+ sandboxMode,
864
+ agentId: context.agentId ?? null,
865
+ });
866
+ const runtimeTools = ["exec", "process"].filter((tool) => isToolAllowedByPolicies(tool, policies));
867
+ const fsTools = ["read", "write", "edit", "apply_patch"].filter((tool) => isToolAllowedByPolicies(tool, policies));
868
+ const fsWorkspaceOnly = context.tools?.fs?.workspaceOnly ?? cfg.tools?.fs?.workspaceOnly;
869
+ const runtimeUnguarded = runtimeTools.length > 0 && sandboxMode !== "all";
870
+ const fsUnguarded = fsTools.length > 0 && sandboxMode !== "all" && fsWorkspaceOnly !== true;
871
+ if (!runtimeUnguarded && !fsUnguarded) {
872
+ continue;
873
+ }
874
+ if (runtimeUnguarded) {
875
+ hasRuntimeRisk = true;
876
+ }
877
+ riskyContexts.push(`${context.label} (sandbox=${sandboxMode}; runtime=[${runtimeTools.join(", ") || "off"}]; fs=[${fsTools.join(", ") || "off"}]; fs.workspaceOnly=${fsWorkspaceOnly === true ? "true" : "false"})`);
878
+ }
879
+ if (riskyContexts.length > 0) {
880
+ findings.push({
881
+ checkId: "security.exposure.open_groups_with_runtime_or_fs",
882
+ severity: hasRuntimeRisk ? "critical" : "warn",
883
+ title: "Open groupPolicy with runtime/filesystem tools exposed",
884
+ detail: `Found groupPolicy="open" at:\n${openGroups.map((p) => `- ${p}`).join("\n")}\n` +
885
+ `Risky tool exposure contexts:\n${riskyContexts.map((line) => `- ${line}`).join("\n")}\n` +
886
+ "Prompt injection in open groups can trigger command/file actions in these contexts.",
887
+ remediation: 'For open groups, prefer tools.profile="messaging" (or deny group:runtime/group:fs), set tools.fs.workspaceOnly=true, and use agents.defaults.sandbox.mode="all" for exposed agents.',
888
+ });
889
+ }
504
890
  return findings;
505
891
  }
@@ -41,7 +41,19 @@ export async function inspectPathPermissions(targetPath, opts) {
41
41
  error: st.error,
42
42
  };
43
43
  }
44
- const bits = modeBits(st.mode);
44
+ let effectiveMode = st.mode;
45
+ let effectiveIsDir = st.isDir;
46
+ if (st.isSymlink) {
47
+ try {
48
+ const target = await fs.stat(targetPath);
49
+ effectiveMode = typeof target.mode === "number" ? target.mode : st.mode;
50
+ effectiveIsDir = target.isDirectory();
51
+ }
52
+ catch {
53
+ // Keep lstat-derived metadata when target lookup fails.
54
+ }
55
+ }
56
+ const bits = modeBits(effectiveMode);
45
57
  const platform = opts?.platform ?? process.platform;
46
58
  if (platform === "win32") {
47
59
  const acl = await inspectWindowsAcl(targetPath, { env: opts?.env, exec: opts?.exec });
@@ -49,8 +61,8 @@ export async function inspectPathPermissions(targetPath, opts) {
49
61
  return {
50
62
  ok: true,
51
63
  isSymlink: st.isSymlink,
52
- isDir: st.isDir,
53
- mode: st.mode,
64
+ isDir: effectiveIsDir,
65
+ mode: effectiveMode,
54
66
  bits,
55
67
  source: "unknown",
56
68
  worldWritable: false,
@@ -63,8 +75,8 @@ export async function inspectPathPermissions(targetPath, opts) {
63
75
  return {
64
76
  ok: true,
65
77
  isSymlink: st.isSymlink,
66
- isDir: st.isDir,
67
- mode: st.mode,
78
+ isDir: effectiveIsDir,
79
+ mode: effectiveMode,
68
80
  bits,
69
81
  source: "windows-acl",
70
82
  worldWritable: acl.untrustedWorld.some((entry) => entry.canWrite),
@@ -77,8 +89,8 @@ export async function inspectPathPermissions(targetPath, opts) {
77
89
  return {
78
90
  ok: true,
79
91
  isSymlink: st.isSymlink,
80
- isDir: st.isDir,
81
- mode: st.mode,
92
+ isDir: effectiveIsDir,
93
+ mode: effectiveMode,
82
94
  bits,
83
95
  source: "posix",
84
96
  worldWritable: isWorldWritable(bits),
@@ -102,32 +114,38 @@ export function formatPermissionRemediation(params) {
102
114
  return `chmod ${mode} ${params.targetPath}`;
103
115
  }
104
116
  export function modeBits(mode) {
105
- if (mode == null)
117
+ if (mode == null) {
106
118
  return null;
119
+ }
107
120
  return mode & 0o777;
108
121
  }
109
122
  export function formatOctal(bits) {
110
- if (bits == null)
123
+ if (bits == null) {
111
124
  return "unknown";
125
+ }
112
126
  return bits.toString(8).padStart(3, "0");
113
127
  }
114
128
  export function isWorldWritable(bits) {
115
- if (bits == null)
129
+ if (bits == null) {
116
130
  return false;
131
+ }
117
132
  return (bits & 0o002) !== 0;
118
133
  }
119
134
  export function isGroupWritable(bits) {
120
- if (bits == null)
135
+ if (bits == null) {
121
136
  return false;
137
+ }
122
138
  return (bits & 0o020) !== 0;
123
139
  }
124
140
  export function isWorldReadable(bits) {
125
- if (bits == null)
141
+ if (bits == null) {
126
142
  return false;
143
+ }
127
144
  return (bits & 0o004) !== 0;
128
145
  }
129
146
  export function isGroupReadable(bits) {
130
- if (bits == null)
147
+ if (bits == null) {
131
148
  return false;
149
+ }
132
150
  return (bits & 0o040) !== 0;
133
151
  }