@poolzin/pool-bot 2026.2.21 → 2026.2.23

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 (378) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/agents/api-key-rotation.js +47 -0
  3. package/dist/agents/apply-patch-update.js +19 -9
  4. package/dist/agents/apply-patch.js +72 -47
  5. package/dist/agents/bash-tools.exec.js +141 -559
  6. package/dist/agents/cli-backends.js +49 -6
  7. package/dist/agents/cli-runner/helpers.js +69 -152
  8. package/dist/agents/cli-runner.js +70 -19
  9. package/dist/agents/identity.js +20 -1
  10. package/dist/agents/image-sanitization.js +9 -0
  11. package/dist/agents/live-auth-keys.js +123 -26
  12. package/dist/agents/live-model-filter.js +13 -4
  13. package/dist/agents/model-catalog.js +40 -9
  14. package/dist/agents/model-forward-compat.js +60 -23
  15. package/dist/agents/model-selection.js +134 -41
  16. package/dist/agents/pi-auth-json.js +2 -2
  17. package/dist/agents/pi-embedded-helpers/bootstrap.js +65 -15
  18. package/dist/agents/pi-embedded-helpers/errors.js +140 -15
  19. package/dist/agents/pi-embedded-helpers/images.js +22 -12
  20. package/dist/agents/pi-embedded-helpers.js +2 -2
  21. package/dist/agents/pi-embedded-runner/abort.js +10 -3
  22. package/dist/agents/pi-embedded-runner/compact.js +230 -32
  23. package/dist/agents/pi-embedded-runner/extra-params.js +203 -12
  24. package/dist/agents/pi-embedded-runner/google.js +109 -19
  25. package/dist/agents/pi-embedded-runner/history.js +35 -17
  26. package/dist/agents/pi-embedded-runner/run/attempt.js +386 -95
  27. package/dist/agents/pi-embedded-runner/run/images.js +81 -55
  28. package/dist/agents/pi-embedded-runner/run/payloads.js +89 -39
  29. package/dist/agents/pi-embedded-runner/run.js +193 -25
  30. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +2 -2
  31. package/dist/agents/pi-embedded-runner/runs.js +17 -8
  32. package/dist/agents/pi-embedded-runner/tool-result-context-guard.js +262 -0
  33. package/dist/agents/pi-embedded-runner.js +1 -1
  34. package/dist/agents/pi-embedded-subscribe.handlers.tools.js +180 -10
  35. package/dist/agents/pi-embedded-subscribe.js +37 -0
  36. package/dist/agents/pi-embedded-subscribe.tools.js +127 -30
  37. package/dist/agents/pi-model-discovery.js +9 -2
  38. package/dist/agents/pi-tool-definition-adapter.js +60 -8
  39. package/dist/agents/pi-tools.before-tool-call.js +1 -1
  40. package/dist/agents/pi-tools.js +113 -94
  41. package/dist/agents/pi-tools.read.js +337 -38
  42. package/dist/agents/poolbot-tools.js +14 -5
  43. package/dist/agents/sandbox/docker.js +10 -5
  44. package/dist/agents/sandbox/registry.js +96 -46
  45. package/dist/agents/sandbox/sanitize-env-vars.js +82 -0
  46. package/dist/agents/sandbox-paths.js +43 -10
  47. package/dist/agents/session-tool-result-guard-wrapper.js +23 -11
  48. package/dist/agents/session-tool-result-guard.js +39 -39
  49. package/dist/agents/session-transcript-repair.js +36 -33
  50. package/dist/agents/session-write-lock.js +62 -44
  51. package/dist/agents/skills/frontmatter.js +49 -88
  52. package/dist/agents/skills/workspace.js +335 -28
  53. package/dist/agents/subagent-announce.js +508 -174
  54. package/dist/agents/subagent-registry.js +45 -4
  55. package/dist/agents/subagent-spawn.js +16 -33
  56. package/dist/agents/system-prompt-report.js +27 -10
  57. package/dist/agents/system-prompt.js +26 -32
  58. package/dist/agents/tool-call-id.js +69 -17
  59. package/dist/agents/tool-display-common.js +1 -1
  60. package/dist/agents/tool-images.js +64 -31
  61. package/dist/agents/tools/canvas-tool.js +17 -11
  62. package/dist/agents/tools/common.js +37 -19
  63. package/dist/agents/tools/cron-tool.js +40 -38
  64. package/dist/agents/tools/gateway.js +70 -2
  65. package/dist/agents/tools/message-tool.js +181 -40
  66. package/dist/agents/tools/nodes-tool.js +128 -36
  67. package/dist/agents/tools/nodes-utils.js +12 -38
  68. package/dist/agents/tools/session-status-tool.js +24 -71
  69. package/dist/agents/tools/sessions-helpers.js +38 -210
  70. package/dist/agents/tools/sessions-spawn-tool.js +28 -198
  71. package/dist/agents/tools/telegram-actions.js +58 -7
  72. package/dist/agents/tools/web-fetch-utils.js +112 -7
  73. package/dist/agents/tools/web-fetch.js +279 -175
  74. package/dist/agents/tools/web-shared.js +71 -8
  75. package/dist/agents/usage.js +25 -16
  76. package/dist/auto-reply/commands-registry.data.js +85 -11
  77. package/dist/auto-reply/dispatch.js +40 -21
  78. package/dist/auto-reply/reply/abort.js +102 -33
  79. package/dist/auto-reply/reply/commands-core.js +82 -33
  80. package/dist/auto-reply/reply/commands-export-session.js +1 -1
  81. package/dist/auto-reply/reply/commands-info.js +41 -12
  82. package/dist/auto-reply/reply/commands-subagents.js +352 -100
  83. package/dist/auto-reply/reply/commands-system-prompt.js +2 -2
  84. package/dist/auto-reply/reply/dispatch-from-config.js +100 -29
  85. package/dist/auto-reply/reply/elevated-unavailable.js +1 -1
  86. package/dist/auto-reply/reply/inbound-meta.js +12 -1
  87. package/dist/auto-reply/reply/mentions.js +18 -11
  88. package/dist/auto-reply/reply/normalize-reply.js +17 -8
  89. package/dist/auto-reply/reply/reply-dispatcher.js +62 -10
  90. package/dist/auto-reply/reply/session.js +102 -21
  91. package/dist/auto-reply/reply/streaming-directives.js +16 -5
  92. package/dist/auto-reply/status.js +73 -50
  93. package/dist/browser/extension-relay.js +3 -3
  94. package/dist/browser/http-auth.js +1 -1
  95. package/dist/browser/paths.js +2 -2
  96. package/dist/build-info.json +3 -3
  97. package/dist/channels/allowlist-match.js +20 -0
  98. package/dist/channels/allowlists/resolve-utils.js +65 -2
  99. package/dist/channels/chat-type.js +8 -4
  100. package/dist/channels/dock.js +127 -35
  101. package/dist/channels/draft-stream-loop.js +6 -2
  102. package/dist/channels/plugins/actions/telegram.js +42 -18
  103. package/dist/channels/plugins/allowlist-match.js +1 -1
  104. package/dist/channels/plugins/group-mentions.js +51 -41
  105. package/dist/channels/plugins/message-action-names.js +2 -0
  106. package/dist/channels/plugins/message-actions.js +24 -5
  107. package/dist/channels/plugins/normalize/discord.js +26 -4
  108. package/dist/channels/plugins/normalize/signal.js +35 -22
  109. package/dist/channels/plugins/onboarding/helpers.js +8 -26
  110. package/dist/channels/plugins/outbound/imessage.js +15 -14
  111. package/dist/channels/registry.js +20 -7
  112. package/dist/cli/acp-cli.js +7 -5
  113. package/dist/cli/browser-cli-extension.js +25 -12
  114. package/dist/cli/browser-cli-state.cookies-storage.js +25 -6
  115. package/dist/cli/browser-cli-state.js +101 -145
  116. package/dist/cli/command-options.js +28 -0
  117. package/dist/cli/completion-cli.js +6 -6
  118. package/dist/cli/cron-cli/register.cron-add.js +25 -1
  119. package/dist/cli/cron-cli/register.cron-edit.js +44 -0
  120. package/dist/cli/cron-cli/shared.js +7 -1
  121. package/dist/cli/daemon-cli/lifecycle-core.js +23 -21
  122. package/dist/cli/daemon-cli/lifecycle.js +23 -247
  123. package/dist/cli/daemon-cli/register-service-commands.js +25 -4
  124. package/dist/cli/daemon-cli.js +1 -0
  125. package/dist/cli/devices-cli.js +33 -20
  126. package/dist/cli/gateway-cli/register.js +37 -105
  127. package/dist/cli/gateway-cli/run.js +49 -11
  128. package/dist/cli/nodes-camera.js +59 -4
  129. package/dist/cli/nodes-cli/register.camera.js +27 -24
  130. package/dist/cli/nodes-cli/rpc.js +21 -38
  131. package/dist/cli/qr-cli.js +2 -2
  132. package/dist/cli/skills-cli.format.js +2 -2
  133. package/dist/cli/update-cli/progress.js +2 -2
  134. package/dist/cli/update-cli/restart-helper.js +28 -7
  135. package/dist/cli/update-cli/shared.js +7 -7
  136. package/dist/cli/update-cli/status.js +1 -1
  137. package/dist/cli/update-cli/update-command.js +14 -8
  138. package/dist/cli/update-cli/wizard.js +2 -2
  139. package/dist/cli/update-cli.js +21 -1027
  140. package/dist/commands/auth-choice.apply.anthropic.js +10 -2
  141. package/dist/commands/channels/add-mutators.js +3 -35
  142. package/dist/commands/channels/add.js +39 -51
  143. package/dist/commands/config-validation.js +1 -1
  144. package/dist/commands/configure.gateway-auth.js +52 -15
  145. package/dist/commands/configure.gateway.js +84 -40
  146. package/dist/commands/doctor-completion.js +3 -3
  147. package/dist/commands/doctor-config-flow.js +536 -16
  148. package/dist/commands/doctor-gateway-services.js +103 -79
  149. package/dist/commands/doctor-memory-search.js +9 -9
  150. package/dist/commands/doctor-platform-notes.js +57 -30
  151. package/dist/commands/doctor-prompter.js +26 -15
  152. package/dist/commands/doctor-session-locks.js +1 -1
  153. package/dist/commands/doctor.js +21 -9
  154. package/dist/commands/model-picker.js +120 -95
  155. package/dist/commands/models/set.js +2 -21
  156. package/dist/commands/models/shared.js +65 -37
  157. package/dist/commands/onboard-helpers.js +81 -39
  158. package/dist/commands/openai-codex-oauth.js +1 -1
  159. package/dist/commands/sessions.js +52 -53
  160. package/dist/commands/status.summary.js +52 -34
  161. package/dist/commands/test-wizard-helpers.js +2 -2
  162. package/dist/config/defaults.js +79 -42
  163. package/dist/config/group-policy.js +50 -18
  164. package/dist/config/includes.js +37 -10
  165. package/dist/config/schema.help.js +5 -4
  166. package/dist/config/schema.hints.js +2 -2
  167. package/dist/config/schema.labels.js +1 -0
  168. package/dist/config/sessions/group.js +12 -11
  169. package/dist/config/sessions/paths.js +137 -11
  170. package/dist/config/sessions/store.js +185 -65
  171. package/dist/config/sessions/types.js +15 -1
  172. package/dist/config/sessions.js +1 -0
  173. package/dist/config/telegram-custom-commands.js +3 -2
  174. package/dist/config/types.js +2 -0
  175. package/dist/config/zod-schema.agent-defaults.js +6 -27
  176. package/dist/config/zod-schema.agent-runtime.js +171 -79
  177. package/dist/config/zod-schema.providers-core.js +138 -65
  178. package/dist/config/zod-schema.session.js +49 -22
  179. package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
  180. package/dist/cron/isolated-agent/run.js +224 -57
  181. package/dist/cron/normalize.js +48 -45
  182. package/dist/cron/run-log.js +14 -0
  183. package/dist/cron/service/jobs.js +190 -28
  184. package/dist/cron/service/normalize.js +29 -11
  185. package/dist/cron/service/store.js +30 -44
  186. package/dist/cron/service/timer.js +182 -96
  187. package/dist/cron/service.js +3 -0
  188. package/dist/cron/stagger.js +37 -0
  189. package/dist/daemon/inspect.js +132 -92
  190. package/dist/daemon/runtime-paths.js +25 -4
  191. package/dist/daemon/service-audit.js +47 -16
  192. package/dist/discord/accounts.js +23 -20
  193. package/dist/discord/monitor/agent-components.js +1115 -219
  194. package/dist/discord/monitor/allow-list.js +114 -34
  195. package/dist/discord/monitor/listeners.js +204 -97
  196. package/dist/discord/monitor/message-handler.js +21 -10
  197. package/dist/discord/monitor/message-handler.preflight.js +195 -101
  198. package/dist/discord/monitor/message-handler.process.js +384 -123
  199. package/dist/discord/monitor/message-utils.js +86 -23
  200. package/dist/discord/monitor/native-command.js +77 -57
  201. package/dist/discord/monitor/provider.js +122 -117
  202. package/dist/discord/monitor/reply-context.js +20 -16
  203. package/dist/discord/monitor/reply-delivery.js +40 -8
  204. package/dist/discord/monitor/rest-fetch.js +22 -0
  205. package/dist/discord/monitor/threading.js +117 -24
  206. package/dist/discord/send.js +2 -1
  207. package/dist/discord/send.outbound.js +124 -11
  208. package/dist/discord/send.shared.js +112 -72
  209. package/dist/discord/voice-message.js +3 -3
  210. package/dist/gateway/auth.js +119 -44
  211. package/dist/gateway/call.js +76 -34
  212. package/dist/gateway/channel-health-monitor.js +57 -50
  213. package/dist/gateway/client.js +63 -29
  214. package/dist/gateway/control-ui-contract.js +1 -1
  215. package/dist/gateway/gateway-config-prompts.shared.js +2 -2
  216. package/dist/gateway/net.js +109 -1
  217. package/dist/gateway/protocol/index.js +5 -8
  218. package/dist/gateway/protocol/schema/agent.js +19 -1
  219. package/dist/gateway/protocol/schema/channels.js +21 -0
  220. package/dist/gateway/protocol/schema/cron.js +43 -30
  221. package/dist/gateway/protocol/schema/protocol-schemas.js +6 -11
  222. package/dist/gateway/protocol/schema/sessions.js +5 -1
  223. package/dist/gateway/protocol/schema.js +0 -1
  224. package/dist/gateway/server/presence-events.js +12 -0
  225. package/dist/gateway/server/ws-connection/message-handler.js +203 -212
  226. package/dist/gateway/server/ws-connection.js +58 -21
  227. package/dist/gateway/server-broadcast.js +18 -13
  228. package/dist/gateway/server-cron.js +177 -10
  229. package/dist/gateway/server-methods/agent-job.js +131 -38
  230. package/dist/gateway/server-methods/send.js +60 -14
  231. package/dist/gateway/server-methods/sessions.js +160 -96
  232. package/dist/gateway/server-methods/system.js +5 -7
  233. package/dist/gateway/server-methods-list.js +8 -0
  234. package/dist/gateway/server-methods.js +24 -8
  235. package/dist/gateway/server-node-events.js +278 -68
  236. package/dist/gateway/session-utils.fs.js +316 -75
  237. package/dist/gateway/session-utils.js +224 -70
  238. package/dist/gateway/sessions-patch.js +63 -20
  239. package/dist/gateway/test-temp-config.js +1 -1
  240. package/dist/gateway/tools-invoke-http.js +118 -70
  241. package/dist/gateway/ws-log.js +135 -107
  242. package/dist/hooks/frontmatter.js +36 -82
  243. package/dist/hooks/install.js +149 -139
  244. package/dist/hooks/internal-hooks.js +29 -4
  245. package/dist/hooks/plugin-hooks.js +2 -1
  246. package/dist/imessage/monitor/deliver.js +10 -4
  247. package/dist/imessage/monitor/monitor-provider.js +138 -375
  248. package/dist/imessage/monitor/runtime.js +4 -8
  249. package/dist/imessage/send.js +65 -19
  250. package/dist/infra/exec-approvals-allowlist.js +7 -0
  251. package/dist/infra/exec-approvals.js +35 -920
  252. package/dist/infra/exec-safe-bin-trust.js +64 -0
  253. package/dist/infra/heartbeat-runner.js +207 -134
  254. package/dist/infra/heartbeat-wake.js +183 -22
  255. package/dist/infra/install-source-utils.js +47 -0
  256. package/dist/infra/net/ssrf.js +170 -36
  257. package/dist/infra/outbound/deliver.js +224 -58
  258. package/dist/infra/outbound/message-action-spec.js +12 -5
  259. package/dist/infra/outbound/outbound-session.js +27 -25
  260. package/dist/infra/poolbot-root.js +32 -22
  261. package/dist/infra/ports.js +14 -11
  262. package/dist/infra/skills-remote.js +48 -37
  263. package/dist/infra/system-events.js +25 -11
  264. package/dist/infra/system-presence.js +26 -33
  265. package/dist/infra/tmp-poolbot-dir.js +81 -2
  266. package/dist/infra/wsl.js +37 -1
  267. package/dist/line/bot-message-context.js +163 -191
  268. package/dist/logging/subsystem.js +59 -22
  269. package/dist/markdown/ir.js +124 -50
  270. package/dist/media/store.js +1 -1
  271. package/dist/media-understanding/runner.entries.js +42 -25
  272. package/dist/media-understanding/runner.js +53 -488
  273. package/dist/memory/embeddings-gemini.js +53 -38
  274. package/dist/memory/manager-embedding-ops.js +48 -69
  275. package/dist/pairing/pairing-store.js +178 -119
  276. package/dist/plugin-sdk/index.js +34 -6
  277. package/dist/plugins/hooks.js +135 -14
  278. package/dist/plugins/install.js +190 -152
  279. package/dist/polls.js +11 -0
  280. package/dist/routing/resolve-route.js +190 -56
  281. package/dist/routing/session-key.js +38 -22
  282. package/dist/runtime.js +35 -9
  283. package/dist/security/audit-channel.js +1 -1
  284. package/dist/sessions/session-key-utils.js +29 -11
  285. package/dist/shared/frontmatter.js +5 -5
  286. package/dist/shared/node-list-types.js +1 -0
  287. package/dist/shared/string-normalization.js +15 -0
  288. package/dist/signal/monitor/event-handler.js +68 -36
  289. package/dist/signal/send.js +29 -37
  290. package/dist/slack/monitor/allow-list.js +10 -11
  291. package/dist/slack/monitor/commands.js +14 -3
  292. package/dist/slack/monitor/events/interactions.js +4 -4
  293. package/dist/slack/monitor/media.js +224 -16
  294. package/dist/slack/monitor/message-handler/dispatch.js +247 -13
  295. package/dist/slack/monitor/message-handler/prepare.js +128 -45
  296. package/dist/slack/monitor/slash.js +357 -144
  297. package/dist/slack/streaming.js +77 -0
  298. package/dist/telegram/accounts.js +40 -13
  299. package/dist/telegram/allowed-updates.js +3 -0
  300. package/dist/telegram/bot/delivery.js +129 -66
  301. package/dist/telegram/bot/helpers.js +136 -122
  302. package/dist/telegram/bot-handlers.js +600 -339
  303. package/dist/telegram/bot-message-context.js +115 -73
  304. package/dist/telegram/bot-message-dispatch.js +235 -104
  305. package/dist/telegram/bot-native-command-menu.js +3 -1
  306. package/dist/telegram/bot-native-commands.js +213 -193
  307. package/dist/telegram/bot.js +24 -132
  308. package/dist/telegram/draft-stream.js +84 -75
  309. package/dist/telegram/format.js +150 -6
  310. package/dist/telegram/send.js +415 -255
  311. package/dist/telegram/targets.js +21 -2
  312. package/dist/telegram/update-offset-store.js +19 -3
  313. package/dist/terminal/restore.js +5 -2
  314. package/dist/test-utils/fetch-mock.js +5 -0
  315. package/dist/version.js +18 -5
  316. package/dist/web/auto-reply/monitor/broadcast.js +7 -3
  317. package/dist/web/auto-reply/monitor/on-message.js +6 -3
  318. package/dist/web/inbound/media.js +34 -8
  319. package/dist/web/inbound/monitor.js +34 -17
  320. package/dist/web/inbound/send-api.js +18 -17
  321. package/dist/web/outbound.js +12 -5
  322. package/dist/wizard/clack-prompter.js +40 -7
  323. package/extensions/bluebubbles/package.json +1 -1
  324. package/extensions/copilot-proxy/package.json +1 -1
  325. package/extensions/device-pair/index.ts +2 -2
  326. package/extensions/diagnostics-otel/package.json +1 -1
  327. package/extensions/discord/package.json +1 -1
  328. package/extensions/feishu/package.json +1 -1
  329. package/extensions/google-antigravity-auth/package.json +1 -1
  330. package/extensions/google-gemini-cli-auth/package.json +1 -1
  331. package/extensions/googlechat/package.json +1 -1
  332. package/extensions/imessage/package.json +1 -1
  333. package/extensions/irc/package.json +1 -1
  334. package/extensions/irc/src/accounts.ts +1 -1
  335. package/extensions/irc/src/onboarding.ts +4 -4
  336. package/extensions/line/package.json +1 -1
  337. package/extensions/llm-task/package.json +1 -1
  338. package/extensions/lobster/package.json +1 -1
  339. package/extensions/matrix/CHANGELOG.md +10 -0
  340. package/extensions/matrix/package.json +1 -1
  341. package/extensions/mattermost/package.json +1 -1
  342. package/extensions/memory-core/package.json +1 -1
  343. package/extensions/memory-lancedb/package.json +1 -1
  344. package/extensions/minimax-portal-auth/package.json +1 -1
  345. package/extensions/msteams/CHANGELOG.md +10 -0
  346. package/extensions/msteams/package.json +1 -1
  347. package/extensions/nextcloud-talk/package.json +1 -1
  348. package/extensions/nostr/CHANGELOG.md +10 -0
  349. package/extensions/nostr/package.json +1 -1
  350. package/extensions/open-prose/package.json +1 -1
  351. package/extensions/openai-codex-auth/package.json +1 -1
  352. package/extensions/signal/package.json +1 -1
  353. package/extensions/slack/package.json +1 -1
  354. package/extensions/telegram/package.json +1 -1
  355. package/extensions/tlon/package.json +1 -1
  356. package/extensions/twitch/CHANGELOG.md +10 -0
  357. package/extensions/twitch/package.json +1 -1
  358. package/extensions/voice-call/CHANGELOG.md +10 -0
  359. package/extensions/voice-call/package.json +1 -1
  360. package/extensions/whatsapp/package.json +1 -1
  361. package/extensions/zalo/CHANGELOG.md +10 -0
  362. package/extensions/zalo/package.json +1 -1
  363. package/extensions/zalouser/CHANGELOG.md +10 -0
  364. package/extensions/zalouser/package.json +1 -1
  365. package/package.json +1 -1
  366. package/skills/apple-reminders/SKILL.md +100 -49
  367. package/skills/coding-agent/SKILL.md +34 -28
  368. package/skills/github/SKILL.md +131 -16
  369. package/skills/imsg/SKILL.md +112 -15
  370. package/skills/openhue/SKILL.md +101 -19
  371. package/skills/tmux/SKILL.md +111 -79
  372. package/skills/weather/SKILL.md +88 -25
  373. package/dist/agents/openclaw-tools.js +0 -151
  374. package/dist/agents/tool-security.js +0 -96
  375. package/dist/gateway/url-validation.js +0 -94
  376. package/dist/infra/openclaw-root.js +0 -109
  377. package/dist/infra/tmp-openclaw-dir.js +0 -81
  378. package/dist/media/path-sanitization.js +0 -78
