@poolzin/pool-bot 2026.2.23 → 2026.2.25

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 (235) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/acp/client.js +207 -18
  3. package/dist/acp/secret-file.js +22 -0
  4. package/dist/agents/agent-scope.js +10 -0
  5. package/dist/agents/bash-process-registry.test-helpers.js +29 -0
  6. package/dist/agents/bash-tools.exec-approval-request.js +20 -0
  7. package/dist/agents/bash-tools.exec-host-gateway.js +230 -0
  8. package/dist/agents/bash-tools.exec-host-node.js +235 -0
  9. package/dist/agents/bash-tools.exec-types.js +1 -0
  10. package/dist/agents/bash-tools.process.js +224 -218
  11. package/dist/agents/content-blocks.js +16 -0
  12. package/dist/agents/model-fallback.js +96 -101
  13. package/dist/agents/models-config.providers.js +299 -182
  14. package/dist/agents/pi-embedded-payloads.js +1 -0
  15. package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +34 -0
  16. package/dist/agents/skills.test-helpers.js +13 -0
  17. package/dist/agents/stable-stringify.js +12 -0
  18. package/dist/agents/subagent-registry.mocks.shared.js +12 -0
  19. package/dist/agents/test-helpers/assistant-message-fixtures.js +29 -0
  20. package/dist/agents/test-helpers/pi-tools-sandbox-context.js +27 -0
  21. package/dist/agents/tool-policy-shared.js +108 -0
  22. package/dist/agents/tools/browser-tool.js +160 -54
  23. package/dist/agents/tools/cron-tool.test-helpers.js +12 -0
  24. package/dist/agents/tools/discord-actions-moderation-shared.js +27 -0
  25. package/dist/agents/tools/image-tool.js +214 -99
  26. package/dist/agents/tools/sessions-history-tool.js +140 -108
  27. package/dist/agents/workspace.js +222 -46
  28. package/dist/auto-reply/commands-registry.js +15 -18
  29. package/dist/auto-reply/fallback-state.js +114 -0
  30. package/dist/auto-reply/model-runtime.js +68 -0
  31. package/dist/auto-reply/reply/agent-runner-execution.js +36 -4
  32. package/dist/auto-reply/reply/agent-runner.js +165 -39
  33. package/dist/auto-reply/reply/commands-setunset-standard.js +13 -0
  34. package/dist/browser/config.js +26 -0
  35. package/dist/browser/navigation-guard.js +31 -0
  36. package/dist/browser/routes/agent.act.js +431 -424
  37. package/dist/browser/routes/agent.shared.js +47 -3
  38. package/dist/browser/routes/agent.snapshot.js +122 -116
  39. package/dist/browser/routes/agent.storage.js +303 -297
  40. package/dist/browser/routes/tabs.js +154 -100
  41. package/dist/browser/server-lifecycle.js +37 -0
  42. package/dist/build-info.json +3 -3
  43. package/dist/channels/allow-from.js +25 -0
  44. package/dist/channels/plugins/account-action-gate.js +13 -0
  45. package/dist/channels/plugins/message-actions.js +10 -0
  46. package/dist/channels/telegram/api.js +18 -0
  47. package/dist/cli/argv.js +84 -21
  48. package/dist/cli/banner.js +2 -1
  49. package/dist/cli/exec-approvals-cli.js +92 -124
  50. package/dist/cli/memory-cli.js +158 -61
  51. package/dist/cli/nodes-cli/register.push.js +63 -0
  52. package/dist/cli/nodes-media-utils.js +21 -0
  53. package/dist/cli/plugins-cli.js +245 -61
  54. package/dist/cli/program/build-program.js +3 -1
  55. package/dist/cli/program/command-registry.js +223 -136
  56. package/dist/cli/program/help.js +43 -12
  57. package/dist/cli/route.js +1 -1
  58. package/dist/cli/test-runtime-capture.js +24 -0
  59. package/dist/commands/agent.js +163 -87
  60. package/dist/commands/channels.mock-harness.js +23 -0
  61. package/dist/commands/daemon-install-runtime-warning.js +11 -0
  62. package/dist/commands/onboard-helpers.js +4 -4
  63. package/dist/commands/sessions.test-helpers.js +61 -0
  64. package/dist/compat/legacy-names.js +2 -2
  65. package/dist/config/commands.js +3 -0
  66. package/dist/config/config.js +1 -1
  67. package/dist/config/env-substitution.js +62 -34
  68. package/dist/config/env-vars.js +9 -0
  69. package/dist/config/io.js +571 -171
  70. package/dist/config/merge-patch.js +50 -4
  71. package/dist/config/redact-snapshot.js +404 -76
  72. package/dist/config/schema.js +58 -570
  73. package/dist/config/validation.js +140 -85
  74. package/dist/config/zod-schema.hooks.js +40 -11
  75. package/dist/config/zod-schema.installs.js +20 -0
  76. package/dist/config/zod-schema.js +8 -7
  77. package/dist/control-ui/assets/{index-HRr1grwl.js → index-Dvkl4Xlx.js} +2 -1
  78. package/dist/control-ui/assets/{index-HRr1grwl.js.map → index-Dvkl4Xlx.js.map} +1 -1
  79. package/dist/control-ui/index.html +1 -1
  80. package/dist/daemon/cmd-argv.js +21 -0
  81. package/dist/daemon/cmd-set.js +58 -0
  82. package/dist/daemon/service-types.js +1 -0
  83. package/dist/discord/monitor/exec-approvals.js +357 -162
  84. package/dist/gateway/auth.js +38 -3
  85. package/dist/gateway/call.js +149 -68
  86. package/dist/gateway/canvas-capability.js +75 -0
  87. package/dist/gateway/control-plane-audit.js +28 -0
  88. package/dist/gateway/control-plane-rate-limit.js +53 -0
  89. package/dist/gateway/events.js +1 -0
  90. package/dist/gateway/hooks.js +109 -54
  91. package/dist/gateway/http-common.js +22 -0
  92. package/dist/gateway/method-scopes.js +169 -0
  93. package/dist/gateway/net.js +23 -0
  94. package/dist/gateway/openresponses-http.js +120 -110
  95. package/dist/gateway/probe-auth.js +2 -0
  96. package/dist/gateway/protocol/index.js +3 -2
  97. package/dist/gateway/protocol/schema/protocol-schemas.js +2 -0
  98. package/dist/gateway/protocol/schema/push.js +18 -0
  99. package/dist/gateway/protocol/schema.js +1 -0
  100. package/dist/gateway/server-http.js +236 -52
  101. package/dist/gateway/server-methods/agent.js +162 -24
  102. package/dist/gateway/server-methods/chat.js +461 -130
  103. package/dist/gateway/server-methods/config.js +193 -150
  104. package/dist/gateway/server-methods/nodes.helpers.js +12 -0
  105. package/dist/gateway/server-methods/nodes.js +251 -69
  106. package/dist/gateway/server-methods/push.js +53 -0
  107. package/dist/gateway/server-reload-handlers.js +2 -3
  108. package/dist/gateway/server-runtime-config.js +5 -0
  109. package/dist/gateway/server-runtime-state.js +2 -0
  110. package/dist/gateway/server-ws-runtime.js +1 -0
  111. package/dist/gateway/server.impl.js +296 -139
  112. package/dist/gateway/session-preview.test-helpers.js +11 -0
  113. package/dist/gateway/startup-auth.js +126 -0
  114. package/dist/gateway/test-helpers.agent-results.js +15 -0
  115. package/dist/gateway/test-helpers.mocks.js +37 -14
  116. package/dist/gateway/test-helpers.server.js +161 -77
  117. package/dist/hooks/bundled/session-memory/handler.js +165 -34
  118. package/dist/hooks/gmail-watcher-lifecycle.js +23 -0
  119. package/dist/infra/archive-path.js +49 -0
  120. package/dist/infra/device-pairing.js +148 -167
  121. package/dist/infra/exec-approvals-allowlist.js +19 -70
  122. package/dist/infra/exec-approvals-analysis.js +44 -17
  123. package/dist/infra/exec-safe-bin-policy.js +269 -0
  124. package/dist/infra/fixed-window-rate-limit.js +33 -0
  125. package/dist/infra/git-root.js +61 -0
  126. package/dist/infra/heartbeat-active-hours.js +2 -2
  127. package/dist/infra/heartbeat-reason.js +40 -0
  128. package/dist/infra/heartbeat-runner.js +72 -32
  129. package/dist/infra/install-source-utils.js +91 -7
  130. package/dist/infra/node-pairing.js +50 -105
  131. package/dist/infra/npm-integrity.js +45 -0
  132. package/dist/infra/npm-pack-install.js +40 -0
  133. package/dist/infra/outbound/channel-adapters.js +20 -7
  134. package/dist/infra/outbound/message-action-runner.js +107 -327
  135. package/dist/infra/outbound/message.js +59 -36
  136. package/dist/infra/outbound/outbound-policy.js +52 -25
  137. package/dist/infra/outbound/outbound-send-service.js +58 -71
  138. package/dist/infra/pairing-files.js +10 -0
  139. package/dist/infra/plain-object.js +9 -0
  140. package/dist/infra/push-apns.js +365 -0
  141. package/dist/infra/restart-sentinel.js +16 -1
  142. package/dist/infra/restart.js +229 -26
  143. package/dist/infra/scp-host.js +54 -0
  144. package/dist/infra/update-startup.js +86 -9
  145. package/dist/media/inbound-path-policy.js +114 -0
  146. package/dist/media/input-files.js +16 -0
  147. package/dist/memory/test-manager.js +8 -0
  148. package/dist/plugin-sdk/temp-path.js +47 -0
  149. package/dist/plugins/discovery.js +217 -23
  150. package/dist/plugins/hook-runner-global.js +16 -0
  151. package/dist/plugins/loader.js +192 -26
  152. package/dist/plugins/logger.js +8 -0
  153. package/dist/plugins/manifest-registry.js +3 -0
  154. package/dist/plugins/path-safety.js +34 -0
  155. package/dist/plugins/registry.js +5 -2
  156. package/dist/plugins/runtime/index.js +271 -206
  157. package/dist/providers/github-copilot-models.js +4 -1
  158. package/dist/security/audit-channel.js +8 -19
  159. package/dist/security/audit-extra.async.js +354 -182
  160. package/dist/security/audit-extra.js +11 -1
  161. package/dist/security/audit-extra.sync.js +340 -33
  162. package/dist/security/audit-fs.js +31 -13
  163. package/dist/security/audit.js +145 -371
  164. package/dist/security/dm-policy-shared.js +24 -0
  165. package/dist/security/external-content.js +20 -8
  166. package/dist/security/fix.js +49 -85
  167. package/dist/security/scan-paths.js +20 -0
  168. package/dist/security/secret-equal.js +3 -7
  169. package/dist/security/windows-acl.js +30 -15
  170. package/dist/shared/node-list-parse.js +13 -0
  171. package/dist/shared/operator-scope-compat.js +37 -0
  172. package/dist/shared/text-chunking.js +29 -0
  173. package/dist/slack/blocks.test-helpers.js +31 -0
  174. package/dist/slack/monitor/mrkdwn.js +8 -0
  175. package/dist/telegram/bot-message-dispatch.js +366 -164
  176. package/dist/telegram/draft-stream.js +30 -7
  177. package/dist/telegram/reasoning-lane-coordinator.js +128 -0
  178. package/dist/terminal/prompt-select-styled.js +9 -0
  179. package/dist/test-utils/command-runner.js +6 -0
  180. package/dist/test-utils/internal-hook-event-payload.js +10 -0
  181. package/dist/test-utils/model-auth-mock.js +12 -0
  182. package/dist/test-utils/provider-usage-fetch.js +14 -0
  183. package/dist/test-utils/temp-home.js +33 -0
  184. package/dist/tui/components/chat-log.js +9 -0
  185. package/dist/tui/tui-command-handlers.js +36 -27
  186. package/dist/tui/tui-event-handlers.js +122 -32
  187. package/dist/tui/tui.js +181 -45
  188. package/dist/utils/mask-api-key.js +10 -0
  189. package/dist/utils/run-with-concurrency.js +39 -0
  190. package/dist/web/media.js +4 -0
  191. package/docs/tools/slash-commands.md +5 -1
  192. package/extensions/bluebubbles/package.json +1 -1
  193. package/extensions/copilot-proxy/package.json +1 -1
  194. package/extensions/diagnostics-otel/package.json +1 -1
  195. package/extensions/discord/package.json +1 -1
  196. package/extensions/feishu/package.json +1 -1
  197. package/extensions/feishu/src/external-keys.ts +19 -0
  198. package/extensions/google-antigravity-auth/package.json +1 -1
  199. package/extensions/google-gemini-cli-auth/package.json +1 -1
  200. package/extensions/googlechat/package.json +1 -1
  201. package/extensions/imessage/package.json +1 -1
  202. package/extensions/irc/package.json +1 -1
  203. package/extensions/line/package.json +1 -1
  204. package/extensions/llm-task/package.json +1 -1
  205. package/extensions/lobster/package.json +1 -1
  206. package/extensions/lobster/src/windows-spawn.ts +193 -0
  207. package/extensions/matrix/CHANGELOG.md +5 -0
  208. package/extensions/matrix/package.json +1 -1
  209. package/extensions/matrix/src/matrix/actions/limits.ts +6 -0
  210. package/extensions/mattermost/package.json +1 -1
  211. package/extensions/mattermost/src/mattermost/reactions.test-helpers.ts +83 -0
  212. package/extensions/memory-core/package.json +1 -1
  213. package/extensions/memory-lancedb/package.json +1 -1
  214. package/extensions/minimax-portal-auth/package.json +1 -1
  215. package/extensions/msteams/CHANGELOG.md +5 -0
  216. package/extensions/msteams/package.json +1 -1
  217. package/extensions/nextcloud-talk/package.json +1 -1
  218. package/extensions/nostr/CHANGELOG.md +5 -0
  219. package/extensions/nostr/package.json +1 -1
  220. package/extensions/open-prose/package.json +1 -1
  221. package/extensions/openai-codex-auth/package.json +1 -1
  222. package/extensions/signal/package.json +1 -1
  223. package/extensions/slack/package.json +1 -1
  224. package/extensions/telegram/package.json +1 -1
  225. package/extensions/tlon/package.json +1 -1
  226. package/extensions/twitch/CHANGELOG.md +5 -0
  227. package/extensions/twitch/package.json +1 -1
  228. package/extensions/voice-call/CHANGELOG.md +5 -0
  229. package/extensions/voice-call/package.json +1 -1
  230. package/extensions/whatsapp/package.json +1 -1
  231. package/extensions/zalo/CHANGELOG.md +5 -0
  232. package/extensions/zalo/package.json +1 -1
  233. package/extensions/zalouser/CHANGELOG.md +5 -0
  234. package/extensions/zalouser/package.json +1 -1
  235. package/package.json +1 -1
