@poolzin/pool-bot 2026.2.0 → 2026.2.2
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 +118 -0
- package/README-header.png +0 -0
- package/dist/agents/bash-tools.exec.js +76 -25
- package/dist/agents/cli-runner/helpers.js +9 -11
- package/dist/agents/context.js +1 -1
- package/dist/agents/identity.js +47 -7
- package/dist/agents/memory-search.js +25 -8
- package/dist/agents/model-catalog.js +1 -1
- package/dist/agents/model-selection.js +21 -0
- package/dist/agents/pi-embedded-block-chunker.js +117 -42
- package/dist/agents/pi-embedded-helpers/errors.js +183 -78
- package/dist/agents/pi-embedded-helpers.js +1 -1
- package/dist/agents/pi-embedded-runner/compact.js +8 -10
- package/dist/agents/pi-embedded-runner/model.js +62 -3
- package/dist/agents/pi-embedded-runner/run/attempt.js +21 -11
- package/dist/agents/pi-embedded-runner/run.js +199 -46
- package/dist/agents/pi-embedded-runner/system-prompt.js +10 -2
- package/dist/agents/pi-embedded-subscribe.js +118 -29
- package/dist/agents/pi-tools.js +10 -5
- package/dist/agents/poolbot-tools.js +15 -10
- package/dist/agents/sandbox-paths.js +31 -0
- package/dist/agents/session-tool-result-guard.js +94 -15
- package/dist/agents/shell-utils.js +51 -0
- package/dist/agents/skills/bundled-context.js +23 -0
- package/dist/agents/skills/bundled-dir.js +41 -7
- package/dist/agents/skills-install.js +60 -23
- package/dist/agents/subagent-announce.js +79 -34
- package/dist/agents/tool-policy.conformance.js +14 -0
- package/dist/agents/tool-policy.js +24 -0
- package/dist/agents/tools/cron-tool.js +166 -19
- package/dist/agents/tools/discord-actions-presence.js +78 -0
- package/dist/agents/tools/image-tool.js +1 -1
- package/dist/agents/tools/message-tool.js +56 -2
- package/dist/agents/tools/sessions-history-tool.js +69 -1
- package/dist/agents/tools/web-search.js +211 -42
- package/dist/agents/usage.js +23 -1
- package/dist/agents/workspace-run.js +67 -0
- package/dist/agents/workspace-templates.js +44 -0
- package/dist/auto-reply/command-auth.js +121 -6
- package/dist/auto-reply/envelope.js +74 -82
- package/dist/auto-reply/reply/commands-compact.js +1 -0
- package/dist/auto-reply/reply/commands-context-report.js +1 -0
- package/dist/auto-reply/reply/commands-context.js +1 -0
- package/dist/auto-reply/reply/commands-models.js +107 -60
- package/dist/auto-reply/reply/commands-ptt.js +171 -0
- package/dist/auto-reply/reply/get-reply-run.js +2 -1
- package/dist/auto-reply/reply/inbound-context.js +5 -1
- package/dist/auto-reply/reply/mentions.js +1 -1
- package/dist/auto-reply/reply/model-selection.js +3 -3
- package/dist/auto-reply/thinking.js +88 -43
- package/dist/browser/bridge-server.js +13 -0
- package/dist/browser/cdp.helpers.js +38 -24
- package/dist/browser/client-fetch.js +50 -7
- package/dist/browser/config.js +1 -10
- package/dist/browser/extension-relay.js +101 -40
- package/dist/browser/pw-ai.js +1 -1
- package/dist/browser/pw-session.js +143 -8
- package/dist/browser/pw-tools-core.interactions.js +125 -27
- package/dist/browser/pw-tools-core.responses.js +1 -1
- package/dist/browser/pw-tools-core.state.js +1 -1
- package/dist/browser/routes/agent.act.js +86 -41
- package/dist/browser/routes/dispatcher.js +4 -4
- package/dist/browser/screenshot.js +1 -1
- package/dist/browser/server.js +13 -0
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/index.html +28 -28
- package/dist/channels/reply-prefix.js +8 -1
- package/dist/cli/cron-cli/register.cron-add.js +61 -40
- package/dist/cli/cron-cli/register.cron-edit.js +60 -34
- package/dist/cli/cron-cli/shared.js +56 -41
- package/dist/cli/dns-cli.js +26 -14
- package/dist/cli/gateway-cli/register.js +37 -19
- package/dist/cli/memory-cli.js +5 -5
- package/dist/cli/parse-bytes.js +37 -0
- package/dist/cli/update-cli.js +173 -52
- package/dist/commands/agent.js +1 -0
- package/dist/commands/auth-choice.apply.oauth.js +1 -1
- package/dist/commands/doctor-config-flow.js +61 -5
- package/dist/commands/doctor-state-migrations.js +1 -1
- package/dist/commands/health.js +1 -1
- package/dist/commands/model-allowlist.js +29 -0
- package/dist/commands/model-picker.js +2 -1
- package/dist/commands/models/list.registry.js +1 -1
- package/dist/commands/models/list.status-command.js +43 -23
- package/dist/commands/models/shared.js +15 -0
- package/dist/commands/onboard-custom.js +384 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice-inference.js +35 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +6 -3
- package/dist/commands/onboard-skills.js +63 -38
- package/dist/commands/openai-model-default.js +41 -0
- package/dist/compat/legacy-names.js +2 -0
- package/dist/config/defaults.js +3 -2
- package/dist/config/paths.js +136 -35
- package/dist/config/plugin-auto-enable.js +21 -5
- package/dist/config/redact-snapshot.js +153 -0
- package/dist/config/schema.field-metadata.js +590 -0
- package/dist/config/schema.js +2 -2
- package/dist/config/sessions/store.js +291 -23
- package/dist/config/zod-schema.agent-defaults.js +3 -0
- package/dist/config/zod-schema.agent-runtime.js +13 -2
- package/dist/config/zod-schema.providers-core.js +142 -0
- package/dist/config/zod-schema.session.js +3 -0
- package/dist/control-ui/assets/{index-CIRDm-Lu.css → index-CSfXd2LO.css} +1 -1
- package/dist/control-ui/assets/{index-CmNMuoem.js → index-HRr1grwl.js} +446 -413
- package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -0
- package/dist/control-ui/index.html +4 -4
- package/dist/cron/delivery.js +57 -0
- package/dist/cron/isolated-agent/delivery-target.js +18 -3
- package/dist/cron/isolated-agent/helpers.js +22 -5
- package/dist/cron/isolated-agent/run.js +172 -63
- package/dist/cron/isolated-agent/session.js +2 -0
- package/dist/cron/normalize.js +356 -28
- package/dist/cron/parse.js +10 -5
- package/dist/cron/run-log.js +35 -10
- package/dist/cron/schedule.js +41 -6
- package/dist/cron/service/jobs.js +208 -35
- package/dist/cron/service/ops.js +72 -16
- package/dist/cron/service/state.js +2 -0
- package/dist/cron/service/store.js +386 -14
- package/dist/cron/service/timer.js +390 -147
- package/dist/cron/session-reaper.js +86 -0
- package/dist/cron/store.js +23 -8
- package/dist/cron/validate-timestamp.js +43 -0
- package/dist/discord/monitor/agent-components.js +438 -0
- package/dist/discord/monitor/allow-list.js +28 -5
- package/dist/discord/monitor/gateway-registry.js +29 -0
- package/dist/discord/monitor/native-command.js +44 -23
- package/dist/discord/monitor/sender-identity.js +45 -0
- package/dist/discord/pluralkit.js +27 -0
- package/dist/discord/send.outbound.js +92 -5
- package/dist/discord/send.shared.js +60 -23
- package/dist/discord/targets.js +84 -1
- package/dist/entry.js +15 -9
- package/dist/extensionAPI.js +8 -0
- package/dist/gateway/control-ui.js +8 -1
- package/dist/gateway/hooks-mapping.js +3 -0
- package/dist/gateway/hooks.js +65 -0
- package/dist/gateway/net.js +96 -31
- package/dist/gateway/node-command-policy.js +50 -15
- package/dist/gateway/origin-check.js +56 -0
- package/dist/gateway/protocol/client-info.js +9 -0
- package/dist/gateway/protocol/index.js +9 -2
- package/dist/gateway/protocol/schema/agents-models-skills.js +71 -1
- package/dist/gateway/protocol/schema/cron.js +22 -10
- package/dist/gateway/protocol/schema/protocol-schemas.js +16 -2
- package/dist/gateway/protocol/schema/sessions.js +12 -0
- package/dist/gateway/server/hooks.js +1 -1
- package/dist/gateway/server-broadcast.js +26 -9
- package/dist/gateway/server-chat.js +112 -23
- package/dist/gateway/server-discovery-runtime.js +10 -2
- package/dist/gateway/server-http.js +109 -11
- package/dist/gateway/server-methods/agent-timestamp.js +60 -0
- package/dist/gateway/server-methods/agents.js +321 -2
- package/dist/gateway/server-methods/usage.js +559 -16
- package/dist/gateway/server-runtime-state.js +22 -8
- package/dist/gateway/server-startup-memory.js +16 -0
- package/dist/gateway/server.impl.js +5 -1
- package/dist/gateway/session-utils.fs.js +23 -25
- package/dist/gateway/session-utils.js +20 -10
- package/dist/gateway/sessions-patch.js +7 -22
- package/dist/gateway/test-helpers.mocks.js +11 -7
- package/dist/gateway/test-helpers.server.js +35 -2
- package/dist/imessage/constants.js +2 -0
- package/dist/imessage/monitor/deliver.js +4 -1
- package/dist/imessage/monitor/monitor-provider.js +51 -1
- package/dist/infra/bonjour-discovery.js +131 -70
- package/dist/infra/control-ui-assets.js +134 -12
- package/dist/infra/errors.js +12 -0
- package/dist/infra/exec-approvals.js +266 -57
- package/dist/infra/format-time/format-datetime.js +79 -0
- package/dist/infra/format-time/format-duration.js +81 -0
- package/dist/infra/format-time/format-relative.js +80 -0
- package/dist/infra/heartbeat-runner.js +140 -49
- package/dist/infra/home-dir.js +54 -0
- package/dist/infra/net/fetch-guard.js +122 -0
- package/dist/infra/net/ssrf.js +65 -29
- package/dist/infra/outbound/abort.js +14 -0
- package/dist/infra/outbound/message-action-runner.js +77 -13
- package/dist/infra/outbound/outbound-session.js +143 -37
- package/dist/infra/poolbot-root.js +43 -1
- package/dist/infra/session-cost-usage.js +631 -41
- package/dist/infra/state-migrations.js +317 -47
- package/dist/infra/update-global.js +35 -0
- package/dist/infra/update-runner.js +149 -43
- package/dist/infra/warning-filter.js +65 -0
- package/dist/infra/widearea-dns.js +30 -9
- package/dist/logging/redact-identifier.js +12 -0
- package/dist/media/fetch.js +81 -58
- package/dist/media/store.js +2 -0
- package/dist/media-understanding/apply.js +403 -3
- package/dist/media-understanding/attachments.js +38 -27
- package/dist/media-understanding/defaults.js +16 -0
- package/dist/media-understanding/providers/deepgram/audio.js +22 -14
- package/dist/media-understanding/providers/google/audio.js +24 -17
- package/dist/media-understanding/providers/google/video.js +24 -17
- package/dist/media-understanding/providers/image.js +3 -3
- package/dist/media-understanding/providers/index.js +4 -1
- package/dist/media-understanding/providers/openai/audio.js +22 -14
- package/dist/media-understanding/providers/shared.js +16 -11
- package/dist/media-understanding/providers/zai/index.js +6 -0
- package/dist/media-understanding/runner.js +158 -90
- package/dist/memory/batch-voyage.js +277 -0
- package/dist/memory/embeddings-voyage.js +75 -0
- package/dist/memory/embeddings.js +28 -16
- package/dist/memory/internal.js +101 -18
- package/dist/memory/manager.js +154 -48
- package/dist/memory/search-manager.js +173 -0
- package/dist/memory/session-files.js +9 -3
- package/dist/node-host/runner.js +34 -24
- package/dist/node-host/with-timeout.js +27 -0
- package/dist/plugins/commands.js +5 -1
- package/dist/plugins/config-state.js +86 -7
- package/dist/plugins/source-display.js +51 -0
- package/dist/process/exec.js +20 -2
- package/dist/routing/resolve-route.js +12 -0
- package/dist/routing/session-key.js +15 -0
- package/dist/runtime.js +2 -0
- package/dist/security/audit-extra.async.js +601 -0
- package/dist/security/audit-extra.js +2 -830
- package/dist/security/audit-extra.sync.js +505 -0
- package/dist/security/channel-metadata.js +34 -0
- package/dist/security/external-content.js +88 -6
- package/dist/security/skill-scanner.js +330 -0
- package/dist/sessions/session-key-utils.js +7 -0
- package/dist/signal/monitor/event-handler.js +80 -1
- package/dist/slack/monitor/media.js +85 -15
- package/dist/tailscale/detect.js +1 -2
- package/dist/telegram/bot/helpers.js +109 -28
- package/dist/telegram/bot-handlers.js +144 -3
- package/dist/telegram/bot-message-context.js +37 -10
- package/dist/telegram/bot-message-dispatch.js +54 -17
- package/dist/telegram/bot-native-commands.js +86 -29
- package/dist/telegram/bot.js +30 -29
- package/dist/telegram/model-buttons.js +163 -0
- package/dist/telegram/monitor.js +110 -85
- package/dist/telegram/send.js +129 -47
- package/dist/terminal/restore.js +45 -0
- package/dist/test-helpers/state-dir-env.js +16 -0
- package/dist/tts/tts.js +12 -6
- package/dist/tui/tui-session-actions.js +166 -54
- package/dist/utils/fetch-timeout.js +20 -0
- package/dist/utils/normalize-secret-input.js +19 -0
- package/dist/utils/transcript-tools.js +58 -0
- package/dist/utils.js +45 -14
- package/dist/version.js +42 -5
- package/dist/wizard/clack-prompter.js +9 -6
- package/extensions/googlechat/node_modules/.bin/poolbot +21 -0
- package/extensions/googlechat/package.json +2 -2
- package/extensions/line/node_modules/.bin/poolbot +21 -0
- package/extensions/line/package.json +1 -1
- package/extensions/matrix/node_modules/.bin/poolbot +21 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/memory-core/node_modules/.bin/poolbot +21 -0
- package/extensions/memory-core/package.json +4 -1
- package/extensions/twitch/node_modules/.bin/poolbot +21 -0
- package/extensions/twitch/package.json +1 -1
- package/package.json +183 -24
- package/dist/control-ui/assets/index-CmNMuoem.js.map +0 -1
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { callGateway, randomIdempotencyKey } from "../../gateway/call.js";
|
|
2
|
+
import { logVerbose } from "../../globals.js";
|
|
3
|
+
const PTT_COMMANDS = {
|
|
4
|
+
start: "talk.ptt.start",
|
|
5
|
+
stop: "talk.ptt.stop",
|
|
6
|
+
once: "talk.ptt.once",
|
|
7
|
+
cancel: "talk.ptt.cancel",
|
|
8
|
+
};
|
|
9
|
+
function normalizeNodeKey(value) {
|
|
10
|
+
return value
|
|
11
|
+
.toLowerCase()
|
|
12
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
13
|
+
.replace(/^-+/, "")
|
|
14
|
+
.replace(/-+$/, "");
|
|
15
|
+
}
|
|
16
|
+
function isIOSNode(node) {
|
|
17
|
+
const platform = node.platform?.toLowerCase() ?? "";
|
|
18
|
+
const family = node.deviceFamily?.toLowerCase() ?? "";
|
|
19
|
+
return (platform.startsWith("ios") ||
|
|
20
|
+
family.includes("iphone") ||
|
|
21
|
+
family.includes("ipad") ||
|
|
22
|
+
family.includes("ios"));
|
|
23
|
+
}
|
|
24
|
+
async function loadNodes(cfg) {
|
|
25
|
+
try {
|
|
26
|
+
const res = await callGateway({
|
|
27
|
+
method: "node.list",
|
|
28
|
+
params: {},
|
|
29
|
+
config: cfg,
|
|
30
|
+
});
|
|
31
|
+
return Array.isArray(res.nodes) ? res.nodes : [];
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
const res = await callGateway({
|
|
35
|
+
method: "node.pair.list",
|
|
36
|
+
params: {},
|
|
37
|
+
config: cfg,
|
|
38
|
+
});
|
|
39
|
+
return Array.isArray(res.paired) ? res.paired : [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function describeNodes(nodes) {
|
|
43
|
+
return nodes
|
|
44
|
+
.map((node) => node.displayName || node.remoteIp || node.nodeId)
|
|
45
|
+
.filter(Boolean)
|
|
46
|
+
.join(", ");
|
|
47
|
+
}
|
|
48
|
+
function resolveNodeId(nodes, query) {
|
|
49
|
+
const trimmed = String(query ?? "").trim();
|
|
50
|
+
if (trimmed) {
|
|
51
|
+
const qNorm = normalizeNodeKey(trimmed);
|
|
52
|
+
const matches = nodes.filter((node) => {
|
|
53
|
+
if (node.nodeId === trimmed) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
if (typeof node.remoteIp === "string" && node.remoteIp === trimmed) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
const name = typeof node.displayName === "string" ? node.displayName : "";
|
|
60
|
+
if (name && normalizeNodeKey(name) === qNorm) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
if (trimmed.length >= 6 && node.nodeId.startsWith(trimmed)) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
});
|
|
68
|
+
if (matches.length === 1) {
|
|
69
|
+
return matches[0].nodeId;
|
|
70
|
+
}
|
|
71
|
+
const known = describeNodes(nodes);
|
|
72
|
+
if (matches.length === 0) {
|
|
73
|
+
throw new Error(`unknown node: ${trimmed}${known ? ` (known: ${known})` : ""}`);
|
|
74
|
+
}
|
|
75
|
+
throw new Error(`ambiguous node: ${trimmed} (matches: ${matches
|
|
76
|
+
.map((node) => node.displayName || node.remoteIp || node.nodeId)
|
|
77
|
+
.join(", ")})`);
|
|
78
|
+
}
|
|
79
|
+
const iosNodes = nodes.filter(isIOSNode);
|
|
80
|
+
const iosConnected = iosNodes.filter((node) => node.connected);
|
|
81
|
+
const iosCandidates = iosConnected.length > 0 ? iosConnected : iosNodes;
|
|
82
|
+
if (iosCandidates.length === 1) {
|
|
83
|
+
return iosCandidates[0].nodeId;
|
|
84
|
+
}
|
|
85
|
+
if (iosCandidates.length > 1) {
|
|
86
|
+
throw new Error(`multiple iOS nodes found (${describeNodes(iosCandidates)}); specify node=<id>`);
|
|
87
|
+
}
|
|
88
|
+
const connected = nodes.filter((node) => node.connected);
|
|
89
|
+
const fallback = connected.length > 0 ? connected : nodes;
|
|
90
|
+
if (fallback.length === 1) {
|
|
91
|
+
return fallback[0].nodeId;
|
|
92
|
+
}
|
|
93
|
+
const known = describeNodes(nodes);
|
|
94
|
+
throw new Error(`node required${known ? ` (known: ${known})` : ""}`);
|
|
95
|
+
}
|
|
96
|
+
function parsePTTArgs(commandBody) {
|
|
97
|
+
const tokens = commandBody.trim().split(/\s+/).slice(1);
|
|
98
|
+
let action;
|
|
99
|
+
let node;
|
|
100
|
+
for (const token of tokens) {
|
|
101
|
+
if (!token) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (token.toLowerCase().startsWith("node=")) {
|
|
105
|
+
node = token.slice("node=".length);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (!action) {
|
|
109
|
+
action = token;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return { action, node };
|
|
113
|
+
}
|
|
114
|
+
function buildPTTHelpText() {
|
|
115
|
+
return [
|
|
116
|
+
"Usage: /ptt <start|stop|once|cancel> [node=<id>]",
|
|
117
|
+
"Example: /ptt once node=iphone",
|
|
118
|
+
].join("\n");
|
|
119
|
+
}
|
|
120
|
+
export const handlePTTCommand = async (params, allowTextCommands) => {
|
|
121
|
+
if (!allowTextCommands) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
const { command, cfg } = params;
|
|
125
|
+
const normalized = command.commandBodyNormalized.trim();
|
|
126
|
+
if (!normalized.startsWith("/ptt")) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
if (!command.isAuthorizedSender) {
|
|
130
|
+
logVerbose(`Ignoring /ptt from unauthorized sender: ${command.senderId || "<unknown>"}`);
|
|
131
|
+
return { shouldContinue: false, reply: { text: "PTT requires an authorized sender." } };
|
|
132
|
+
}
|
|
133
|
+
const parsed = parsePTTArgs(normalized);
|
|
134
|
+
const actionKey = parsed.action?.trim().toLowerCase() ?? "";
|
|
135
|
+
const commandId = PTT_COMMANDS[actionKey];
|
|
136
|
+
if (!commandId) {
|
|
137
|
+
return { shouldContinue: false, reply: { text: buildPTTHelpText() } };
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
const nodes = await loadNodes(cfg);
|
|
141
|
+
const nodeId = resolveNodeId(nodes, parsed.node);
|
|
142
|
+
const invokeParams = {
|
|
143
|
+
nodeId,
|
|
144
|
+
command: commandId,
|
|
145
|
+
params: {},
|
|
146
|
+
idempotencyKey: randomIdempotencyKey(),
|
|
147
|
+
timeoutMs: 15_000,
|
|
148
|
+
};
|
|
149
|
+
const res = await callGateway({
|
|
150
|
+
method: "node.invoke",
|
|
151
|
+
params: invokeParams,
|
|
152
|
+
config: cfg,
|
|
153
|
+
});
|
|
154
|
+
const payload = res.payload && typeof res.payload === "object" ? res.payload : {};
|
|
155
|
+
const lines = [`PTT ${actionKey} → ${nodeId}`];
|
|
156
|
+
if (typeof payload.status === "string") {
|
|
157
|
+
lines.push(`status: ${payload.status}`);
|
|
158
|
+
}
|
|
159
|
+
if (typeof payload.captureId === "string") {
|
|
160
|
+
lines.push(`captureId: ${payload.captureId}`);
|
|
161
|
+
}
|
|
162
|
+
if (typeof payload.transcript === "string" && payload.transcript.trim()) {
|
|
163
|
+
lines.push(`transcript: ${payload.transcript}`);
|
|
164
|
+
}
|
|
165
|
+
return { shouldContinue: false, reply: { text: lines.join("\n") } };
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
169
|
+
return { shouldContinue: false, reply: { text: `PTT failed: ${message}` } };
|
|
170
|
+
}
|
|
171
|
+
};
|
|
@@ -118,7 +118,7 @@ export async function runPreparedReply(params) {
|
|
|
118
118
|
const prefixedBody = [threadStarterNote, prefixedBodyBase].filter(Boolean).join("\n\n");
|
|
119
119
|
const mediaNote = buildInboundMediaNote(ctx);
|
|
120
120
|
const mediaReplyHint = mediaNote
|
|
121
|
-
? "To send an image back, prefer the message tool (media/path/filePath). If you must inline, use MEDIA
|
|
121
|
+
? "To send an image back, prefer the message tool (media/path/filePath). If you must inline, use MEDIA:https://example.com/image.jpg (spaces ok, quote if needed) or a safe relative path like MEDIA:./image.jpg. Avoid absolute paths (MEDIA:/...) and ~ paths — they are blocked for security. Keep caption in the text body."
|
|
122
122
|
: undefined;
|
|
123
123
|
let prefixedCommandBody = mediaNote
|
|
124
124
|
? [mediaNote, mediaReplyHint, prefixedBody ?? ""].filter(Boolean).join("\n").trim()
|
|
@@ -242,6 +242,7 @@ export async function runPreparedReply(params) {
|
|
|
242
242
|
senderName: sessionCtx.SenderName?.trim() || undefined,
|
|
243
243
|
senderUsername: sessionCtx.SenderUsername?.trim() || undefined,
|
|
244
244
|
senderE164: sessionCtx.SenderE164?.trim() || undefined,
|
|
245
|
+
senderIsOwner: command.senderIsOwner,
|
|
245
246
|
sessionFile,
|
|
246
247
|
workspaceDir,
|
|
247
248
|
config: cfg,
|
|
@@ -24,7 +24,11 @@ export function finalizeInboundContext(ctx, opts = {}) {
|
|
|
24
24
|
}
|
|
25
25
|
const bodyForAgentSource = opts.forceBodyForAgent
|
|
26
26
|
? normalized.Body
|
|
27
|
-
: (normalized.BodyForAgent ??
|
|
27
|
+
: (normalized.BodyForAgent ??
|
|
28
|
+
// Prefer "clean" text over legacy envelope-shaped Body when upstream forgets to set BodyForAgent.
|
|
29
|
+
normalized.CommandBody ??
|
|
30
|
+
normalized.RawBody ??
|
|
31
|
+
normalized.Body);
|
|
28
32
|
normalized.BodyForAgent = normalizeInboundTextNewlines(bodyForAgentSource);
|
|
29
33
|
const bodyForCommandsSource = opts.forceBodyForCommands
|
|
30
34
|
? (normalized.CommandBody ?? normalized.RawBody ?? normalized.Body)
|
|
@@ -73,7 +73,7 @@ export function matchesMentionWithExplicit(params) {
|
|
|
73
73
|
const explicitAvailable = params.explicit?.canResolveExplicit === true;
|
|
74
74
|
const hasAnyMention = params.explicit?.hasAnyMention === true;
|
|
75
75
|
if (hasAnyMention && explicitAvailable)
|
|
76
|
-
return explicit;
|
|
76
|
+
return explicit || params.mentionRegexes.some((re) => re.test(cleaned));
|
|
77
77
|
if (!cleaned)
|
|
78
78
|
return explicit;
|
|
79
79
|
return explicit || params.mentionRegexes.some((re) => re.test(cleaned));
|
|
@@ -65,7 +65,7 @@ function resolveParentSessionKeyCandidate(params) {
|
|
|
65
65
|
return derived;
|
|
66
66
|
return null;
|
|
67
67
|
}
|
|
68
|
-
function resolveStoredModelOverride(params) {
|
|
68
|
+
export function resolveStoredModelOverride(params) {
|
|
69
69
|
const direct = resolveModelOverrideFromEntry(params.sessionEntry);
|
|
70
70
|
if (direct)
|
|
71
71
|
return { ...direct, source: "session" };
|
|
@@ -327,9 +327,9 @@ export function resolveModelDirectiveSelection(params) {
|
|
|
327
327
|
defaultProvider,
|
|
328
328
|
defaultModel,
|
|
329
329
|
});
|
|
330
|
-
return { candidate,
|
|
330
|
+
return Object.assign({ candidate }, details);
|
|
331
331
|
})
|
|
332
|
-
.
|
|
332
|
+
.toSorted((a, b) => {
|
|
333
333
|
if (b.score !== a.score)
|
|
334
334
|
return b.score - a.score;
|
|
335
335
|
if (a.isDefault !== b.isDefault)
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
function normalizeProviderId(provider) {
|
|
2
|
-
if (!provider)
|
|
2
|
+
if (!provider) {
|
|
3
3
|
return "";
|
|
4
|
+
}
|
|
4
5
|
const normalized = provider.trim().toLowerCase();
|
|
5
|
-
if (normalized === "z.ai" || normalized === "z-ai")
|
|
6
|
+
if (normalized === "z.ai" || normalized === "z-ai") {
|
|
6
7
|
return "zai";
|
|
8
|
+
}
|
|
7
9
|
return normalized;
|
|
8
10
|
}
|
|
9
11
|
export function isBinaryThinkingProvider(provider) {
|
|
@@ -11,38 +13,52 @@ export function isBinaryThinkingProvider(provider) {
|
|
|
11
13
|
}
|
|
12
14
|
export const XHIGH_MODEL_REFS = [
|
|
13
15
|
"openai/gpt-5.2",
|
|
16
|
+
"openai-codex/gpt-5.3-codex",
|
|
14
17
|
"openai-codex/gpt-5.2-codex",
|
|
15
18
|
"openai-codex/gpt-5.1-codex",
|
|
19
|
+
"github-copilot/gpt-5.2-codex",
|
|
20
|
+
"github-copilot/gpt-5.2",
|
|
16
21
|
];
|
|
17
22
|
const XHIGH_MODEL_SET = new Set(XHIGH_MODEL_REFS.map((entry) => entry.toLowerCase()));
|
|
18
23
|
const XHIGH_MODEL_IDS = new Set(XHIGH_MODEL_REFS.map((entry) => entry.split("/")[1]?.toLowerCase()).filter((entry) => Boolean(entry)));
|
|
19
24
|
// Normalize user-provided thinking level strings to the canonical enum.
|
|
20
25
|
export function normalizeThinkLevel(raw) {
|
|
21
|
-
if (!raw)
|
|
26
|
+
if (!raw) {
|
|
22
27
|
return undefined;
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
}
|
|
29
|
+
const key = raw.trim().toLowerCase();
|
|
30
|
+
const collapsed = key.replace(/[\s_-]+/g, "");
|
|
31
|
+
if (collapsed === "xhigh" || collapsed === "extrahigh") {
|
|
32
|
+
return "xhigh";
|
|
33
|
+
}
|
|
34
|
+
if (["off"].includes(key)) {
|
|
25
35
|
return "off";
|
|
26
|
-
|
|
36
|
+
}
|
|
37
|
+
if (["on", "enable", "enabled"].includes(key)) {
|
|
27
38
|
return "low";
|
|
28
|
-
|
|
39
|
+
}
|
|
40
|
+
if (["min", "minimal"].includes(key)) {
|
|
29
41
|
return "minimal";
|
|
30
|
-
|
|
42
|
+
}
|
|
43
|
+
if (["low", "thinkhard", "think-hard", "think_hard"].includes(key)) {
|
|
31
44
|
return "low";
|
|
32
|
-
|
|
45
|
+
}
|
|
46
|
+
if (["mid", "med", "medium", "thinkharder", "think-harder", "harder"].includes(key)) {
|
|
33
47
|
return "medium";
|
|
34
|
-
|
|
48
|
+
}
|
|
49
|
+
if (["high", "ultra", "ultrathink", "think-hard", "thinkhardest", "highest", "max"].includes(key)) {
|
|
35
50
|
return "high";
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (["think"].includes(key))
|
|
51
|
+
}
|
|
52
|
+
if (["think"].includes(key)) {
|
|
39
53
|
return "minimal";
|
|
54
|
+
}
|
|
40
55
|
return undefined;
|
|
41
56
|
}
|
|
42
57
|
export function supportsXHighThinking(provider, model) {
|
|
43
58
|
const modelKey = model?.trim().toLowerCase();
|
|
44
|
-
if (!modelKey)
|
|
59
|
+
if (!modelKey) {
|
|
45
60
|
return false;
|
|
61
|
+
}
|
|
46
62
|
const providerKey = provider?.trim().toLowerCase();
|
|
47
63
|
if (providerKey) {
|
|
48
64
|
return XHIGH_MODEL_SET.has(`${providerKey}/${modelKey}`);
|
|
@@ -51,13 +67,15 @@ export function supportsXHighThinking(provider, model) {
|
|
|
51
67
|
}
|
|
52
68
|
export function listThinkingLevels(provider, model) {
|
|
53
69
|
const levels = ["off", "minimal", "low", "medium", "high"];
|
|
54
|
-
if (supportsXHighThinking(provider, model))
|
|
70
|
+
if (supportsXHighThinking(provider, model)) {
|
|
55
71
|
levels.push("xhigh");
|
|
72
|
+
}
|
|
56
73
|
return levels;
|
|
57
74
|
}
|
|
58
75
|
export function listThinkingLevelLabels(provider, model) {
|
|
59
|
-
if (isBinaryThinkingProvider(provider))
|
|
76
|
+
if (isBinaryThinkingProvider(provider)) {
|
|
60
77
|
return ["off", "on"];
|
|
78
|
+
}
|
|
61
79
|
return listThinkingLevels(provider, model);
|
|
62
80
|
}
|
|
63
81
|
export function formatThinkingLevels(provider, model, separator = ", ") {
|
|
@@ -65,53 +83,69 @@ export function formatThinkingLevels(provider, model, separator = ", ") {
|
|
|
65
83
|
}
|
|
66
84
|
export function formatXHighModelHint() {
|
|
67
85
|
const refs = [...XHIGH_MODEL_REFS];
|
|
68
|
-
if (refs.length === 0)
|
|
86
|
+
if (refs.length === 0) {
|
|
69
87
|
return "unknown model";
|
|
70
|
-
|
|
88
|
+
}
|
|
89
|
+
if (refs.length === 1) {
|
|
71
90
|
return refs[0];
|
|
72
|
-
|
|
91
|
+
}
|
|
92
|
+
if (refs.length === 2) {
|
|
73
93
|
return `${refs[0]} or ${refs[1]}`;
|
|
94
|
+
}
|
|
74
95
|
return `${refs.slice(0, -1).join(", ")} or ${refs[refs.length - 1]}`;
|
|
75
96
|
}
|
|
76
97
|
// Normalize verbose flags used to toggle agent verbosity.
|
|
77
98
|
export function normalizeVerboseLevel(raw) {
|
|
78
|
-
if (!raw)
|
|
99
|
+
if (!raw) {
|
|
79
100
|
return undefined;
|
|
101
|
+
}
|
|
80
102
|
const key = raw.toLowerCase();
|
|
81
|
-
if (["off", "false", "no", "0"].includes(key))
|
|
103
|
+
if (["off", "false", "no", "0"].includes(key)) {
|
|
82
104
|
return "off";
|
|
83
|
-
|
|
105
|
+
}
|
|
106
|
+
if (["full", "all", "everything"].includes(key)) {
|
|
84
107
|
return "full";
|
|
85
|
-
|
|
108
|
+
}
|
|
109
|
+
if (["on", "minimal", "true", "yes", "1"].includes(key)) {
|
|
86
110
|
return "on";
|
|
111
|
+
}
|
|
87
112
|
return undefined;
|
|
88
113
|
}
|
|
89
114
|
// Normalize system notice flags used to toggle system notifications.
|
|
90
115
|
export function normalizeNoticeLevel(raw) {
|
|
91
|
-
if (!raw)
|
|
116
|
+
if (!raw) {
|
|
92
117
|
return undefined;
|
|
118
|
+
}
|
|
93
119
|
const key = raw.toLowerCase();
|
|
94
|
-
if (["off", "false", "no", "0"].includes(key))
|
|
120
|
+
if (["off", "false", "no", "0"].includes(key)) {
|
|
95
121
|
return "off";
|
|
96
|
-
|
|
122
|
+
}
|
|
123
|
+
if (["full", "all", "everything"].includes(key)) {
|
|
97
124
|
return "full";
|
|
98
|
-
|
|
125
|
+
}
|
|
126
|
+
if (["on", "minimal", "true", "yes", "1"].includes(key)) {
|
|
99
127
|
return "on";
|
|
128
|
+
}
|
|
100
129
|
return undefined;
|
|
101
130
|
}
|
|
102
131
|
// Normalize response-usage display modes used to toggle per-response usage footers.
|
|
103
132
|
export function normalizeUsageDisplay(raw) {
|
|
104
|
-
if (!raw)
|
|
133
|
+
if (!raw) {
|
|
105
134
|
return undefined;
|
|
135
|
+
}
|
|
106
136
|
const key = raw.toLowerCase();
|
|
107
|
-
if (["off", "false", "no", "0", "disable", "disabled"].includes(key))
|
|
137
|
+
if (["off", "false", "no", "0", "disable", "disabled"].includes(key)) {
|
|
108
138
|
return "off";
|
|
109
|
-
|
|
139
|
+
}
|
|
140
|
+
if (["on", "true", "yes", "1", "enable", "enabled"].includes(key)) {
|
|
110
141
|
return "tokens";
|
|
111
|
-
|
|
142
|
+
}
|
|
143
|
+
if (["tokens", "token", "tok", "minimal", "min"].includes(key)) {
|
|
112
144
|
return "tokens";
|
|
113
|
-
|
|
145
|
+
}
|
|
146
|
+
if (["full", "session"].includes(key)) {
|
|
114
147
|
return "full";
|
|
148
|
+
}
|
|
115
149
|
return undefined;
|
|
116
150
|
}
|
|
117
151
|
export function resolveResponseUsageMode(raw) {
|
|
@@ -119,36 +153,47 @@ export function resolveResponseUsageMode(raw) {
|
|
|
119
153
|
}
|
|
120
154
|
// Normalize elevated flags used to toggle elevated bash permissions.
|
|
121
155
|
export function normalizeElevatedLevel(raw) {
|
|
122
|
-
if (!raw)
|
|
156
|
+
if (!raw) {
|
|
123
157
|
return undefined;
|
|
158
|
+
}
|
|
124
159
|
const key = raw.toLowerCase();
|
|
125
|
-
if (["off", "false", "no", "0"].includes(key))
|
|
160
|
+
if (["off", "false", "no", "0"].includes(key)) {
|
|
126
161
|
return "off";
|
|
127
|
-
|
|
162
|
+
}
|
|
163
|
+
if (["full", "auto", "auto-approve", "autoapprove"].includes(key)) {
|
|
128
164
|
return "full";
|
|
129
|
-
|
|
165
|
+
}
|
|
166
|
+
if (["ask", "prompt", "approval", "approve"].includes(key)) {
|
|
130
167
|
return "ask";
|
|
131
|
-
|
|
168
|
+
}
|
|
169
|
+
if (["on", "true", "yes", "1"].includes(key)) {
|
|
132
170
|
return "on";
|
|
171
|
+
}
|
|
133
172
|
return undefined;
|
|
134
173
|
}
|
|
135
174
|
export function resolveElevatedMode(level) {
|
|
136
|
-
if (!level || level === "off")
|
|
175
|
+
if (!level || level === "off") {
|
|
137
176
|
return "off";
|
|
138
|
-
|
|
177
|
+
}
|
|
178
|
+
if (level === "full") {
|
|
139
179
|
return "full";
|
|
180
|
+
}
|
|
140
181
|
return "ask";
|
|
141
182
|
}
|
|
142
183
|
// Normalize reasoning visibility flags used to toggle reasoning exposure.
|
|
143
184
|
export function normalizeReasoningLevel(raw) {
|
|
144
|
-
if (!raw)
|
|
185
|
+
if (!raw) {
|
|
145
186
|
return undefined;
|
|
187
|
+
}
|
|
146
188
|
const key = raw.toLowerCase();
|
|
147
|
-
if (["off", "false", "no", "0", "hide", "hidden", "disable", "disabled"].includes(key))
|
|
189
|
+
if (["off", "false", "no", "0", "hide", "hidden", "disable", "disabled"].includes(key)) {
|
|
148
190
|
return "off";
|
|
149
|
-
|
|
191
|
+
}
|
|
192
|
+
if (["on", "true", "yes", "1", "show", "visible", "enable", "enabled"].includes(key)) {
|
|
150
193
|
return "on";
|
|
151
|
-
|
|
194
|
+
}
|
|
195
|
+
if (["stream", "streaming", "draft", "live"].includes(key)) {
|
|
152
196
|
return "stream";
|
|
197
|
+
}
|
|
153
198
|
return undefined;
|
|
154
199
|
}
|
|
@@ -6,6 +6,19 @@ export async function startBrowserBridgeServer(params) {
|
|
|
6
6
|
const port = params.port ?? 0;
|
|
7
7
|
const app = express();
|
|
8
8
|
app.use(express.json({ limit: "1mb" }));
|
|
9
|
+
app.use((req, res, next) => {
|
|
10
|
+
const ctrl = new AbortController();
|
|
11
|
+
const abort = () => ctrl.abort(new Error("request aborted"));
|
|
12
|
+
req.once("aborted", abort);
|
|
13
|
+
res.once("close", () => {
|
|
14
|
+
if (!res.writableEnded) {
|
|
15
|
+
abort();
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
// Make the signal available to browser route handlers (best-effort).
|
|
19
|
+
req.signal = ctrl.signal;
|
|
20
|
+
next();
|
|
21
|
+
});
|
|
9
22
|
const authToken = params.authToken?.trim();
|
|
10
23
|
if (authToken) {
|
|
11
24
|
app.use((req, res, next) => {
|
|
@@ -1,30 +1,26 @@
|
|
|
1
1
|
import WebSocket from "ws";
|
|
2
|
+
import { isLoopbackHost } from "../gateway/net.js";
|
|
2
3
|
import { rawDataToString } from "../infra/ws.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
return (h === "localhost" ||
|
|
6
|
-
h === "127.0.0.1" ||
|
|
7
|
-
h === "0.0.0.0" ||
|
|
8
|
-
h === "[::1]" ||
|
|
9
|
-
h === "::1" ||
|
|
10
|
-
h === "[::]" ||
|
|
11
|
-
h === "::");
|
|
12
|
-
}
|
|
4
|
+
import { getChromeExtensionRelayAuthHeaders } from "./extension-relay.js";
|
|
5
|
+
export { isLoopbackHost };
|
|
13
6
|
export function getHeadersWithAuth(url, headers = {}) {
|
|
7
|
+
const relayHeaders = getChromeExtensionRelayAuthHeaders(url);
|
|
8
|
+
const mergedHeaders = { ...relayHeaders, ...headers };
|
|
14
9
|
try {
|
|
15
10
|
const parsed = new URL(url);
|
|
16
|
-
const hasAuthHeader = Object.keys(
|
|
17
|
-
if (hasAuthHeader)
|
|
18
|
-
return
|
|
11
|
+
const hasAuthHeader = Object.keys(mergedHeaders).some((key) => key.toLowerCase() === "authorization");
|
|
12
|
+
if (hasAuthHeader) {
|
|
13
|
+
return mergedHeaders;
|
|
14
|
+
}
|
|
19
15
|
if (parsed.username || parsed.password) {
|
|
20
16
|
const auth = Buffer.from(`${parsed.username}:${parsed.password}`).toString("base64");
|
|
21
|
-
return { ...
|
|
17
|
+
return { ...mergedHeaders, Authorization: `Basic ${auth}` };
|
|
22
18
|
}
|
|
23
19
|
}
|
|
24
20
|
catch {
|
|
25
21
|
// ignore
|
|
26
22
|
}
|
|
27
|
-
return
|
|
23
|
+
return mergedHeaders;
|
|
28
24
|
}
|
|
29
25
|
export function appendCdpPath(cdpUrl, path) {
|
|
30
26
|
const url = new URL(cdpUrl);
|
|
@@ -36,17 +32,18 @@ export function appendCdpPath(cdpUrl, path) {
|
|
|
36
32
|
function createCdpSender(ws) {
|
|
37
33
|
let nextId = 1;
|
|
38
34
|
const pending = new Map();
|
|
39
|
-
const send = (method, params) => {
|
|
35
|
+
const send = (method, params, sessionId) => {
|
|
40
36
|
const id = nextId++;
|
|
41
|
-
const msg = { id, method, params };
|
|
37
|
+
const msg = { id, method, params, sessionId };
|
|
42
38
|
ws.send(JSON.stringify(msg));
|
|
43
39
|
return new Promise((resolve, reject) => {
|
|
44
40
|
pending.set(id, { resolve, reject });
|
|
45
41
|
});
|
|
46
42
|
};
|
|
47
43
|
const closeWithError = (err) => {
|
|
48
|
-
for (const [, p] of pending)
|
|
44
|
+
for (const [, p] of pending) {
|
|
49
45
|
p.reject(err);
|
|
46
|
+
}
|
|
50
47
|
pending.clear();
|
|
51
48
|
try {
|
|
52
49
|
ws.close();
|
|
@@ -55,14 +52,19 @@ function createCdpSender(ws) {
|
|
|
55
52
|
// ignore
|
|
56
53
|
}
|
|
57
54
|
};
|
|
55
|
+
ws.on("error", (err) => {
|
|
56
|
+
closeWithError(err instanceof Error ? err : new Error(String(err)));
|
|
57
|
+
});
|
|
58
58
|
ws.on("message", (data) => {
|
|
59
59
|
try {
|
|
60
60
|
const parsed = JSON.parse(rawDataToString(data));
|
|
61
|
-
if (typeof parsed.id !== "number")
|
|
61
|
+
if (typeof parsed.id !== "number") {
|
|
62
62
|
return;
|
|
63
|
+
}
|
|
63
64
|
const p = pending.get(parsed.id);
|
|
64
|
-
if (!p)
|
|
65
|
+
if (!p) {
|
|
65
66
|
return;
|
|
67
|
+
}
|
|
66
68
|
pending.delete(parsed.id);
|
|
67
69
|
if (parsed.error?.message) {
|
|
68
70
|
p.reject(new Error(parsed.error.message));
|
|
@@ -85,8 +87,9 @@ export async function fetchJson(url, timeoutMs = 1500, init) {
|
|
|
85
87
|
try {
|
|
86
88
|
const headers = getHeadersWithAuth(url, init?.headers || {});
|
|
87
89
|
const res = await fetch(url, { ...init, headers, signal: ctrl.signal });
|
|
88
|
-
if (!res.ok)
|
|
90
|
+
if (!res.ok) {
|
|
89
91
|
throw new Error(`HTTP ${res.status}`);
|
|
92
|
+
}
|
|
90
93
|
return (await res.json());
|
|
91
94
|
}
|
|
92
95
|
finally {
|
|
@@ -99,8 +102,9 @@ export async function fetchOk(url, timeoutMs = 1500, init) {
|
|
|
99
102
|
try {
|
|
100
103
|
const headers = getHeadersWithAuth(url, init?.headers || {});
|
|
101
104
|
const res = await fetch(url, { ...init, headers, signal: ctrl.signal });
|
|
102
|
-
if (!res.ok)
|
|
105
|
+
if (!res.ok) {
|
|
103
106
|
throw new Error(`HTTP ${res.status}`);
|
|
107
|
+
}
|
|
104
108
|
}
|
|
105
109
|
finally {
|
|
106
110
|
clearTimeout(t);
|
|
@@ -108,16 +112,26 @@ export async function fetchOk(url, timeoutMs = 1500, init) {
|
|
|
108
112
|
}
|
|
109
113
|
export async function withCdpSocket(wsUrl, fn, opts) {
|
|
110
114
|
const headers = getHeadersWithAuth(wsUrl, opts?.headers ?? {});
|
|
115
|
+
const handshakeTimeoutMs = typeof opts?.handshakeTimeoutMs === "number" && Number.isFinite(opts.handshakeTimeoutMs)
|
|
116
|
+
? Math.max(1, Math.floor(opts.handshakeTimeoutMs))
|
|
117
|
+
: 5000;
|
|
111
118
|
const ws = new WebSocket(wsUrl, {
|
|
112
|
-
handshakeTimeout:
|
|
119
|
+
handshakeTimeout: handshakeTimeoutMs,
|
|
113
120
|
...(Object.keys(headers).length ? { headers } : {}),
|
|
114
121
|
});
|
|
115
122
|
const { send, closeWithError } = createCdpSender(ws);
|
|
116
123
|
const openPromise = new Promise((resolve, reject) => {
|
|
117
124
|
ws.once("open", () => resolve());
|
|
118
125
|
ws.once("error", (err) => reject(err));
|
|
126
|
+
ws.once("close", () => reject(new Error("CDP socket closed")));
|
|
119
127
|
});
|
|
120
|
-
|
|
128
|
+
try {
|
|
129
|
+
await openPromise;
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
closeWithError(err instanceof Error ? err : new Error(String(err)));
|
|
133
|
+
throw err;
|
|
134
|
+
}
|
|
121
135
|
try {
|
|
122
136
|
return await fn(send);
|
|
123
137
|
}
|