@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,97 +1,223 @@
1
+ import { createSubsystemLogger } from "../logging/subsystem.js";
2
+ import { isSensitiveConfigPath } from "./schema.hints.js";
3
+ const log = createSubsystemLogger("config/redaction");
4
+ const ENV_VAR_PLACEHOLDER_PATTERN = /^\$\{[^}]*\}$/;
5
+ function isSensitivePath(path) {
6
+ if (path.endsWith("[]")) {
7
+ return isSensitiveConfigPath(path.slice(0, -2));
8
+ }
9
+ else {
10
+ return isSensitiveConfigPath(path);
11
+ }
12
+ }
13
+ function isEnvVarPlaceholder(value) {
14
+ return ENV_VAR_PLACEHOLDER_PATTERN.test(value.trim());
15
+ }
16
+ function isExtensionPath(path) {
17
+ return (path === "plugins" ||
18
+ path.startsWith("plugins.") ||
19
+ path === "channels" ||
20
+ path.startsWith("channels."));
21
+ }
22
+ function isExplicitlyNonSensitivePath(hints, paths) {
23
+ if (!hints) {
24
+ return false;
25
+ }
26
+ return paths.some((path) => hints[path]?.sensitive === false);
27
+ }
1
28
  /**
2
29
  * Sentinel value used to replace sensitive config fields in gateway responses.
3
30
  * Write-side handlers (config.set, config.apply, config.patch) detect this
4
31
  * sentinel and restore the original value from the on-disk config, so a
5
32
  * round-trip through the Web UI does not corrupt credentials.
6
33
  */
