@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,5 +1,11 @@
1
- import { BASE_CHUNK_RATIO, MIN_CHUNK_RATIO, SAFETY_MARGIN, computeAdaptiveChunkRatio, estimateMessagesTokens, isOversizedForSummary, pruneHistoryForContextShare, resolveContextWindowTokens, summarizeInStages, } from "../compaction.js";
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { extractSections } from "../../auto-reply/reply/post-compaction-context.js";
4
+ import { createSubsystemLogger } from "../../logging/subsystem.js";
5
+ import { BASE_CHUNK_RATIO, MIN_CHUNK_RATIO, SAFETY_MARGIN, SUMMARIZATION_OVERHEAD_TOKENS, computeAdaptiveChunkRatio, estimateMessagesTokens, isOversizedForSummary, pruneHistoryForContextShare, resolveContextWindowTokens, summarizeInStages, } from "../compaction.js";
6
+ import { collectTextContentBlocks } from "../content-blocks.js";
2
7
  import { getCompactionSafeguardRuntime } from "./compaction-safeguard-runtime.js";
8
+ const log = createSubsystemLogger("compaction-safeguard");
3
9
  const FALLBACK_SUMMARY = "Summary unavailable due to context limits. Older messages were truncated.";
4
10
  const TURN_PREFIX_INSTRUCTIONS = "This summary covers the prefix of a split turn. Focus on the original request," +
5
11
  " early progress, and any details needed to understand the retained suffix.";
@@ -9,54 +15,51 @@ function normalizeFailureText(text) {
9
15
  return text.replace(/\s+/g, " ").trim();
10
16
  }
11
17
  function truncateFailureText(text, maxChars) {
12
- if (text.length <= maxChars)
18
+ if (text.length <= maxChars) {
13
19
  return text;
20
+ }
14
21
  return `${text.slice(0, Math.max(0, maxChars - 3))}...`;
15
22
  }
16
23
  function formatToolFailureMeta(details) {
17
- if (!details || typeof details !== "object")
24
+ if (!details || typeof details !== "object") {
18
25
  return undefined;
26
+ }
19
27
  const record = details;
20
28
  const status = typeof record.status === "string" ? record.status : undefined;
21
29
  const exitCode = typeof record.exitCode === "number" && Number.isFinite(record.exitCode)
22
30
  ? record.exitCode
23
31
  : undefined;
24
32
  const parts = [];
25
- if (status)
33
+ if (status) {
26
34
  parts.push(`status=${status}`);
27
- if (exitCode !== undefined)
35
+ }
36
+ if (exitCode !== undefined) {
28
37
  parts.push(`exitCode=${exitCode}`);
38
+ }
29
39
  return parts.length > 0 ? parts.join(" ") : undefined;
30
40
  }
31
41
  function extractToolResultText(content) {
32
- if (!Array.isArray(content))
33
- return "";
34
- const parts = [];
35
- for (const block of content) {
36
- if (!block || typeof block !== "object")
37
- continue;
38
- const rec = block;
39
- if (rec.type === "text" && typeof rec.text === "string") {
40
- parts.push(rec.text);
41
- }
42
- }
43
- return parts.join("\n");
42
+ return collectTextContentBlocks(content).join("\n");
44
43
  }