@@ -1,120 +1,174 @@
1
1
  import { getProfileContext, jsonError, toNumber, toStringOrEmpty } from "./utils.js";
2
+ function resolveTabsProfileContext(req, res, ctx) {
3
+ const profileCtx = getProfileContext(req, ctx);
4
+ if ("error" in profileCtx) {
5
+ jsonError(res, profileCtx.status, profileCtx.error);
6
+ return null;
7
+ }
8
+ return profileCtx;
9
+ }
10
+ function handleTabsRouteError(ctx, res, err, opts) {
11
+ if (opts?.mapTabError) {
12
+ const mapped = ctx.mapTabError(err);
13
+ if (mapped) {
14
+ return jsonError(res, mapped.status, mapped.message);
15
+ }
16
+ }
17
+ return jsonError(res, 500, String(err));
18
+ }
19
+ async function withTabsProfileRoute(params) {
20
+ const profileCtx = resolveTabsProfileContext(params.req, params.res, params.ctx);
21
+ if (!profileCtx) {
22
+ return;
23
+ }
24
+ try {
25
+ await params.run(profileCtx);
26
+ }
27
+ catch (err) {
28
+ handleTabsRouteError(params.ctx, params.res, err, { mapTabError: params.mapTabError });
29
+ }
30
+ }
31
+ async function ensureBrowserRunning(profileCtx, res) {
32
+ if (!(await profileCtx.isReachable(300))) {
33
+ jsonError(res, 409, "browser not running");
34
+ return false;
35
+ }
36
+ return true;
37
+ }
38
+ function resolveIndexedTab(tabs, index) {
39
+ return typeof index === "number" ? tabs[index] : tabs.at(0);
40
+ }
41
+ function parseRequiredTargetId(res, rawTargetId) {
42
+ const targetId = toStringOrEmpty(rawTargetId);
43
+ if (!targetId) {
44
+ jsonError(res, 400, "targetId is required");
45
+ return null;
46
+ }
47
+ return targetId;
48
+ }
49
+ async function runTabTargetMutation(params) {
50
+ await withTabsProfileRoute({
51
+ req: params.req,
52
+ res: params.res,
53
+ ctx: params.ctx,
54
+ mapTabError: true,
55
+ run: async (profileCtx) => {
56
+ if (!(await ensureBrowserRunning(profileCtx, params.res))) {
57
+ return;
58
+ }
59
+ await params.mutate(profileCtx, params.targetId);
60
+ params.res.json({ ok: true });
61
+ },
62
+ });
63
+ }
2
64
  export function registerBrowserTabRoutes(app, ctx) {
3
65
  app.get("/tabs", async (req, res) => {
4
- const profileCtx = getProfileContext(req, ctx);
5
- if ("error" in profileCtx)
6
- return jsonError(res, profileCtx.status, profileCtx.error);
7
- try {
8
- const reachable = await profileCtx.isReachable(300);
9
- if (!reachable)
10
- return res.json({ running: false, tabs: [] });
11
- const tabs = await profileCtx.listTabs();
12
- res.json({ running: true, tabs });
13
- }
14
- catch (err) {
15
- jsonError(res, 500, String(err));
16
- }
66
+ await withTabsProfileRoute({
67
+ req,
68
+ res,
69
+ ctx,
70
+ run: async (profileCtx) => {
71
+ const reachable = await profileCtx.isReachable(300);
72
+ if (!reachable) {
73
+ return res.json({ running: false, tabs: [] });
74
+ }
75
+ const tabs = await profileCtx.listTabs();
76
+ res.json({ running: true, tabs });
77
+ },
78
+ });
17
79
  });
18
80
  app.post("/tabs/open", async (req, res) => {
19
- const profileCtx = getProfileContext(req, ctx);
20
- if ("error" in profileCtx)
21
- return jsonError(res, profileCtx.status, profileCtx.error);
22
81
  const url = toStringOrEmpty(req.body?.url);
23
- if (!url)
82
+ if (!url) {
24
83
  return jsonError(res, 400, "url is required");
25
- try {
26
- await profileCtx.ensureBrowserAvailable();
27
- const tab = await profileCtx.openTab(url);
28
- res.json(tab);
29
- }
30
- catch (err) {
31
- jsonError(res, 500, String(err));
32
84
  }
85
+ await withTabsProfileRoute({
86
+ req,
87
+ res,
88
+ ctx,
89
+ mapTabError: true,
90
+ run: async (profileCtx) => {
91
+ await profileCtx.ensureBrowserAvailable();
92
+ const tab = await profileCtx.openTab(url);
93
+ res.json(tab);
94
+ },
95
+ });
33
96
  });
34
97
  app.post("/tabs/focus", async (req, res) => {
35
- const profileCtx = getProfileContext(req, ctx);
36
- if ("error" in profileCtx)
37
- return jsonError(res, profileCtx.status, profileCtx.error);
38
- const targetId = toStringOrEmpty(req.body?.targetId);
39
- if (!targetId)
40
- return jsonError(res, 400, "targetId is required");
41
- try {
42
- if (!(await profileCtx.isReachable(300)))
43
- return jsonError(res, 409, "browser not running");
44
- await profileCtx.focusTab(targetId);
45
- res.json({ ok: true });
46
- }
47
- catch (err) {
48
- const mapped = ctx.mapTabError(err);
49
- if (mapped)
50
- return jsonError(res, mapped.status, mapped.message);
51
- jsonError(res, 500, String(err));
98
+ const targetId = parseRequiredTargetId(res, req.body?.targetId);
99
+ if (!targetId) {
100
+ return;
52
101
  }
102
+ await runTabTargetMutation({
103
+ req,
104
+ res,
105
+ ctx,
106
+ targetId,
107
+ mutate: async (profileCtx, id) => {
108
+ await profileCtx.focusTab(id);
109
+ },
110
+ });
53
111
  });
54
112
  app.delete("/tabs/:targetId", async (req, res) => {
55
- const profileCtx = getProfileContext(req, ctx);
56
- if ("error" in profileCtx)
57
- return jsonError(res, profileCtx.status, profileCtx.error);
58
- const targetId = toStringOrEmpty(req.params.targetId);
59
- if (!targetId)
60
- return jsonError(res, 400, "targetId is required");
61
- try {
62
- if (!(await profileCtx.isReachable(300)))
63
- return jsonError(res, 409, "browser not running");
64
- await profileCtx.closeTab(targetId);
65
- res.json({ ok: true });
66
- }
67
- catch (err) {
68
- const mapped = ctx.mapTabError(err);
69
- if (mapped)
70
- return jsonError(res, mapped.status, mapped.message);
71
- jsonError(res, 500, String(err));
113
+ const targetId = parseRequiredTargetId(res, req.params.targetId);
114
+ if (!targetId) {
115
+ return;
72
116
  }
117
+ await runTabTargetMutation({
118
+ req,
119
+ res,
120
+ ctx,
121
+ targetId,
122
+ mutate: async (profileCtx, id) => {
123
+ await profileCtx.closeTab(id);
124
+ },
125
+ });
73
126
  });
74
127
  app.post("/tabs/action", async (req, res) => {
75
- const profileCtx = getProfileContext(req, ctx);
76
- if ("error" in profileCtx)
77
- return jsonError(res, profileCtx.status, profileCtx.error);
78
128
  const action = toStringOrEmpty(req.body?.action);
79
129
  const index = toNumber(req.body?.index);
80
- try {
81
- if (action === "list") {
82
- const reachable = await profileCtx.isReachable(300);
83
- if (!reachable)
84
- return res.json({ ok: true, tabs: [] });
85
- const tabs = await profileCtx.listTabs();
86
- return res.json({ ok: true, tabs });
87
- }
88
- if (action === "new") {
89
- await profileCtx.ensureBrowserAvailable();
90
- const tab = await profileCtx.openTab("about:blank");
91
- return res.json({ ok: true, tab });
92
- }
93
- if (action === "close") {
94
- const tabs = await profileCtx.listTabs();
95
- const target = typeof index === "number" ? tabs[index] : tabs.at(0);
96
- if (!target)
97
- return jsonError(res, 404, "tab not found");
98
- await profileCtx.closeTab(target.targetId);
99
- return res.json({ ok: true, targetId: target.targetId });
100
- }
101
- if (action === "select") {
102
- if (typeof index !== "number")
103
- return jsonError(res, 400, "index is required");
104
- const tabs = await profileCtx.listTabs();
105
- const target = tabs[index];
106
- if (!target)
107
- return jsonError(res, 404, "tab not found");
108
- await profileCtx.focusTab(target.targetId);
109
- return res.json({ ok: true, targetId: target.targetId });
110
- }
111
- return jsonError(res, 400, "unknown tab action");
112
- }
113
- catch (err) {
114
- const mapped = ctx.mapTabError(err);
115
- if (mapped)
116
- return jsonError(res, mapped.status, mapped.message);
117
- jsonError(res, 500, String(err));
118
- }
130
+ await withTabsProfileRoute({
131
+ req,
132
+ res,
133
+ ctx,
134
+ mapTabError: true,
135
+ run: async (profileCtx) => {
136
+ if (action === "list") {
137
+ const reachable = await profileCtx.isReachable(300);
138
+ if (!reachable) {
139
+ return res.json({ ok: true, tabs: [] });
140
+ }
141
+ const tabs = await profileCtx.listTabs();
142
+ return res.json({ ok: true, tabs });
143
+ }
144
+ if (action === "new") {
145
+ await profileCtx.ensureBrowserAvailable();
146
+ const tab = await profileCtx.openTab("about:blank");
147
+ return res.json({ ok: true, tab });
148
+ }
149
+ if (action === "close") {
150
+ const tabs = await profileCtx.listTabs();
151
+ const target = resolveIndexedTab(tabs, index);
152
+ if (!target) {
153
+ return jsonError(res, 404, "tab not found");
154
+ }
155
+ await profileCtx.closeTab(target.targetId);
156
+ return res.json({ ok: true, targetId: target.targetId });
157
+ }
158
+ if (action === "select") {
159
+ if (typeof index !== "number") {
160
+ return jsonError(res, 400, "index is required");
161
+ }
162
+ const tabs = await profileCtx.listTabs();
163
+ const target = tabs[index];
164
+ if (!target) {
165
+ return jsonError(res, 404, "tab not found");
166
+ }
167
+ await profileCtx.focusTab(target.targetId);
168
+ return res.json({ ok: true, targetId: target.targetId });
169
+ }
170
+ return jsonError(res, 400, "unknown tab action");
171
+ },
172
+ });
119
173
  });
120
174
  }
@@ -0,0 +1,37 @@
1
+ import { resolveProfile } from "./config.js";
2
+ import { ensureChromeExtensionRelayServer } from "./extension-relay.js";
3
+ import { createBrowserRouteContext, listKnownProfileNames, } from "./server-context.js";
4
+ export async function ensureExtensionRelayForProfiles(params) {
5
+ for (const name of Object.keys(params.resolved.profiles)) {
6
+ const profile = resolveProfile(params.resolved, name);
7
+ if (!profile || profile.driver !== "extension") {
8
+ continue;
9
+ }
10
+ await ensureChromeExtensionRelayServer({ cdpUrl: profile.cdpUrl }).catch((err) => {
11
+ params.onWarn(`Chrome extension relay init failed for profile "${name}": ${String(err)}`);
12
+ });
13
+ }
14
+ }
15
+ export async function stopKnownBrowserProfiles(params) {
16
+ const current = params.getState();
17
+ if (!current) {
18
+ return;
19
+ }
20
+ const ctx = createBrowserRouteContext({
21
+ getState: params.getState,
22
+ refreshConfigFromDisk: true,
23
+ });
24
+ try {
25
+ for (const name of listKnownProfileNames(current)) {
26
+ try {
27
+ await ctx.forProfile(name).stopRunningBrowser();
28
+ }
29
+ catch {
30
+ // ignore
31
+ }
32
+ }
33
+ }
34
+ catch (err) {
35
+ params.onWarn(`poolbot browser stop failed: ${String(err)}`);
36
+ }
37
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2026.2.23",
3
- "commit": "ef242fa9f8b367333f246a3777937c94c68f5847",
4
- "builtAt": "2026-02-18T18:15:41.704Z"
2
+ "version": "2026.2.25",
3
+ "commit": "748e2d3171e75e9165f427279d4a3f1ef76c14aa",
4
+ "builtAt": "2026-02-22T07:21:30.369Z"
5
5
  }
@@ -0,0 +1,25 @@
1
+ export function mergeAllowFromSources(params) {
2
+ return [...(params.allowFrom ?? []), ...(params.storeAllowFrom ?? [])]
3
+ .map((value) => String(value).trim())
4
+ .filter(Boolean);
5
+ }
6
+ export function firstDefined(...values) {
7
+ for (const value of values) {
8
+ if (typeof value !== "undefined") {
9
+ return value;
10
+ }
11
+ }
12
+ return undefined;
13
+ }
14
+ export function isSenderIdAllowed(allow, senderId, allowWhenEmpty) {
15
+ if (!allow.hasEntries) {
16
+ return allowWhenEmpty;
17
+ }
18
+ if (allow.hasWildcard) {
19
+ return true;
20
+ }
21
+ if (!senderId) {
22
+ return false;
23
+ }
24
+ return allow.entries.includes(senderId);
25
+ }
@@ -0,0 +1,13 @@
1
+ export function createAccountActionGate(params) {
2
+ return (key, defaultValue = true) => {
3
+ const accountValue = params.accountActions?.[key];
4
+ if (accountValue !== undefined) {
5
+ return accountValue;
6
+ }
7
+ const baseValue = params.baseActions?.[key];
8
+ if (baseValue !== undefined) {
9
+ return baseValue;
10
+ }
11
+ return defaultValue;
12
+ };
13
+ }
@@ -1,4 +1,11 @@
1
1
  import { getChannelPlugin, listChannelPlugins } from "./index.js";
2
+ const trustedRequesterRequiredByChannel = {
3
+ discord: new Set(["timeout", "kick", "ban"]),
4
+ };
5
+ function requiresTrustedRequesterSender(ctx) {
6
+ const actions = trustedRequesterRequiredByChannel[ctx.channel];
7
+ return Boolean(actions?.has(ctx.action) && ctx.toolContext);
8
+ }
2
9
  export function listChannelMessageActions(cfg) {
3
10
  const actions = new Set(["send", "broadcast"]);
4
11
  for (const plugin of listChannelPlugins()) {
@@ -43,6 +50,9 @@ export function supportsChannelMessageCardsForChannel(params) {
43
50
  return plugin?.actions?.supportsCards?.({ cfg: params.cfg }) === true;
44
51
  }
45
52
  export async function dispatchChannelMessageAction(ctx) {
53
+ if (requiresTrustedRequesterSender(ctx) && !ctx.requesterSenderId?.trim()) {
54
+ throw new Error(`Trusted sender identity is required for ${ctx.channel}:${ctx.action} in tool-driven contexts.`);
55
+ }
46
56
  const plugin = getChannelPlugin(ctx.channel);
47
57
  if (!plugin?.actions?.handleAction) {
48
58
  return null;
@@ -0,0 +1,18 @@
1
+ export async function fetchTelegramChatId(params) {
2
+ const url = `https://api.telegram.org/bot${params.token}/getChat?chat_id=${encodeURIComponent(params.chatId)}`;
3
+ try {
4
+ const res = await fetch(url, params.signal ? { signal: params.signal } : undefined);
5
+ if (!res.ok) {
6
+ return null;
7
+ }
8
+ const data = (await res.json().catch(() => null));
9
+ const id = data?.ok ? data?.result?.id : undefined;
10
+ if (typeof id === "number" || typeof id === "string") {
11
+ return String(id);
12
+ }
13
+ return null;
14
+ }
15
+ catch {
16
+ return null;
17
+ }
18
+ }
package/dist/cli/argv.js CHANGED
@@ -1,40 +1,85 @@
1
1
  const HELP_FLAGS = new Set(["-h", "--help"]);
2
- const VERSION_FLAGS = new Set(["-v", "-V", "--version"]);
2
+ const VERSION_FLAGS = new Set(["-V", "--version"]);
3
+ const ROOT_VERSION_ALIAS_FLAG = "-v";
4
+ const ROOT_BOOLEAN_FLAGS = new Set(["--dev", "--no-color"]);
5
+ const ROOT_VALUE_FLAGS = new Set(["--profile"]);
3
6
  const FLAG_TERMINATOR = "--";
4
7
  export function hasHelpOrVersion(argv) {
5
- return argv.some((arg) => HELP_FLAGS.has(arg) || VERSION_FLAGS.has(arg));
8
+ return (argv.some((arg) => HELP_FLAGS.has(arg) || VERSION_FLAGS.has(arg)) || hasRootVersionAlias(argv));
6
9
  }
7
10
  function isValueToken(arg) {
8
- if (!arg)
11
+ if (!arg) {
9
12
  return false;
10
- if (arg === FLAG_TERMINATOR)
13
+ }
14
+ if (arg === FLAG_TERMINATOR) {
11
15
  return false;
12
- if (!arg.startsWith("-"))
16
+ }
17
+ if (!arg.startsWith("-")) {
13
18
  return true;
19
+ }
14
20
  return /^-\d+(?:\.\d+)?$/.test(arg);
15
21
  }
16
22
  function parsePositiveInt(value) {
17
23
  const parsed = Number.parseInt(value, 10);
18
- if (Number.isNaN(parsed) || parsed <= 0)
24
+ if (Number.isNaN(parsed) || parsed <= 0) {
19
25
  return undefined;
26
+ }
20
27
  return parsed;
21
28
  }
22
29
  export function hasFlag(argv, name) {
23
30
  const args = argv.slice(2);
24
31
  for (const arg of args) {
25
- if (arg === FLAG_TERMINATOR)
32
+ if (arg === FLAG_TERMINATOR) {
26
33
  break;
27
- if (arg === name)
34
+ }
35
+ if (arg === name) {
28
36
  return true;
37
+ }
29
38
  }
30
39
  return false;
31
40
  }
41
+ export function hasRootVersionAlias(argv) {
42
+ const args = argv.slice(2);
43
+ let hasAlias = false;
44
+ for (let i = 0; i < args.length; i += 1) {
45
+ const arg = args[i];
46
+ if (!arg) {
47
+ continue;
48
+ }
49
+ if (arg === FLAG_TERMINATOR) {
50
+ break;
51
+ }
52
+ if (arg === ROOT_VERSION_ALIAS_FLAG) {
53
+ hasAlias = true;
54
+ continue;
55
+ }
56
+ if (ROOT_BOOLEAN_FLAGS.has(arg)) {
57
+ continue;
58
+ }
59
+ if (arg.startsWith("--profile=")) {
60
+ continue;
61
+ }
62
+ if (ROOT_VALUE_FLAGS.has(arg)) {
63
+ const next = args[i + 1];
64
+ if (isValueToken(next)) {
65
+ i += 1;
66
+ }
67
+ continue;
68
+ }
69
+ if (arg.startsWith("-")) {
70
+ continue;
71
+ }
72
+ return false;
73
+ }
74
+ return hasAlias;
75
+ }
32
76
  export function getFlagValue(argv, name) {
33
77
  const args = argv.slice(2);
34
78
  for (let i = 0; i < args.length; i += 1) {
35
79
  const arg = args[i];
36
- if (arg === FLAG_TERMINATOR)
80
+ if (arg === FLAG_TERMINATOR) {
37
81
  break;
82
+ }
38
83
  if (arg === name) {
39
84
  const next = args[i + 1];
40
85
  return isValueToken(next) ? next : null;
@@ -47,16 +92,19 @@ export function getFlagValue(argv, name) {
47
92
  return undefined;
48
93
  }
49
94
  export function getVerboseFlag(argv, options) {
50
- if (hasFlag(argv, "--verbose"))
95
+ if (hasFlag(argv, "--verbose")) {
51
96
  return true;
52
- if (options?.includeDebug && hasFlag(argv, "--debug"))
97
+ }
98
+ if (options?.includeDebug && hasFlag(argv, "--debug")) {
53
99
  return true;
100
+ }
54
101
  return false;
55
102
  }
56
103
  export function getPositiveIntFlagValue(argv, name) {
57
104
  const raw = getFlagValue(argv, name);
58
- if (raw === null || raw === undefined)
105
+ if (raw === null || raw === undefined) {
59
106
  return raw;
107
+ }
60
108
  return parsePositiveInt(raw);
61
109
  }
62
110
  export function getCommandPath(argv, depth = 2) {
@@ -64,15 +112,19 @@ export function getCommandPath(argv, depth = 2) {
64
112
  const path = [];
65
113
  for (let i = 0; i < args.length; i += 1) {
66
114
  const arg = args[i];
67
- if (!arg)
115
+ if (!arg) {
68
116
  continue;
69
- if (arg === "--")
117
+ }
118
+ if (arg === "--") {
70
119
  break;
71
- if (arg.startsWith("-"))
120
+ }
121
+ if (arg.startsWith("-")) {
72
122
  continue;
123
+ }
73
124
  path.push(arg);
74
- if (path.length >= depth)
125
+ if (path.length >= depth) {
75
126
  break;
127
+ }
76
128
  }
77
129
  return path;
78
130
  }
@@ -94,8 +146,9 @@ export function buildParseArgv(params) {
94
146
  : baseArgv;
95
147
  const executable = (normalizedArgv[0]?.split(/[/\\]/).pop() ?? "").toLowerCase();
96
148
  const looksLikeNode = normalizedArgv.length >= 2 && (isNodeExecutable(executable) || isBunExecutable(executable));
97
- if (looksLikeNode)
149
+ if (looksLikeNode) {
98
150
  return normalizedArgv;
151
+ }
99
152
  return ["node", programName || "poolbot", ...normalizedArgv];
100
153
  }
101
154
  const nodeExecutablePattern = /^node-\d+(?:\.\d+)*(?:\.exe)?$/;
@@ -110,15 +163,25 @@ function isBunExecutable(executable) {
110
163
  return executable === "bun" || executable === "bun.exe";
111
164
  }
112
165
  export function shouldMigrateStateFromPath(path) {
113
- if (path.length === 0)
166
+ if (path.length === 0) {
114
167
  return true;
168
+ }
115
169
  const [primary, secondary] = path;
116
- if (primary === "health" || primary === "status" || primary === "sessions")
170
+ if (primary === "health" || primary === "status" || primary === "sessions") {
117
171
  return false;
118
- if (primary === "memory" && secondary === "status")
172
+ }
173
+ if (primary === "config" && (secondary === "get" || secondary === "unset")) {
119
174
  return false;
120
- if (primary === "agent")
175
+ }
176
+ if (primary === "models" && (secondary === "list" || secondary === "status")) {
121
177
  return false;
178
+ }
179
+ if (primary === "memory" && secondary === "status") {
180
+ return false;
181
+ }
182
+ if (primary === "agent") {
183
+ return false;
184
+ }
122
185
  return true;
123
186
  }
124
187
  export function shouldMigrateState(argv) {
@@ -1,6 +1,7 @@
1
1
  import { resolveCommitHash } from "../infra/git-commit.js";
2
2
  import { visibleWidth } from "../terminal/ansi.js";
3
3
  import { isRich, theme } from "../terminal/theme.js";
4
+ import { hasRootVersionAlias } from "./argv.js";
4
5
  import { pickTagline } from "./tagline.js";
5
6
  import { resolveCliName } from "./cli-name.js";
6
7
  let bannerEmitted = false;
@@ -18,7 +19,7 @@ function splitGraphemes(value) {
18
19
  }
19
20
  }
20
21
  const hasJsonFlag = (argv) => argv.some((arg) => arg === "--json" || arg.startsWith("--json="));
21
- const hasVersionFlag = (argv) => argv.some((arg) => arg === "--version" || arg === "-V" || arg === "-v");
22
+ const hasVersionFlag = (argv) => argv.some((arg) => arg === "--version" || arg === "-V") || hasRootVersionAlias(argv);
22
23
  export function formatCliBannerLine(version, options = {}) {
23
24
  const commit = options.commit ?? resolveCommitHash({ env: options.env });
24
25
  const commitLabel = commit ?? "unknown";