7
- export const REDACTED_SENTINEL = "__POOLBOT_REDACTED__";
8
- /**
9
- * Patterns that identify sensitive config field names.
10
- * Aligned with the UI-hint logic in schema.ts.
11
- */
12
- const SENSITIVE_KEY_PATTERNS = [/token/i, /password/i, /secret/i, /api.?key/i];
13
- function isSensitiveKey(key) {
14
- return SENSITIVE_KEY_PATTERNS.some((pattern) => pattern.test(key));
34
+ export const REDACTED_SENTINEL = "__CLAWDBOT_REDACTED__";
35
+ // ConfigUiHints' keys look like this:
36
+ // - path.subpath.key (nested objects)
37
+ // - path.subpath[].key (object in array in object)
38
+ // - path.*.key (object in record in object)
39
+ // records are handled by the lookup, but arrays need two entries in
40
+ // the Set, as their first lookup is done before the code knows it's
41
+ // an array.
42
+ function buildRedactionLookup(hints) {
43
+ let result = new Set();
44
+ for (const [path, hint] of Object.entries(hints)) {
45
+ if (!hint.sensitive) {
46
+ continue;
47
+ }
48
+ const parts = path.split(".");
49
+ let joinedPath = parts.shift() ?? "";
50
+ result.add(joinedPath);
51
+ if (joinedPath.endsWith("[]")) {
52
+ result.add(joinedPath.slice(0, -2));
53
+ }
54
+ for (const part of parts) {
55
+ if (part.endsWith("[]")) {
56
+ result.add(`${joinedPath}.${part.slice(0, -2)}`);
57
+ }
58
+ // hey, greptile, notice how this is *NOT* in an else block?
59
+ joinedPath = `${joinedPath}.${part}`;
60
+ result.add(joinedPath);
61
+ }
62
+ }
63
+ if (result.size !== 0) {
64
+ result.add("");
65
+ }
66
+ return result;
15
67
  }
16
68
  /**
17
- * Deep-walk an object and replace values whose key matches a sensitive pattern
69
+ * Deep-walk an object and replace string values at sensitive paths
18
70
  * with the redaction sentinel.
19
71
  */
20
- function redactObject(obj) {
21
- if (obj === null || obj === undefined) {
22
- return obj;
72
+ function redactObject(obj, hints) {
73
+ if (hints) {
74
+ const lookup = buildRedactionLookup(hints);
75
+ return lookup.has("")
76
+ ? redactObjectWithLookup(obj, lookup, "", [], hints)
77
+ : redactObjectGuessing(obj, "", [], hints);
23
78
  }
24
- if (typeof obj !== "object") {
25
- return obj;
26
- }
27
- if (Array.isArray(obj)) {
28
- return obj.map(redactObject);
79
+ else {
80
+ return redactObjectGuessing(obj, "", []);
29
81
  }
30
- const result = {};
31
- for (const [key, value] of Object.entries(obj)) {
32
- if (isSensitiveKey(key) && value !== null && value !== undefined) {
33
- result[key] = REDACTED_SENTINEL;
34
- }
35
- else if (typeof value === "object" && value !== null) {
36
- result[key] = redactObject(value);
82
+ }
83
+ /**
84
+ * Collect all sensitive string values from a config object.
85
+ * Used for text-based redaction of the raw JSON5 source.
86
+ */
87
+ function collectSensitiveValues(obj, hints) {
88
+ const result = [];
89
+ if (hints) {
90
+ const lookup = buildRedactionLookup(hints);
91
+ if (lookup.has("")) {
92
+ redactObjectWithLookup(obj, lookup, "", result, hints);
37
93
  }
38
94
  else {
39
- result[key] = value;
95
+ redactObjectGuessing(obj, "", result, hints);
40
96
  }
41
97
  }
98
+ else {
99
+ redactObjectGuessing(obj, "", result);
100
+ }
42
101
  return result;
43
102
  }
44
- export function redactConfigObject(value) {
45
- return redactObject(value);
46
- }
47
103
  /**
48
- * Collect all sensitive string values from a config object.
49
- * Used for text-based redaction of the raw JSON5 source.
104
+ * Worker for redactObject() and collectSensitiveValues().
105
+ * Used when there are ConfigUiHints available.
50
106
  */
51
- function collectSensitiveValues(obj) {
52
- const values = [];
53
- if (obj === null || obj === undefined || typeof obj !== "object") {
54
- return values;
107
+ function redactObjectWithLookup(obj, lookup, prefix, values, hints) {
108
+ if (obj === null || obj === undefined) {
109
+ return obj;
55
110
  }
56
111
  if (Array.isArray(obj)) {
57
- for (const item of obj) {
58
- values.push(...collectSensitiveValues(item));
112
+ const path = `${prefix}[]`;
113
+ if (!lookup.has(path)) {
114
+ if (!isExtensionPath(prefix)) {
115
+ return obj;
116
+ }
117
+ return redactObjectGuessing(obj, prefix, values, hints);
59
118
  }
60
- return values;
119
+ return obj.map((item) => {
120
+ if (typeof item === "string" && !isEnvVarPlaceholder(item)) {
121
+ values.push(item);
122
+ return REDACTED_SENTINEL;
123
+ }
124
+ return redactObjectWithLookup(item, lookup, path, values, hints);
125
+ });
61
126
  }
62
- for (const [key, value] of Object.entries(obj)) {
63
- if (isSensitiveKey(key) && typeof value === "string" && value.length > 0) {
64
- values.push(value);
127
+ if (typeof obj === "object") {
128
+ const result = {};
129
+ for (const [key, value] of Object.entries(obj)) {
130
+ const path = prefix ? `${prefix}.${key}` : key;
131
+ const wildcardPath = prefix ? `${prefix}.*` : "*";
132
+ let matched = false;
133
+ for (const candidate of [path, wildcardPath]) {
134
+ result[key] = value;
135
+ if (lookup.has(candidate)) {
136
+ matched = true;
137
+ // Hey, greptile, look here, this **IS** only applied to strings
138
+ if (typeof value === "string" && !isEnvVarPlaceholder(value)) {
139
+ result[key] = REDACTED_SENTINEL;
140
+ values.push(value);
141
+ }
142
+ else if (typeof value === "object" && value !== null) {
143
+ result[key] = redactObjectWithLookup(value, lookup, candidate, values, hints);
144
+ }
145
+ break;
146
+ }
147
+ }
148
+ if (!matched && isExtensionPath(path)) {
149
+ const markedNonSensitive = isExplicitlyNonSensitivePath(hints, [path, wildcardPath]);
150
+ if (typeof value === "string" &&
151
+ !markedNonSensitive &&
152
+ isSensitivePath(path) &&
153
+ !isEnvVarPlaceholder(value)) {
154
+ result[key] = REDACTED_SENTINEL;
155
+ values.push(value);
156
+ }
157
+ else if (typeof value === "object" && value !== null) {
158
+ result[key] = redactObjectGuessing(value, path, values, hints);
159
+ }
160
+ }
65
161
  }
66
- else if (typeof value === "object" && value !== null) {
67
- values.push(...collectSensitiveValues(value));
162
+ return result;
163
+ }
164
+ return obj;
165
+ }
166
+ /**
167
+ * Worker for redactObject() and collectSensitiveValues().
168
+ * Used when ConfigUiHints are NOT available.
169
+ */
170
+ function redactObjectGuessing(obj, prefix, values, hints) {
171
+ if (obj === null || obj === undefined) {
172
+ return obj;
173
+ }
174
+ if (Array.isArray(obj)) {
175
+ return obj.map((item) => {
176
+ const path = `${prefix}[]`;
177
+ if (!isExplicitlyNonSensitivePath(hints, [path]) &&
178
+ isSensitivePath(path) &&
179
+ typeof item === "string" &&
180
+ !isEnvVarPlaceholder(item)) {
181
+ values.push(item);
182
+ return REDACTED_SENTINEL;
183
+ }
184
+ return redactObjectGuessing(item, path, values, hints);
185
+ });
186
+ }
187
+ if (typeof obj === "object") {
188
+ const result = {};
189
+ for (const [key, value] of Object.entries(obj)) {
190
+ const dotPath = prefix ? `${prefix}.${key}` : key;
191
+ const wildcardPath = prefix ? `${prefix}.*` : "*";
192
+ if (!isExplicitlyNonSensitivePath(hints, [dotPath, wildcardPath]) &&
193
+ isSensitivePath(dotPath) &&
194
+ typeof value === "string" &&
195
+ !isEnvVarPlaceholder(value)) {
196
+ result[key] = REDACTED_SENTINEL;
197
+ values.push(value);
198
+ }
199
+ else if (typeof value === "object" && value !== null) {
200
+ result[key] = redactObjectGuessing(value, dotPath, values, hints);
201
+ }
202
+ else {
203
+ result[key] = value;
204
+ }
68
205
  }
206
+ return result;
69
207
  }
70
- return values;
208
+ return obj;
71
209
  }
72
210
  /**
73
211
  * Replace known sensitive values in a raw JSON5 string with the sentinel.
74
212
  * Values are replaced longest-first to avoid partial matches.
75
213
  */
76
- function redactRawText(raw, config) {
77
- const sensitiveValues = collectSensitiveValues(config);
214
+ function redactRawText(raw, config, hints) {
215
+ const sensitiveValues = collectSensitiveValues(config, hints);
78
216
  sensitiveValues.sort((a, b) => b.length - a.length);
79
217
  let result = raw;
80
218
  for (const value of sensitiveValues) {
81
- const escaped = value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
82
- result = result.replace(new RegExp(escaped, "g"), REDACTED_SENTINEL);
219
+ result = result.replaceAll(value, REDACTED_SENTINEL);
83
220
  }
84
- const keyValuePattern = /(^|[{\s,])((["'])([^"']+)\3|([A-Za-z0-9_$.-]+))(\s*:\s*)(["'])([^"']*)\7/g;
85
- result = result.replace(keyValuePattern, (match, prefix, keyExpr, _keyQuote, keyQuoted, keyBare, sep, valQuote, val) => {
86
- const key = (keyQuoted ?? keyBare);
87
- if (!key || !isSensitiveKey(key)) {
88
- return match;
89
- }
90
- if (val === REDACTED_SENTINEL) {
91
- return match;
92
- }
93
- return `${prefix}${keyExpr}${sep}${valQuote}${REDACTED_SENTINEL}${valQuote}`;
94
- });
95
221
  return result;
96
222
  }
97
223
  /**
@@ -101,49 +227,251 @@ function redactRawText(raw, config) {
101
227
  *
102
228
  * Both `config` (the parsed object) and `raw` (the JSON5 source) are scrubbed
103
229
  * so no credential can leak through either path.
230
+ *
231
+ * When `uiHints` are provided, sensitivity is determined from the schema hints.
232
+ * Without hints, falls back to regex-based detection via `isSensitivePath()`.
104
233
  */
105
- export function redactConfigSnapshot(snapshot) {
106
- const redactedConfig = redactConfigObject(snapshot.config);
107
- const redactedRaw = snapshot.raw ? redactRawText(snapshot.raw, snapshot.config) : null;
108
- const redactedParsed = snapshot.parsed ? redactConfigObject(snapshot.parsed) : snapshot.parsed;
234
+ /**
235
+ * Redact sensitive fields from a plain config object (not a full snapshot).
236
+ * Used by write endpoints (config.set, config.patch, config.apply) to avoid
237
+ * leaking credentials in their responses.
238
+ */
239
+ export function redactConfigObject(value, uiHints) {
240
+ return redactObject(value, uiHints);
241
+ }
242
+ export function redactConfigSnapshot(snapshot, uiHints) {
243
+ if (!snapshot.valid) {
244
+ // This is bad. We could try to redact the raw string using known key names,
245
+ // but then we would not be able to restore them, and would trash the user's
246
+ // credentials. Less than ideal---we should never delete important data.
247
+ // On the other hand, we cannot hand out "raw" if we're not sure we have
248
+ // properly redacted all sensitive data. Handing out a partially or, worse,
249
+ // unredacted config string would be bad.
250
+ // Therefore, the only safe route is to reject handling out broken configs.
251
+ return {
252
+ ...snapshot,
253
+ config: {},
254
+ raw: null,
255
+ parsed: null,
256
+ resolved: {},
257
+ };
258
+ }
259
+ // else: snapshot.config must be valid and populated, as that is what
260
+ // readConfigFileSnapshot() does when it creates the snapshot.
261
+ const redactedConfig = redactObject(snapshot.config, uiHints);
262
+ const redactedRaw = snapshot.raw ? redactRawText(snapshot.raw, snapshot.config, uiHints) : null;
263
+ const redactedParsed = snapshot.parsed ? redactObject(snapshot.parsed, uiHints) : snapshot.parsed;
264
+ // Also redact the resolved config (contains values after ${ENV} substitution)
265
+ const redactedResolved = redactConfigObject(snapshot.resolved, uiHints);
109
266
  return {
110
267
  ...snapshot,
111
268
  config: redactedConfig,
112
269
  raw: redactedRaw,
113
270
  parsed: redactedParsed,
271
+ resolved: redactedResolved,
114
272
  };
115
273
  }
116
274
  /**
117
275
  * Deep-walk `incoming` and replace any {@link REDACTED_SENTINEL} values
118
- * (on sensitive keys) with the corresponding value from `original`.
276
+ * (on sensitive paths) with the corresponding value from `original`.
119
277
  *
120
278
  * This is called by config.set / config.apply / config.patch before writing,
121
279
  * so that credentials survive a Web UI round-trip unmodified.
122
280
  */
123
- export function restoreRedactedValues(incoming, original) {
281
+ export function restoreRedactedValues(incoming, original, hints) {
124
282
  if (incoming === null || incoming === undefined) {
125
- return incoming;
283
+ return { ok: false, error: "no input" };
126
284
  }
127
285
  if (typeof incoming !== "object") {
286
+ return { ok: false, error: "input not an object" };
287
+ }
288
+ try {
289
+ if (hints) {
290
+ const lookup = buildRedactionLookup(hints);
291
+ if (lookup.has("")) {
292
+ return {
293
+ ok: true,
294
+ result: restoreRedactedValuesWithLookup(incoming, original, lookup, "", hints),
295
+ };
296
+ }
297
+ else {
298
+ return { ok: true, result: restoreRedactedValuesGuessing(incoming, original, "", hints) };
299
+ }
300
+ }
301
+ else {
302
+ return { ok: true, result: restoreRedactedValuesGuessing(incoming, original, "") };
303
+ }
304
+ }
305
+ catch (err) {
306
+ if (err instanceof RedactionError) {
307
+ return {
308
+ ok: false,
309
+ humanReadableMessage: `Sentinel value "${REDACTED_SENTINEL}" in key ${err.key} is not valid as real data`,
310
+ };
311
+ }
312
+ throw err; // some coding error, pass through
313
+ }
314
+ }
315
+ class RedactionError extends Error {
316
+ key;
317
+ constructor(key) {
318
+ super("internal error class---should never escape");
319
+ this.key = key;
320
+ this.name = "RedactionError";
321
+ }
322
+ }
323
+ function restoreOriginalValueOrThrow(params) {
324
+ if (params.key in params.original) {
325
+ return params.original[params.key];
326
+ }
327
+ log.warn(`Cannot un-redact config key ${params.path} as it doesn't have any value`);
328
+ throw new RedactionError(params.path);
329
+ }
330
+ function mapRedactedArray(params) {
331
+ const originalArray = Array.isArray(params.original) ? params.original : [];
332
+ if (params.incoming.length < originalArray.length) {
333
+ log.warn(`Redacted config array key ${params.path} has been truncated`);
334
+ }
335
+ return params.incoming.map((item, index) => params.mapItem(item, index, originalArray));
336
+ }
337
+ function toObjectRecord(value) {
338
+ if (value && typeof value === "object" && !Array.isArray(value)) {
339
+ return value;
340
+ }
341
+ return {};
342
+ }
343
+ function shouldPassThroughRestoreValue(incoming) {
344
+ return incoming === null || incoming === undefined || typeof incoming !== "object";
345
+ }
346
+ function toRestoreArrayContext(incoming, prefix) {
347
+ if (!Array.isArray(incoming)) {
348
+ return null;
349
+ }
350
+ return { incoming, path: `${prefix}[]` };
351
+ }
352
+ function restoreArrayItemWithLookup(params) {
353
+ if (params.item === REDACTED_SENTINEL) {
354
+ return params.originalArray[params.index];
355
+ }
356
+ return restoreRedactedValuesWithLookup(params.item, params.originalArray[params.index], params.lookup, params.path, params.hints);
357
+ }
358
+ function restoreArrayItemWithGuessing(params) {
359
+ if (!isExplicitlyNonSensitivePath(params.hints, [params.path]) &&
360
+ isSensitivePath(params.path) &&
361
+ params.item === REDACTED_SENTINEL) {
362
+ return params.originalArray[params.index];
363
+ }
364
+ return restoreRedactedValuesGuessing(params.item, params.originalArray[params.index], params.path, params.hints);
365
+ }
366
+ function restoreGuessingArray(incoming, original, path, hints) {
367
+ return mapRedactedArray({
368
+ incoming,
369
+ original,
370
+ path,
371
+ mapItem: (item, index, originalArray) => restoreArrayItemWithGuessing({
372
+ item,
373
+ index,
374
+ originalArray,
375
+ path,
376
+ hints,
377
+ }),
378
+ });
379
+ }
380
+ /**
381
+ * Worker for restoreRedactedValues().
382
+ * Used when there are ConfigUiHints available.
383
+ */
384
+ function restoreRedactedValuesWithLookup(incoming, original, lookup, prefix, hints) {
385
+ if (shouldPassThroughRestoreValue(incoming)) {
128
386
  return incoming;
129
387
  }
130
- if (Array.isArray(incoming)) {
131
- const origArr = Array.isArray(original) ? original : [];
132
- return incoming.map((item, i) => restoreRedactedValues(item, origArr[i]));
388
+ const arrayContext = toRestoreArrayContext(incoming, prefix);
389
+ if (arrayContext) {
390
+ // Note: If the user removed an item in the middle of the array,
391
+ // we have no way of knowing which one. In this case, the last
392
+ // element(s) get(s) chopped off. Not good, so please don't put
393
+ // sensitive string array in the config...
394
+ const { incoming: incomingArray, path } = arrayContext;
395
+ if (!lookup.has(path)) {
396
+ if (!isExtensionPath(prefix)) {
397
+ return incomingArray;
398
+ }
399
+ return restoreRedactedValuesGuessing(incomingArray, original, prefix, hints);
400
+ }
401
+ return mapRedactedArray({
402
+ incoming: incomingArray,
403
+ original,
404
+ path,
405
+ mapItem: (item, index, originalArray) => restoreArrayItemWithLookup({
406
+ item,
407
+ index,
408
+ originalArray,
409
+ lookup,
410
+ path,
411
+ hints,
412
+ }),
413
+ });
133
414
  }
134
- const orig = original && typeof original === "object" && !Array.isArray(original)
135
- ? original
136
- : {};
415
+ const orig = toObjectRecord(original);
137
416
  const result = {};
138
417
  for (const [key, value] of Object.entries(incoming)) {
139
- if (isSensitiveKey(key) && value === REDACTED_SENTINEL) {
140
- if (!(key in orig)) {
141
- throw new Error(`config write rejected: "${key}" is redacted; set an explicit value instead of ${REDACTED_SENTINEL}`);
418
+ result[key] = value;
419
+ const path = prefix ? `${prefix}.${key}` : key;
420
+ const wildcardPath = prefix ? `${prefix}.*` : "*";
421
+ let matched = false;
422
+ for (const candidate of [path, wildcardPath]) {
423
+ if (lookup.has(candidate)) {
424
+ matched = true;
425
+ if (value === REDACTED_SENTINEL) {
426
+ result[key] = restoreOriginalValueOrThrow({ key, path: candidate, original: orig });
427
+ }
428
+ else if (typeof value === "object" && value !== null) {
429
+ result[key] = restoreRedactedValuesWithLookup(value, orig[key], lookup, candidate, hints);
430
+ }
431
+ break;
142
432
  }
143
- result[key] = orig[key];
433
+ }
434
+ if (!matched && isExtensionPath(path)) {
435
+ const markedNonSensitive = isExplicitlyNonSensitivePath(hints, [path, wildcardPath]);
436
+ if (!markedNonSensitive && isSensitivePath(path) && value === REDACTED_SENTINEL) {
437
+ result[key] = restoreOriginalValueOrThrow({ key, path, original: orig });
438
+ }
439
+ else if (typeof value === "object" && value !== null) {
440
+ result[key] = restoreRedactedValuesGuessing(value, orig[key], path, hints);
441
+ }
442
+ }
443
+ }
444
+ return result;
445
+ }
446
+ /**
447
+ * Worker for restoreRedactedValues().
448
+ * Used when ConfigUiHints are NOT available.
449
+ */
450
+ function restoreRedactedValuesGuessing(incoming, original, prefix, hints) {
451
+ if (shouldPassThroughRestoreValue(incoming)) {
452
+ return incoming;
453
+ }
454
+ const arrayContext = toRestoreArrayContext(incoming, prefix);
455
+ if (arrayContext) {
456
+ // Note: If the user removed an item in the middle of the array,
457
+ // we have no way of knowing which one. In this case, the last
458
+ // element(s) get(s) chopped off. Not good, so please don't put
459
+ // sensitive string array in the config...
460
+ const { incoming: incomingArray, path } = arrayContext;
461
+ return restoreGuessingArray(incomingArray, original, path, hints);
462
+ }
463
+ const orig = toObjectRecord(original);
464
+ const result = {};
465
+ for (const [key, value] of Object.entries(incoming)) {
466
+ const path = prefix ? `${prefix}.${key}` : key;
467
+ const wildcardPath = prefix ? `${prefix}.*` : "*";
468
+ if (!isExplicitlyNonSensitivePath(hints, [path, wildcardPath]) &&
469
+ isSensitivePath(path) &&
470
+ value === REDACTED_SENTINEL) {
471
+ result[key] = restoreOriginalValueOrThrow({ key, path, original: orig });
144
472
  }
145
473
  else if (typeof value === "object" && value !== null) {
146
- result[key] = restoreRedactedValues(value, orig[key]);
474
+ result[key] = restoreRedactedValuesGuessing(value, orig[key], path, hints);
147
475
  }
148
476
  else {
149
477
  result[key] = value;