45
44
  function collectToolFailures(messages) {
46
45
  const failures = [];
47
46
  const seen = new Set();
48
47
  for (const message of messages) {
49
- if (!message || typeof message !== "object")
48
+ if (!message || typeof message !== "object") {
50
49
  continue;
50
+ }
51
51
  const role = message.role;
52
- if (role !== "toolResult")
52
+ if (role !== "toolResult") {
53
53
  continue;
54
+ }
54
55
  const toolResult = message;
55
- if (toolResult.isError !== true)
56
+ if (toolResult.isError !== true) {
56
57
  continue;
58
+ }
57
59
  const toolCallId = typeof toolResult.toolCallId === "string" ? toolResult.toolCallId : "";
58
- if (!toolCallId || seen.has(toolCallId))
60
+ if (!toolCallId || seen.has(toolCallId)) {
59
61
  continue;
62
+ }
60
63
  seen.add(toolCallId);
61
64
  const toolName = typeof toolResult.toolName === "string" && toolResult.toolName.trim()
62
65
  ? toolResult.toolName
@@ -70,8 +73,9 @@ function collectToolFailures(messages) {
70
73
  return failures;
71
74
  }
72
75
  function formatToolFailuresSection(failures) {
73
- if (failures.length === 0)
76
+ if (failures.length === 0) {
74
77
  return "";
78
+ }
75
79
  const lines = failures.slice(0, MAX_TOOL_FAILURES).map((failure) => {
76
80
  const meta = failure.meta ? ` (${failure.meta})` : "";
77
81
  return `- ${failure.toolName}${meta}: ${failure.summary}`;
@@ -83,8 +87,8 @@ function formatToolFailuresSection(failures) {
83
87
  }
84
88
  function computeFileLists(fileOps) {
85
89
  const modified = new Set([...fileOps.edited, ...fileOps.written]);
86
- const readFiles = [...fileOps.read].filter((f) => !modified.has(f)).sort();
87
- const modifiedFiles = [...modified].sort();
90
+ const readFiles = [...fileOps.read].filter((f) => !modified.has(f)).toSorted();
91
+ const modifiedFiles = [...modified].toSorted();
88
92
  return { readFiles, modifiedFiles };
89
93
  }
90
94
  function formatFileOperations(readFiles, modifiedFiles) {
@@ -95,10 +99,39 @@ function formatFileOperations(readFiles, modifiedFiles) {
95
99
  if (modifiedFiles.length > 0) {
96
100
  sections.push(`<modified-files>\n${modifiedFiles.join("\n")}\n</modified-files>`);
97
101
  }
98
- if (sections.length === 0)
102
+ if (sections.length === 0) {
99
103
  return "";
104
+ }
100
105
  return `\n\n${sections.join("\n\n")}`;
101
106
  }
107
+ /**
108
+ * Read and format critical workspace context for compaction summary.
109
+ * Extracts "Session Startup" and "Red Lines" from AGENTS.md.
110
+ * Limited to 2000 chars to avoid bloating the summary.
111
+ */
112
+ async function readWorkspaceContextForSummary() {
113
+ const MAX_SUMMARY_CONTEXT_CHARS = 2000;
114
+ const workspaceDir = process.cwd();
115
+ const agentsPath = path.join(workspaceDir, "AGENTS.md");
116
+ try {
117
+ if (!fs.existsSync(agentsPath)) {
118
+ return "";
119
+ }
120
+ const content = await fs.promises.readFile(agentsPath, "utf-8");
121
+ const sections = extractSections(content, ["Session Startup", "Red Lines"]);
122
+ if (sections.length === 0) {
123
+ return "";
124
+ }
125
+ const combined = sections.join("\n\n");
126
+ const safeContent = combined.length > MAX_SUMMARY_CONTEXT_CHARS
127
+ ? combined.slice(0, MAX_SUMMARY_CONTEXT_CHARS) + "\n...[truncated]..."
128
+ : combined;
129
+ return `\n\n<workspace-critical-rules>\n${safeContent}\n</workspace-critical-rules>`;
130
+ }
131
+ catch {
132
+ return "";
133
+ }
134
+ }
102
135
  export default function compactionSafeguardExtension(api) {
103
136
  api.on("session_before_compact", async (event, ctx) => {
104
137
  const { preparation, customInstructions, signal } = event;
@@ -133,10 +166,11 @@ export default function compactionSafeguardExtension(api) {
133
166
  };
134
167
  }
135
168
  try {
136
- const contextWindowTokens = resolveContextWindowTokens(model);
169
+ const runtime = getCompactionSafeguardRuntime(ctx.sessionManager);
170
+ const modelContextWindow = resolveContextWindowTokens(model);
171
+ const contextWindowTokens = runtime?.contextWindowTokens ?? modelContextWindow;
137
172
  const turnPrefixMessages = preparation.turnPrefixMessages ?? [];
138
173
  let messagesToSummarize = preparation.messagesToSummarize;
139
- const runtime = getCompactionSafeguardRuntime(ctx.sessionManager);
140
174
  const maxHistoryShare = runtime?.maxHistoryShare ?? 0.5;
141
175
  const tokensBefore = typeof preparation.tokensBefore === "number" && Number.isFinite(preparation.tokensBefore)
142
176
  ? preparation.tokensBefore
@@ -156,14 +190,15 @@ export default function compactionSafeguardExtension(api) {
156
190
  });
157
191
  if (pruned.droppedChunks > 0) {
158
192
  const newContentRatio = (newContentTokens / contextWindowTokens) * 100;
159
- console.warn(`Compaction safeguard: new content uses ${newContentRatio.toFixed(1)}% of context; dropped ${pruned.droppedChunks} older chunk(s) ` +
193
+ log.warn(`Compaction safeguard: new content uses ${newContentRatio.toFixed(1)}% of context; dropped ${pruned.droppedChunks} older chunk(s) ` +
160
194
  `(${pruned.droppedMessages} messages) to fit history budget.`);
161
195
  messagesToSummarize = pruned.messages;
162
196
  // Summarize dropped messages so context isn't lost
163
197
  if (pruned.droppedMessagesList.length > 0) {
164
198
  try {
165
199
  const droppedChunkRatio = computeAdaptiveChunkRatio(pruned.droppedMessagesList, contextWindowTokens);
166
- const droppedMaxChunkTokens = Math.max(1, Math.floor(contextWindowTokens * droppedChunkRatio));
200
+ const droppedMaxChunkTokens = Math.max(1, Math.floor(contextWindowTokens * droppedChunkRatio) -
201
+ SUMMARIZATION_OVERHEAD_TOKENS);
167
202
  droppedSummary = await summarizeInStages({
168
203
  messages: pruned.droppedMessagesList,
169
204
  model,
@@ -177,16 +212,18 @@ export default function compactionSafeguardExtension(api) {
177
212
  });
178
213
  }
179
214
  catch (droppedError) {
180
- console.warn(`Compaction safeguard: failed to summarize dropped messages, continuing without: ${droppedError instanceof Error ? droppedError.message : String(droppedError)}`);
215
+ log.warn(`Compaction safeguard: failed to summarize dropped messages, continuing without: ${droppedError instanceof Error ? droppedError.message : String(droppedError)}`);
181
216
  }
182
217
  }
183
218
  }
184
219
  }
185
220
  }
186
- // Use adaptive chunk ratio based on message sizes
221
+ // Use adaptive chunk ratio based on message sizes, reserving headroom for
222
+ // the summarization prompt, system prompt, previous summary, and reasoning budget
223
+ // that generateSummary adds on top of the serialized conversation chunk.
187
224
  const allMessages = [...messagesToSummarize, ...turnPrefixMessages];
188
225
  const adaptiveRatio = computeAdaptiveChunkRatio(allMessages, contextWindowTokens);
189
- const maxChunkTokens = Math.max(1, Math.floor(contextWindowTokens * adaptiveRatio));
226
+ const maxChunkTokens = Math.max(1, Math.floor(contextWindowTokens * adaptiveRatio) - SUMMARIZATION_OVERHEAD_TOKENS);
190
227
  const reserveTokens = Math.max(1, Math.floor(preparation.settings.reserveTokens));
191
228
  // Feed dropped-messages summary as previousSummary so the main summarization
192
229
  // incorporates context from pruned messages instead of losing it entirely.
@@ -219,6 +256,11 @@ export default function compactionSafeguardExtension(api) {
219
256
  }
220
257
  summary += toolFailureSection;
221
258
  summary += fileOpsSummary;
259
+ // Append workspace critical context (Session Startup + Red Lines from AGENTS.md)
260
+ const workspaceContext = await readWorkspaceContextForSummary();
261
+ if (workspaceContext) {
262
+ summary += workspaceContext;
263
+ }
222
264
  return {
223
265
  compaction: {
224
266
  summary,
@@ -229,7 +271,7 @@ export default function compactionSafeguardExtension(api) {
229
271
  };
230
272
  }
231
273
  catch (error) {
232
- console.warn(`Compaction summarization failed; truncating history: ${error instanceof Error ? error.message : String(error)}`);
274
+ log.warn(`Compaction summarization failed; truncating history: ${error instanceof Error ? error.message : String(error)}`);
233
275
  return {
234
276
  compaction: {
235
277
  summary: fallbackSummary,
@@ -17,3 +17,43 @@ export function resolveCompactionReserveTokensFloor(cfg) {
17
17
  }
18
18
  return DEFAULT_PI_COMPACTION_RESERVE_TOKENS_FLOOR;
19
19
  }
20
+ function toNonNegativeInt(value) {
21
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
22
+ return undefined;
23
+ }
24
+ return Math.floor(value);
25
+ }
26
+ function toPositiveInt(value) {
27
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
28
+ return undefined;
29
+ }
30
+ return Math.floor(value);
31
+ }
32
+ export function applyPiCompactionSettingsFromConfig(params) {
33
+ const currentReserveTokens = params.settingsManager.getCompactionReserveTokens();
34
+ const currentKeepRecentTokens = params.settingsManager.getCompactionKeepRecentTokens();
35
+ const compactionCfg = params.cfg?.agents?.defaults?.compaction;
36
+ const configuredReserveTokens = toNonNegativeInt(compactionCfg?.reserveTokens);
37
+ const configuredKeepRecentTokens = toPositiveInt(compactionCfg?.keepRecentTokens);
38
+ const reserveTokensFloor = resolveCompactionReserveTokensFloor(params.cfg);
39
+ const targetReserveTokens = Math.max(configuredReserveTokens ?? currentReserveTokens, reserveTokensFloor);
40
+ const targetKeepRecentTokens = configuredKeepRecentTokens ?? currentKeepRecentTokens;
41
+ const overrides = {};
42
+ if (targetReserveTokens !== currentReserveTokens) {
43
+ overrides.reserveTokens = targetReserveTokens;
44
+ }
45
+ if (targetKeepRecentTokens !== currentKeepRecentTokens) {
46
+ overrides.keepRecentTokens = targetKeepRecentTokens;
47
+ }
48
+ const didOverride = Object.keys(overrides).length > 0;
49
+ if (didOverride) {
50
+ params.settingsManager.applyOverrides({ compaction: overrides });
51
+ }
52
+ return {
53
+ didOverride,
54
+ compaction: {
55
+ reserveTokens: targetReserveTokens,
56
+ keepRecentTokens: targetKeepRecentTokens,
57
+ },
58
+ };
59
+ }
@@ -5,6 +5,7 @@ import { normalizeMessageChannel } from "../utils/message-channel.js";
5
5
  import { resolveAgentConfig, resolveAgentIdFromSessionKey } from "./agent-scope.js";
6
6
  import { compileGlobPatterns, matchesAnyGlobPattern } from "./glob-pattern.js";
7
7
  import { pickSandboxToolPolicy } from "./sandbox-tool-policy.js";
8
+ import { DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH } from "../config/agent-limits.js";
8
9
  import { expandToolGroups, normalizeToolName } from "./tool-policy.js";
9
10
  function makeToolPolicyMatcher(policy) {
10
11
  const deny = compileGlobPatterns({
@@ -75,7 +76,7 @@ function resolveSubagentDenyList(depth, maxSpawnDepth) {
75
76
  }
76
77
  export function resolveSubagentToolPolicy(cfg, depth) {
77
78
  const configured = cfg?.tools?.subagents?.tools;
78
- const maxSpawnDepth = cfg?.agents?.defaults?.subagents?.maxSpawnDepth ?? 1;
79
+ const maxSpawnDepth = cfg?.agents?.defaults?.subagents?.maxSpawnDepth ?? DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH;
79
80
  const effectiveDepth = typeof depth === "number" && depth >= 0 ? depth : 1;
80
81
  const baseDeny = resolveSubagentDenyList(effectiveDepth, maxSpawnDepth);
81
82
  const deny = [...baseDeny, ...(Array.isArray(configured?.deny) ? configured.deny : [])];
@@ -46,7 +46,7 @@ export function loadPoolConfig(cfg) {
46
46
  }
47
47
  try {
48
48
  TokenPool.addToken(providerID, tokenCfg.id, tokenCfg.key, {
49
- tier: tokenCfg.tier ?? "paid",
49
+ tier: (tokenCfg.tier ?? "paid"),
50
50
  label: tokenCfg.label,
51
51
  enabled: tokenCfg.enabled ?? true,
52
52
  });
@@ -1,23 +1,31 @@
1
+ import crypto from "node:crypto";
1
2
  import { startBrowserBridgeServer, stopBrowserBridgeServer } from "../../browser/bridge-server.js";
2
3
  import { resolveProfile } from "../../browser/config.js";
3
- import { DEFAULT_BROWSER_EVALUATE_ENABLED, DEFAULT_CLAWD_BROWSER_COLOR, } from "../../browser/constants.js";
4
+ import { DEFAULT_BROWSER_EVALUATE_ENABLED, DEFAULT_CLAWD_BROWSER_COLOR, DEFAULT_CLAWD_BROWSER_PROFILE_NAME, } from "../../browser/constants.js";
5
+ import { defaultRuntime } from "../../runtime.js";
4
6
  import { BROWSER_BRIDGES } from "./browser-bridges.js";
5
- import { DEFAULT_SANDBOX_BROWSER_IMAGE, SANDBOX_AGENT_WORKSPACE_MOUNT } from "./constants.js";
6
- import { buildSandboxCreateArgs, dockerContainerState, execDocker, readDockerPort, } from "./docker.js";
7
- import { updateBrowserRegistry } from "./registry.js";
8
- import { slugifySessionKey } from "./shared.js";
7
+ import { computeSandboxBrowserConfigHash } from "./config-hash.js";
8
+ import { resolveSandboxBrowserDockerCreateConfig } from "./config.js";
9
+ import { DEFAULT_SANDBOX_BROWSER_IMAGE, SANDBOX_AGENT_WORKSPACE_MOUNT, SANDBOX_BROWSER_SECURITY_HASH_EPOCH, } from "./constants.js";
10
+ import { buildSandboxCreateArgs, dockerContainerState, execDocker, readDockerContainerEnvVar, readDockerContainerLabel, readDockerPort, } from "./docker.js";
11
+ import { buildNoVncDirectUrl, buildNoVncObserverTokenUrl, consumeNoVncObserverToken, generateNoVncPassword, isNoVncEnabled, NOVNC_PASSWORD_ENV_KEY, issueNoVncObserverToken, } from "./novnc-auth.js";
12
+ import { readBrowserRegistry, updateBrowserRegistry } from "./registry.js";
13
+ import { resolveSandboxAgentId, slugifySessionKey } from "./shared.js";
9
14
  import { isToolAllowed } from "./tool-policy.js";
15
+ const HOT_BROWSER_WINDOW_MS = 5 * 60 * 1000;
16
+ const CDP_SOURCE_RANGE_ENV_KEY = "POOLBOT_BROWSER_CDP_SOURCE_RANGE";
10
17
  async function waitForSandboxCdp(params) {
11
18
  const deadline = Date.now() + Math.max(0, params.timeoutMs);
12
19
  const url = `http://127.0.0.1:${params.cdpPort}/json/version`;
13
20
  while (Date.now() < deadline) {
14
21
  try {
15
22
  const ctrl = new AbortController();
16
- const t = setTimeout(() => ctrl.abort(), 1000);
23
+ const t = setTimeout(ctrl.abort.bind(ctrl), 1000);
17
24
  try {
18
25
  const res = await fetch(url, { signal: ctrl.signal });
19
- if (res.ok)
26
+ if (res.ok) {
20
27
  return true;
28
+ }
21
29
  }
22
30
  finally {
23
31
  clearTimeout(t);
@@ -46,9 +54,13 @@ function buildSandboxBrowserResolvedConfig(params) {
46
54
  headless: params.headless,
47
55
  noSandbox: false,
48
56
  attachOnly: true,
49
- defaultProfile: "clawd",
57
+ defaultProfile: DEFAULT_CLAWD_BROWSER_PROFILE_NAME,
58
+ extraArgs: [],
50
59
  profiles: {
51
- clawd: { cdpPort: params.cdpPort, color: DEFAULT_CLAWD_BROWSER_COLOR },
60
+ [DEFAULT_CLAWD_BROWSER_PROFILE_NAME]: {
61
+ cdpPort: params.cdpPort,
62
+ color: DEFAULT_CLAWD_BROWSER_COLOR,
63
+ },
52
64
  },
53
65
  };
54
66
  }
@@ -56,26 +68,115 @@ async function ensureSandboxBrowserImage(image) {
56
68
  const result = await execDocker(["image", "inspect", image], {
57
69
  allowFailure: true,
58
70
  });
59
- if (result.code === 0)
71
+ if (result.code === 0) {
60
72
  return;
73
+ }
61
74
  throw new Error(`Sandbox browser image not found: ${image}. Build it with scripts/sandbox-browser-setup.sh.`);
62
75
  }
76
+ async function ensureDockerNetwork(network) {
77
+ const normalized = network.trim().toLowerCase();
78
+ if (!normalized ||
79
+ normalized === "bridge" ||
80
+ normalized === "none" ||
81
+ normalized.startsWith("container:")) {
82
+ return;
83
+ }
84
+ const inspect = await execDocker(["network", "inspect", network], { allowFailure: true });
85
+ if (inspect.code === 0) {
86
+ return;
87
+ }
88
+ await execDocker(["network", "create", "--driver", "bridge", network]);
89
+ }
63
90
  export async function ensureSandboxBrowser(params) {
64
- if (!params.cfg.browser.enabled)
91
+ if (!params.cfg.browser.enabled) {
65
92
  return null;
66
- if (!isToolAllowed(params.cfg.tools, "browser"))
93
+ }
94
+ if (!isToolAllowed(params.cfg.tools, "browser")) {
67
95
  return null;
96
+ }
68
97
  const slug = params.cfg.scope === "shared" ? "shared" : slugifySessionKey(params.scopeKey);
69
98
  const name = `${params.cfg.browser.containerPrefix}${slug}`;
70
99
  const containerName = name.slice(0, 63);
71
100
  const state = await dockerContainerState(containerName);
72
- if (!state.exists) {
73
- await ensureSandboxBrowserImage(params.cfg.browser.image ?? DEFAULT_SANDBOX_BROWSER_IMAGE);
101
+ const browserImage = params.cfg.browser.image ?? DEFAULT_SANDBOX_BROWSER_IMAGE;
102
+ const cdpSourceRange = params.cfg.browser.cdpSourceRange?.trim() || undefined;
103
+ const browserDockerCfg = resolveSandboxBrowserDockerCreateConfig({
104
+ docker: params.cfg.docker,
105
+ browser: { ...params.cfg.browser, image: browserImage },
106
+ });
107
+ const expectedHash = computeSandboxBrowserConfigHash({
108
+ docker: browserDockerCfg,
109
+ browser: {
110
+ cdpPort: params.cfg.browser.cdpPort,
111
+ vncPort: params.cfg.browser.vncPort,
112
+ noVncPort: params.cfg.browser.noVncPort,
113
+ headless: params.cfg.browser.headless,
114
+ enableNoVnc: params.cfg.browser.enableNoVnc,
115
+ cdpSourceRange,
116
+ },
117
+ securityEpoch: SANDBOX_BROWSER_SECURITY_HASH_EPOCH,
118
+ workspaceAccess: params.cfg.workspaceAccess,
119
+ workspaceDir: params.workspaceDir,
120
+ agentWorkspaceDir: params.agentWorkspaceDir,
121
+ });
122
+ const now = Date.now();
123
+ let hasContainer = state.exists;
124
+ let running = state.running;
125
+ let currentHash = null;
126
+ let hashMismatch = false;
127
+ const noVncEnabled = isNoVncEnabled(params.cfg.browser);
128
+ let noVncPassword;
129
+ if (hasContainer) {
130
+ if (noVncEnabled) {
131
+ noVncPassword =
132
+ (await readDockerContainerEnvVar(containerName, NOVNC_PASSWORD_ENV_KEY)) ?? undefined;
133
+ }
134
+ const registry = await readBrowserRegistry();
135
+ const registryEntry = registry.entries.find((entry) => entry.containerName === containerName);
136
+ currentHash = await readDockerContainerLabel(containerName, "poolbot.configHash");
137
+ hashMismatch = !currentHash || currentHash !== expectedHash;
138
+ if (!currentHash) {
139
+ currentHash = registryEntry?.configHash ?? null;
140
+ hashMismatch = !currentHash || currentHash !== expectedHash;
141
+ }
142
+ if (hashMismatch) {
143
+ const lastUsedAtMs = registryEntry?.lastUsedAtMs;
144
+ const isHot = running && (typeof lastUsedAtMs !== "number" || now - lastUsedAtMs < HOT_BROWSER_WINDOW_MS);
145
+ if (isHot) {
146
+ const hint = (() => {
147
+ if (params.cfg.scope === "session") {
148
+ return `poolbot sandbox recreate --browser --session ${params.scopeKey}`;
149
+ }
150
+ if (params.cfg.scope === "agent") {
151
+ const agentId = resolveSandboxAgentId(params.scopeKey) ?? "main";
152
+ return `poolbot sandbox recreate --browser --agent ${agentId}`;
153
+ }
154
+ return "poolbot sandbox recreate --browser --all";
155
+ })();
156
+ defaultRuntime.log(`Sandbox browser config changed for ${containerName} (recently used). Recreate to apply: ${hint}`);
157
+ }
158
+ else {
159
+ await execDocker(["rm", "-f", containerName], { allowFailure: true });
160
+ hasContainer = false;
161
+ running = false;
162
+ }
163
+ }
164
+ }
165
+ if (!hasContainer) {
166
+ if (noVncEnabled) {
167
+ noVncPassword = generateNoVncPassword();
168
+ }
169
+ await ensureDockerNetwork(browserDockerCfg.network);
170
+ await ensureSandboxBrowserImage(browserImage);
74
171
  const args = buildSandboxCreateArgs({
75
172
  name: containerName,
76
- cfg: params.cfg.docker,
173
+ cfg: browserDockerCfg,
77
174
  scopeKey: params.scopeKey,
78
- labels: { "poolbot.sandboxBrowser": "1" },
175
+ labels: {
176
+ "poolbot.sandboxBrowser": "1",
177
+ "poolbot.browserConfigEpoch": SANDBOX_BROWSER_SECURITY_HASH_EPOCH,
178
+ },
179
+ configHash: expectedHash,
79
180
  });
80
181
  const mainMountSuffix = params.cfg.workspaceAccess === "ro" && params.workspaceDir === params.agentWorkspaceDir
81
182
  ? ":ro"
@@ -86,48 +187,75 @@ export async function ensureSandboxBrowser(params) {
86
187
  args.push("-v", `${params.agentWorkspaceDir}:${SANDBOX_AGENT_WORKSPACE_MOUNT}${agentMountSuffix}`);
87
188
  }
88
189
  args.push("-p", `127.0.0.1::${params.cfg.browser.cdpPort}`);
89
- if (params.cfg.browser.enableNoVnc && !params.cfg.browser.headless) {
190
+ if (noVncEnabled) {
90
191
  args.push("-p", `127.0.0.1::${params.cfg.browser.noVncPort}`);
91
192
  }
92
193
  args.push("-e", `POOLBOT_BROWSER_HEADLESS=${params.cfg.browser.headless ? "1" : "0"}`);
93
- args.push("-e", `CLAWDBOT_BROWSER_HEADLESS=${params.cfg.browser.headless ? "1" : "0"}`);
94
194
  args.push("-e", `POOLBOT_BROWSER_ENABLE_NOVNC=${params.cfg.browser.enableNoVnc ? "1" : "0"}`);
95
- args.push("-e", `CLAWDBOT_BROWSER_ENABLE_NOVNC=${params.cfg.browser.enableNoVnc ? "1" : "0"}`);
96
195
  args.push("-e", `POOLBOT_BROWSER_CDP_PORT=${params.cfg.browser.cdpPort}`);
97
- args.push("-e", `CLAWDBOT_BROWSER_CDP_PORT=${params.cfg.browser.cdpPort}`);
196
+ if (cdpSourceRange) {
197
+ args.push("-e", `${CDP_SOURCE_RANGE_ENV_KEY}=${cdpSourceRange}`);
198
+ }
98
199
  args.push("-e", `POOLBOT_BROWSER_VNC_PORT=${params.cfg.browser.vncPort}`);
99
- args.push("-e", `CLAWDBOT_BROWSER_VNC_PORT=${params.cfg.browser.vncPort}`);
100
200
  args.push("-e", `POOLBOT_BROWSER_NOVNC_PORT=${params.cfg.browser.noVncPort}`);
101
- args.push("-e", `CLAWDBOT_BROWSER_NOVNC_PORT=${params.cfg.browser.noVncPort}`);
102
- args.push(params.cfg.browser.image);
201
+ if (noVncEnabled && noVncPassword) {
202
+ args.push("-e", `${NOVNC_PASSWORD_ENV_KEY}=${noVncPassword}`);
203
+ }
204
+ args.push(browserImage);
103
205
  await execDocker(args);
104
206
  await execDocker(["start", containerName]);
105
207
  }
106
- else if (!state.running) {
208
+ else if (!running) {
107
209
  await execDocker(["start", containerName]);
108
210
  }
109
211
  const mappedCdp = await readDockerPort(containerName, params.cfg.browser.cdpPort);
110
212
  if (!mappedCdp) {
111
213
  throw new Error(`Failed to resolve CDP port mapping for ${containerName}.`);
112
214
  }
113
- const mappedNoVnc = params.cfg.browser.enableNoVnc && !params.cfg.browser.headless
215
+ const mappedNoVnc = noVncEnabled
114
216
  ? await readDockerPort(containerName, params.cfg.browser.noVncPort)
115
217
  : null;
218
+ if (noVncEnabled && !noVncPassword) {
219
+ noVncPassword =
220
+ (await readDockerContainerEnvVar(containerName, NOVNC_PASSWORD_ENV_KEY)) ?? undefined;
221
+ }
116
222
  const existing = BROWSER_BRIDGES.get(params.scopeKey);
117
- const existingProfile = existing ? resolveProfile(existing.bridge.state.resolved, "clawd") : null;
223
+ const existingProfile = existing
224
+ ? resolveProfile(existing.bridge.state.resolved, DEFAULT_CLAWD_BROWSER_PROFILE_NAME)
225
+ : null;
226
+ let desiredAuthToken = params.bridgeAuth?.token?.trim() || undefined;
227
+ let desiredAuthPassword = params.bridgeAuth?.password?.trim() || undefined;
228
+ if (!desiredAuthToken && !desiredAuthPassword) {
229
+ // Always require auth for the sandbox bridge server, even if gateway auth
230
+ // mode doesn't produce a shared secret (e.g. trusted-proxy).
231
+ // Keep it stable across calls by reusing the existing bridge auth.
232
+ desiredAuthToken = existing?.authToken;
233
+ desiredAuthPassword = existing?.authPassword;
234
+ if (!desiredAuthToken && !desiredAuthPassword) {
235
+ desiredAuthToken = crypto.randomBytes(24).toString("hex");
236
+ }
237
+ }
118
238
  const shouldReuse = existing && existing.containerName === containerName && existingProfile?.cdpPort === mappedCdp;
239
+ const authMatches = !existing ||
240
+ (existing.authToken === desiredAuthToken && existing.authPassword === desiredAuthPassword);
119
241
  if (existing && !shouldReuse) {
120
242
  await stopBrowserBridgeServer(existing.bridge.server).catch(() => undefined);
121
243
  BROWSER_BRIDGES.delete(params.scopeKey);
122
244
  }
245
+ if (existing && shouldReuse && !authMatches) {
246
+ await stopBrowserBridgeServer(existing.bridge.server).catch(() => undefined);
247
+ BROWSER_BRIDGES.delete(params.scopeKey);
248
+ }
123
249
  const bridge = (() => {
124
- if (shouldReuse && existing)
250
+ if (shouldReuse && authMatches && existing) {
125
251
  return existing.bridge;
252
+ }
126
253
  return null;
127
254
  })();
128
255
  const ensureBridge = async () => {
129
- if (bridge)
256
+ if (bridge) {
130
257
  return bridge;
258
+ }
131
259
  const onEnsureAttachTarget = params.cfg.browser.autoStart
132
260
  ? async () => {
133
261
  const state = await dockerContainerState(containerName);
@@ -150,28 +278,37 @@ export async function ensureSandboxBrowser(params) {
150
278
  headless: params.cfg.browser.headless,
151
279
  evaluateEnabled: params.evaluateEnabled ?? DEFAULT_BROWSER_EVALUATE_ENABLED,
152
280
  }),
281
+ authToken: desiredAuthToken,
282
+ authPassword: desiredAuthPassword,
153
283
  onEnsureAttachTarget,
284
+ resolveSandboxNoVncToken: consumeNoVncObserverToken,
154
285
  });
155
286
  };
156
287
  const resolvedBridge = await ensureBridge();
157
- if (!shouldReuse) {
288
+ if (!shouldReuse || !authMatches) {
158
289
  BROWSER_BRIDGES.set(params.scopeKey, {
159
290
  bridge: resolvedBridge,
160
291
  containerName,
292
+ authToken: desiredAuthToken,
293
+ authPassword: desiredAuthPassword,
161
294
  });
162
295
  }
163
- const now = Date.now();
164
296
  await updateBrowserRegistry({
165
297
  containerName,
166
298
  sessionKey: params.scopeKey,
167
299
  createdAtMs: now,
168
300
  lastUsedAtMs: now,
169
- image: params.cfg.browser.image,
301
+ image: browserImage,
302
+ configHash: hashMismatch && running ? (currentHash ?? undefined) : expectedHash,
170
303
  cdpPort: mappedCdp,
171
304
  noVncPort: mappedNoVnc ?? undefined,
172
305
  });
173
- const noVncUrl = mappedNoVnc && params.cfg.browser.enableNoVnc && !params.cfg.browser.headless
174
- ? `http://127.0.0.1:${mappedNoVnc}/vnc.html?autoconnect=1&resize=remote`
306
+ const noVncUrl = mappedNoVnc && noVncEnabled
307
+ ? (() => {
308
+ const directUrl = buildNoVncDirectUrl(mappedNoVnc, noVncPassword);
309
+ const token = issueNoVncObserverToken({ url: directUrl });
310
+ return buildNoVncObserverTokenUrl(resolvedBridge.baseUrl, token);
311
+ })()
175
312
  : undefined;
176
313
  return {
177
314
  bridgeUrl: resolvedBridge.baseUrl,
@@ -1,45 +1,32 @@
1
- import crypto from "node:crypto";
2
- function isPrimitive(value) {
3
- return value === null || (typeof value !== "object" && typeof value !== "function");
4
- }
1
+ import { hashTextSha256 } from "./hash.js";
5
2
  function normalizeForHash(value) {
6
- if (value === undefined)
3
+ if (value === undefined) {
7
4
  return undefined;
5
+ }
8
6
  if (Array.isArray(value)) {
9
- const normalized = value
10
- .map(normalizeForHash)
11
- .filter((item) => item !== undefined);
12
- const primitives = normalized.filter(isPrimitive);
13
- if (primitives.length === normalized.length) {
14
- return [...primitives].sort((a, b) => primitiveToString(a).localeCompare(primitiveToString(b)));
15
- }
16
- return normalized;
7
+ return value.map(normalizeForHash).filter((item) => item !== undefined);
17
8
  }
18
9
  if (value && typeof value === "object") {
19
- const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b));
10
+ const entries = Object.entries(value).toSorted(([a], [b]) => a.localeCompare(b));
20
11
  const normalized = {};
21
12
  for (const [key, entryValue] of entries) {
22
13
  const next = normalizeForHash(entryValue);
23
- if (next !== undefined)
14
+ if (next !== undefined) {
24
15
  normalized[key] = next;
16
+ }
25
17
  }
26
18
  return normalized;
27
19
  }
28
20
  return value;
29
21
  }
30
- function primitiveToString(value) {
31
- if (value === null)
32
- return "null";
33
- if (typeof value === "string")
34
- return value;
35
- if (typeof value === "number")
36
- return String(value);
37
- if (typeof value === "boolean")
38
- return value ? "true" : "false";
39
- return JSON.stringify(value);
40
- }
41
22
  export function computeSandboxConfigHash(input) {
23
+ return computeHash(input);
24
+ }
25
+ export function computeSandboxBrowserConfigHash(input) {
26
+ return computeHash(input);
27
+ }
28
+ function computeHash(input) {
42
29
  const payload = normalizeForHash(input);
43
30
  const raw = JSON.stringify(payload);
44
- return crypto.createHash("sha1").update(raw).digest("hex");
31
+ return hashTextSha256(raw);
45
32
  }