@poolzin/pool-bot 2026.1.39 → 2026.2.1

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 (511) hide show
  1. package/assets/chrome-extension/README.md +3 -3
  2. package/assets/chrome-extension/background.js +5 -5
  3. package/assets/chrome-extension/manifest.json +3 -3
  4. package/assets/chrome-extension/options.html +4 -4
  5. package/assets/chrome-extension/options.js +1 -1
  6. package/dist/acp/client.js +3 -3
  7. package/dist/acp/types.js +1 -1
  8. package/dist/agents/agent-paths.js +3 -3
  9. package/dist/agents/auth-profiles/paths.js +3 -3
  10. package/dist/agents/bash-tools.exec.js +76 -25
  11. package/dist/agents/cli-runner/helpers.js +10 -12
  12. package/dist/agents/cli-runner.js +2 -2
  13. package/dist/agents/cloudflare-ai-gateway.js +31 -0
  14. package/dist/agents/compaction.js +16 -2
  15. package/dist/agents/context-window-guard.js +13 -10
  16. package/dist/agents/context.js +4 -4
  17. package/dist/agents/docs-path.js +1 -1
  18. package/dist/agents/identity.js +47 -7
  19. package/dist/agents/memory-search.js +25 -8
  20. package/dist/agents/minimax-vlm.js +1 -1
  21. package/dist/agents/model-auth.js +12 -1
  22. package/dist/agents/model-catalog.js +4 -4
  23. package/dist/agents/model-selection.js +31 -4
  24. package/dist/agents/models-config.js +3 -3
  25. package/dist/agents/models-config.providers.js +147 -39
  26. package/dist/agents/pi-embedded-block-chunker.js +117 -42
  27. package/dist/agents/pi-embedded-helpers/errors.js +183 -78
  28. package/dist/agents/pi-embedded-helpers/openai.js +1 -1
  29. package/dist/agents/pi-embedded-helpers.js +1 -1
  30. package/dist/agents/pi-embedded-runner/compact.js +9 -8
  31. package/dist/agents/pi-embedded-runner/model.js +63 -4
  32. package/dist/agents/pi-embedded-runner/run/attempt.js +27 -17
  33. package/dist/agents/pi-embedded-runner/run.js +203 -50
  34. package/dist/agents/pi-embedded-runner/system-prompt.js +10 -2
  35. package/dist/agents/pi-embedded-runner/tool-result-truncation.js +275 -0
  36. package/dist/agents/pi-embedded-runner/utils.js +1 -1
  37. package/dist/agents/pi-embedded-subscribe.js +118 -29
  38. package/dist/agents/pi-model-discovery.js +10 -0
  39. package/dist/agents/pi-tool-definition-adapter.js +50 -9
  40. package/dist/agents/pi-tools.before-tool-call.js +67 -0
  41. package/dist/agents/pi-tools.js +20 -10
  42. package/dist/agents/pi-tools.read.js +2 -2
  43. package/dist/agents/poolbot-tools.js +15 -10
  44. package/dist/agents/sandbox-paths.js +31 -0
  45. package/dist/agents/session-file-repair.js +83 -0
  46. package/dist/agents/session-tool-result-guard.js +94 -15
  47. package/dist/agents/session-transcript-repair.js +68 -0
  48. package/dist/agents/shell-utils.js +51 -0
  49. package/dist/agents/skills/bundled-context.js +23 -0
  50. package/dist/agents/skills/bundled-dir.js +41 -7
  51. package/dist/agents/skills/frontmatter.js +1 -1
  52. package/dist/agents/skills/workspace.js +2 -2
  53. package/dist/agents/skills-install.js +60 -23
  54. package/dist/agents/subagent-announce.js +79 -34
  55. package/dist/agents/system-prompt.js +28 -4
  56. package/dist/agents/together-models.js +127 -0
  57. package/dist/agents/tool-images.js +1 -1
  58. package/dist/agents/tool-policy.conformance.js +14 -0
  59. package/dist/agents/tool-policy.js +25 -1
  60. package/dist/agents/tools/browser-tool.js +3 -3
  61. package/dist/agents/tools/cron-tool.js +166 -19
  62. package/dist/agents/tools/discord-actions-presence.js +78 -0
  63. package/dist/agents/tools/image-tool.js +2 -2
  64. package/dist/agents/tools/memory-tool.js +93 -5
  65. package/dist/agents/tools/message-tool.js +56 -2
  66. package/dist/agents/tools/sessions-history-tool.js +69 -1
  67. package/dist/agents/tools/web-search.js +211 -42
  68. package/dist/agents/usage.js +23 -1
  69. package/dist/agents/workspace-run.js +67 -0
  70. package/dist/agents/workspace-templates.js +44 -0
  71. package/dist/auto-reply/command-auth.js +121 -6
  72. package/dist/auto-reply/commands-registry.data.js +1 -1
  73. package/dist/auto-reply/envelope.js +50 -72
  74. package/dist/auto-reply/reply/commands-compact.js +1 -0
  75. package/dist/auto-reply/reply/commands-context-report.js +3 -2
  76. package/dist/auto-reply/reply/commands-context.js +1 -0
  77. package/dist/auto-reply/reply/commands-models.js +107 -60
  78. package/dist/auto-reply/reply/commands-ptt.js +171 -0
  79. package/dist/auto-reply/reply/commands-session.js +2 -2
  80. package/dist/auto-reply/reply/get-reply-run.js +16 -5
  81. package/dist/auto-reply/reply/groups.js +1 -1
  82. package/dist/auto-reply/reply/inbound-context.js +9 -1
  83. package/dist/auto-reply/reply/inbound-meta.js +130 -0
  84. package/dist/auto-reply/reply/model-selection.js +3 -3
  85. package/dist/auto-reply/reply/untrusted-context.js +15 -0
  86. package/dist/auto-reply/status.js +1 -1
  87. package/dist/auto-reply/thinking.js +88 -43
  88. package/dist/browser/bridge-server.js +13 -0
  89. package/dist/browser/cdp.helpers.js +38 -24
  90. package/dist/browser/client-fetch.js +51 -8
  91. package/dist/browser/config.js +2 -11
  92. package/dist/browser/extension-relay.js +104 -43
  93. package/dist/browser/pw-ai.js +1 -1
  94. package/dist/browser/pw-session.js +143 -8
  95. package/dist/browser/pw-tools-core.interactions.js +125 -27
  96. package/dist/browser/pw-tools-core.responses.js +1 -1
  97. package/dist/browser/pw-tools-core.state.js +1 -1
  98. package/dist/browser/routes/agent.act.js +86 -41
  99. package/dist/browser/routes/dispatcher.js +4 -4
  100. package/dist/browser/screenshot.js +1 -1
  101. package/dist/browser/server-context.js +2 -2
  102. package/dist/browser/server.js +13 -0
  103. package/dist/build-info.json +3 -3
  104. package/dist/canvas-host/a2ui.js +3 -3
  105. package/dist/channels/plugins/catalog.js +2 -2
  106. package/dist/channels/plugins/onboarding/imessage.js +1 -1
  107. package/dist/channels/plugins/onboarding/signal.js +1 -1
  108. package/dist/channels/plugins/onboarding/slack.js +4 -4
  109. package/dist/channels/plugins/onboarding/whatsapp.js +3 -3
  110. package/dist/channels/plugins/pairing-message.js +1 -1
  111. package/dist/channels/reply-prefix.js +8 -1
  112. package/dist/cli/browser-cli-extension.js +2 -2
  113. package/dist/cli/cron-cli/register.cron-add.js +61 -40
  114. package/dist/cli/cron-cli/register.cron-edit.js +60 -34
  115. package/dist/cli/cron-cli/shared.js +56 -41
  116. package/dist/cli/dns-cli.js +26 -14
  117. package/dist/cli/docs-cli.js +1 -1
  118. package/dist/cli/gateway-cli/dev.js +1 -1
  119. package/dist/cli/gateway-cli/register.js +37 -19
  120. package/dist/cli/memory-cli.js +30 -20
  121. package/dist/cli/nodes-cli/register.canvas.js +1 -1
  122. package/dist/cli/parse-bytes.js +37 -0
  123. package/dist/cli/plugins-cli.js +1 -1
  124. package/dist/cli/run-main.js +2 -2
  125. package/dist/cli/security-cli.js +1 -1
  126. package/dist/cli/tagline.js +1 -1
  127. package/dist/cli/update-cli.js +173 -52
  128. package/dist/cli/webhooks-cli.js +5 -5
  129. package/dist/commands/agent.js +1 -0
  130. package/dist/commands/agents.commands.add.js +1 -1
  131. package/dist/commands/auth-choice.apply.api-providers.js +305 -17
  132. package/dist/commands/auth-choice.apply.js +4 -1
  133. package/dist/commands/auth-choice.apply.plugin-provider.js +2 -2
  134. package/dist/commands/auth-choice.apply.xai.js +63 -0
  135. package/dist/commands/auth-choice.preferred-provider.js +7 -1
  136. package/dist/commands/configure.wizard.js +1 -1
  137. package/dist/commands/dashboard.js +1 -1
  138. package/dist/commands/docs.js +1 -1
  139. package/dist/commands/doctor-config-flow.js +61 -5
  140. package/dist/commands/doctor-gateway-services.js +3 -3
  141. package/dist/commands/doctor-state-migrations.js +1 -1
  142. package/dist/commands/doctor-update.js +3 -3
  143. package/dist/commands/doctor.js +1 -1
  144. package/dist/commands/health.js +1 -1
  145. package/dist/commands/model-allowlist.js +29 -0
  146. package/dist/commands/model-picker.js +2 -1
  147. package/dist/commands/models/list.probe.js +2 -2
  148. package/dist/commands/models/list.registry.js +4 -4
  149. package/dist/commands/models/list.status-command.js +44 -24
  150. package/dist/commands/models/shared.js +15 -0
  151. package/dist/commands/onboard-auth.config-core.js +366 -28
  152. package/dist/commands/onboard-auth.credentials.js +71 -9
  153. package/dist/commands/onboard-auth.js +3 -3
  154. package/dist/commands/onboard-auth.models.js +26 -24
  155. package/dist/commands/onboard-custom.js +384 -0
  156. package/dist/commands/onboard-non-interactive/local/auth-choice-inference.js +35 -0
  157. package/dist/commands/onboard-non-interactive/local/auth-choice.js +146 -9
  158. package/dist/commands/onboard-skills.js +63 -38
  159. package/dist/commands/openai-model-default.js +41 -0
  160. package/dist/commands/status-all/report-lines.js +1 -1
  161. package/dist/commands/status.command.js +1 -1
  162. package/dist/commands/uninstall.js +3 -3
  163. package/dist/compat/legacy-names.js +1 -1
  164. package/dist/config/defaults.js +3 -2
  165. package/dist/config/io.js +3 -3
  166. package/dist/config/paths.js +136 -35
  167. package/dist/config/plugin-auto-enable.js +21 -5
  168. package/dist/config/redact-snapshot.js +153 -0
  169. package/dist/config/schema.field-metadata.js +590 -0
  170. package/dist/config/schema.js +3 -3
  171. package/dist/config/sessions/store.js +291 -23
  172. package/dist/config/types.memory.js +1 -0
  173. package/dist/config/version.js +4 -4
  174. package/dist/config/zod-schema.agent-defaults.js +3 -0
  175. package/dist/config/zod-schema.agent-runtime.js +13 -2
  176. package/dist/config/zod-schema.providers-core.js +142 -0
  177. package/dist/config/zod-schema.session.js +3 -0
  178. package/dist/cron/delivery.js +57 -0
  179. package/dist/cron/isolated-agent/delivery-target.js +18 -3
  180. package/dist/cron/isolated-agent/helpers.js +22 -5
  181. package/dist/cron/isolated-agent/run.js +171 -63
  182. package/dist/cron/isolated-agent/session.js +2 -0
  183. package/dist/cron/normalize.js +356 -28
  184. package/dist/cron/parse.js +10 -5
  185. package/dist/cron/run-log.js +35 -10
  186. package/dist/cron/schedule.js +41 -6
  187. package/dist/cron/service/jobs.js +208 -35
  188. package/dist/cron/service/ops.js +72 -16
  189. package/dist/cron/service/state.js +2 -0
  190. package/dist/cron/service/store.js +386 -14
  191. package/dist/cron/service/timer.js +390 -147
  192. package/dist/cron/session-reaper.js +86 -0
  193. package/dist/cron/store.js +23 -8
  194. package/dist/cron/validate-timestamp.js +43 -0
  195. package/dist/daemon/constants.js +7 -7
  196. package/dist/daemon/inspect.js +6 -6
  197. package/dist/daemon/systemd-unit.js +1 -1
  198. package/dist/discord/monitor/agent-components.js +438 -0
  199. package/dist/discord/monitor/allow-list.js +28 -5
  200. package/dist/discord/monitor/gateway-registry.js +29 -0
  201. package/dist/discord/monitor/native-command.js +44 -23
  202. package/dist/discord/monitor/sender-identity.js +45 -0
  203. package/dist/discord/pluralkit.js +27 -0
  204. package/dist/discord/send.outbound.js +92 -5
  205. package/dist/discord/send.shared.js +60 -23
  206. package/dist/discord/targets.js +84 -1
  207. package/dist/entry.js +15 -9
  208. package/dist/extensionAPI.js +8 -0
  209. package/dist/gateway/control-ui.js +8 -1
  210. package/dist/gateway/hooks-mapping.js +3 -0
  211. package/dist/gateway/hooks.js +65 -0
  212. package/dist/gateway/live-image-probe.js +1 -66
  213. package/dist/gateway/net.js +96 -31
  214. package/dist/gateway/node-command-policy.js +50 -15
  215. package/dist/gateway/openai-http.js +2 -2
  216. package/dist/gateway/openresponses-http.js +4 -4
  217. package/dist/gateway/origin-check.js +56 -0
  218. package/dist/gateway/protocol/client-info.js +9 -0
  219. package/dist/gateway/protocol/index.js +9 -2
  220. package/dist/gateway/protocol/schema/agents-models-skills.js +71 -1
  221. package/dist/gateway/protocol/schema/cron.js +22 -10
  222. package/dist/gateway/protocol/schema/protocol-schemas.js +16 -2
  223. package/dist/gateway/protocol/schema/sessions.js +12 -0
  224. package/dist/gateway/server/hooks.js +1 -1
  225. package/dist/gateway/server-broadcast.js +26 -9
  226. package/dist/gateway/server-chat.js +112 -23
  227. package/dist/gateway/server-discovery-runtime.js +10 -2
  228. package/dist/gateway/server-discovery.js +2 -2
  229. package/dist/gateway/server-http.js +110 -12
  230. package/dist/gateway/server-methods/agent-timestamp.js +60 -0
  231. package/dist/gateway/server-methods/agents.js +321 -2
  232. package/dist/gateway/server-methods/usage.js +559 -16
  233. package/dist/gateway/server-runtime-state.js +22 -8
  234. package/dist/gateway/server-startup-memory.js +16 -0
  235. package/dist/gateway/server.impl.js +7 -3
  236. package/dist/gateway/session-utils.fs.js +23 -25
  237. package/dist/gateway/session-utils.js +20 -10
  238. package/dist/gateway/sessions-patch.js +7 -22
  239. package/dist/gateway/test-helpers.server.js +35 -2
  240. package/dist/hooks/frontmatter.js +1 -1
  241. package/dist/hooks/hooks-status.js +1 -1
  242. package/dist/hooks/install.js +2 -2
  243. package/dist/hooks/loader.js +1 -1
  244. package/dist/hooks/workspace.js +3 -3
  245. package/dist/imessage/constants.js +2 -0
  246. package/dist/imessage/monitor/deliver.js +4 -1
  247. package/dist/imessage/monitor/monitor-provider.js +51 -1
  248. package/dist/index.js +2 -2
  249. package/dist/infra/bonjour-discovery.js +131 -70
  250. package/dist/infra/bonjour.js +3 -3
  251. package/dist/infra/control-ui-assets.js +134 -12
  252. package/dist/infra/errors.js +12 -0
  253. package/dist/infra/exec-approvals.js +266 -57
  254. package/dist/infra/format-time/format-datetime.js +79 -0
  255. package/dist/infra/format-time/format-duration.js +81 -0
  256. package/dist/infra/format-time/format-relative.js +80 -0
  257. package/dist/infra/heartbeat-runner.js +140 -49
  258. package/dist/infra/home-dir.js +54 -0
  259. package/dist/infra/net/fetch-guard.js +122 -0
  260. package/dist/infra/net/ssrf.js +65 -29
  261. package/dist/infra/outbound/abort.js +14 -0
  262. package/dist/infra/outbound/message-action-runner.js +77 -13
  263. package/dist/infra/outbound/outbound-session.js +143 -37
  264. package/dist/infra/path-env.js +3 -3
  265. package/dist/infra/poolbot-root.js +43 -1
  266. package/dist/infra/provider-usage.fetch.minimax.js +1 -1
  267. package/dist/infra/restart.js +1 -1
  268. package/dist/infra/session-cost-usage.js +631 -41
  269. package/dist/infra/state-migrations.js +317 -47
  270. package/dist/infra/tailscale.js +1 -1
  271. package/dist/infra/update-global.js +35 -0
  272. package/dist/infra/update-runner.js +149 -43
  273. package/dist/infra/warning-filter.js +65 -0
  274. package/dist/infra/widearea-dns.js +30 -9
  275. package/dist/logging/redact-identifier.js +12 -0
  276. package/dist/macos/relay.js +2 -2
  277. package/dist/media/fetch.js +81 -58
  278. package/dist/media/input-files.js +1 -1
  279. package/dist/media/mime.js +4 -0
  280. package/dist/media/png-encode.js +74 -0
  281. package/dist/media-understanding/apply.js +403 -3
  282. package/dist/media-understanding/attachments.js +38 -27
  283. package/dist/media-understanding/defaults.js +16 -0
  284. package/dist/media-understanding/providers/deepgram/audio.js +22 -14
  285. package/dist/media-understanding/providers/google/audio.js +24 -17
  286. package/dist/media-understanding/providers/google/video.js +24 -17
  287. package/dist/media-understanding/providers/image.js +4 -4
  288. package/dist/media-understanding/providers/index.js +4 -1
  289. package/dist/media-understanding/providers/openai/audio.js +22 -14
  290. package/dist/media-understanding/providers/shared.js +16 -11
  291. package/dist/media-understanding/providers/zai/index.js +6 -0
  292. package/dist/media-understanding/runner.js +158 -90
  293. package/dist/memory/backend-config.js +207 -0
  294. package/dist/memory/batch-voyage.js +277 -0
  295. package/dist/memory/embeddings-voyage.js +75 -0
  296. package/dist/memory/embeddings.js +29 -17
  297. package/dist/memory/internal.js +101 -18
  298. package/dist/memory/manager.js +155 -48
  299. package/dist/memory/search-manager.js +173 -0
  300. package/dist/memory/session-files.js +9 -3
  301. package/dist/memory/types.js +1 -0
  302. package/dist/node-host/runner.js +36 -26
  303. package/dist/node-host/with-timeout.js +27 -0
  304. package/dist/pairing/pairing-messages.js +1 -1
  305. package/dist/plugins/commands.js +5 -1
  306. package/dist/plugins/config-state.js +86 -7
  307. package/dist/plugins/discovery.js +1 -1
  308. package/dist/plugins/install.js +2 -2
  309. package/dist/plugins/source-display.js +51 -0
  310. package/dist/plugins/update.js +1 -1
  311. package/dist/process/exec.js +20 -2
  312. package/dist/routing/resolve-route.js +12 -0
  313. package/dist/routing/session-key.js +15 -0
  314. package/dist/runtime.js +2 -0
  315. package/dist/security/audit-extra.async.js +601 -0
  316. package/dist/security/audit-extra.js +2 -830
  317. package/dist/security/audit-extra.sync.js +505 -0
  318. package/dist/security/audit.js +2 -2
  319. package/dist/security/channel-metadata.js +34 -0
  320. package/dist/security/external-content.js +88 -6
  321. package/dist/security/skill-scanner.js +330 -0
  322. package/dist/sessions/session-key-utils.js +7 -0
  323. package/dist/shared/text/reasoning-tags.js +52 -7
  324. package/dist/signal/monitor/event-handler.js +80 -1
  325. package/dist/slack/monitor/media.js +85 -15
  326. package/dist/tailscale/detect.js +145 -0
  327. package/dist/telegram/bot/helpers.js +109 -28
  328. package/dist/telegram/bot-handlers.js +144 -3
  329. package/dist/telegram/bot-message-context.js +38 -11
  330. package/dist/telegram/bot-message-dispatch.js +48 -15
  331. package/dist/telegram/bot-native-commands.js +86 -29
  332. package/dist/telegram/bot.js +30 -29
  333. package/dist/telegram/model-buttons.js +163 -0
  334. package/dist/telegram/monitor.js +110 -85
  335. package/dist/telegram/send.js +129 -47
  336. package/dist/terminal/restore.js +45 -0
  337. package/dist/test-helpers/state-dir-env.js +16 -0
  338. package/dist/test-helpers/workspace.js +11 -0
  339. package/dist/test-utils/channel-plugins.js +82 -0
  340. package/dist/test-utils/ports.js +73 -0
  341. package/dist/tts/tts.js +12 -6
  342. package/dist/tui/tui-session-actions.js +166 -54
  343. package/dist/utils/fetch-timeout.js +20 -0
  344. package/dist/utils/normalize-secret-input.js +19 -0
  345. package/dist/utils/shell-argv.js +61 -0
  346. package/dist/utils/transcript-tools.js +58 -0
  347. package/dist/utils.js +55 -14
  348. package/dist/version.js +42 -5
  349. package/dist/web/qr-image.js +1 -61
  350. package/dist/wizard/onboarding.finalize.js +7 -7
  351. package/dist/wizard/onboarding.js +3 -3
  352. package/docs/RELEASE_WORKFOTS_COMPARISON.md +3 -3
  353. package/docs/_config.yml +2 -2
  354. package/docs/_layouts/default.html +9 -9
  355. package/docs/concepts/typebox.md +1 -1
  356. package/docs/docs.json +1 -1
  357. package/docs/northflank.mdx +7 -7
  358. package/docs/railway.mdx +3 -3
  359. package/docs/render.mdx +5 -5
  360. package/docs/start/lore.md +2 -2
  361. package/extensions/bluebubbles/index.ts +2 -2
  362. package/extensions/bluebubbles/package.json +1 -1
  363. package/extensions/bluebubbles/src/accounts.ts +8 -8
  364. package/extensions/bluebubbles/src/actions.test.ts +22 -22
  365. package/extensions/bluebubbles/src/actions.ts +5 -5
  366. package/extensions/bluebubbles/src/attachments.ts +2 -2
  367. package/extensions/bluebubbles/src/channel.ts +16 -16
  368. package/extensions/bluebubbles/src/chat.ts +2 -2
  369. package/extensions/bluebubbles/src/media-send.ts +2 -2
  370. package/extensions/bluebubbles/src/monitor.test.ts +46 -46
  371. package/extensions/bluebubbles/src/monitor.ts +5 -5
  372. package/extensions/bluebubbles/src/onboarding.ts +7 -7
  373. package/extensions/bluebubbles/src/reactions.ts +2 -2
  374. package/extensions/bluebubbles/src/send.ts +2 -2
  375. package/extensions/copilot-proxy/README.md +1 -1
  376. package/extensions/copilot-proxy/package.json +1 -1
  377. package/extensions/diagnostics-otel/index.ts +2 -2
  378. package/extensions/diagnostics-otel/package.json +1 -1
  379. package/extensions/diagnostics-otel/src/service.ts +3 -3
  380. package/extensions/discord/index.ts +2 -2
  381. package/extensions/discord/package.json +1 -1
  382. package/extensions/google-antigravity-auth/README.md +1 -1
  383. package/extensions/google-antigravity-auth/index.ts +1 -1
  384. package/extensions/google-antigravity-auth/package.json +1 -1
  385. package/extensions/google-gemini-cli-auth/README.md +1 -1
  386. package/extensions/google-gemini-cli-auth/oauth.ts +1 -1
  387. package/extensions/google-gemini-cli-auth/package.json +1 -1
  388. package/extensions/googlechat/index.ts +3 -3
  389. package/extensions/googlechat/package.json +1 -1
  390. package/extensions/googlechat/src/accounts.ts +8 -8
  391. package/extensions/googlechat/src/actions.ts +6 -6
  392. package/extensions/googlechat/src/channel.ts +21 -21
  393. package/extensions/googlechat/src/monitor.ts +8 -8
  394. package/extensions/googlechat/src/onboarding.ts +10 -10
  395. package/extensions/imessage/index.ts +2 -2
  396. package/extensions/imessage/package.json +1 -1
  397. package/extensions/line/index.ts +2 -2
  398. package/extensions/line/package.json +1 -1
  399. package/extensions/line/src/card-command.ts +2 -2
  400. package/extensions/line/src/channel.logout.test.ts +4 -4
  401. package/extensions/line/src/channel.sendPayload.test.ts +8 -8
  402. package/extensions/line/src/channel.ts +3 -3
  403. package/extensions/llm-task/README.md +3 -3
  404. package/extensions/llm-task/index.ts +2 -2
  405. package/extensions/llm-task/package.json +1 -1
  406. package/extensions/llm-task/src/llm-task-tool.ts +4 -4
  407. package/extensions/lobster/README.md +6 -6
  408. package/extensions/lobster/index.ts +2 -2
  409. package/extensions/lobster/src/lobster-tool.test.ts +4 -4
  410. package/extensions/lobster/src/lobster-tool.ts +2 -2
  411. package/extensions/matrix/index.ts +2 -2
  412. package/extensions/matrix/package.json +1 -1
  413. package/extensions/matrix/src/matrix/client/config.ts +1 -1
  414. package/extensions/matrix/src/matrix/monitor/handler.ts +1 -1
  415. package/extensions/matrix/src/onboarding.ts +1 -1
  416. package/extensions/mattermost/index.ts +2 -2
  417. package/extensions/mattermost/package.json +1 -1
  418. package/extensions/mattermost/src/mattermost/accounts.ts +8 -8
  419. package/extensions/mattermost/src/mattermost/monitor-helpers.ts +5 -5
  420. package/extensions/mattermost/src/mattermost/monitor.ts +2 -2
  421. package/extensions/mattermost/src/onboarding-helpers.ts +3 -3
  422. package/extensions/mattermost/src/onboarding.ts +2 -2
  423. package/extensions/memory-core/index.ts +2 -2
  424. package/extensions/memory-core/package.json +1 -1
  425. package/extensions/memory-lancedb/index.ts +3 -3
  426. package/extensions/memory-lancedb/package.json +1 -1
  427. package/extensions/msteams/index.ts +2 -2
  428. package/extensions/msteams/package.json +1 -1
  429. package/extensions/msteams/src/channel.directory.test.ts +2 -2
  430. package/extensions/msteams/src/channel.ts +2 -2
  431. package/extensions/msteams/src/graph-upload.ts +4 -4
  432. package/extensions/msteams/src/monitor-handler.ts +2 -2
  433. package/extensions/msteams/src/monitor.ts +2 -2
  434. package/extensions/msteams/src/onboarding.ts +9 -9
  435. package/extensions/msteams/src/reply-dispatcher.ts +2 -2
  436. package/extensions/msteams/src/send-context.ts +2 -2
  437. package/extensions/msteams/src/send.ts +4 -4
  438. package/extensions/nextcloud-talk/index.ts +2 -2
  439. package/extensions/nextcloud-talk/package.json +1 -1
  440. package/extensions/nextcloud-talk/src/channel.ts +7 -7
  441. package/extensions/nextcloud-talk/src/inbound.ts +7 -7
  442. package/extensions/nextcloud-talk/src/onboarding.ts +1 -1
  443. package/extensions/nostr/README.md +2 -2
  444. package/extensions/nostr/index.ts +5 -5
  445. package/extensions/nostr/package.json +1 -1
  446. package/extensions/nostr/src/types.ts +4 -4
  447. package/extensions/open-prose/index.ts +2 -2
  448. package/extensions/qwen-portal-auth/README.md +1 -1
  449. package/extensions/signal/index.ts +2 -2
  450. package/extensions/signal/package.json +1 -1
  451. package/extensions/slack/index.ts +2 -2
  452. package/extensions/slack/package.json +1 -1
  453. package/extensions/telegram/index.ts +2 -2
  454. package/extensions/telegram/package.json +1 -1
  455. package/extensions/telegram/src/channel.ts +2 -2
  456. package/extensions/tlon/README.md +2 -2
  457. package/extensions/tlon/index.ts +2 -2
  458. package/extensions/tlon/package.json +1 -1
  459. package/extensions/tlon/src/channel.ts +13 -13
  460. package/extensions/tlon/src/monitor/index.ts +3 -3
  461. package/extensions/tlon/src/onboarding.ts +3 -3
  462. package/extensions/tlon/src/types.ts +3 -3
  463. package/extensions/twitch/README.md +1 -1
  464. package/extensions/twitch/index.ts +2 -2
  465. package/extensions/twitch/package.json +1 -1
  466. package/extensions/twitch/src/config.ts +3 -3
  467. package/extensions/twitch/src/monitor.ts +3 -3
  468. package/extensions/twitch/src/onboarding.ts +9 -9
  469. package/extensions/twitch/src/outbound.test.ts +2 -2
  470. package/extensions/twitch/src/plugin.test.ts +2 -2
  471. package/extensions/twitch/src/plugin.ts +8 -8
  472. package/extensions/twitch/src/send.test.ts +2 -2
  473. package/extensions/twitch/src/send.ts +4 -4
  474. package/extensions/twitch/src/token.test.ts +8 -8
  475. package/extensions/twitch/src/token.ts +3 -3
  476. package/extensions/twitch/src/twitch-client.ts +3 -3
  477. package/extensions/twitch/src/types.ts +3 -3
  478. package/extensions/twitch/src/utils/markdown.ts +1 -1
  479. package/extensions/voice-call/README.md +3 -3
  480. package/extensions/voice-call/package.json +1 -1
  481. package/extensions/voice-call/src/core-bridge.ts +2 -2
  482. package/extensions/voice-call/src/response-generator.ts +1 -1
  483. package/extensions/whatsapp/index.ts +2 -2
  484. package/extensions/whatsapp/package.json +1 -1
  485. package/extensions/zalo/README.md +1 -1
  486. package/extensions/zalo/index.ts +2 -2
  487. package/extensions/zalo/package.json +1 -1
  488. package/extensions/zalo/src/accounts.ts +8 -8
  489. package/extensions/zalo/src/actions.ts +4 -4
  490. package/extensions/zalo/src/channel.directory.test.ts +2 -2
  491. package/extensions/zalo/src/channel.ts +18 -18
  492. package/extensions/zalo/src/monitor.ts +9 -9
  493. package/extensions/zalo/src/monitor.webhook.test.ts +2 -2
  494. package/extensions/zalo/src/onboarding.ts +24 -24
  495. package/extensions/zalo/src/send.ts +2 -2
  496. package/extensions/zalouser/README.md +2 -2
  497. package/extensions/zalouser/index.ts +2 -2
  498. package/extensions/zalouser/package.json +1 -1
  499. package/extensions/zalouser/src/accounts.ts +9 -9
  500. package/extensions/zalouser/src/channel.ts +24 -24
  501. package/extensions/zalouser/src/monitor.ts +4 -4
  502. package/extensions/zalouser/src/onboarding.ts +28 -28
  503. package/package.json +13 -251
  504. package/skills/nano-banana-pro/scripts/generate_image.py +1 -1
  505. package/skills/tmux/scripts/find-sessions.sh +1 -1
  506. package/CHANGELOG.md +0 -102
  507. package/README-header.png +0 -0
  508. package/git-hooks/pre-commit +0 -4
  509. package/scripts/format-staged.js +0 -148
  510. package/scripts/postinstall.js +0 -300
  511. package/scripts/setup-git-hooks.js +0 -96
