@poolzin/pool-bot 2026.2.24 → 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 (191) hide show
  1. package/CHANGELOG.md +21 -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/sessions.test-helpers.js +61 -0
  63. package/dist/config/commands.js +3 -0
  64. package/dist/config/config.js +1 -1
  65. package/dist/config/env-substitution.js +62 -34
  66. package/dist/config/env-vars.js +9 -0
  67. package/dist/config/io.js +571 -171
  68. package/dist/config/merge-patch.js +50 -4
  69. package/dist/config/redact-snapshot.js +404 -76
  70. package/dist/config/schema.js +58 -570
  71. package/dist/config/validation.js +140 -85
  72. package/dist/config/zod-schema.hooks.js +40 -11
  73. package/dist/config/zod-schema.installs.js +20 -0
  74. package/dist/config/zod-schema.js +8 -7
  75. package/dist/daemon/cmd-argv.js +21 -0
  76. package/dist/daemon/cmd-set.js +58 -0
  77. package/dist/daemon/service-types.js +1 -0
  78. package/dist/discord/monitor/exec-approvals.js +357 -162
  79. package/dist/gateway/auth.js +38 -3
  80. package/dist/gateway/call.js +149 -68
  81. package/dist/gateway/canvas-capability.js +75 -0
  82. package/dist/gateway/control-plane-audit.js +28 -0
  83. package/dist/gateway/control-plane-rate-limit.js +53 -0
  84. package/dist/gateway/events.js +1 -0
  85. package/dist/gateway/hooks.js +109 -54
  86. package/dist/gateway/http-common.js +22 -0
  87. package/dist/gateway/method-scopes.js +169 -0
  88. package/dist/gateway/net.js +23 -0
  89. package/dist/gateway/openresponses-http.js +120 -110
  90. package/dist/gateway/probe-auth.js +2 -0
  91. package/dist/gateway/protocol/index.js +3 -2
  92. package/dist/gateway/protocol/schema/protocol-schemas.js +2 -0
  93. package/dist/gateway/protocol/schema/push.js +18 -0
  94. package/dist/gateway/protocol/schema.js +1 -0
  95. package/dist/gateway/server-http.js +236 -52
  96. package/dist/gateway/server-methods/agent.js +162 -24
  97. package/dist/gateway/server-methods/chat.js +461 -130
  98. package/dist/gateway/server-methods/config.js +193 -150
  99. package/dist/gateway/server-methods/nodes.helpers.js +12 -0
  100. package/dist/gateway/server-methods/nodes.js +251 -69
  101. package/dist/gateway/server-methods/push.js +53 -0
  102. package/dist/gateway/server-reload-handlers.js +2 -3
  103. package/dist/gateway/server-runtime-config.js +5 -0
  104. package/dist/gateway/server-runtime-state.js +2 -0
  105. package/dist/gateway/server-ws-runtime.js +1 -0
  106. package/dist/gateway/server.impl.js +296 -139
  107. package/dist/gateway/session-preview.test-helpers.js +11 -0
  108. package/dist/gateway/startup-auth.js +126 -0
  109. package/dist/gateway/test-helpers.agent-results.js +15 -0
  110. package/dist/gateway/test-helpers.mocks.js +37 -14
  111. package/dist/gateway/test-helpers.server.js +161 -77
  112. package/dist/hooks/bundled/session-memory/handler.js +165 -34
  113. package/dist/hooks/gmail-watcher-lifecycle.js +23 -0
  114. package/dist/infra/archive-path.js +49 -0
  115. package/dist/infra/device-pairing.js +148 -167
  116. package/dist/infra/exec-approvals-allowlist.js +19 -70
  117. package/dist/infra/exec-approvals-analysis.js +44 -17
  118. package/dist/infra/exec-safe-bin-policy.js +269 -0
  119. package/dist/infra/fixed-window-rate-limit.js +33 -0
  120. package/dist/infra/git-root.js +61 -0
  121. package/dist/infra/heartbeat-active-hours.js +2 -2
  122. package/dist/infra/heartbeat-reason.js +40 -0
  123. package/dist/infra/heartbeat-runner.js +72 -32
  124. package/dist/infra/install-source-utils.js +91 -7
  125. package/dist/infra/node-pairing.js +50 -105
  126. package/dist/infra/npm-integrity.js +45 -0
  127. package/dist/infra/npm-pack-install.js +40 -0
  128. package/dist/infra/outbound/channel-adapters.js +20 -7
  129. package/dist/infra/outbound/message-action-runner.js +107 -327
  130. package/dist/infra/outbound/message.js +59 -36
  131. package/dist/infra/outbound/outbound-policy.js +52 -25
  132. package/dist/infra/outbound/outbound-send-service.js +58 -71
  133. package/dist/infra/pairing-files.js +10 -0
  134. package/dist/infra/plain-object.js +9 -0
  135. package/dist/infra/push-apns.js +365 -0
  136. package/dist/infra/restart-sentinel.js +16 -1
  137. package/dist/infra/restart.js +229 -26
  138. package/dist/infra/scp-host.js +54 -0
  139. package/dist/infra/update-startup.js +86 -9
  140. package/dist/media/inbound-path-policy.js +114 -0
  141. package/dist/media/input-files.js +16 -0
  142. package/dist/memory/test-manager.js +8 -0
  143. package/dist/plugin-sdk/temp-path.js +47 -0
  144. package/dist/plugins/discovery.js +217 -23
  145. package/dist/plugins/hook-runner-global.js +16 -0
  146. package/dist/plugins/loader.js +192 -26
  147. package/dist/plugins/logger.js +8 -0
  148. package/dist/plugins/manifest-registry.js +3 -0
  149. package/dist/plugins/path-safety.js +34 -0
  150. package/dist/plugins/registry.js +5 -2
  151. package/dist/plugins/runtime/index.js +271 -206
  152. package/dist/providers/github-copilot-models.js +4 -1
  153. package/dist/security/audit-channel.js +8 -19
  154. package/dist/security/audit-extra.async.js +354 -182
  155. package/dist/security/audit-extra.js +11 -1
  156. package/dist/security/audit-extra.sync.js +340 -33
  157. package/dist/security/audit-fs.js +31 -13
  158. package/dist/security/audit.js +145 -371
  159. package/dist/security/dm-policy-shared.js +24 -0
  160. package/dist/security/external-content.js +20 -8
  161. package/dist/security/fix.js +49 -85
  162. package/dist/security/scan-paths.js +20 -0
  163. package/dist/security/secret-equal.js +3 -7
  164. package/dist/security/windows-acl.js +30 -15
  165. package/dist/shared/node-list-parse.js +13 -0
  166. package/dist/shared/operator-scope-compat.js +37 -0
  167. package/dist/shared/text-chunking.js +29 -0
  168. package/dist/slack/blocks.test-helpers.js +31 -0
  169. package/dist/slack/monitor/mrkdwn.js +8 -0
  170. package/dist/telegram/bot-message-dispatch.js +366 -164
  171. package/dist/telegram/draft-stream.js +30 -7
  172. package/dist/telegram/reasoning-lane-coordinator.js +128 -0
  173. package/dist/terminal/prompt-select-styled.js +9 -0
  174. package/dist/test-utils/command-runner.js +6 -0
  175. package/dist/test-utils/internal-hook-event-payload.js +10 -0
  176. package/dist/test-utils/model-auth-mock.js +12 -0
  177. package/dist/test-utils/provider-usage-fetch.js +14 -0
  178. package/dist/test-utils/temp-home.js +33 -0
  179. package/dist/tui/components/chat-log.js +9 -0
  180. package/dist/tui/tui-command-handlers.js +36 -27
  181. package/dist/tui/tui-event-handlers.js +122 -32
  182. package/dist/tui/tui.js +181 -45
  183. package/dist/utils/mask-api-key.js +10 -0
  184. package/dist/utils/run-with-concurrency.js +39 -0
  185. package/dist/web/media.js +4 -0
  186. package/docs/tools/slash-commands.md +5 -1
  187. package/extensions/feishu/src/external-keys.ts +19 -0
  188. package/extensions/lobster/src/windows-spawn.ts +193 -0
  189. package/extensions/matrix/src/matrix/actions/limits.ts +6 -0
  190. package/extensions/mattermost/src/mattermost/reactions.test-helpers.ts +83 -0
  191. package/package.json +1 -1
