@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.
- package/CHANGELOG.md +29 -0
- package/dist/acp/client.js +207 -18
- package/dist/acp/secret-file.js +22 -0
- package/dist/agents/agent-scope.js +10 -0
- package/dist/agents/bash-process-registry.test-helpers.js +29 -0
- package/dist/agents/bash-tools.exec-approval-request.js +20 -0
- package/dist/agents/bash-tools.exec-host-gateway.js +230 -0
- package/dist/agents/bash-tools.exec-host-node.js +235 -0
- package/dist/agents/bash-tools.exec-types.js +1 -0
- package/dist/agents/bash-tools.process.js +224 -218
- package/dist/agents/content-blocks.js +16 -0
- package/dist/agents/model-fallback.js +96 -101
- package/dist/agents/models-config.providers.js +299 -182
- package/dist/agents/pi-embedded-payloads.js +1 -0
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +34 -0
- package/dist/agents/skills.test-helpers.js +13 -0
- package/dist/agents/stable-stringify.js +12 -0
- package/dist/agents/subagent-registry.mocks.shared.js +12 -0
- package/dist/agents/test-helpers/assistant-message-fixtures.js +29 -0
- package/dist/agents/test-helpers/pi-tools-sandbox-context.js +27 -0
- package/dist/agents/tool-policy-shared.js +108 -0
- package/dist/agents/tools/browser-tool.js +160 -54
- package/dist/agents/tools/cron-tool.test-helpers.js +12 -0
- package/dist/agents/tools/discord-actions-moderation-shared.js +27 -0
- package/dist/agents/tools/image-tool.js +214 -99
- package/dist/agents/tools/sessions-history-tool.js +140 -108
- package/dist/agents/workspace.js +222 -46
- package/dist/auto-reply/commands-registry.js +15 -18
- package/dist/auto-reply/fallback-state.js +114 -0
- package/dist/auto-reply/model-runtime.js +68 -0
- package/dist/auto-reply/reply/agent-runner-execution.js +36 -4
- package/dist/auto-reply/reply/agent-runner.js +165 -39
- package/dist/auto-reply/reply/commands-setunset-standard.js +13 -0
- package/dist/browser/config.js +26 -0
- package/dist/browser/navigation-guard.js +31 -0
- package/dist/browser/routes/agent.act.js +431 -424
- package/dist/browser/routes/agent.shared.js +47 -3
- package/dist/browser/routes/agent.snapshot.js +122 -116
- package/dist/browser/routes/agent.storage.js +303 -297
- package/dist/browser/routes/tabs.js +154 -100
- package/dist/browser/server-lifecycle.js +37 -0
- package/dist/build-info.json +3 -3
- package/dist/channels/allow-from.js +25 -0
- package/dist/channels/plugins/account-action-gate.js +13 -0
- package/dist/channels/plugins/message-actions.js +10 -0
- package/dist/channels/telegram/api.js +18 -0
- package/dist/cli/argv.js +84 -21
- package/dist/cli/banner.js +2 -1
- package/dist/cli/exec-approvals-cli.js +92 -124
- package/dist/cli/memory-cli.js +158 -61
- package/dist/cli/nodes-cli/register.push.js +63 -0
- package/dist/cli/nodes-media-utils.js +21 -0
- package/dist/cli/plugins-cli.js +245 -61
- package/dist/cli/program/build-program.js +3 -1
- package/dist/cli/program/command-registry.js +223 -136
- package/dist/cli/program/help.js +43 -12
- package/dist/cli/route.js +1 -1
- package/dist/cli/test-runtime-capture.js +24 -0
- package/dist/commands/agent.js +163 -87
- package/dist/commands/channels.mock-harness.js +23 -0
- package/dist/commands/daemon-install-runtime-warning.js +11 -0
- package/dist/commands/onboard-helpers.js +4 -4
- package/dist/commands/sessions.test-helpers.js +61 -0
- package/dist/compat/legacy-names.js +2 -2
- package/dist/config/commands.js +3 -0
- package/dist/config/config.js +1 -1
- package/dist/config/env-substitution.js +62 -34
- package/dist/config/env-vars.js +9 -0
- package/dist/config/io.js +571 -171
- package/dist/config/merge-patch.js +50 -4
- package/dist/config/redact-snapshot.js +404 -76
- package/dist/config/schema.js +58 -570
- package/dist/config/validation.js +140 -85
- package/dist/config/zod-schema.hooks.js +40 -11
- package/dist/config/zod-schema.installs.js +20 -0
- package/dist/config/zod-schema.js +8 -7
- package/dist/control-ui/assets/{index-HRr1grwl.js → index-Dvkl4Xlx.js} +2 -1
- package/dist/control-ui/assets/{index-HRr1grwl.js.map → index-Dvkl4Xlx.js.map} +1 -1
- package/dist/control-ui/index.html +1 -1
- package/dist/daemon/cmd-argv.js +21 -0
- package/dist/daemon/cmd-set.js +58 -0
- package/dist/daemon/service-types.js +1 -0
- package/dist/discord/monitor/exec-approvals.js +357 -162
- package/dist/gateway/auth.js +38 -3
- package/dist/gateway/call.js +149 -68
- package/dist/gateway/canvas-capability.js +75 -0
- package/dist/gateway/control-plane-audit.js +28 -0
- package/dist/gateway/control-plane-rate-limit.js +53 -0
- package/dist/gateway/events.js +1 -0
- package/dist/gateway/hooks.js +109 -54
- package/dist/gateway/http-common.js +22 -0
- package/dist/gateway/method-scopes.js +169 -0
- package/dist/gateway/net.js +23 -0
- package/dist/gateway/openresponses-http.js +120 -110
- package/dist/gateway/probe-auth.js +2 -0
- package/dist/gateway/protocol/index.js +3 -2
- package/dist/gateway/protocol/schema/protocol-schemas.js +2 -0
- package/dist/gateway/protocol/schema/push.js +18 -0
- package/dist/gateway/protocol/schema.js +1 -0
- package/dist/gateway/server-http.js +236 -52
- package/dist/gateway/server-methods/agent.js +162 -24
- package/dist/gateway/server-methods/chat.js +461 -130
- package/dist/gateway/server-methods/config.js +193 -150
- package/dist/gateway/server-methods/nodes.helpers.js +12 -0
- package/dist/gateway/server-methods/nodes.js +251 -69
- package/dist/gateway/server-methods/push.js +53 -0
- package/dist/gateway/server-reload-handlers.js +2 -3
- package/dist/gateway/server-runtime-config.js +5 -0
- package/dist/gateway/server-runtime-state.js +2 -0
- package/dist/gateway/server-ws-runtime.js +1 -0
- package/dist/gateway/server.impl.js +296 -139
- package/dist/gateway/session-preview.test-helpers.js +11 -0
- package/dist/gateway/startup-auth.js +126 -0
- package/dist/gateway/test-helpers.agent-results.js +15 -0
- package/dist/gateway/test-helpers.mocks.js +37 -14
- package/dist/gateway/test-helpers.server.js +161 -77
- package/dist/hooks/bundled/session-memory/handler.js +165 -34
- package/dist/hooks/gmail-watcher-lifecycle.js +23 -0
- package/dist/infra/archive-path.js +49 -0
- package/dist/infra/device-pairing.js +148 -167
- package/dist/infra/exec-approvals-allowlist.js +19 -70
- package/dist/infra/exec-approvals-analysis.js +44 -17
- package/dist/infra/exec-safe-bin-policy.js +269 -0
- package/dist/infra/fixed-window-rate-limit.js +33 -0
- package/dist/infra/git-root.js +61 -0
- package/dist/infra/heartbeat-active-hours.js +2 -2
- package/dist/infra/heartbeat-reason.js +40 -0
- package/dist/infra/heartbeat-runner.js +72 -32
- package/dist/infra/install-source-utils.js +91 -7
- package/dist/infra/node-pairing.js +50 -105
- package/dist/infra/npm-integrity.js +45 -0
- package/dist/infra/npm-pack-install.js +40 -0
- package/dist/infra/outbound/channel-adapters.js +20 -7
- package/dist/infra/outbound/message-action-runner.js +107 -327
- package/dist/infra/outbound/message.js +59 -36
- package/dist/infra/outbound/outbound-policy.js +52 -25
- package/dist/infra/outbound/outbound-send-service.js +58 -71
- package/dist/infra/pairing-files.js +10 -0
- package/dist/infra/plain-object.js +9 -0
- package/dist/infra/push-apns.js +365 -0
- package/dist/infra/restart-sentinel.js +16 -1
- package/dist/infra/restart.js +229 -26
- package/dist/infra/scp-host.js +54 -0
- package/dist/infra/update-startup.js +86 -9
- package/dist/media/inbound-path-policy.js +114 -0
- package/dist/media/input-files.js +16 -0
- package/dist/memory/test-manager.js +8 -0
- package/dist/plugin-sdk/temp-path.js +47 -0
- package/dist/plugins/discovery.js +217 -23
- package/dist/plugins/hook-runner-global.js +16 -0
- package/dist/plugins/loader.js +192 -26
- package/dist/plugins/logger.js +8 -0
- package/dist/plugins/manifest-registry.js +3 -0
- package/dist/plugins/path-safety.js +34 -0
- package/dist/plugins/registry.js +5 -2
- package/dist/plugins/runtime/index.js +271 -206
- package/dist/providers/github-copilot-models.js +4 -1
- package/dist/security/audit-channel.js +8 -19
- package/dist/security/audit-extra.async.js +354 -182
- package/dist/security/audit-extra.js +11 -1
- package/dist/security/audit-extra.sync.js +340 -33
- package/dist/security/audit-fs.js +31 -13
- package/dist/security/audit.js +145 -371
- package/dist/security/dm-policy-shared.js +24 -0
- package/dist/security/external-content.js +20 -8
- package/dist/security/fix.js +49 -85
- package/dist/security/scan-paths.js +20 -0
- package/dist/security/secret-equal.js +3 -7
- package/dist/security/windows-acl.js +30 -15
- package/dist/shared/node-list-parse.js +13 -0
- package/dist/shared/operator-scope-compat.js +37 -0
- package/dist/shared/text-chunking.js +29 -0
- package/dist/slack/blocks.test-helpers.js +31 -0
- package/dist/slack/monitor/mrkdwn.js +8 -0
- package/dist/telegram/bot-message-dispatch.js +366 -164
- package/dist/telegram/draft-stream.js +30 -7
- package/dist/telegram/reasoning-lane-coordinator.js +128 -0
- package/dist/terminal/prompt-select-styled.js +9 -0
- package/dist/test-utils/command-runner.js +6 -0
- package/dist/test-utils/internal-hook-event-payload.js +10 -0
- package/dist/test-utils/model-auth-mock.js +12 -0
- package/dist/test-utils/provider-usage-fetch.js +14 -0
- package/dist/test-utils/temp-home.js +33 -0
- package/dist/tui/components/chat-log.js +9 -0
- package/dist/tui/tui-command-handlers.js +36 -27
- package/dist/tui/tui-event-handlers.js +122 -32
- package/dist/tui/tui.js +181 -45
- package/dist/utils/mask-api-key.js +10 -0
- package/dist/utils/run-with-concurrency.js +39 -0
- package/dist/web/media.js +4 -0
- package/docs/tools/slash-commands.md +5 -1
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/discord/package.json +1 -1
- package/extensions/feishu/package.json +1 -1
- package/extensions/feishu/src/external-keys.ts +19 -0
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/lobster/src/windows-spawn.ts +193 -0
- package/extensions/matrix/CHANGELOG.md +5 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/matrix/src/matrix/actions/limits.ts +6 -0
- package/extensions/mattermost/package.json +1 -1
- package/extensions/mattermost/src/mattermost/reactions.test-helpers.ts +83 -0
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +5 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +5 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/openai-codex-auth/package.json +1 -1
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +5 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +5 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +5 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +5 -0
- package/extensions/zalouser/package.json +1 -1
- package/package.json +1 -1
|
@@ -11,14 +11,24 @@ export const SELECTOR_UNSUPPORTED_MESSAGE = [
|
|
|
11
11
|
].join("\n");
|
|
12
12
|
export function readBody(req) {
|
|
13
13
|
const body = req.body;
|
|
14
|
-
if (!body || typeof body !== "object" || Array.isArray(body))
|
|
14
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
15
15
|
return {};
|
|
16
|
+
}
|
|
16
17
|
return body;
|
|
17
18
|
}
|
|
19
|
+
export function resolveTargetIdFromBody(body) {
|
|
20
|
+
const targetId = typeof body.targetId === "string" ? body.targetId.trim() : "";
|
|
21
|
+
return targetId || undefined;
|
|
22
|
+
}
|
|
23
|
+
export function resolveTargetIdFromQuery(query) {
|
|
24
|
+
const targetId = typeof query.targetId === "string" ? query.targetId.trim() : "";
|
|
25
|
+
return targetId || undefined;
|
|
26
|
+
}
|
|
18
27
|
export function handleRouteError(ctx, res, err) {
|
|
19
28
|
const mapped = ctx.mapTabError(err);
|
|
20
|
-
if (mapped)
|
|
29
|
+
if (mapped) {
|
|
21
30
|
return jsonError(res, mapped.status, mapped.message);
|
|
31
|
+
}
|
|
22
32
|
jsonError(res, 500, String(err));
|
|
23
33
|
}
|
|
24
34
|
export function resolveProfileContext(req, res, ctx) {
|
|
@@ -34,8 +44,9 @@ export async function getPwAiModule() {
|
|
|
34
44
|
}
|
|
35
45
|
export async function requirePwAi(res, feature) {
|
|
36
46
|
const mod = await getPwAiModule();
|
|
37
|
-
if (mod)
|
|
47
|
+
if (mod) {
|
|
38
48
|
return mod;
|
|
49
|
+
}
|
|
39
50
|
jsonError(res, 501, [
|
|
40
51
|
`Playwright is not available in this gateway build; '${feature}' is unsupported.`,
|
|
41
52
|
"Install the full Playwright package (not playwright-core) and restart the gateway, or reinstall with browser support.",
|
|
@@ -43,3 +54,36 @@ export async function requirePwAi(res, feature) {
|
|
|
43
54
|
].join("\n"));
|
|
44
55
|
return null;
|
|
45
56
|
}
|
|
57
|
+
export async function withRouteTabContext(params) {
|
|
58
|
+
const profileCtx = resolveProfileContext(params.req, params.res, params.ctx);
|
|
59
|
+
if (!profileCtx) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const tab = await profileCtx.ensureTabAvailable(params.targetId);
|
|
64
|
+
return await params.run({
|
|
65
|
+
profileCtx,
|
|
66
|
+
tab,
|
|
67
|
+
cdpUrl: profileCtx.profile.cdpUrl,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
handleRouteError(params.ctx, params.res, err);
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export async function withPlaywrightRouteContext(params) {
|
|
76
|
+
return await withRouteTabContext({
|
|
77
|
+
req: params.req,
|
|
78
|
+
res: params.res,
|
|
79
|
+
ctx: params.ctx,
|
|
80
|
+
targetId: params.targetId,
|
|
81
|
+
run: async ({ profileCtx, tab, cdpUrl }) => {
|
|
82
|
+
const pw = await requirePwAi(params.res, params.feature);
|
|
83
|
+
if (!pw) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
return await params.run({ profileCtx, tab, cdpUrl, pw });
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
@@ -2,67 +2,71 @@ import path from "node:path";
|
|
|
2
2
|
import { ensureMediaDir, saveMediaBuffer } from "../../media/store.js";
|
|
3
3
|
import { captureScreenshot, snapshotAria } from "../cdp.js";
|
|
4
4
|
import { DEFAULT_AI_SNAPSHOT_EFFICIENT_DEPTH, DEFAULT_AI_SNAPSHOT_EFFICIENT_MAX_CHARS, DEFAULT_AI_SNAPSHOT_MAX_CHARS, } from "../constants.js";
|
|
5
|
+
import { withBrowserNavigationPolicy } from "../navigation-guard.js";
|
|
5
6
|
import { DEFAULT_BROWSER_SCREENSHOT_MAX_BYTES, DEFAULT_BROWSER_SCREENSHOT_MAX_SIDE, normalizeBrowserScreenshot, } from "../screenshot.js";
|
|
6
|
-
import { getPwAiModule, handleRouteError, readBody, requirePwAi, resolveProfileContext, } from "./agent.shared.js";
|
|
7
|
+
import { getPwAiModule, handleRouteError, readBody, requirePwAi, resolveProfileContext, withPlaywrightRouteContext, withRouteTabContext, } from "./agent.shared.js";
|
|
7
8
|
import { jsonError, toBoolean, toNumber, toStringOrEmpty } from "./utils.js";
|
|
9
|
+
async function saveBrowserMediaResponse(params) {
|
|
10
|
+
await ensureMediaDir();
|
|
11
|
+
const saved = await saveMediaBuffer(params.buffer, params.contentType, "browser", params.maxBytes);
|
|
12
|
+
params.res.json({
|
|
13
|
+
ok: true,
|
|
14
|
+
path: path.resolve(saved.path),
|
|
15
|
+
targetId: params.targetId,
|
|
16
|
+
url: params.url,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
8
19
|
export function registerBrowserAgentSnapshotRoutes(app, ctx) {
|
|
9
20
|
app.post("/navigate", async (req, res) => {
|
|
10
|
-
const profileCtx = resolveProfileContext(req, res, ctx);
|
|
11
|
-
if (!profileCtx)
|
|
12
|
-
return;
|
|
13
21
|
const body = readBody(req);
|
|
14
22
|
const url = toStringOrEmpty(body.url);
|
|
15
23
|
const targetId = toStringOrEmpty(body.targetId) || undefined;
|
|
16
|
-
if (!url)
|
|
24
|
+
if (!url) {
|
|
17
25
|
return jsonError(res, 400, "url is required");
|
|
18
|
-
try {
|
|
19
|
-
const tab = await profileCtx.ensureTabAvailable(targetId);
|
|
20
|
-
const pw = await requirePwAi(res, "navigate");
|
|
21
|
-
if (!pw)
|
|
22
|
-
return;
|
|
23
|
-
const result = await pw.navigateViaPlaywright({
|
|
24
|
-
cdpUrl: profileCtx.profile.cdpUrl,
|
|
25
|
-
targetId: tab.targetId,
|
|
26
|
-
url,
|
|
27
|
-
});
|
|
28
|
-
res.json({ ok: true, targetId: tab.targetId, ...result });
|
|
29
|
-
}
|
|
30
|
-
catch (err) {
|
|
31
|
-
handleRouteError(ctx, res, err);
|
|
32
26
|
}
|
|
27
|
+
await withPlaywrightRouteContext({
|
|
28
|
+
req,
|
|
29
|
+
res,
|
|
30
|
+
ctx,
|
|
31
|
+
targetId,
|
|
32
|
+
feature: "navigate",
|
|
33
|
+
run: async ({ cdpUrl, tab, pw }) => {
|
|
34
|
+
const result = await pw.navigateViaPlaywright({
|
|
35
|
+
cdpUrl,
|
|
36
|
+
targetId: tab.targetId,
|
|
37
|
+
url,
|
|
38
|
+
...withBrowserNavigationPolicy(ctx.state().resolved.ssrfPolicy),
|
|
39
|
+
});
|
|
40
|
+
res.json({ ok: true, targetId: tab.targetId, ...result });
|
|
41
|
+
},
|
|
42
|
+
});
|
|
33
43
|
});
|
|
34
44
|
app.post("/pdf", async (req, res) => {
|
|
35
|
-
const profileCtx = resolveProfileContext(req, res, ctx);
|
|
36
|
-
if (!profileCtx)
|
|
37
|
-
return;
|
|
38
45
|
const body = readBody(req);
|
|
39
46
|
const targetId = toStringOrEmpty(body.targetId) || undefined;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
47
|
+
await withPlaywrightRouteContext({
|
|
48
|
+
req,
|
|
49
|
+
res,
|
|
50
|
+
ctx,
|
|
51
|
+
targetId,
|
|
52
|
+
feature: "pdf",
|
|
53
|
+
run: async ({ cdpUrl, tab, pw }) => {
|
|
54
|
+
const pdf = await pw.pdfViaPlaywright({
|
|
55
|
+
cdpUrl,
|
|
56
|
+
targetId: tab.targetId,
|
|
57
|
+
});
|
|
58
|
+
await saveBrowserMediaResponse({
|
|
59
|
+
res,
|
|
60
|
+
buffer: pdf.buffer,
|
|
61
|
+
contentType: "application/pdf",
|
|
62
|
+
maxBytes: pdf.buffer.byteLength,
|
|
63
|
+
targetId: tab.targetId,
|
|
64
|
+
url: tab.url,
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
});
|
|
61
68
|
});
|
|
62
69
|
app.post("/screenshot", async (req, res) => {
|
|
63
|
-
const profileCtx = resolveProfileContext(req, res, ctx);
|
|
64
|
-
if (!profileCtx)
|
|
65
|
-
return;
|
|
66
70
|
const body = readBody(req);
|
|
67
71
|
const targetId = toStringOrEmpty(body.targetId) || undefined;
|
|
68
72
|
const fullPage = toBoolean(body.fullPage) ?? false;
|
|
@@ -72,53 +76,60 @@ export function registerBrowserAgentSnapshotRoutes(app, ctx) {
|
|
|
72
76
|
if (fullPage && (ref || element)) {
|
|
73
77
|
return jsonError(res, 400, "fullPage is not supported for element screenshots");
|
|
74
78
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
79
|
+
await withRouteTabContext({
|
|
80
|
+
req,
|
|
81
|
+
res,
|
|
82
|
+
ctx,
|
|
83
|
+
targetId,
|
|
84
|
+
run: async ({ profileCtx, tab, cdpUrl }) => {
|
|
85
|
+
let buffer;
|
|
86
|
+
const shouldUsePlaywright = profileCtx.profile.driver === "extension" ||
|
|
87
|
+
!tab.wsUrl ||
|
|
88
|
+
Boolean(ref) ||
|
|
89
|
+
Boolean(element);
|
|
90
|
+
if (shouldUsePlaywright) {
|
|
91
|
+
const pw = await requirePwAi(res, "screenshot");
|
|
92
|
+
if (!pw) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const snap = await pw.takeScreenshotViaPlaywright({
|
|
96
|
+
cdpUrl,
|
|
97
|
+
targetId: tab.targetId,
|
|
98
|
+
ref,
|
|
99
|
+
element,
|
|
100
|
+
fullPage,
|
|
101
|
+
type,
|
|
102
|
+
});
|
|
103
|
+
buffer = snap.buffer;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
buffer = await captureScreenshot({
|
|
107
|
+
wsUrl: tab.wsUrl ?? "",
|
|
108
|
+
fullPage,
|
|
109
|
+
format: type,
|
|
110
|
+
quality: type === "jpeg" ? 85 : undefined,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
const normalized = await normalizeBrowserScreenshot(buffer, {
|
|
114
|
+
maxSide: DEFAULT_BROWSER_SCREENSHOT_MAX_SIDE,
|
|
115
|
+
maxBytes: DEFAULT_BROWSER_SCREENSHOT_MAX_BYTES,
|
|
90
116
|
});
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
quality: type === "jpeg" ? 85 : undefined,
|
|
117
|
+
await saveBrowserMediaResponse({
|
|
118
|
+
res,
|
|
119
|
+
buffer: normalized.buffer,
|
|
120
|
+
contentType: normalized.contentType ?? `image/${type}`,
|
|
121
|
+
maxBytes: DEFAULT_BROWSER_SCREENSHOT_MAX_BYTES,
|
|
122
|
+
targetId: tab.targetId,
|
|
123
|
+
url: tab.url,
|
|
99
124
|
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
maxSide: DEFAULT_BROWSER_SCREENSHOT_MAX_SIDE,
|
|
103
|
-
maxBytes: DEFAULT_BROWSER_SCREENSHOT_MAX_BYTES,
|
|
104
|
-
});
|
|
105
|
-
await ensureMediaDir();
|
|
106
|
-
const saved = await saveMediaBuffer(normalized.buffer, normalized.contentType ?? `image/${type}`, "browser", DEFAULT_BROWSER_SCREENSHOT_MAX_BYTES);
|
|
107
|
-
res.json({
|
|
108
|
-
ok: true,
|
|
109
|
-
path: path.resolve(saved.path),
|
|
110
|
-
targetId: tab.targetId,
|
|
111
|
-
url: tab.url,
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
catch (err) {
|
|
115
|
-
handleRouteError(ctx, res, err);
|
|
116
|
-
}
|
|
125
|
+
},
|
|
126
|
+
});
|
|
117
127
|
});
|
|
118
128
|
app.get("/snapshot", async (req, res) => {
|
|
119
129
|
const profileCtx = resolveProfileContext(req, res, ctx);
|
|
120
|
-
if (!profileCtx)
|
|
130
|
+
if (!profileCtx) {
|
|
121
131
|
return;
|
|
132
|
+
}
|
|
122
133
|
const targetId = typeof req.query.targetId === "string" ? req.query.targetId.trim() : "";
|
|
123
134
|
const mode = req.query.mode === "efficient" ? "efficient" : undefined;
|
|
124
135
|
const labels = toBoolean(req.query.labels) ?? undefined;
|
|
@@ -148,6 +159,8 @@ export function registerBrowserAgentSnapshotRoutes(app, ctx) {
|
|
|
148
159
|
const depth = depthRaw ?? (mode === "efficient" ? DEFAULT_AI_SNAPSHOT_EFFICIENT_DEPTH : undefined);
|
|
149
160
|
const selector = toStringOrEmpty(req.query.selector);
|
|
150
161
|
const frameSelector = toStringOrEmpty(req.query.frame);
|
|
162
|
+
const selectorValue = selector.trim() || undefined;
|
|
163
|
+
const frameSelectorValue = frameSelector.trim() || undefined;
|
|
151
164
|
try {
|
|
152
165
|
const tab = await profileCtx.ensureTabAvailable(targetId || undefined);
|
|
153
166
|
if ((labels || mode === "efficient") && format === "aria") {
|
|
@@ -155,28 +168,30 @@ export function registerBrowserAgentSnapshotRoutes(app, ctx) {
|
|
|
155
168
|
}
|
|
156
169
|
if (format === "ai") {
|
|
157
170
|
const pw = await requirePwAi(res, "ai snapshot");
|
|
158
|
-
if (!pw)
|
|
171
|
+
if (!pw) {
|
|
159
172
|
return;
|
|
173
|
+
}
|
|
160
174
|
const wantsRoleSnapshot = labels === true ||
|
|
161
175
|
mode === "efficient" ||
|
|
162
176
|
interactive === true ||
|
|
163
177
|
compact === true ||
|
|
164
178
|
depth !== undefined ||
|
|
165
|
-
Boolean(
|
|
166
|
-
Boolean(
|
|
179
|
+
Boolean(selectorValue) ||
|
|
180
|
+
Boolean(frameSelectorValue);
|
|
181
|
+
const roleSnapshotArgs = {
|
|
182
|
+
cdpUrl: profileCtx.profile.cdpUrl,
|
|
183
|
+
targetId: tab.targetId,
|
|
184
|
+
selector: selectorValue,
|
|
185
|
+
frameSelector: frameSelectorValue,
|
|
186
|
+
refsMode,
|
|
187
|
+
options: {
|
|
188
|
+
interactive: interactive ?? undefined,
|
|
189
|
+
compact: compact ?? undefined,
|
|
190
|
+
maxDepth: depth ?? undefined,
|
|
191
|
+
},
|
|
192
|
+
};
|
|
167
193
|
const snap = wantsRoleSnapshot
|
|
168
|
-
? await pw.snapshotRoleViaPlaywright(
|
|
169
|
-
cdpUrl: profileCtx.profile.cdpUrl,
|
|
170
|
-
targetId: tab.targetId,
|
|
171
|
-
selector: selector.trim() || undefined,
|
|
172
|
-
frameSelector: frameSelector.trim() || undefined,
|
|
173
|
-
refsMode,
|
|
174
|
-
options: {
|
|
175
|
-
interactive: interactive ?? undefined,
|
|
176
|
-
compact: compact ?? undefined,
|
|
177
|
-
maxDepth: depth ?? undefined,
|
|
178
|
-
},
|
|
179
|
-
})
|
|
194
|
+
? await pw.snapshotRoleViaPlaywright(roleSnapshotArgs)
|
|
180
195
|
: await pw
|
|
181
196
|
.snapshotAiViaPlaywright({
|
|
182
197
|
cdpUrl: profileCtx.profile.cdpUrl,
|
|
@@ -186,18 +201,7 @@ export function registerBrowserAgentSnapshotRoutes(app, ctx) {
|
|
|
186
201
|
.catch(async (err) => {
|
|
187
202
|
// Public-API fallback when Playwright's private _snapshotForAI is missing.
|
|
188
203
|
if (String(err).toLowerCase().includes("_snapshotforai")) {
|
|
189
|
-
return await pw.snapshotRoleViaPlaywright(
|
|
190
|
-
cdpUrl: profileCtx.profile.cdpUrl,
|
|
191
|
-
targetId: tab.targetId,
|
|
192
|
-
selector: selector.trim() || undefined,
|
|
193
|
-
frameSelector: frameSelector.trim() || undefined,
|
|
194
|
-
refsMode,
|
|
195
|
-
options: {
|
|
196
|
-
interactive: interactive ?? undefined,
|
|
197
|
-
compact: compact ?? undefined,
|
|
198
|
-
maxDepth: depth ?? undefined,
|
|
199
|
-
},
|
|
200
|
-
});
|
|
204
|
+
return await pw.snapshotRoleViaPlaywright(roleSnapshotArgs);
|
|
201
205
|
}
|
|
202
206
|
throw err;
|
|
203
207
|
});
|
|
@@ -241,8 +245,9 @@ export function registerBrowserAgentSnapshotRoutes(app, ctx) {
|
|
|
241
245
|
// Extension relay doesn't expose per-page WS URLs; run AX snapshot via Playwright CDP session.
|
|
242
246
|
// Also covers cases where wsUrl is missing/unusable.
|
|
243
247
|
return requirePwAi(res, "aria snapshot").then(async (pw) => {
|
|
244
|
-
if (!pw)
|
|
248
|
+
if (!pw) {
|
|
245
249
|
return null;
|
|
250
|
+
}
|
|
246
251
|
return await pw.snapshotAriaViaPlaywright({
|
|
247
252
|
cdpUrl: profileCtx.profile.cdpUrl,
|
|
248
253
|
targetId: tab.targetId,
|
|
@@ -252,8 +257,9 @@ export function registerBrowserAgentSnapshotRoutes(app, ctx) {
|
|
|
252
257
|
})()
|
|
253
258
|
: snapshotAria({ wsUrl: tab.wsUrl ?? "", limit });
|
|
254
259
|
const resolved = await Promise.resolve(snap);
|
|
255
|
-
if (!resolved)
|
|
260
|
+
if (!resolved) {
|
|
256
261
|
return;
|
|
262
|
+
}
|
|
257
263
|
return res.json({
|
|
258
264
|
ok: true,
|
|
259
265
|
format,
|