@@ -1,5 +1,7 @@
1
+ import fs from "node:fs";
1
2
  import os from "node:os";
2
3
  import path from "node:path";
4
+ import { expandHomePrefix, resolveRequiredHomeDir } from "../infra/home-dir.js";
3
5
  /**
4
6
  * Nix mode detection: When CLAWDBOT_NIX_MODE=1, the gateway is running under Nix.
5
7
  * In this mode:
@@ -11,32 +13,73 @@ export function resolveIsNixMode(env = process.env) {
11
13
  return env.CLAWDBOT_NIX_MODE === "1";
12
14
  }
13
15
  export const isNixMode = resolveIsNixMode();
14
- const LEGACY_STATE_DIRNAME = ".poolbot";
16
+ const LEGACY_STATE_DIRNAMES = [".clawdbot", ".moltbot", ".moldbot"];
15
17
  const NEW_STATE_DIRNAME = ".poolbot";
16
18
  const CONFIG_FILENAME = "poolbot.json";
17
- function legacyStateDir(homedir = os.homedir) {
18
- return path.join(homedir(), LEGACY_STATE_DIRNAME);
19
+ const LEGACY_CONFIG_FILENAMES = ["clawdbot.json", "moltbot.json", "moldbot.json"];
20
+ function resolveDefaultHomeDir() {
21
+ return resolveRequiredHomeDir(process.env, os.homedir);
19
22
  }
20
- function newStateDir(homedir = os.homedir) {
23
+ /** Build a homedir thunk that respects MOLTBOT_HOME for the given env. */
24
+ function envHomedir(env) {
25
+ return () => resolveRequiredHomeDir(env, os.homedir);
26
+ }
27
+ function legacyStateDirs(homedir = resolveDefaultHomeDir) {
28
+ return LEGACY_STATE_DIRNAMES.map((dir) => path.join(homedir(), dir));
29
+ }
30
+ function newStateDir(homedir = resolveDefaultHomeDir) {
21
31
  return path.join(homedir(), NEW_STATE_DIRNAME);
22
32
  }