@@ -8,38 +8,44 @@ import { CONFIG_PATH } from "../config/config.js";
8
8
  import { resolveSessionTranscriptsDirForAgent } from "../config/sessions.js";
9
9
  import { callGateway } from "../gateway/call.js";
10
10
  import { normalizeControlUiBasePath } from "../gateway/control-ui-shared.js";
11
+ import { pickPrimaryLanIPv4, isValidIPv4 } from "../gateway/net.js";
11
12
  import { isSafeExecutableValue } from "../infra/exec-safety.js";
12
13
  import { pickPrimaryTailnetIPv4 } from "../infra/tailnet.js";
13
14
  import { isWSL } from "../infra/wsl.js";
14
15
  import { runCommandWithTimeout } from "../process/exec.js";
15
16
  import { stylePromptTitle } from "../terminal/prompt-style.js";
16
- import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
17
17
  import { CONFIG_DIR, resolveUserPath, shortenHomeInString, shortenHomePath, sleep, } from "../utils.js";
18
+ import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
18
19
  import { VERSION } from "../version.js";
19
20
  export function guardCancel(value, runtime) {
20
21
  if (isCancel(value)) {
21
22
  cancel(stylePromptTitle("Setup cancelled.") ?? "Setup cancelled.");
22
23
  runtime.exit(0);
24
+ throw new Error("unreachable");
23
25
  }
24
26
  return value;
25
27
  }
