@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
@@ -25,6 +25,7 @@ import { truncateUtf16Safe } from "../../utils.js";
25
25
  import { resolveControlCommandGate } from "../../channels/command-gating.js";
26
26
  import { resolveIMessageAccount } from "../accounts.js";
27
27
  import { createIMessageRpcClient } from "../client.js";
28
+ import { DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS } from "../constants.js";
28
29
  import { probeIMessage } from "../probe.js";
29
30
  import { sendMessageIMessage } from "../send.js";
30
31
  import { formatIMessageChatTarget, isAllowedIMessageSender, normalizeIMessageHandle, } from "../targets.js";
@@ -72,6 +73,38 @@ function describeReplyContext(message) {
72
73
  const sender = normalizeReplyField(message.reply_to_sender);
73
74
  return { body, id, sender };
74
75
  }
76
+ class SentMessageCache {
77
+ cache = new Map();
78
+ ttlMs = 5000;
79
+ remember(scope, text) {
80
+ if (!text?.trim())
81
+ return;
82
+ const key = `${scope}:${text.trim()}`;
83
+ this.cache.set(key, Date.now());
84
+ this.cleanup();
85
+ }
86
+ has(scope, text) {
87
+ if (!text?.trim())
88
+ return false;
89
+ const key = `${scope}:${text.trim()}`;
90
+ const timestamp = this.cache.get(key);
91
+ if (!timestamp)
92
+ return false;
93
+ const age = Date.now() - timestamp;
94
+ if (age > this.ttlMs) {
95
+ this.cache.delete(key);
96
+ return false;
97
+ }
98
+ return true;
99
+ }
100
+ cleanup() {
101
+ const now = Date.now();
102
+ for (const [text, timestamp] of this.cache.entries()) {
103
+ if (now - timestamp > this.ttlMs)
104
+ this.cache.delete(text);
105
+ }
106
+ }
107
+ }
75
108
  export async function monitorIMessageProvider(opts = {}) {
76
109
  const runtime = resolveRuntime(opts);
77
110
  const cfg = opts.config ?? loadConfig();
@@ -84,6 +117,7 @@ export async function monitorIMessageProvider(opts = {}) {
84
117
  cfg.messages?.groupChat?.historyLimit ??
85
118
  DEFAULT_GROUP_HISTORY_LIMIT);
86
119
  const groupHistories = new Map();
120
+ const sentMessageCache = new SentMessageCache();
87
121
  const textLimit = resolveTextChunkLimit(cfg, "imessage", accountInfo.accountId);
88
122
  const allowFrom = normalizeAllowList(opts.allowFrom ?? imessageCfg.allowFrom);
89
123
  const groupAllowFrom = normalizeAllowList(opts.groupAllowFrom ??
@@ -96,6 +130,7 @@ export async function monitorIMessageProvider(opts = {}) {
96
130
  const mediaMaxBytes = (opts.mediaMaxMb ?? imessageCfg.mediaMaxMb ?? 16) * 1024 * 1024;
97
131
  const cliPath = opts.cliPath ?? imessageCfg.cliPath ?? "imsg";
98
132
  const dbPath = opts.dbPath ?? imessageCfg.dbPath;
133
+ const probeTimeoutMs = imessageCfg.probeTimeoutMs ?? DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS;
99
134
  // Resolve remoteHost: explicit config, or auto-detect from SSH wrapper script
100
135
  let remoteHost = imessageCfg.remoteHost;
101
136
  if (!remoteHost && cliPath && cliPath !== "imsg") {
@@ -290,6 +325,11 @@ export async function monitorIMessageProvider(opts = {}) {
290
325
  });
291
326
  const mentionRegexes = buildMentionRegexes(cfg, route.agentId);
292
327
  const messageText = (message.text ?? "").trim();
328
+ const echoScope = `${accountInfo.accountId}:${isGroup ? formatIMessageChatTarget(chatId) : `imessage:${sender}`}`;
329
+ if (messageText && sentMessageCache.has(echoScope, messageText)) {
330
+ logVerbose(`imessage: skipping echo message (matches recently sent text within 5s): "${truncateUtf16Safe(messageText, 50)}"`);
331
+ return;
332
+ }
293
333
  const attachments = includeAttachments ? (message.attachments ?? []) : [];
294
334
  // Filter to valid attachments with paths
295
335
  const validAttachments = attachments.filter((entry) => entry?.original_path && !entry?.missing);
@@ -426,8 +466,17 @@ export async function monitorIMessageProvider(opts = {}) {
426
466
  });
427
467
  }
428
468
  const imessageTo = (isGroup ? chatTarget : undefined) || `imessage:${sender}`;
469
+ const inboundHistory = isGroup && historyKey && historyLimit > 0
470
+ ? (groupHistories.get(historyKey) ?? []).map((entry) => ({
471
+ sender: entry.sender,
472
+ body: entry.body,
473
+ timestamp: entry.timestamp,
474
+ }))
475
+ : undefined;
429
476
  const ctxPayload = finalizeInboundContext({
430
477
  Body: combinedBody,
478
+ BodyForAgent: bodyText,
479
+ InboundHistory: inboundHistory,
431
480
  RawBody: bodyText,
432
481
  CommandBody: bodyText,
433
482
  From: isGroup ? `imessage:group:${chatId ?? "unknown"}` : `imessage:${sender}`,
@@ -495,6 +544,7 @@ export async function monitorIMessageProvider(opts = {}) {
495
544
  runtime,
496
545
  maxBytes: mediaMaxBytes,
497
546
  textLimit,
547
+ sentMessageCache,
498
548
  });
499
549
  },
500
550
  onError: (err, info) => {
@@ -542,7 +592,7 @@ export async function monitorIMessageProvider(opts = {}) {
542
592
  abortSignal: opts.abortSignal,
543
593
  runtime,
544
594
  check: async () => {
545
- const probe = await probeIMessage(2000, { cliPath, dbPath, runtime });
595
+ const probe = await probeIMessage(probeTimeoutMs, { cliPath, dbPath, runtime });
546
596
  if (probe.ok)
547
597
  return { ok: true };
548
598
  if (probe.fatal) {
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import { ensureBinary } from "./infra/binaries.js";
13
13
  import { loadDotEnv } from "./infra/dotenv.js";
14
14
  import { normalizeEnv } from "./infra/env.js";
15
15
  import { isMainModule } from "./infra/is-main.js";
16
- import { ensureMoltbotCliOnPath } from "./infra/path-env.js";
16
+ import { ensurePoolbotCliOnPath } from "./infra/path-env.js";
17
17
  import { describePortOwner, ensurePortAvailable, handlePortError, PortInUseError, } from "./infra/ports.js";
18
18
  import { assertSupportedRuntime } from "./infra/runtime-guard.js";
19
19
  import { formatUncaughtError } from "./infra/errors.js";
@@ -23,7 +23,7 @@ import { runCommandWithTimeout, runExec } from "./process/exec.js";
23
23
  import { assertWebChannel, normalizeE164, toWhatsappJid } from "./utils.js";
24
24
  loadDotEnv({ quiet: true });
25
25
  normalizeEnv();
26
- ensureMoltbotCliOnPath();
26
+ ensurePoolbotCliOnPath();
27
27
  // Capture all console output into structured logs while keeping stdout/stderr behavior.
28
28
  enableConsoleCapture();
29
29
  // Enforce the minimum supported runtime before doing any work.
@@ -1,14 +1,15 @@
1
1
  import { runCommandWithTimeout } from "../process/exec.js";
2
- import { WIDE_AREA_DISCOVERY_DOMAIN } from "./widearea-dns.js";
2
+ import { resolveWideAreaDiscoveryDomain } from "./widearea-dns.js";
3
3
  const DEFAULT_TIMEOUT_MS = 2000;
4
- const DEFAULT_DOMAINS = ["local.", WIDE_AREA_DISCOVERY_DOMAIN];
4
+ const GATEWAY_SERVICE_TYPE = "_poolbot-gw._tcp";
5
5
  function decodeDnsSdEscapes(value) {
6
6
  let decoded = false;
7
7
  const bytes = [];
8
8
  let pending = "";
9
9
  const flush = () => {
10
- if (!pending)
10
+ if (!pending) {
11
11
  return;
12
+ }
12
13
  bytes.push(...Buffer.from(pending, "utf8"));
13
14
  pending = "";
14
15
  };
@@ -31,18 +32,21 @@ function decodeDnsSdEscapes(value) {
31
32
  }
32
33
  pending += ch;
33
34
  }
34
- if (!decoded)
35
+ if (!decoded) {
35
36
  return value;
37
+ }
36
38
  flush();
37
39
  return Buffer.from(bytes).toString("utf8");
38
40
  }
39
41
  function isTailnetIPv4(address) {
40
42
  const parts = address.split(".");
41
- if (parts.length !== 4)
43
+ if (parts.length !== 4) {
42
44
  return false;
45
+ }
43
46
  const octets = parts.map((p) => Number.parseInt(p, 10));
44
- if (octets.some((n) => !Number.isFinite(n) || n < 0 || n > 255))
47
+ if (octets.some((n) => !Number.isFinite(n) || n < 0 || n > 255)) {
45
48
  return false;
49
+ }
46
50
  // Tailscale IPv4 range: 100.64.0.0/10
47
51
  const [a, b] = octets;
48
52
  return a === 100 && b >= 64 && b <= 127;
@@ -59,8 +63,9 @@ function parseDigTxt(stdout) {
59
63
  const tokens = [];
60
64
  for (const raw of stdout.split("\n")) {
61
65
  const line = raw.trim();
62
- if (!line)
66
+ if (!line) {
63
67
  continue;
68
+ }
64
69
  const matches = Array.from(line.matchAll(/"([^"]*)"/g), (m) => m[1] ?? "");
65
70
  for (const m of matches) {
66
71
  const unescaped = m.replaceAll("\\\\", "\\").replaceAll('\\"', '"').replaceAll("\\n", "\n");
@@ -75,35 +80,43 @@ function parseDigSrv(stdout) {
75
80
  .split("\n")
76
81
  .map((l) => l.trim())
77
82
  .find(Boolean);
78
- if (!line)
83
+ if (!line) {
79
84
  return null;
85
+ }
80
86
  const parts = line.split(/\s+/).filter(Boolean);
81
- if (parts.length < 4)
87
+ if (parts.length < 4) {
82
88
  return null;
89
+ }
83
90
  const port = Number.parseInt(parts[2] ?? "", 10);
84
91
  const hostRaw = parts[3] ?? "";
85
- if (!Number.isFinite(port) || port <= 0)
92
+ if (!Number.isFinite(port) || port <= 0) {
86
93
  return null;
94
+ }
87
95
  const host = hostRaw.replace(/\.$/, "");
88
- if (!host)
96
+ if (!host) {
89
97
  return null;
98
+ }
90
99
  return { host, port };
91
100
  }
92
101
  function parseTailscaleStatusIPv4s(stdout) {
93
102
  const parsed = stdout ? JSON.parse(stdout) : {};
94
103
  const out = [];
95
104
  const addIps = (value) => {
96
- if (!value || typeof value !== "object")
105
+ if (!value || typeof value !== "object") {
97
106
  return;
107
+ }
98
108
  const ips = value.TailscaleIPs;
99
- if (!Array.isArray(ips))
109
+ if (!Array.isArray(ips)) {
100
110
  return;
111
+ }
101
112
  for (const ip of ips) {
102
- if (typeof ip !== "string")
113
+ if (typeof ip !== "string") {
103
114
  continue;
115
+ }
104
116
  const trimmed = ip.trim();
105
- if (trimmed && isTailnetIPv4(trimmed))
117
+ if (trimmed && isTailnetIPv4(trimmed)) {
106
118
  out.push(trimmed);
119
+ }
107
120
  }
108
121
  };
109
122
  addIps(parsed.Self);
@@ -116,8 +129,9 @@ function parseTailscaleStatusIPv4s(stdout) {
116
129
  return [...new Set(out)];
117
130
  }
118
131
  function parseIntOrNull(value) {
119
- if (!value)
132
+ if (!value) {
120
133
  return undefined;
134
+ }
121
135
  const parsed = Number.parseInt(value, 10);
122
136
  return Number.isFinite(parsed) ? parsed : undefined;
123
137
  }
@@ -125,12 +139,14 @@ function parseTxtTokens(tokens) {
125
139
  const txt = {};
126
140
  for (const token of tokens) {
127
141
  const idx = token.indexOf("=");
128
- if (idx <= 0)
142
+ if (idx <= 0) {
129
143
  continue;
144
+ }
130
145
  const key = token.slice(0, idx).trim();
131
146
  const value = decodeDnsSdEscapes(token.slice(idx + 1).trim());
132
- if (!key)
147
+ if (!key) {
133
148
  continue;
149
+ }
134
150
  txt[key] = value;
135
151
  }
136
152
  return txt;
@@ -139,10 +155,12 @@ function parseDnsSdBrowse(stdout) {
139
155
  const instances = new Set();
140
156
  for (const raw of stdout.split("\n")) {
141
157
  const line = raw.trim();
142
- if (!line || !line.includes("_poolbot-gw._tcp"))
158
+ if (!line || !line.includes(GATEWAY_SERVICE_TYPE)) {
143
159
  continue;
144
- if (!line.includes("Add"))
160
+ }
161
+ if (!line.includes("Add")) {
145
162
  continue;
163
+ }
146
164
  const match = line.match(/_poolbot-gw\._tcp\.?\s+(.+)$/);
147
165
  if (match?.[1]) {
148
166
  instances.add(decodeDnsSdEscapes(match[1].trim()));
@@ -156,8 +174,9 @@ function parseDnsSdResolve(stdout, instanceName) {
156
174
  let txt = {};
157
175
  for (const raw of stdout.split("\n")) {
158
176
  const line = raw.trim();
159
- if (!line)
177
+ if (!line) {
160
178
  continue;
179
+ }
161
180
  if (line.includes("can be reached at")) {
162
181
  const match = line.match(/can be reached at\s+([^\s:]+):(\d+)/i);
163
182
  if (match?.[1]) {
@@ -174,49 +193,59 @@ function parseDnsSdResolve(stdout, instanceName) {
174
193
  }
175
194
  }
176
195
  beacon.txt = Object.keys(txt).length ? txt : undefined;
177
- if (txt.displayName)
196
+ if (txt.displayName) {
178
197
  beacon.displayName = decodeDnsSdEscapes(txt.displayName);
179
- if (txt.lanHost)
198
+ }
199
+ if (txt.lanHost) {
180
200
  beacon.lanHost = txt.lanHost;
181
- if (txt.tailnetDns)
201
+ }
202
+ if (txt.tailnetDns) {
182
203
  beacon.tailnetDns = txt.tailnetDns;
183
- if (txt.cliPath)
204
+ }
205
+ if (txt.cliPath) {
184
206
  beacon.cliPath = txt.cliPath;
207
+ }
185
208
  beacon.gatewayPort = parseIntOrNull(txt.gatewayPort);
186
209
  beacon.sshPort = parseIntOrNull(txt.sshPort);
187
210
  if (txt.gatewayTls) {
188
211
  const raw = txt.gatewayTls.trim().toLowerCase();
189
212
  beacon.gatewayTls = raw === "1" || raw === "true" || raw === "yes";
190
213
  }
191
- if (txt.gatewayTlsSha256)
214
+ if (txt.gatewayTlsSha256) {
192
215
  beacon.gatewayTlsFingerprintSha256 = txt.gatewayTlsSha256;
193
- if (txt.role)
216
+ }
217
+ if (txt.role) {
194
218
  beacon.role = txt.role;
195
- if (txt.transport)
219
+ }
220
+ if (txt.transport) {
196
221
  beacon.transport = txt.transport;
197
- if (!beacon.displayName)
222
+ }
223
+ if (!beacon.displayName) {
198
224
  beacon.displayName = decodedInstanceName;
225
+ }
199
226
  return beacon;
200
227
  }
201
228
  async function discoverViaDnsSd(domain, timeoutMs, run) {
202
- const browse = await run(["dns-sd", "-B", "_poolbot-gw._tcp", domain], {
229
+ const browse = await run(["dns-sd", "-B", GATEWAY_SERVICE_TYPE, domain], {
203
230
  timeoutMs,
204
231
  });
205
232
  const instances = parseDnsSdBrowse(browse.stdout);
206
233
  const results = [];
207
234
  for (const instance of instances) {
208
- const resolved = await run(["dns-sd", "-L", instance, "_poolbot-gw._tcp", domain], {
235
+ const resolved = await run(["dns-sd", "-L", instance, GATEWAY_SERVICE_TYPE, domain], {
209
236
  timeoutMs,
210
237
  });
211
238
  const parsed = parseDnsSdResolve(resolved.stdout, instance);
212
- if (parsed)
239
+ if (parsed) {
213
240
  results.push({ ...parsed, domain });
241
+ }
214
242
  }
215
243
  return results;
216
244
  }
217
245
  async function discoverWideAreaViaTailnetDns(domain, timeoutMs, run) {
218
- if (domain !== WIDE_AREA_DISCOVERY_DOMAIN)
246
+ if (!domain || domain === "local.") {
219
247
  return [];
248
+ }
220
249
  const startedAt = Date.now();
221
250
  const remainingMs = () => timeoutMs - (Date.now() - startedAt);
222
251
  const tailscaleCandidates = ["tailscale", "/Applications/Tailscale.app/Contents/MacOS/Tailscale"];
@@ -227,20 +256,23 @@ async function discoverWideAreaViaTailnetDns(domain, timeoutMs, run) {
227
256
  timeoutMs: Math.max(1, Math.min(700, remainingMs())),
228
257
  });
229
258
  ips = parseTailscaleStatusIPv4s(res.stdout);
230
- if (ips.length > 0)
259
+ if (ips.length > 0) {
231
260
  break;
261
+ }
232
262
  }
233
263
  catch {
234
264
  // ignore
235
265
  }
236
266
  }
237
- if (ips.length === 0)
267
+ if (ips.length === 0) {
238
268
  return [];
239
- if (remainingMs() <= 0)
269
+ }
270
+ if (remainingMs() <= 0) {
240
271
  return [];
272
+ }
241
273
  // Keep scans bounded: this is a fallback and should not block long.
242
274
  ips = ips.slice(0, 40);
243
- const probeName = `_poolbot-gw._tcp.${domain.replace(/\.$/, "")}`;
275
+ const probeName = `${GATEWAY_SERVICE_TYPE}.${domain.replace(/\.$/, "")}`;
244
276
  const concurrency = 6;
245
277
  let nextIndex = 0;
246
278
  let nameserver = null;
@@ -248,20 +280,24 @@ async function discoverWideAreaViaTailnetDns(domain, timeoutMs, run) {
248
280
  const worker = async () => {
249
281
  while (nameserver === null) {
250
282
  const budget = remainingMs();
251
- if (budget <= 0)
283
+ if (budget <= 0) {
252
284
  return;
285
+ }
253
286
  const i = nextIndex;
254
287
  nextIndex += 1;
255
- if (i >= ips.length)
288
+ if (i >= ips.length) {
256
289
  return;
290
+ }
257
291
  const ip = ips[i] ?? "";
258
- if (!ip)
292
+ if (!ip) {
259
293
  continue;
294
+ }
260
295
  try {
261
296
  const probe = await run(["dig", "+short", "+time=1", "+tries=1", `@${ip}`, probeName, "PTR"], { timeoutMs: Math.max(1, Math.min(250, budget)) });
262
297
  const lines = parseDigShortLines(probe.stdout);
263
- if (lines.length === 0)
298
+ if (lines.length === 0) {
264
299
  continue;
300
+ }
265
301
  nameserver = ip;
266
302
  ptrs = lines;
267
303
  return;
@@ -272,26 +308,31 @@ async function discoverWideAreaViaTailnetDns(domain, timeoutMs, run) {
272
308
  }
273
309
  };
274
310
  await Promise.all(Array.from({ length: Math.min(concurrency, ips.length) }, () => worker()));
275
- if (!nameserver || ptrs.length === 0)
311
+ if (!nameserver || ptrs.length === 0) {
276
312
  return [];
277
- if (remainingMs() <= 0)
313
+ }
314
+ if (remainingMs() <= 0) {
278
315
  return [];
316
+ }
279
317
  const nameserverArg = `@${String(nameserver)}`;
280
318
  const results = [];
281
319
  for (const ptr of ptrs) {
282
320
  const budget = remainingMs();
283
- if (budget <= 0)
321
+ if (budget <= 0) {
284
322
  break;
323
+ }
285
324
  const ptrName = ptr.trim().replace(/\.$/, "");
286
- if (!ptrName)
325
+ if (!ptrName) {
287
326
  continue;
327
+ }
288
328
  const instanceName = ptrName.replace(/\.?_poolbot-gw\._tcp\..*$/, "");
289
329
  const srv = await run(["dig", "+short", "+time=1", "+tries=1", nameserverArg, ptrName, "SRV"], {
290
330
  timeoutMs: Math.max(1, Math.min(350, budget)),
291
331
  }).catch(() => null);
292
332
  const srvParsed = srv ? parseDigSrv(srv.stdout) : null;
293
- if (!srvParsed)
333
+ if (!srvParsed) {
294
334
  continue;
335
+ }
295
336
  const txtBudget = remainingMs();
296
337
  if (txtBudget <= 0) {
297
338
  results.push({
@@ -324,12 +365,15 @@ async function discoverWideAreaViaTailnetDns(domain, timeoutMs, run) {
324
365
  const raw = txtMap.gatewayTls.trim().toLowerCase();
325
366
  beacon.gatewayTls = raw === "1" || raw === "true" || raw === "yes";
326
367
  }
327
- if (txtMap.gatewayTlsSha256)
368
+ if (txtMap.gatewayTlsSha256) {
328
369
  beacon.gatewayTlsFingerprintSha256 = txtMap.gatewayTlsSha256;
329
- if (txtMap.role)
370
+ }
371
+ if (txtMap.role) {
330
372
  beacon.role = txtMap.role;
331
- if (txtMap.transport)
373
+ }
374
+ if (txtMap.transport) {
332
375
  beacon.transport = txtMap.transport;
376
+ }
333
377
  results.push(beacon);
334
378
  }
335
379
  return results;
@@ -339,12 +383,14 @@ function parseAvahiBrowse(stdout) {
339
383
  let current = null;
340
384
  for (const raw of stdout.split("\n")) {
341
385
  const line = raw.trimEnd();
342
- if (!line)
386
+ if (!line) {
343
387
  continue;
344
- if (line.startsWith("=") && line.includes("_poolbot-gw._tcp")) {
345
- if (current)
388
+ }
389
+ if (line.startsWith("=") && line.includes(GATEWAY_SERVICE_TYPE)) {
390
+ if (current) {
346
391
  results.push(current);
347
- const marker = " _poolbot-gw._tcp";
392
+ }
393
+ const marker = ` ${GATEWAY_SERVICE_TYPE}`;
348
394
  const idx = line.indexOf(marker);
349
395
  const left = idx >= 0 ? line.slice(0, idx).trim() : line;
350
396
  const parts = left.split(/\s+/);
@@ -355,53 +401,64 @@ function parseAvahiBrowse(stdout) {
355
401
  };
356
402
  continue;
357
403
  }
358
- if (!current)
404
+ if (!current) {
359
405
  continue;
406
+ }
360
407
  const trimmed = line.trim();
361
408
  if (trimmed.startsWith("hostname =")) {
362
409
  const match = trimmed.match(/hostname\s*=\s*\[([^\]]+)\]/);
363
- if (match?.[1])
410
+ if (match?.[1]) {
364
411
  current.host = match[1];
412
+ }
365
413
  continue;
366
414
  }
367
415
  if (trimmed.startsWith("port =")) {
368
416
  const match = trimmed.match(/port\s*=\s*\[(\d+)\]/);
369
- if (match?.[1])
417
+ if (match?.[1]) {
370
418
  current.port = parseIntOrNull(match[1]);
419
+ }
371
420
  continue;
372
421
  }
373
422
  if (trimmed.startsWith("txt =")) {
374
423
  const tokens = Array.from(trimmed.matchAll(/"([^"]*)"/g), (m) => m[1]);
375
424
  const txt = parseTxtTokens(tokens);
376
425
  current.txt = Object.keys(txt).length ? txt : undefined;
377
- if (txt.displayName)
426
+ if (txt.displayName) {
378
427
  current.displayName = txt.displayName;
379
- if (txt.lanHost)
428
+ }
429
+ if (txt.lanHost) {
380
430
  current.lanHost = txt.lanHost;
381
- if (txt.tailnetDns)
431
+ }
432
+ if (txt.tailnetDns) {
382
433
  current.tailnetDns = txt.tailnetDns;
383
- if (txt.cliPath)
434
+ }
435
+ if (txt.cliPath) {
384
436
  current.cliPath = txt.cliPath;
437
+ }
385
438
  current.gatewayPort = parseIntOrNull(txt.gatewayPort);
386
439
  current.sshPort = parseIntOrNull(txt.sshPort);
387
440
  if (txt.gatewayTls) {
388
441
  const raw = txt.gatewayTls.trim().toLowerCase();
389
442
  current.gatewayTls = raw === "1" || raw === "true" || raw === "yes";
390
443
  }
391
- if (txt.gatewayTlsSha256)
444
+ if (txt.gatewayTlsSha256) {
392
445
  current.gatewayTlsFingerprintSha256 = txt.gatewayTlsSha256;
393
- if (txt.role)
446
+ }
447
+ if (txt.role) {
394
448
  current.role = txt.role;
395
- if (txt.transport)
449
+ }
450
+ if (txt.transport) {
396
451
  current.transport = txt.transport;
452
+ }
397
453
  }
398
454
  }
399
- if (current)
455
+ if (current) {
400
456
  results.push(current);
457
+ }
401
458
  return results;
402
459
  }
403
460
  async function discoverViaAvahi(domain, timeoutMs, run) {
404
- const args = ["avahi-browse", "-rt", "_poolbot-gw._tcp"];
461
+ const args = ["avahi-browse", "-rt", GATEWAY_SERVICE_TYPE];
405
462
  if (domain && domain !== "local.") {
406
463
  // avahi-browse wants a plain domain (no trailing dot)
407
464
  args.push("-d", domain.replace(/\.$/, ""));
@@ -416,8 +473,10 @@ export async function discoverGatewayBeacons(opts = {}) {
416
473
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
417
474
  const platform = opts.platform ?? process.platform;
418
475
  const run = opts.run ?? runCommandWithTimeout;
476
+ const wideAreaDomain = resolveWideAreaDiscoveryDomain({ configDomain: opts.wideAreaDomain });
419
477
  const domainsRaw = Array.isArray(opts.domains) ? opts.domains : [];
420
- const domains = (domainsRaw.length > 0 ? domainsRaw : [...DEFAULT_DOMAINS])
478
+ const defaultDomains = ["local.", ...(wideAreaDomain ? [wideAreaDomain] : [])];
479
+ const domains = (domainsRaw.length > 0 ? domainsRaw : defaultDomains)
421
480
  .map((d) => String(d).trim())
422
481
  .filter(Boolean)
423
482
  .map((d) => (d.endsWith(".") ? d : `${d}.`));
@@ -425,10 +484,12 @@ export async function discoverGatewayBeacons(opts = {}) {
425
484
  if (platform === "darwin") {
426
485
  const perDomain = await Promise.allSettled(domains.map(async (domain) => await discoverViaDnsSd(domain, timeoutMs, run)));
427
486
  const discovered = perDomain.flatMap((r) => (r.status === "fulfilled" ? r.value : []));
428
- const wantsWideArea = domains.includes(WIDE_AREA_DISCOVERY_DOMAIN);
429
- const hasWideArea = discovered.some((b) => b.domain === WIDE_AREA_DISCOVERY_DOMAIN);
430
- if (wantsWideArea && !hasWideArea) {
431
- const fallback = await discoverWideAreaViaTailnetDns(WIDE_AREA_DISCOVERY_DOMAIN, timeoutMs, run).catch(() => []);
487
+ const wantsWideArea = wideAreaDomain ? domains.includes(wideAreaDomain) : false;
488
+ const hasWideArea = wideAreaDomain
489
+ ? discovered.some((b) => b.domain === wideAreaDomain)
490
+ : false;
491
+ if (wantsWideArea && !hasWideArea && wideAreaDomain) {
492
+ const fallback = await discoverWideAreaViaTailnetDns(wideAreaDomain, timeoutMs, run).catch(() => []);
432
493
  return [...discovered, ...fallback];
433
494
  }
434
495
  return discovered;
@@ -16,11 +16,11 @@ function isDisabledByEnv() {
16
16
  }
17
17
  function safeServiceName(name) {
18
18
  const trimmed = name.trim();
19
- return trimmed.length > 0 ? trimmed : "Moltbot";
19
+ return trimmed.length > 0 ? trimmed : "Poolbot";
20
20
  }
21
21
  function prettifyInstanceName(name) {
22
22
  const normalized = name.trim().replace(/\s+/g, " ");
23
- return normalized.replace(/\s+\(Moltbot\)\s*$/i, "").trim() || normalized;
23
+ return normalized.replace(/\s+\(Poolbot\)\s*$/i, "").trim() || normalized;
24
24
  }
25
25
  function serviceSummary(label, svc) {
26
26
  let fqdn = "unknown";
@@ -63,7 +63,7 @@ export async function startGatewayBonjourAdvertiser(opts) {
63
63
  .trim() || "poolbot";
64
64
  const instanceName = typeof opts.instanceName === "string" && opts.instanceName.trim()
65
65
  ? opts.instanceName.trim()
66
- : `${hostname} (Moltbot)`;
66
+ : `${hostname} (Poolbot)`;
67
67
  const displayName = prettifyInstanceName(instanceName);
68
68
  const txtBase = {
69
69
  role: "gateway",