33
+ export function resolveLegacyStateDir(homedir = resolveDefaultHomeDir) {
34
+ return legacyStateDirs(homedir)[0] ?? newStateDir(homedir);
35
+ }
36
+ export function resolveLegacyStateDirs(homedir = resolveDefaultHomeDir) {
37
+ return legacyStateDirs(homedir);
38
+ }
39
+ export function resolveNewStateDir(homedir = resolveDefaultHomeDir) {
40
+ return newStateDir(homedir);
41
+ }
23
42
  /**
24
43
  * State directory for mutable data (sessions, logs, caches).
25
44
  * Can be overridden via MOLTBOT_STATE_DIR (preferred) or CLAWDBOT_STATE_DIR (legacy).
26
- * Default: ~/.poolbot (legacy default for compatibility)
45
+ * Default: ~/.poolbot
27
46
  */
28
- export function resolveStateDir(env = process.env, homedir = os.homedir) {
47
+ export function resolveStateDir(env = process.env, homedir = envHomedir(env)) {
48
+ const effectiveHomedir = () => resolveRequiredHomeDir(env, homedir);
29
49
  const override = env.MOLTBOT_STATE_DIR?.trim() || env.CLAWDBOT_STATE_DIR?.trim();
30
- if (override)
31
- return resolveUserPath(override);
32
- return legacyStateDir(homedir);
50
+ if (override) {
51
+ return resolveUserPath(override, env, effectiveHomedir);
52
+ }
53
+ const newDir = newStateDir(effectiveHomedir);
54
+ const legacyDirs = legacyStateDirs(effectiveHomedir);
55
+ const hasNew = fs.existsSync(newDir);
56
+ if (hasNew) {
57
+ return newDir;
58
+ }
59
+ const existingLegacy = legacyDirs.find((dir) => {
60
+ try {
61
+ return fs.existsSync(dir);
62
+ }
63
+ catch {
64
+ return false;
65
+ }
66
+ });
67
+ if (existingLegacy) {
68
+ return existingLegacy;
69
+ }
70
+ return newDir;
33
71
  }
34
- function resolveUserPath(input) {
72
+ function resolveUserPath(input, env = process.env, homedir = envHomedir(env)) {
35
73
  const trimmed = input.trim();
36
- if (!trimmed)
74
+ if (!trimmed) {
37
75
  return trimmed;
76
+ }
38
77
  if (trimmed.startsWith("~")) {
39
- const expanded = trimmed.replace(/^~(?=$|[\\/])/, os.homedir());
78
+ const expanded = expandHomePrefix(trimmed, {
79
+ home: resolveRequiredHomeDir(env, homedir),
80
+ env,
81
+ homedir,
82
+ });
40
83
  return path.resolve(expanded);
41
84
  }
42
85
  return path.resolve(trimmed);
@@ -47,32 +90,88 @@ export const STATE_DIR = resolveStateDir();
47
90
  * Can be overridden via MOLTBOT_CONFIG_PATH (preferred) or CLAWDBOT_CONFIG_PATH (legacy).
48
91
  * Default: ~/.poolbot/poolbot.json (or $*_STATE_DIR/poolbot.json)
49
92
  */
50
- export function resolveConfigPath(env = process.env, stateDir = resolveStateDir(env, os.homedir)) {
93
+ export function resolveCanonicalConfigPath(env = process.env, stateDir = resolveStateDir(env, envHomedir(env))) {
51
94
  const override = env.MOLTBOT_CONFIG_PATH?.trim() || env.CLAWDBOT_CONFIG_PATH?.trim();
52
- if (override)
53
- return resolveUserPath(override);
95
+ if (override) {
96
+ return resolveUserPath(override, env, envHomedir(env));
97
+ }
54
98
  return path.join(stateDir, CONFIG_FILENAME);
55
99
  }
56
- export const CONFIG_PATH = resolveConfigPath();
57
100
  /**
58
- * Resolve default config path candidates across new + legacy locations.
59
- * Order: explicit config path state-dir-derived paths → new default → legacy default.
101
+ * Resolve the active config path by preferring existing config candidates
102
+ * before falling back to the canonical path.
60
103
  */
61
- export function resolveDefaultConfigCandidates(env = process.env, homedir = os.homedir) {
104
+ export function resolveConfigPathCandidate(env = process.env, homedir = envHomedir(env)) {
105
+ const candidates = resolveDefaultConfigCandidates(env, homedir);
106
+ const existing = candidates.find((candidate) => {
107
+ try {
108
+ return fs.existsSync(candidate);
109
+ }
110
+ catch {
111
+ return false;
112
+ }
113
+ });
114
+ if (existing) {
115
+ return existing;
116
+ }
117
+ return resolveCanonicalConfigPath(env, resolveStateDir(env, homedir));
118
+ }
119
+ /**
120
+ * Active config path (prefers existing config files).
121
+ */
122
+ export function resolveConfigPath(env = process.env, stateDir = resolveStateDir(env, envHomedir(env)), homedir = envHomedir(env)) {
123
+ const override = env.MOLTBOT_CONFIG_PATH?.trim() || env.CLAWDBOT_CONFIG_PATH?.trim();
124
+ if (override) {
125
+ return resolveUserPath(override, env, homedir);
126
+ }
127
+ const stateOverride = env.MOLTBOT_STATE_DIR?.trim() || env.CLAWDBOT_STATE_DIR?.trim();
128
+ const candidates = [
129
+ path.join(stateDir, CONFIG_FILENAME),
130
+ ...LEGACY_CONFIG_FILENAMES.map((name) => path.join(stateDir, name)),
131
+ ];
132
+ const existing = candidates.find((candidate) => {
133
+ try {
134
+ return fs.existsSync(candidate);
135
+ }
136
+ catch {
137
+ return false;
138
+ }
139
+ });
140
+ if (existing) {
141
+ return existing;
142
+ }
143
+ if (stateOverride) {
144
+ return path.join(stateDir, CONFIG_FILENAME);
145
+ }
146
+ const defaultStateDir = resolveStateDir(env, homedir);
147
+ if (path.resolve(stateDir) === path.resolve(defaultStateDir)) {
148
+ return resolveConfigPathCandidate(env, homedir);
149
+ }
150
+ return path.join(stateDir, CONFIG_FILENAME);
151
+ }
152
+ export const CONFIG_PATH = resolveConfigPathCandidate();
153
+ /**
154
+ * Resolve default config path candidates across default locations.
155
+ * Order: explicit config path → state-dir-derived paths → new default.
156
+ */
157
+ export function resolveDefaultConfigCandidates(env = process.env, homedir = envHomedir(env)) {
158
+ const effectiveHomedir = () => resolveRequiredHomeDir(env, homedir);
62
159
  const explicit = env.MOLTBOT_CONFIG_PATH?.trim() || env.CLAWDBOT_CONFIG_PATH?.trim();
63
- if (explicit)
64
- return [resolveUserPath(explicit)];
160
+ if (explicit) {
161
+ return [resolveUserPath(explicit, env, effectiveHomedir)];
162
+ }
65
163
  const candidates = [];
66
- const poolbotStateDir = env.MOLTBOT_STATE_DIR?.trim();
164
+ const poolbotStateDir = env.MOLTBOT_STATE_DIR?.trim() || env.CLAWDBOT_STATE_DIR?.trim();
67
165
  if (poolbotStateDir) {
68
- candidates.push(path.join(resolveUserPath(poolbotStateDir), CONFIG_FILENAME));
166
+ const resolved = resolveUserPath(poolbotStateDir, env, effectiveHomedir);
167
+ candidates.push(path.join(resolved, CONFIG_FILENAME));
168
+ candidates.push(...LEGACY_CONFIG_FILENAMES.map((name) => path.join(resolved, name)));
69
169
  }
70
- const legacyStateDirOverride = env.CLAWDBOT_STATE_DIR?.trim();
71
- if (legacyStateDirOverride) {
72
- candidates.push(path.join(resolveUserPath(legacyStateDirOverride), CONFIG_FILENAME));
170
+ const defaultDirs = [newStateDir(effectiveHomedir), ...legacyStateDirs(effectiveHomedir)];
171
+ for (const dir of defaultDirs) {
172
+ candidates.push(path.join(dir, CONFIG_FILENAME));
173
+ candidates.push(...LEGACY_CONFIG_FILENAMES.map((name) => path.join(dir, name)));
73
174
  }
74
- candidates.push(path.join(newStateDir(homedir), CONFIG_FILENAME));
75
- candidates.push(path.join(legacyStateDir(homedir), CONFIG_FILENAME));
76
175
  return candidates;
77
176
  }
78
177
  export const DEFAULT_GATEWAY_PORT = 18789;
@@ -93,28 +192,30 @@ const OAUTH_FILENAME = "oauth.json";
93
192
  * Precedence:
94
193
  * - `CLAWDBOT_OAUTH_DIR` (explicit override)
95
194
  * - `$*_STATE_DIR/credentials` (canonical server/default)
96
- * - `~/.poolbot/credentials` (legacy default)
97
195
  */
98
- export function resolveOAuthDir(env = process.env, stateDir = resolveStateDir(env, os.homedir)) {
196
+ export function resolveOAuthDir(env = process.env, stateDir = resolveStateDir(env, envHomedir(env))) {
99
197
  const override = env.CLAWDBOT_OAUTH_DIR?.trim();
100
- if (override)
101
- return resolveUserPath(override);
198
+ if (override) {
199
+ return resolveUserPath(override, env, envHomedir(env));
200
+ }
102
201
  return path.join(stateDir, "credentials");
103
202
  }
104
- export function resolveOAuthPath(env = process.env, stateDir = resolveStateDir(env, os.homedir)) {
203
+ export function resolveOAuthPath(env = process.env, stateDir = resolveStateDir(env, envHomedir(env))) {
105
204
  return path.join(resolveOAuthDir(env, stateDir), OAUTH_FILENAME);
106
205
  }
107
206
  export function resolveGatewayPort(cfg, env = process.env) {
108
207
  const envRaw = env.CLAWDBOT_GATEWAY_PORT?.trim();
109
208
  if (envRaw) {
110
209
  const parsed = Number.parseInt(envRaw, 10);
111
- if (Number.isFinite(parsed) && parsed > 0)
210
+ if (Number.isFinite(parsed) && parsed > 0) {
112
211
  return parsed;
212
+ }
113
213
  }
114
214
  const configPort = cfg?.gateway?.port;
115
215
  if (typeof configPort === "number" && Number.isFinite(configPort)) {
116
- if (configPort > 0)
216
+ if (configPort > 0) {
117
217
  return configPort;
218
+ }
118
219
  }
119
220
  return DEFAULT_GATEWAY_PORT;
120
221
  }
@@ -1,6 +1,7 @@
1
- import { getChatChannelMeta, listChatChannels, normalizeChatChannelId, } from "../channels/registry.js";
2
- import { getChannelPluginCatalogEntry, listChannelPluginCatalogEntries, } from "../channels/plugins/catalog.js";
3
1
  import { normalizeProviderId } from "../agents/model-selection.js";
2
+ import { getChannelPluginCatalogEntry, listChannelPluginCatalogEntries, } from "../channels/plugins/catalog.js";
3
+ import { getChatChannelMeta, listChatChannels, normalizeChatChannelId, } from "../channels/registry.js";
4
+ import { isRecord } from "../utils.js";
4
5
  import { hasAnyWhatsAppAuth } from "../web/accounts.js";
5
6
  const CHANNEL_PLUGIN_IDS = Array.from(new Set([
6
7
  ...listChatChannels().map((meta) => meta.id),
@@ -11,10 +12,8 @@ const PROVIDER_PLUGIN_IDS = [
11
12
  { pluginId: "google-gemini-cli-auth", providerId: "google-gemini-cli" },
12
13
  { pluginId: "qwen-portal-auth", providerId: "qwen-portal" },
13
14
  { pluginId: "copilot-proxy", providerId: "copilot-proxy" },
15
+ { pluginId: "minimax-portal-auth", providerId: "minimax-portal" },
14
16
  ];
15
- function isRecord(value) {
16
- return Boolean(value && typeof value === "object" && !Array.isArray(value));
17
- }
18
17
  function hasNonEmptyString(value) {
19
18
  return typeof value === "string" && value.trim().length > 0;
20
19
  }
@@ -63,6 +62,21 @@ function isDiscordConfigured(cfg, env) {
63
62
  return true;
64
63
  return recordHasKeys(entry);
65
64
  }
65
+ function isIrcConfigured(cfg, env) {
66
+ if (hasNonEmptyString(env.IRC_HOST) && hasNonEmptyString(env.IRC_NICK)) {
67
+ return true;
68
+ }
69
+ const entry = resolveChannelConfig(cfg, "irc");
70
+ if (!entry)
71
+ return false;
72
+ if (hasNonEmptyString(entry.host) || hasNonEmptyString(entry.nick)) {
73
+ return true;
74
+ }
75
+ if (accountsHaveKeys(entry.accounts, ["host", "nick"])) {
76
+ return true;
77
+ }
78
+ return recordHasKeys(entry);
79
+ }
66
80
  function isSlackConfigured(cfg, env) {
67
81
  if (hasNonEmptyString(env.SLACK_BOT_TOKEN) ||
68
82
  hasNonEmptyString(env.SLACK_APP_TOKEN) ||
@@ -124,6 +138,8 @@ export function isChannelConfigured(cfg, channelId, env = process.env) {
124
138
  return isTelegramConfigured(cfg, env);
125
139
  case "discord":
126
140
  return isDiscordConfigured(cfg, env);
141
+ case "irc":
142
+ return isIrcConfigured(cfg, env);
127
143
  case "slack":
128
144
  return isSlackConfigured(cfg, env);
129
145
  case "signal":
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Sentinel value used to replace sensitive config fields in gateway responses.
3
+ * Write-side handlers (config.set, config.apply, config.patch) detect this
4
+ * sentinel and restore the original value from the on-disk config, so a
5
+ * round-trip through the Web UI does not corrupt credentials.
6
+ */
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));
15
+ }
16
+ /**
17
+ * Deep-walk an object and replace values whose key matches a sensitive pattern
18
+ * with the redaction sentinel.
19
+ */
20
+ function redactObject(obj) {
21
+ if (obj === null || obj === undefined) {
22
+ return obj;
23
+ }
24
+ if (typeof obj !== "object") {
25
+ return obj;
26
+ }
27
+ if (Array.isArray(obj)) {
28
+ return obj.map(redactObject);
29
+ }
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);
37
+ }
38
+ else {
39
+ result[key] = value;
40
+ }
41
+ }
42
+ return result;
43
+ }
44
+ export function redactConfigObject(value) {
45
+ return redactObject(value);
46
+ }
47
+ /**
48
+ * Collect all sensitive string values from a config object.
49
+ * Used for text-based redaction of the raw JSON5 source.
50
+ */
51
+ function collectSensitiveValues(obj) {
52
+ const values = [];
53
+ if (obj === null || obj === undefined || typeof obj !== "object") {
54
+ return values;
55
+ }
56
+ if (Array.isArray(obj)) {
57
+ for (const item of obj) {
58
+ values.push(...collectSensitiveValues(item));
59
+ }
60
+ return values;
61
+ }
62
+ for (const [key, value] of Object.entries(obj)) {
63
+ if (isSensitiveKey(key) && typeof value === "string" && value.length > 0) {
64
+ values.push(value);
65
+ }
66
+ else if (typeof value === "object" && value !== null) {
67
+ values.push(...collectSensitiveValues(value));
68
+ }
69
+ }
70
+ return values;
71
+ }
72
+ /**
73
+ * Replace known sensitive values in a raw JSON5 string with the sentinel.
74
+ * Values are replaced longest-first to avoid partial matches.
75
+ */
76
+ function redactRawText(raw, config) {
77
+ const sensitiveValues = collectSensitiveValues(config);
78
+ sensitiveValues.sort((a, b) => b.length - a.length);
79
+ let result = raw;
80
+ for (const value of sensitiveValues) {
81
+ const escaped = value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
82
+ result = result.replace(new RegExp(escaped, "g"), REDACTED_SENTINEL);
83
+ }
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
+ return result;
96
+ }
97
+ /**
98
+ * Returns a copy of the config snapshot with all sensitive fields
99
+ * replaced by {@link REDACTED_SENTINEL}. The `hash` is preserved
100
+ * (it tracks config identity, not content).
101
+ *
102
+ * Both `config` (the parsed object) and `raw` (the JSON5 source) are scrubbed
103
+ * so no credential can leak through either path.
104
+ */
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;
109
+ return {
110
+ ...snapshot,
111
+ config: redactedConfig,
112
+ raw: redactedRaw,
113
+ parsed: redactedParsed,
114
+ };
115
+ }
116
+ /**
117
+ * Deep-walk `incoming` and replace any {@link REDACTED_SENTINEL} values
118
+ * (on sensitive keys) with the corresponding value from `original`.
119
+ *
120
+ * This is called by config.set / config.apply / config.patch before writing,
121
+ * so that credentials survive a Web UI round-trip unmodified.
122
+ */
123
+ export function restoreRedactedValues(incoming, original) {
124
+ if (incoming === null || incoming === undefined) {
125
+ return incoming;
126
+ }
127
+ if (typeof incoming !== "object") {
128
+ return incoming;
129
+ }
130
+ if (Array.isArray(incoming)) {
131
+ const origArr = Array.isArray(original) ? original : [];
132
+ return incoming.map((item, i) => restoreRedactedValues(item, origArr[i]));
133
+ }
134
+ const orig = original && typeof original === "object" && !Array.isArray(original)
135
+ ? original
136
+ : {};
137
+ const result = {};
138
+ 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}`);
142
+ }
143
+ result[key] = orig[key];
144
+ }
145
+ else if (typeof value === "object" && value !== null) {
146
+ result[key] = restoreRedactedValues(value, orig[key]);
147
+ }
148
+ else {
149
+ result[key] = value;
150
+ }
151
+ }
152
+ return result;
153
+ }