26
28
  export function summarizeExistingConfig(config) {
27
29
  const rows = [];
28
30
  const defaults = config.agents?.defaults;
29
- if (defaults?.workspace)
31
+ if (defaults?.workspace) {
30
32
  rows.push(shortenHomeInString(`workspace: ${defaults.workspace}`));
33
+ }
31
34
  if (defaults?.model) {
32
35
  const model = typeof defaults.model === "string" ? defaults.model : defaults.model.primary;
33
- if (model)
36
+ if (model) {
34
37
  rows.push(shortenHomeInString(`model: ${model}`));
38
+ }
35
39
  }
36
- if (config.gateway?.mode)
40
+ if (config.gateway?.mode) {
37
41
  rows.push(shortenHomeInString(`gateway.mode: ${config.gateway.mode}`));
42
+ }
38
43
  if (typeof config.gateway?.port === "number") {
39
44
  rows.push(shortenHomeInString(`gateway.port: ${config.gateway.port}`));
40
45
  }
41
- if (config.gateway?.bind)
46
+ if (config.gateway?.bind) {
42
47
  rows.push(shortenHomeInString(`gateway.bind: ${config.gateway.bind}`));
48
+ }
43
49
  if (config.gateway?.remote?.url) {
44
50
  rows.push(shortenHomeInString(`gateway.remote.url: ${config.gateway.remote.url}`));
45
51
  }
@@ -51,14 +57,40 @@ export function summarizeExistingConfig(config) {
51
57
  export function randomToken() {
52
58
  return crypto.randomBytes(24).toString("hex");
53
59
  }
60
+ export function normalizeGatewayTokenInput(value) {
61
+ if (typeof value !== "string") {
62
+ return "";
63
+ }
64
+ const trimmed = value.trim();
65
+ // Reject the literal string "undefined" — a common bug when JS undefined
66
+ // gets coerced to a string via template literals or String(undefined).
67
+ if (trimmed === "undefined" || trimmed === "null") {
68
+ return "";
69
+ }
70
+ return trimmed;
71
+ }
72
+ export function validateGatewayPasswordInput(value) {
73
+ if (typeof value !== "string") {
74
+ return "Required";
75
+ }
76
+ const trimmed = value.trim();
77
+ if (!trimmed) {
78
+ return "Required";
79
+ }
80
+ if (trimmed === "undefined" || trimmed === "null") {
81
+ return 'Cannot be the literal string "undefined" or "null"';
82
+ }
83
+ return undefined;
84
+ }
54
85
  export function printWizardHeader(runtime) {
55
86
  const header = [
56
- "████░░░███░░░███░░█░░░░████░░░███░░▀█▀",
57
- "█░░░█░█░░░█░█░░░█░█░░░░█░░░█░█░░░█░░█░",
58
- "████░░█░░░█░█░░░█░█░░░░████░░█░░░█░░█░",
59
- "█░░░░░█░░░█░█░░░█░█░░░░█░░░█░█░░░█░░█░",
60
- "█░░░░░░███░░░███░░█████░████░░░███░░░█░",
61
- " 🎱 RACK 'EM UP 🎱",
87
+ "▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄",
88
+ "██░▄▄▄░██░▄▄░██░▄▄▄██░▀██░██░▄▄▀██░████░▄▄▀██░███░██",
89
+ "██░███░██░▀▀░██░▄▄▄██░█░█░██░█████░████░▀▀░██░█░█░██",
90
+ "██░▀▀▀░██░█████░▀▀▀██░██▄░██░▀▀▄██░▀▀░█░██░██▄▀▄▀▄██",
91
+ "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀",
92
+ " 🦞 POOL BOT 🦞 ",
93
+ " ",
62
94
  ].join("\n");
63
95
  runtime.log(header);
64
96
  }
@@ -103,10 +135,12 @@ export async function resolveBrowserOpenCommand() {
103
135
  }
104
136
  if (wsl) {
105
137
  const hasWslview = await detectBinary("wslview");
106
- if (hasWslview)
138
+ if (hasWslview) {
107
139
  return { argv: ["wslview"], command: "wslview" };
108
- if (!hasDisplay)
140
+ }
141
+ if (!hasDisplay) {
109
142
  return { argv: null, reason: "wsl-no-wslview" };
143
+ }
110
144
  }
111
145
  const hasXdgOpen = await detectBinary("xdg-open");
112
146
  return hasXdgOpen
@@ -117,16 +151,18 @@ export async function resolveBrowserOpenCommand() {
117
151
  }
118
152
  export async function detectBrowserOpenSupport() {
119
153
  const resolved = await resolveBrowserOpenCommand();
120
- if (!resolved.argv)
154
+ if (!resolved.argv) {
121
155
  return { ok: false, reason: resolved.reason };
156
+ }
122
157
  return { ok: true, command: resolved.command };
123
158
  }
124
159
  export function formatControlUiSshHint(params) {
125
160
  const basePath = normalizeControlUiBasePath(params.basePath);
126
161
  const uiPath = basePath ? `${basePath}/` : "/";
127
162
  const localUrl = `http://localhost:${params.port}${uiPath}`;
128
- const tokenParam = params.token ? `?token=${encodeURIComponent(params.token)}` : "";
129
- const authedUrl = params.token ? `${localUrl}${tokenParam}` : undefined;
163
+ const authedUrl = params.token
164
+ ? `${localUrl}#token=${encodeURIComponent(params.token)}`
165
+ : undefined;
130
166
  const sshTarget = resolveSshTargetHint();
131
167
  return [
132
168
  "No GUI detected. Open from your computer:",
@@ -135,8 +171,8 @@ export function formatControlUiSshHint(params) {
135
171
  localUrl,
136
172
  authedUrl,
137
173
  "Docs:",
138
- "https://docs.molt.bot/gateway/remote",
139
- "https://docs.molt.bot/web/control-ui",
174
+ "https://docs.poolbot.ai/gateway/remote",
175
+ "https://docs.poolbot.ai/web/control-ui",
140
176
  ]
141
177
  .filter(Boolean)
142
178
  .join("\n");
@@ -148,11 +184,13 @@ function resolveSshTargetHint() {
148
184
  return `${user}@${host}`;
149
185
  }
150
186
  export async function openUrl(url) {
151
- if (shouldSkipBrowserOpenInTests())
187
+ if (shouldSkipBrowserOpenInTests()) {
152
188
  return false;
189
+ }
153
190
  const resolved = await resolveBrowserOpenCommand();
154
- if (!resolved.argv)
191
+ if (!resolved.argv) {
155
192
  return false;
193
+ }
156
194
  const quoteUrl = resolved.quoteUrl === true;
157
195
  const command = [...resolved.argv];
158
196
  if (quoteUrl) {
@@ -178,13 +216,16 @@ export async function openUrl(url) {
178
216
  }
179
217
  }
180
218
  export async function openUrlInBackground(url) {
181
- if (shouldSkipBrowserOpenInTests())
219
+ if (shouldSkipBrowserOpenInTests()) {
182
220
  return false;
183
- if (process.platform !== "darwin")
221
+ }
222
+ if (process.platform !== "darwin") {
184
223
  return false;
224
+ }
185
225
  const resolved = await resolveBrowserOpenCommand();
186
- if (!resolved.argv || resolved.command !== "open")
226
+ if (!resolved.argv || resolved.command !== "open") {
187
227
  return false;
228
+ }
188
229
  const command = ["open", "-g", url];
189
230
  try {
190
231
  await runCommandWithTimeout(command, { timeoutMs: 5_000 });
@@ -212,8 +253,9 @@ export function resolveNodeManagerOptions() {
212
253
  ];
213
254
  }
214
255
  export async function moveToTrash(pathname, runtime) {
215
- if (!pathname)
256
+ if (!pathname) {
216
257
  return;
258
+ }
217
259
  try {
218
260
  await fs.access(pathname);
219
261
  }
@@ -230,8 +272,9 @@ export async function moveToTrash(pathname, runtime) {
230
272
  }
231
273
  export async function handleReset(scope, workspaceDir, runtime) {
232
274
  await moveToTrash(CONFIG_PATH, runtime);
233
- if (scope === "config")
275
+ if (scope === "config") {
234
276
  return;
277
+ }
235
278
  await moveToTrash(path.join(CONFIG_DIR, "credentials"), runtime);
236
279
  await moveToTrash(resolveSessionTranscriptsDirForAgent(), runtime);
237
280
  if (scope === "full") {
@@ -239,10 +282,12 @@ export async function handleReset(scope, workspaceDir, runtime) {
239
282
  }
240
283
  }
241
284
  export async function detectBinary(name) {
242
- if (!name?.trim())
285
+ if (!name?.trim()) {
243
286
  return false;
244
- if (!isSafeExecutableValue(name))
287
+ }
288
+ if (!isSafeExecutableValue(name)) {
245
289
  return false;
290
+ }
246
291
  const resolved = name.startsWith("~") ? resolveUserPath(name) : name;
247
292
  if (path.isAbsolute(resolved) ||
248
293
  resolved.startsWith(".") ||
@@ -266,8 +311,9 @@ export async function detectBinary(name) {
266
311
  }
267
312
  }
268
313
  function shouldSkipBrowserOpenInTests() {
269
- if (process.env.VITEST)
314
+ if (process.env.VITEST) {
270
315
  return true;
316
+ }
271
317
  return process.env.NODE_ENV === "test";
272
318
  }
273
319
  export async function probeGatewayReachable(params) {
@@ -302,8 +348,9 @@ export async function waitForGatewayReachable(params) {
302
348
  password: params.password,
303
349
  timeoutMs: probeTimeoutMs,
304
350
  });
305
- if (probe.ok)
351
+ if (probe.ok) {
306
352
  return probe;
353
+ }
307
354
  lastDetail = probe.detail;
308
355
  await sleep(pollMs);
309
356
  }
@@ -336,8 +383,12 @@ export function resolveControlUiLinks(params) {
336
383
  if (bind === "custom" && customBindHost && isValidIPv4(customBindHost)) {
337
384
  return customBindHost;
338
385
  }
339
- if (bind === "tailnet" && tailnetIPv4)
386
+ if (bind === "tailnet" && tailnetIPv4) {
340
387
  return tailnetIPv4 ?? "127.0.0.1";
388
+ }
389
+ if (bind === "lan") {
390
+ return pickPrimaryLanIPv4() ?? "127.0.0.1";
391
+ }
341
392
  return "127.0.0.1";
342
393
  })();
343
394
  const basePath = normalizeControlUiBasePath(params.basePath);
@@ -348,12 +399,3 @@ export function resolveControlUiLinks(params) {
348
399
  wsUrl: `ws://${host}:${port}${wsPath}`,
349
400
  };
350
401
  }
351
- function isValidIPv4(host) {
352
- const parts = host.split(".");
353
- if (parts.length !== 4)
354
- return false;
355
- return parts.every((part) => {
356
- const n = Number.parseInt(part, 10);
357
- return !Number.isNaN(n) && n >= 0 && n <= 255 && part === String(n);
358
- });
359
- }
@@ -34,7 +34,7 @@ export async function loginOpenAICodexOAuth(params) {
34
34
  catch (err) {
35
35
  spin.stop("OpenAI OAuth failed");
36
36
  runtime.error(String(err));
37
- await prompter.note("Trouble with OAuth? See https://docs.openclaw.ai/start/faq", "OAuth help");
37
+ await prompter.note("Trouble with OAuth? See https://docs.poolbot.dev/start/faq", "OAuth help");
38
38
  throw err;
39
39
  }
40
40
  }
@@ -2,8 +2,11 @@ import { lookupContextTokens } from "../agents/context.js";
2
2
  import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL, DEFAULT_PROVIDER } from "../agents/defaults.js";
3
3
  import { resolveConfiguredModelRef } from "../agents/model-selection.js";
4
4
  import { loadConfig } from "../config/config.js";
5
- import { loadSessionStore, resolveStorePath } from "../config/sessions.js";
5
+ import { loadSessionStore, resolveFreshSessionTotalTokens, resolveStorePath, } from "../config/sessions.js";
6
+ import { classifySessionKey, resolveSessionModelRef } from "../gateway/session-utils.js";
6
7
  import { info } from "../globals.js";
8
+ import { formatTimeAgo } from "../infra/format-time/format-relative.js";
9
+ import { parseAgentSessionKey } from "../routing/session-key.js";
7
10
  import { isRich, theme } from "../terminal/theme.js";
8
11
  const KIND_PAD = 6;
9
12
  const KEY_PAD = 26;
@@ -12,25 +15,33 @@ const MODEL_PAD = 14;
12
15
  const TOKENS_PAD = 20;
13
16
  const formatKTokens = (value) => `${(value / 1000).toFixed(value >= 10_000 ? 0 : 1)}k`;
14
17
  const truncateKey = (key) => {
15
- if (key.length <= KEY_PAD)
18
+ if (key.length <= KEY_PAD) {
16
19
  return key;
20
+ }
17
21
  const head = Math.max(4, KEY_PAD - 10);
18
22
  return `${key.slice(0, head)}...${key.slice(-6)}`;
19
23
  };
20
24
  const colorByPct = (label, pct, rich) => {
21
- if (!rich || pct === null)
25
+ if (!rich || pct === null) {
22
26
  return label;
23
- if (pct >= 95)
27
+ }
28
+ if (pct >= 95) {
24
29
  return theme.error(label);
25
- if (pct >= 80)
30
+ }
31
+ if (pct >= 80) {
26
32
  return theme.warn(label);
27
- if (pct >= 60)
33
+ }
34
+ if (pct >= 60) {
28
35
  return theme.success(label);
36
+ }
29
37
  return theme.muted(label);
30
38
  };
31
39
  const formatTokensCell = (total, contextTokens, rich) => {
32
- if (!total)
33
- return "-".padEnd(TOKENS_PAD);
40
+ if (total === undefined) {
41
+ const ctxLabel = contextTokens ? formatKTokens(contextTokens) : "?";
42
+ const label = `unknown/${ctxLabel} (?%)`;
43
+ return rich ? theme.muted(label.padEnd(TOKENS_PAD)) : label.padEnd(TOKENS_PAD);
44
+ }
34
45
  const totalLabel = formatKTokens(total);
35
46
  const ctxLabel = contextTokens ? formatKTokens(contextTokens) : "?";
36
47
  const pct = contextTokens ? Math.min(999, Math.round((total / contextTokens) * 100)) : null;
@@ -40,18 +51,22 @@ const formatTokensCell = (total, contextTokens, rich) => {
40
51
  };
41
52
  const formatKindCell = (kind, rich) => {
42
53
  const label = kind.padEnd(KIND_PAD);
43
- if (!rich)
54
+ if (!rich) {
44
55
  return label;
45
- if (kind === "group")
56
+ }
57
+ if (kind === "group") {
46
58
  return theme.accentBright(label);
47
- if (kind === "global")
59
+ }
60
+ if (kind === "global") {
48
61
  return theme.warn(label);
49
- if (kind === "direct")
62
+ }
63
+ if (kind === "direct") {
50
64
  return theme.accent(label);
65
+ }
51
66
  return theme.muted(label);
52
67
  };
53
68
  const formatAgeCell = (updatedAt, rich) => {
54
- const ageLabel = updatedAt ? formatAge(Date.now() - updatedAt) : "unknown";
69
+ const ageLabel = updatedAt ? formatTimeAgo(Date.now() - updatedAt) : "unknown";
55
70
  const padded = ageLabel.padEnd(AGE_PAD);
56
71
  return rich ? theme.muted(padded) : padded;
57
72
  };
@@ -74,40 +89,13 @@ const formatFlagsCell = (row, rich) => {
74
89
  const label = flags.join(" ");
75
90
  return label.length === 0 ? "" : rich ? theme.muted(label) : label;
76
91
  };
77
- const formatAge = (ms) => {
78
- if (!ms || ms < 0)
79
- return "unknown";
80
- const minutes = Math.round(ms / 60_000);
81
- if (minutes < 1)
82
- return "just now";
83
- if (minutes < 60)
84
- return `${minutes}m ago`;
85
- const hours = Math.round(minutes / 60);
86
- if (hours < 48)
87
- return `${hours}h ago`;
88
- const days = Math.round(hours / 24);
89
- return `${days}d ago`;
90
- };
91
- function classifyKey(key, entry) {
92
- if (key === "global")
93
- return "global";
94
- if (key === "unknown")
95
- return "unknown";
96
- if (entry?.chatType === "group" || entry?.chatType === "channel") {
97
- return "group";
98
- }
99
- if (key.includes(":group:") || key.includes(":channel:")) {
100
- return "group";
101
- }
102
- return "direct";
103
- }
104
92
  function toRows(store) {
105
93
  return Object.entries(store)
106
94
  .map(([key, entry]) => {
107
95
  const updatedAt = entry?.updatedAt ?? null;
108
96
  return {
109
97
  key,
110
- kind: classifyKey(key, entry),
98
+ kind: classifySessionKey(key, entry),
111
99
  updatedAt,
112
100
  ageMs: updatedAt ? Date.now() - updatedAt : null,
113
101
  sessionId: entry?.sessionId,
@@ -122,11 +110,15 @@ function toRows(store) {
122
110
  inputTokens: entry?.inputTokens,
123
111
  outputTokens: entry?.outputTokens,
124
112
  totalTokens: entry?.totalTokens,
113
+ totalTokensFresh: entry?.totalTokensFresh,
125
114
  model: entry?.model,
115
+ modelProvider: entry?.modelProvider,
116
+ providerOverride: entry?.providerOverride,
117
+ modelOverride: entry?.modelOverride,
126
118
  contextTokens: entry?.contextTokens,
127
119
  };
128
120
  })
129
- .sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
121
+ .toSorted((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
130
122
  }
131
123
  export async function sessionsCommand(opts, runtime) {
132
124
  const cfg = loadConfig();
@@ -152,10 +144,12 @@ export async function sessionsCommand(opts, runtime) {
152
144
  activeMinutes = parsed;
153
145
  }
154
146
  const rows = toRows(store).filter((row) => {
155
- if (activeMinutes === undefined)
147
+ if (activeMinutes === undefined) {
156
148
  return true;
157
- if (!row.updatedAt)
149
+ }
150
+ if (!row.updatedAt) {
158
151
  return false;
152
+ }
159
153
  return Date.now() - row.updatedAt <= activeMinutes * 60_000;
160
154
  });
161
155
  if (opts.json) {
@@ -163,11 +157,17 @@ export async function sessionsCommand(opts, runtime) {
163
157
  path: storePath,
164
158
  count: rows.length,
165
159
  activeMinutes: activeMinutes ?? null,
166
- sessions: rows.map((r) => ({
167
- ...r,
168
- contextTokens: r.contextTokens ?? lookupContextTokens(r.model) ?? configContextTokens ?? null,
169
- model: r.model ?? configModel ?? null,
170
- })),
160
+ sessions: rows.map((r) => {
161
+ const resolvedModel = resolveSessionModelRef(cfg, r, parseAgentSessionKey(r.key)?.agentId);
162
+ const model = resolvedModel.model ?? configModel;
163
+ return {
164
+ ...r,
165
+ totalTokens: resolveFreshSessionTotalTokens(r) ?? null,
166
+ totalTokensFresh: typeof r.totalTokens === "number" ? r.totalTokensFresh !== false : false,
167
+ contextTokens: r.contextTokens ?? lookupContextTokens(model) ?? configContextTokens ?? null,
168
+ model,
169
+ };
170
+ }),
171
171
  }, null, 2));
172
172
  return;
173
173
  }
@@ -191,11 +191,10 @@ export async function sessionsCommand(opts, runtime) {
191
191
  ].join(" ");
192
192
  runtime.log(rich ? theme.heading(header) : header);
193
193
  for (const row of rows) {
194
- const model = row.model ?? configModel;
194
+ const resolvedModel = resolveSessionModelRef(cfg, row, parseAgentSessionKey(row.key)?.agentId);
195
+ const model = resolvedModel.model ?? configModel;
195
196
  const contextTokens = row.contextTokens ?? lookupContextTokens(model) ?? configContextTokens;
196
- const input = row.inputTokens ?? 0;
197
- const output = row.outputTokens ?? 0;
198
- const total = row.totalTokens ?? input + output;
197
+ const total = resolveFreshSessionTotalTokens(row);
199
198
  const keyLabel = truncateKey(row.key).padEnd(KEY_PAD);
200
199
  const keyCell = rich ? theme.accent(keyLabel) : keyLabel;
201
200
  const line = [
@@ -2,52 +2,67 @@ import { lookupContextTokens } from "../agents/context.js";
2
2
  import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL, DEFAULT_PROVIDER } from "../agents/defaults.js";
3
3
  import { resolveConfiguredModelRef } from "../agents/model-selection.js";
4
4
  import { loadConfig } from "../config/config.js";
5
- import { loadSessionStore, resolveMainSessionKey, resolveStorePath, } from "../config/sessions.js";
6
- import { listAgentsForGateway } from "../gateway/session-utils.js";
5
+ import { loadSessionStore, resolveFreshSessionTotalTokens, resolveMainSessionKey, resolveStorePath, } from "../config/sessions.js";
6
+ import { classifySessionKey, listAgentsForGateway, resolveSessionModelRef, } from "../gateway/session-utils.js";
7
7
  import { buildChannelSummary } from "../infra/channel-summary.js";
8
8
  import { resolveHeartbeatSummaryForAgent } from "../infra/heartbeat-runner.js";
9
9
  import { peekSystemEvents } from "../infra/system-events.js";
10
10
  import { parseAgentSessionKey } from "../routing/session-key.js";
11
11
  import { resolveLinkChannelContext } from "./status.link-channel.js";
12
- const classifyKey = (key, entry) => {
13
- if (key === "global")
14
- return "global";
15
- if (key === "unknown")
16
- return "unknown";
17
- if (entry?.chatType === "group" || entry?.chatType === "channel") {
18
- return "group";
19
- }
20
- if (key.includes(":group:") || key.includes(":channel:")) {
21
- return "group";
22
- }
23
- return "direct";
24
- };
25
12
  const buildFlags = (entry) => {
26
- if (!entry)
13
+ if (!entry) {
27
14
  return [];
15
+ }
28
16
  const flags = [];
29
17
  const think = entry?.thinkingLevel;
30
- if (typeof think === "string" && think.length > 0)
18
+ if (typeof think === "string" && think.length > 0) {
31
19
  flags.push(`think:${think}`);
20
+ }
32
21
  const verbose = entry?.verboseLevel;
33
- if (typeof verbose === "string" && verbose.length > 0)
22
+ if (typeof verbose === "string" && verbose.length > 0) {
34
23
  flags.push(`verbose:${verbose}`);
24
+ }
35
25
  const reasoning = entry?.reasoningLevel;
36
- if (typeof reasoning === "string" && reasoning.length > 0)
26
+ if (typeof reasoning === "string" && reasoning.length > 0) {
37
27
  flags.push(`reasoning:${reasoning}`);
28
+ }
38
29
  const elevated = entry?.elevatedLevel;
39
- if (typeof elevated === "string" && elevated.length > 0)
30
+ if (typeof elevated === "string" && elevated.length > 0) {
40
31
  flags.push(`elevated:${elevated}`);
41
- if (entry?.systemSent)
32
+ }
33
+ if (entry?.systemSent) {
42
34
  flags.push("system");
43
- if (entry?.abortedLastRun)
35
+ }
36
+ if (entry?.abortedLastRun) {
44
37
  flags.push("aborted");
38
+ }
45
39
  const sessionId = entry?.sessionId;
46
- if (typeof sessionId === "string" && sessionId.length > 0)
40
+ if (typeof sessionId === "string" && sessionId.length > 0) {
47
41
  flags.push(`id:${sessionId}`);
42
+ }
48
43
  return flags;
49
44
  };
50
- export async function getStatusSummary() {
45
+ export function redactSensitiveStatusSummary(summary) {
46
+ return {
47
+ ...summary,
48
+ sessions: {
49
+ ...summary.sessions,
50
+ paths: [],
51
+ defaults: {
52
+ model: null,
53
+ contextTokens: null,
54
+ },
55
+ recent: [],
56
+ byAgent: summary.sessions.byAgent.map((entry) => ({
57
+ ...entry,
58
+ path: "[redacted]",
59
+ recent: [],
60
+ })),
61
+ },
62
+ };
63
+ }
64
+ export async function getStatusSummary(options = {}) {
65
+ const { includeSensitive = true } = options;
51
66
  const cfg = loadConfig();
52
67
  const linkContext = await resolveLinkChannelContext(cfg);
53
68
  const agentList = listAgentsForGateway(cfg);
@@ -79,8 +94,9 @@ export async function getStatusSummary() {
79
94
  const storeCache = new Map();
80
95
  const loadStore = (storePath) => {
81
96
  const cached = storeCache.get(storePath);
82
- if (cached)
97
+ if (cached) {
83
98
  return cached;
99
+ }
84
100
  const store = loadSessionStore(storePath);
85
101
  storeCache.set(storePath, store);
86
102
  return store;
@@ -90,13 +106,13 @@ export async function getStatusSummary() {
90
106
  .map(([key, entry]) => {
91
107
  const updatedAt = entry?.updatedAt ?? null;
92
108
  const age = updatedAt ? now - updatedAt : null;
93
- const model = entry?.model ?? configModel ?? null;
109
+ const resolvedModel = resolveSessionModelRef(cfg, entry, opts.agentIdOverride);
110
+ const model = resolvedModel.model ?? configModel ?? null;
94
111
  const contextTokens = entry?.contextTokens ?? lookupContextTokens(model) ?? configContextTokens ?? null;
95
- const input = entry?.inputTokens ?? 0;
96
- const output = entry?.outputTokens ?? 0;
97
- const total = entry?.totalTokens ?? input + output;
98
- const remaining = contextTokens != null ? Math.max(0, contextTokens - total) : null;
99
- const pct = contextTokens && contextTokens > 0
112
+ const total = resolveFreshSessionTotalTokens(entry);
113
+ const totalTokensFresh = typeof entry?.totalTokens === "number" ? entry?.totalTokensFresh !== false : false;
114
+ const remaining = contextTokens != null && total !== undefined ? Math.max(0, contextTokens - total) : null;
115
+ const pct = contextTokens && contextTokens > 0 && total !== undefined
100
116
  ? Math.min(999, Math.round((total / contextTokens) * 100))
101
117
  : null;
102
118
  const parsedAgentId = parseAgentSessionKey(key)?.agentId;
@@ -104,7 +120,7 @@ export async function getStatusSummary() {
104
120
  return {
105
121
  agentId,
106
122
  key,
107
- kind: classifyKey(key, entry),
123
+ kind: classifySessionKey(key, entry),
108
124
  sessionId: entry?.sessionId,
109
125
  updatedAt,
110
126
  age,
@@ -117,6 +133,7 @@ export async function getStatusSummary() {
117
133
  inputTokens: entry?.inputTokens,
118
134
  outputTokens: entry?.outputTokens,
119
135
  totalTokens: total ?? null,
136
+ totalTokensFresh,
120
137
  remainingTokens: remaining,
121
138
  percentUsed: pct,
122
139
  model,
@@ -140,10 +157,10 @@ export async function getStatusSummary() {
140
157
  });
141
158
  const allSessions = Array.from(paths)
142
159
  .flatMap((storePath) => buildSessionRows(loadStore(storePath)))
143
- .sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
160
+ .toSorted((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
144
161
  const recent = allSessions.slice(0, 10);
145
162
  const totalSessions = allSessions.length;
146
- return {
163
+ const summary = {
147
164
  linkChannel: linkContext
148
165
  ? {
149
166
  id: linkContext.plugin.id,
@@ -169,4 +186,5 @@ export async function getStatusSummary() {
169
186
  byAgent,
170
187
  },
171
188
  };
189
+ return includeSensitive ? summary : redactSensitiveStatusSummary(summary);
172
190
  }
@@ -27,7 +27,7 @@ export function createWizardPrompter(overrides, options) {
27
27
  ...overrides,
28
28
  };
29
29
  }
30
- export async function setupAuthTestEnv(prefix = "openclaw-auth-", options) {
30
+ export async function setupAuthTestEnv(prefix = "poolbot-auth-", options) {
31
31
  const stateDir = await makeTempWorkspace(prefix);
32
32
  const agentDir = path.join(stateDir, options?.agentSubdir ?? "agent");
33
33
  process.env.POOLBOT_STATE_DIR = stateDir;
@@ -52,7 +52,7 @@ export function createAuthTestLifecycle(envKeys) {
52
52
  },
53
53
  };
54
54
  }
55
- export function requireOpenClawAgentDir() {
55
+ export function requirePoolbotAgentDir() {
56
56
  const agentDir = process.env.POOLBOT_AGENT_DIR;
57
57
  if (!agentDir) {
58
58
  throw new Error("POOLBOT_AGENT_DIR not set");