@@ -0,0 +1,193 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ type SpawnTarget = {
5
+ command: string;
6
+ argv: string[];
7
+ windowsHide?: boolean;
8
+ };
9
+
10
+ function isFilePath(value: string): boolean {
11
+ try {
12
+ const stat = fs.statSync(value);
13
+ return stat.isFile();
14
+ } catch {
15
+ return false;
16
+ }
17
+ }
18
+
19
+ function resolveWindowsExecutablePath(execPath: string, env: NodeJS.ProcessEnv): string {
20
+ if (execPath.includes("/") || execPath.includes("\\") || path.isAbsolute(execPath)) {
21
+ return execPath;
22
+ }
23
+
24
+ const pathValue = env.PATH ?? env.Path ?? process.env.PATH ?? process.env.Path ?? "";
25
+ const pathEntries = pathValue
26
+ .split(";")
27
+ .map((entry) => entry.trim())
28
+ .filter(Boolean);
29
+
30
+ const hasExtension = path.extname(execPath).length > 0;
31
+ const pathExtRaw =
32
+ env.PATHEXT ??
33
+ env.Pathext ??
34
+ process.env.PATHEXT ??
35
+ process.env.Pathext ??
36
+ ".EXE;.CMD;.BAT;.COM";
37
+ const pathExt = hasExtension
38
+ ? [""]
39
+ : pathExtRaw
40
+ .split(";")
41
+ .map((ext) => ext.trim())
42
+ .filter(Boolean)
43
+ .map((ext) => (ext.startsWith(".") ? ext : `.${ext}`));
44
+
45
+ for (const dir of pathEntries) {
46
+ for (const ext of pathExt) {
47
+ for (const candidateExt of [ext, ext.toLowerCase(), ext.toUpperCase()]) {
48
+ const candidate = path.join(dir, `${execPath}${candidateExt}`);
49
+ if (isFilePath(candidate)) {
50
+ return candidate;
51
+ }
52
+ }
53
+ }
54
+ }
55
+
56
+ return execPath;
57
+ }
58
+
59
+ function resolveBinEntry(binField: string | Record<string, string> | undefined): string | null {
60
+ if (typeof binField === "string") {
61
+ const trimmed = binField.trim();
62
+ return trimmed || null;
63
+ }
64
+ if (!binField || typeof binField !== "object") {
65
+ return null;
66
+ }
67
+
68
+ const preferred = binField.lobster;
69
+ if (typeof preferred === "string" && preferred.trim()) {
70
+ return preferred.trim();
71
+ }
72
+
73
+ for (const value of Object.values(binField)) {
74
+ if (typeof value === "string" && value.trim()) {
75
+ return value.trim();
76
+ }
77
+ }
78
+ return null;
79
+ }
80
+
81
+ function resolveLobsterScriptFromPackageJson(wrapperPath: string): string | null {
82
+ const wrapperDir = path.dirname(wrapperPath);
83
+ const packageDirs = [
84
+ // Local install: <repo>/node_modules/.bin/lobster.cmd -> ../lobster
85
+ path.resolve(wrapperDir, "..", "lobster"),
86
+ // Global npm install: <npm-prefix>/lobster.cmd -> ./node_modules/lobster
87
+ path.resolve(wrapperDir, "node_modules", "lobster"),
88
+ ];
89
+
90
+ for (const packageDir of packageDirs) {
91
+ const packageJsonPath = path.join(packageDir, "package.json");
92
+ if (!isFilePath(packageJsonPath)) {
93
+ continue;
94
+ }
95
+
96
+ try {
97
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")) as {
98
+ bin?: string | Record<string, string>;
99
+ };
100
+ const scriptRel = resolveBinEntry(packageJson.bin);
101
+ if (!scriptRel) {
102
+ continue;
103
+ }
104
+ const scriptPath = path.resolve(packageDir, scriptRel);
105
+ if (isFilePath(scriptPath)) {
106
+ return scriptPath;
107
+ }
108
+ } catch {
109
+ // Ignore malformed package metadata; caller will throw a guided error.
110
+ }
111
+ }
112
+
113
+ return null;
114
+ }
115
+
116
+ function resolveLobsterScriptFromCmdShim(wrapperPath: string): string | null {
117
+ if (!isFilePath(wrapperPath)) {
118
+ return null;
119
+ }
120
+
121
+ try {
122
+ const content = fs.readFileSync(wrapperPath, "utf8");
123
+ const candidates: string[] = [];
124
+ const extractRelativeFromToken = (token: string): string | null => {
125
+ const match = token.match(/%~?dp0%\s*[\\/]*(.*)$/i);
126
+ if (!match) {
127
+ return null;
128
+ }
129
+ const relative = match[1];
130
+ if (!relative) {
131
+ return null;
132
+ }
133
+ return relative;
134
+ };
135
+
136
+ const matches = content.matchAll(/"([^"\r\n]*)"/g);
137
+ for (const match of matches) {
138
+ const token = match[1] ?? "";
139
+ const relative = extractRelativeFromToken(token);
140
+ if (!relative) {
141
+ continue;
142
+ }
143
+
144
+ const normalizedRelative = relative
145
+ .trim()
146
+ .replace(/[\\/]+/g, path.sep)
147
+ .replace(/^[\\/]+/, "");
148
+ const candidate = path.resolve(path.dirname(wrapperPath), normalizedRelative);
149
+ if (isFilePath(candidate)) {
150
+ candidates.push(candidate);
151
+ }
152
+ }
153
+
154
+ const nonNode = candidates.find((candidate) => {
155
+ const base = path.basename(candidate).toLowerCase();
156
+ return base !== "node.exe" && base !== "node";
157
+ });
158
+ if (nonNode) {
159
+ return nonNode;
160
+ }
161
+ } catch {
162
+ // Ignore unreadable shims; caller will throw a guided error.
163
+ }
164
+
165
+ return null;
166
+ }
167
+
168
+ export function resolveWindowsLobsterSpawn(
169
+ execPath: string,
170
+ argv: string[],
171
+ env: NodeJS.ProcessEnv,
172
+ ): SpawnTarget {
173
+ const resolvedExecPath = resolveWindowsExecutablePath(execPath, env);
174
+ const ext = path.extname(resolvedExecPath).toLowerCase();
175
+ if (ext !== ".cmd" && ext !== ".bat") {
176
+ return { command: resolvedExecPath, argv };
177
+ }
178
+
179
+ const scriptPath =
180
+ resolveLobsterScriptFromCmdShim(resolvedExecPath) ??
181
+ resolveLobsterScriptFromPackageJson(resolvedExecPath);
182
+ if (!scriptPath) {
183
+ throw new Error(
184
+ `${path.basename(resolvedExecPath)} wrapper resolved, but no Node entrypoint could be resolved without shell execution. Ensure Lobster is installed and runnable on PATH (prefer lobster.exe).`,
185
+ );
186
+ }
187
+
188
+ const entryExt = path.extname(scriptPath).toLowerCase();
189
+ if (entryExt === ".exe") {
190
+ return { command: scriptPath, argv, windowsHide: true };
191
+ }
192
+ return { command: process.execPath, argv: [scriptPath, ...argv], windowsHide: true };
193
+ }
@@ -0,0 +1,6 @@
1
+ export function resolveMatrixActionLimit(raw: unknown, fallback: number): number {
2
+ if (typeof raw !== "number" || !Number.isFinite(raw)) {
3
+ return fallback;
4
+ }
5
+ return Math.max(1, Math.floor(raw));
6
+ }
@@ -0,0 +1,83 @@
1
+ import type { PoolBotConfig } from "poolbot/plugin-sdk";
2
+ import { expect, vi } from "vitest";
3
+
4
+ export function createMattermostTestConfig(): PoolBotConfig {
5
+ return {
6
+ channels: {
7
+ mattermost: {
8
+ enabled: true,
9
+ botToken: "test-token",
10
+ baseUrl: "https://chat.example.com",
11
+ },
12
+ },
13
+ };
14
+ }
15
+
16
+ export function createMattermostReactionFetchMock(params: {
17
+ postId: string;
18
+ emojiName: string;
19
+ mode: "add" | "remove" | "both";
20
+ userId?: string;
21
+ status?: number;
22
+ body?: unknown;
23
+ }) {
24
+ const userId = params.userId ?? "BOT123";
25
+ const mode = params.mode;
26
+ const allowAdd = mode === "add" || mode === "both";
27
+ const allowRemove = mode === "remove" || mode === "both";
28
+ const addStatus = params.status ?? 201;
29
+ const removeStatus = params.status ?? 204;
30
+ const removePath = `/api/v4/users/${userId}/posts/${params.postId}/reactions/${encodeURIComponent(params.emojiName)}`;
31
+
32
+ return vi.fn(async (url: any, init?: any) => {
33
+ if (String(url).endsWith("/api/v4/users/me")) {
34
+ return new Response(JSON.stringify({ id: userId }), {
35
+ status: 200,
36
+ headers: { "content-type": "application/json" },
37
+ });
38
+ }
39
+
40
+ if (allowAdd && String(url).endsWith("/api/v4/reactions")) {
41
+ expect(init?.method).toBe("POST");
42
+ expect(JSON.parse(init?.body)).toEqual({
43
+ user_id: userId,
44
+ post_id: params.postId,
45
+ emoji_name: params.emojiName,
46
+ });
47
+
48
+ const responseBody = params.body === undefined ? { ok: true } : params.body;
49
+ return new Response(
50
+ responseBody === null ? null : JSON.stringify(responseBody),
51
+ responseBody === null
52
+ ? { status: addStatus, headers: { "content-type": "text/plain" } }
53
+ : { status: addStatus, headers: { "content-type": "application/json" } },
54
+ );
55
+ }
56
+
57
+ if (allowRemove && String(url).endsWith(removePath)) {
58
+ expect(init?.method).toBe("DELETE");
59
+ const responseBody = params.body === undefined ? null : params.body;
60
+ return new Response(
61
+ responseBody === null ? null : JSON.stringify(responseBody),
62
+ responseBody === null
63
+ ? { status: removeStatus, headers: { "content-type": "text/plain" } }
64
+ : { status: removeStatus, headers: { "content-type": "application/json" } },
65
+ );
66
+ }
67
+
68
+ throw new Error(`unexpected url: ${url}`);
69
+ });
70
+ }
71
+
72
+ export async function withMockedGlobalFetch<T>(
73
+ fetchImpl: typeof fetch,
74
+ run: () => Promise<T>,
75
+ ): Promise<T> {
76
+ const prevFetch = globalThis.fetch;
77
+ (globalThis as any).fetch = fetchImpl;
78
+ try {
79
+ return await run();
80
+ } finally {
81
+ (globalThis as any).fetch = prevFetch;
82
+ }
83
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolzin/pool-bot",
3
- "version": "2026.2.24",
3
+ "version": "2026.2.25",
4
4
  "description": "🎱 Pool Bot - AI assistant with PLCODE integrations",
5
5
  "keywords": [],
6
6
  "license": "MIT",