@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
|
@@ -4,6 +4,7 @@ import { CHANNEL_IDS, normalizeChatChannelId } from "../channels/registry.js";
|
|
|
4
4
|
import { normalizePluginsConfig, resolveEnableState, resolveMemorySlotDecision, } from "../plugins/config-state.js";
|
|
5
5
|
import { loadPluginManifestRegistry } from "../plugins/manifest-registry.js";
|
|
6
6
|
import { validateJsonSchemaValue } from "../plugins/schema-validator.js";
|
|
7
|
+
import { isRecord } from "../utils.js";
|
|
7
8
|
import { findDuplicateAgentDirs, formatDuplicateAgentDirError } from "./agent-dirs.js";
|
|
8
9
|
import { applyAgentDefaults, applyModelDefaults, applySessionDefaults } from "./defaults.js";
|
|
9
10
|
import { findLegacyConfigIssues } from "./legacy.js";
|
|
@@ -16,28 +17,35 @@ function isWorkspaceAvatarPath(value, workspaceDir) {
|
|
|
16
17
|
const workspaceRoot = path.resolve(workspaceDir);
|
|
17
18
|
const resolved = path.resolve(workspaceRoot, value);
|
|
18
19
|
const relative = path.relative(workspaceRoot, resolved);
|
|
19
|
-
if (relative === "")
|
|
20
|
+
if (relative === "") {
|
|
20
21
|
return true;
|
|
21
|
-
|
|
22
|
+
}
|
|
23
|
+
if (relative.startsWith("..")) {
|
|
22
24
|
return false;
|
|
25
|
+
}
|
|
23
26
|
return !path.isAbsolute(relative);
|
|
24
27
|
}
|
|
25
28
|
function validateIdentityAvatar(config) {
|
|
26
29
|
const agents = config.agents?.list;
|
|
27
|
-
if (!Array.isArray(agents) || agents.length === 0)
|
|
30
|
+
if (!Array.isArray(agents) || agents.length === 0) {
|
|
28
31
|
return [];
|
|
32
|
+
}
|
|
29
33
|
const issues = [];
|
|
30
34
|
for (const [index, entry] of agents.entries()) {
|
|
31
|
-
if (!entry || typeof entry !== "object")
|
|
35
|
+
if (!entry || typeof entry !== "object") {
|
|
32
36
|
continue;
|
|
37
|
+
}
|
|
33
38
|
const avatarRaw = entry.identity?.avatar;
|
|
34
|
-
if (typeof avatarRaw !== "string")
|
|
39
|
+
if (typeof avatarRaw !== "string") {
|
|
35
40
|
continue;
|
|
41
|
+
}
|
|
36
42
|
const avatar = avatarRaw.trim();
|
|
37
|
-
if (!avatar)
|
|
43
|
+
if (!avatar) {
|
|
38
44
|
continue;
|
|
39
|
-
|
|
45
|
+
}
|
|
46
|
+
if (AVATAR_DATA_RE.test(avatar) || AVATAR_HTTP_RE.test(avatar)) {
|
|
40
47
|
continue;
|
|
48
|
+
}
|
|
41
49
|
if (avatar.startsWith("~")) {
|
|
42
50
|
issues.push({
|
|
43
51
|
path: `agents.list.${index}.identity.avatar`,
|
|
@@ -63,7 +71,11 @@ function validateIdentityAvatar(config) {
|
|
|
63
71
|
}
|
|
64
72
|
return issues;
|
|
65
73
|
}
|
|
66
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Validates config without applying runtime defaults.
|
|
76
|
+
* Use this when you need the raw validated config (e.g., for writing back to file).
|
|
77
|
+
*/
|
|
78
|
+
export function validateConfigObjectRaw(raw) {
|
|
67
79
|
const legacyIssues = findLegacyConfigIssues(raw);
|
|
68
80
|
if (legacyIssues.length > 0) {
|
|
69
81
|
return {
|
|
@@ -102,42 +114,136 @@ export function validateConfigObject(raw) {
|
|
|
102
114
|
}
|
|
103
115
|
return {
|
|
104
116
|
ok: true,
|
|
105
|
-
config:
|
|
117
|
+
config: validated.data,
|
|
106
118
|
};
|
|
107
119
|
}
|
|
108
|
-
function
|
|
109
|
-
|
|
120
|
+
export function validateConfigObject(raw) {
|
|
121
|
+
const result = validateConfigObjectRaw(raw);
|
|
122
|
+
if (!result.ok) {
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
ok: true,
|
|
127
|
+
config: applyModelDefaults(applyAgentDefaults(applySessionDefaults(result.config))),
|
|
128
|
+
};
|
|
110
129
|
}
|
|
111
130
|
export function validateConfigObjectWithPlugins(raw) {
|
|
112
|
-
|
|
131
|
+
return validateConfigObjectWithPluginsBase(raw, { applyDefaults: true });
|
|
132
|
+
}
|
|
133
|
+
export function validateConfigObjectRawWithPlugins(raw) {
|
|
134
|
+
return validateConfigObjectWithPluginsBase(raw, { applyDefaults: false });
|
|
135
|
+
}
|
|
136
|
+
function validateConfigObjectWithPluginsBase(raw, opts) {
|
|
137
|
+
const base = opts.applyDefaults ? validateConfigObject(raw) : validateConfigObjectRaw(raw);
|
|
113
138
|
if (!base.ok) {
|
|
114
139
|
return { ok: false, issues: base.issues, warnings: [] };
|
|
115
140
|
}
|
|
116
141
|
const config = base.config;
|
|
117
142
|
const issues = [];
|
|
118
143
|
const warnings = [];
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
144
|
+
const hasExplicitPluginsConfig = isRecord(raw) && Object.prototype.hasOwnProperty.call(raw, "plugins");
|
|
145
|
+
let registryInfo = null;
|
|
146
|
+
const ensureRegistry = () => {
|
|
147
|
+
if (registryInfo) {
|
|
148
|
+
return registryInfo;
|
|
149
|
+
}
|
|
150
|
+
const workspaceDir = resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config));
|
|
151
|
+
const registry = loadPluginManifestRegistry({
|
|
152
|
+
config,
|
|
153
|
+
workspaceDir: workspaceDir ?? undefined,
|
|
154
|
+
});
|
|
155
|
+
const knownIds = new Set(registry.plugins.map((record) => record.id));
|
|
156
|
+
const normalizedPlugins = normalizePluginsConfig(config.plugins);
|
|
157
|
+
for (const diag of registry.diagnostics) {
|
|
158
|
+
let path = diag.pluginId ? `plugins.entries.${diag.pluginId}` : "plugins";
|
|
159
|
+
if (!diag.pluginId && diag.message.includes("plugin path not found")) {
|
|
160
|
+
path = "plugins.load.paths";
|
|
161
|
+
}
|
|
162
|
+
const pluginLabel = diag.pluginId ? `plugin ${diag.pluginId}` : "plugin";
|
|
163
|
+
const message = `${pluginLabel}: ${diag.message}`;
|
|
164
|
+
if (diag.level === "error") {
|
|
165
|
+
issues.push({ path, message });
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
warnings.push({ path, message });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
registryInfo = { registry, knownIds, normalizedPlugins };
|
|
172
|
+
return registryInfo;
|
|
173
|
+
};
|
|
174
|
+
const allowedChannels = new Set(["defaults", ...CHANNEL_IDS]);
|
|
175
|
+
if (config.channels && isRecord(config.channels)) {
|
|
176
|
+
for (const key of Object.keys(config.channels)) {
|
|
177
|
+
const trimmed = key.trim();
|
|
178
|
+
if (!trimmed) {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (!allowedChannels.has(trimmed)) {
|
|
182
|
+
const { registry } = ensureRegistry();
|
|
183
|
+
for (const record of registry.plugins) {
|
|
184
|
+
for (const channelId of record.channels) {
|
|
185
|
+
allowedChannels.add(channelId);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (!allowedChannels.has(trimmed)) {
|
|
190
|
+
issues.push({
|
|
191
|
+
path: `channels.${trimmed}`,
|
|
192
|
+
message: `unknown channel id: ${trimmed}`,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const heartbeatChannelIds = new Set();
|
|
198
|
+
for (const channelId of CHANNEL_IDS) {
|
|
199
|
+
heartbeatChannelIds.add(channelId.toLowerCase());
|
|
200
|
+
}
|
|
201
|
+
const validateHeartbeatTarget = (target, path) => {
|
|
202
|
+
if (typeof target !== "string") {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const trimmed = target.trim();
|
|
206
|
+
if (!trimmed) {
|
|
207
|
+
issues.push({ path, message: "heartbeat target must not be empty" });
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const normalized = trimmed.toLowerCase();
|
|
211
|
+
if (normalized === "last" || normalized === "none") {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (normalizeChatChannelId(trimmed)) {
|
|
215
|
+
return;
|
|
131
216
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
217
|
+
if (!heartbeatChannelIds.has(normalized)) {
|
|
218
|
+
const { registry } = ensureRegistry();
|
|
219
|
+
for (const record of registry.plugins) {
|
|
220
|
+
for (const channelId of record.channels) {
|
|
221
|
+
const pluginChannel = channelId.trim();
|
|
222
|
+
if (pluginChannel) {
|
|
223
|
+
heartbeatChannelIds.add(pluginChannel.toLowerCase());
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
136
227
|
}
|
|
137
|
-
|
|
138
|
-
|
|
228
|
+
if (heartbeatChannelIds.has(normalized)) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
issues.push({ path, message: `unknown heartbeat target: ${target}` });
|
|
232
|
+
};
|
|
233
|
+
validateHeartbeatTarget(config.agents?.defaults?.heartbeat?.target, "agents.defaults.heartbeat.target");
|
|
234
|
+
if (Array.isArray(config.agents?.list)) {
|
|
235
|
+
for (const [index, entry] of config.agents.list.entries()) {
|
|
236
|
+
validateHeartbeatTarget(entry?.heartbeat?.target, `agents.list.${index}.heartbeat.target`);
|
|
139
237
|
}
|
|
140
238
|
}
|
|
239
|
+
if (!hasExplicitPluginsConfig) {
|
|
240
|
+
if (issues.length > 0) {
|
|
241
|
+
return { ok: false, issues, warnings };
|
|
242
|
+
}
|
|
243
|
+
return { ok: true, config, warnings };
|
|
244
|
+
}
|
|
245
|
+
const { registry, knownIds, normalizedPlugins } = ensureRegistry();
|
|
246
|
+
const pluginsConfig = config.plugins;
|
|
141
247
|
const entries = pluginsConfig?.entries;
|
|
142
248
|
if (entries && isRecord(entries)) {
|
|
143
249
|
for (const pluginId of Object.keys(entries)) {
|
|
@@ -151,8 +257,9 @@ export function validateConfigObjectWithPlugins(raw) {
|
|
|
151
257
|
}
|
|
152
258
|
const allow = pluginsConfig?.allow ?? [];
|
|
153
259
|
for (const pluginId of allow) {
|
|
154
|
-
if (typeof pluginId !== "string" || !pluginId.trim())
|
|
260
|
+
if (typeof pluginId !== "string" || !pluginId.trim()) {
|
|
155
261
|
continue;
|
|
262
|
+
}
|
|
156
263
|
if (!knownIds.has(pluginId)) {
|
|
157
264
|
issues.push({
|
|
158
265
|
path: "plugins.allow",
|
|
@@ -162,8 +269,9 @@ export function validateConfigObjectWithPlugins(raw) {
|
|
|
162
269
|
}
|
|
163
270
|
const deny = pluginsConfig?.deny ?? [];
|
|
164
271
|
for (const pluginId of deny) {
|
|
165
|
-
if (typeof pluginId !== "string" || !pluginId.trim())
|
|
272
|
+
if (typeof pluginId !== "string" || !pluginId.trim()) {
|
|
166
273
|
continue;
|
|
274
|
+
}
|
|
167
275
|
if (!knownIds.has(pluginId)) {
|
|
168
276
|
issues.push({
|
|
169
277
|
path: "plugins.deny",
|
|
@@ -178,59 +286,6 @@ export function validateConfigObjectWithPlugins(raw) {
|
|
|
178
286
|
message: `plugin not found: ${memorySlot}`,
|
|
179
287
|
});
|
|
180
288
|
}
|
|
181
|
-
const allowedChannels = new Set(["defaults", ...CHANNEL_IDS]);
|
|
182
|
-
for (const record of registry.plugins) {
|
|
183
|
-
for (const channelId of record.channels) {
|
|
184
|
-
allowedChannels.add(channelId);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
if (config.channels && isRecord(config.channels)) {
|
|
188
|
-
for (const key of Object.keys(config.channels)) {
|
|
189
|
-
const trimmed = key.trim();
|
|
190
|
-
if (!trimmed)
|
|
191
|
-
continue;
|
|
192
|
-
if (!allowedChannels.has(trimmed)) {
|
|
193
|
-
issues.push({
|
|
194
|
-
path: `channels.${trimmed}`,
|
|
195
|
-
message: `unknown channel id: ${trimmed}`,
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
const heartbeatChannelIds = new Set();
|
|
201
|
-
for (const channelId of CHANNEL_IDS) {
|
|
202
|
-
heartbeatChannelIds.add(channelId.toLowerCase());
|
|
203
|
-
}
|
|
204
|
-
for (const record of registry.plugins) {
|
|
205
|
-
for (const channelId of record.channels) {
|
|
206
|
-
const trimmed = channelId.trim();
|
|
207
|
-
if (trimmed)
|
|
208
|
-
heartbeatChannelIds.add(trimmed.toLowerCase());
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
const validateHeartbeatTarget = (target, path) => {
|
|
212
|
-
if (typeof target !== "string")
|
|
213
|
-
return;
|
|
214
|
-
const trimmed = target.trim();
|
|
215
|
-
if (!trimmed) {
|
|
216
|
-
issues.push({ path, message: "heartbeat target must not be empty" });
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
const normalized = trimmed.toLowerCase();
|
|
220
|
-
if (normalized === "last" || normalized === "none")
|
|
221
|
-
return;
|
|
222
|
-
if (normalizeChatChannelId(trimmed))
|
|
223
|
-
return;
|
|
224
|
-
if (heartbeatChannelIds.has(normalized))
|
|
225
|
-
return;
|
|
226
|
-
issues.push({ path, message: `unknown heartbeat target: ${target}` });
|
|
227
|
-
};
|
|
228
|
-
validateHeartbeatTarget(config.agents?.defaults?.heartbeat?.target, "agents.defaults.heartbeat.target");
|
|
229
|
-
if (Array.isArray(config.agents?.list)) {
|
|
230
|
-
for (const [index, entry] of config.agents.list.entries()) {
|
|
231
|
-
validateHeartbeatTarget(entry?.heartbeat?.target, `agents.list.${index}.heartbeat.target`);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
289
|
let selectedMemoryPluginId = null;
|
|
235
290
|
const seenPlugins = new Set();
|
|
236
291
|
for (const record of registry.plugins) {
|
|
@@ -1,4 +1,33 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import { z } from "zod";
|
|
3
|
+
import { InstallRecordShape } from "./zod-schema.installs.js";
|
|
4
|
+
import { sensitive } from "./zod-schema.sensitive.js";
|
|
5
|
+
function isSafeRelativeModulePath(raw) {
|
|
6
|
+
const value = raw.trim();
|
|
7
|
+
if (!value) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
// Hook modules are loaded via file-path resolution + dynamic import().
|
|
11
|
+
// Keep this strictly relative to a configured base dir to avoid path traversal and surprises.
|
|
12
|
+
if (path.isAbsolute(value)) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
if (value.startsWith("~")) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
// Disallow URL-ish and drive-relative forms (e.g. "file:...", "C:foo").
|
|
19
|
+
if (value.includes(":")) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
const parts = value.split(/[\\/]+/g);
|
|
23
|
+
if (parts.some((part) => part === "..")) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
const SafeRelativeModulePathSchema = z
|
|
29
|
+
.string()
|
|
30
|
+
.refine(isSafeRelativeModulePath, "module must be a safe relative path (no absolute paths)");
|
|
2
31
|
export const HookMappingSchema = z
|
|
3
32
|
.object({
|
|
4
33
|
id: z.string().optional(),
|
|
@@ -11,7 +40,8 @@ export const HookMappingSchema = z
|
|
|
11
40
|
action: z.union([z.literal("wake"), z.literal("agent")]).optional(),
|
|
12
41
|
wakeMode: z.union([z.literal("now"), z.literal("next-heartbeat")]).optional(),
|
|
13
42
|
name: z.string().optional(),
|
|
14
|
-
|
|
43
|
+
agentId: z.string().optional(),
|
|
44
|
+
sessionKey: z.string().optional().register(sensitive),
|
|
15
45
|
messageTemplate: z.string().optional(),
|
|
16
46
|
textTemplate: z.string().optional(),
|
|
17
47
|
deliver: z.boolean().optional(),
|
|
@@ -22,6 +52,7 @@ export const HookMappingSchema = z
|
|
|
22
52
|
z.literal("whatsapp"),
|
|
23
53
|
z.literal("telegram"),
|
|
24
54
|
z.literal("discord"),
|
|
55
|
+
z.literal("irc"),
|
|
25
56
|
z.literal("slack"),
|
|
26
57
|
z.literal("signal"),
|
|
27
58
|
z.literal("imessage"),
|
|
@@ -34,7 +65,7 @@ export const HookMappingSchema = z
|
|
|
34
65
|
timeoutSeconds: z.number().int().positive().optional(),
|
|
35
66
|
transform: z
|
|
36
67
|
.object({
|
|
37
|
-
module:
|
|
68
|
+
module: SafeRelativeModulePathSchema,
|
|
38
69
|
export: z.string().optional(),
|
|
39
70
|
})
|
|
40
71
|
.strict()
|
|
@@ -45,7 +76,7 @@ export const HookMappingSchema = z
|
|
|
45
76
|
export const InternalHookHandlerSchema = z
|
|
46
77
|
.object({
|
|
47
78
|
event: z.string(),
|
|
48
|
-
module:
|
|
79
|
+
module: SafeRelativeModulePathSchema,
|
|
49
80
|
export: z.string().optional(),
|
|
50
81
|
})
|
|
51
82
|
.strict();
|
|
@@ -54,15 +85,13 @@ const HookConfigSchema = z
|
|
|
54
85
|
enabled: z.boolean().optional(),
|
|
55
86
|
env: z.record(z.string(), z.string()).optional(),
|
|
56
87
|
})
|
|
57
|
-
|
|
88
|
+
// Hook configs are intentionally open-ended (handlers can define their own keys).
|
|
89
|
+
// Keep enabled/env typed, but allow additional per-hook keys without marking the
|
|
90
|
+
// whole config invalid (which triggers doctor/best-effort loads).
|
|
91
|
+
.passthrough();
|
|
58
92
|
const HookInstallRecordSchema = z
|
|
59
93
|
.object({
|
|
60
|
-
|
|
61
|
-
spec: z.string().optional(),
|
|
62
|
-
sourcePath: z.string().optional(),
|
|
63
|
-
installPath: z.string().optional(),
|
|
64
|
-
version: z.string().optional(),
|
|
65
|
-
installedAt: z.string().optional(),
|
|
94
|
+
...InstallRecordShape,
|
|
66
95
|
hooks: z.array(z.string()).optional(),
|
|
67
96
|
})
|
|
68
97
|
.strict();
|
|
@@ -87,7 +116,7 @@ export const HooksGmailSchema = z
|
|
|
87
116
|
label: z.string().optional(),
|
|
88
117
|
topic: z.string().optional(),
|
|
89
118
|
subscription: z.string().optional(),
|
|
90
|
-
pushToken: z.string().optional(),
|
|
119
|
+
pushToken: z.string().optional().register(sensitive),
|
|
91
120
|
hookUrl: z.string().optional(),
|
|
92
121
|
includeBody: z.boolean().optional(),
|
|
93
122
|
maxBytes: z.number().int().positive().optional(),
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const InstallSourceSchema = z.union([
|
|
3
|
+
z.literal("npm"),
|
|
4
|
+
z.literal("archive"),
|
|
5
|
+
z.literal("path"),
|
|
6
|
+
]);
|
|
7
|
+
export const InstallRecordShape = {
|
|
8
|
+
source: InstallSourceSchema,
|
|
9
|
+
spec: z.string().optional(),
|
|
10
|
+
sourcePath: z.string().optional(),
|
|
11
|
+
installPath: z.string().optional(),
|
|
12
|
+
version: z.string().optional(),
|
|
13
|
+
resolvedName: z.string().optional(),
|
|
14
|
+
resolvedVersion: z.string().optional(),
|
|
15
|
+
resolvedSpec: z.string().optional(),
|
|
16
|
+
integrity: z.string().optional(),
|
|
17
|
+
shasum: z.string().optional(),
|
|
18
|
+
resolvedAt: z.string().optional(),
|
|
19
|
+
installedAt: z.string().optional(),
|
|
20
|
+
};
|
|
@@ -6,6 +6,7 @@ import { HexColorSchema, ModelsConfigSchema } from "./zod-schema.core.js";
|
|
|
6
6
|
import { HookMappingSchema, HooksGmailSchema, InternalHooksSchema } from "./zod-schema.hooks.js";
|
|
7
7
|
import { ChannelsSchema } from "./zod-schema.providers.js";
|
|
8
8
|
import { CommandsSchema, MessagesSchema, SessionSchema } from "./zod-schema.session.js";
|
|
9
|
+
import { sensitive } from "./zod-schema.sensitive.js";
|
|
9
10
|
const BrowserSnapshotDefaultsSchema = z
|
|
10
11
|
.object({
|
|
11
12
|
mode: z.literal("efficient").optional(),
|
|
@@ -226,7 +227,7 @@ export const PoolBotSchema = z
|
|
|
226
227
|
.object({
|
|
227
228
|
enabled: z.boolean().optional(),
|
|
228
229
|
path: z.string().optional(),
|
|
229
|
-
token: z.string().optional(),
|
|
230
|
+
token: z.string().optional().register(sensitive),
|
|
230
231
|
maxBodyBytes: z.number().int().positive().optional(),
|
|
231
232
|
presets: z.array(z.string()).optional(),
|
|
232
233
|
transformsDir: z.string().optional(),
|
|
@@ -286,7 +287,7 @@ export const PoolBotSchema = z
|
|
|
286
287
|
voiceAliases: z.record(z.string(), z.string()).optional(),
|
|
287
288
|
modelId: z.string().optional(),
|
|
288
289
|
outputFormat: z.string().optional(),
|
|
289
|
-
apiKey: z.string().optional(),
|
|
290
|
+
apiKey: z.string().optional().register(sensitive),
|
|
290
291
|
interruptOnSpeech: z.boolean().optional(),
|
|
291
292
|
})
|
|
292
293
|
.strict()
|
|
@@ -316,8 +317,8 @@ export const PoolBotSchema = z
|
|
|
316
317
|
auth: z
|
|
317
318
|
.object({
|
|
318
319
|
mode: z.union([z.literal("token"), z.literal("password")]).optional(),
|
|
319
|
-
token: z.string().optional(),
|
|
320
|
-
password: z.string().optional(),
|
|
320
|
+
token: z.string().optional().register(sensitive),
|
|
321
|
+
password: z.string().optional().register(sensitive),
|
|
321
322
|
allowTailscale: z.boolean().optional(),
|
|
322
323
|
})
|
|
323
324
|
.strict()
|
|
@@ -334,8 +335,8 @@ export const PoolBotSchema = z
|
|
|
334
335
|
.object({
|
|
335
336
|
url: z.string().optional(),
|
|
336
337
|
transport: z.union([z.literal("ssh"), z.literal("direct")]).optional(),
|
|
337
|
-
token: z.string().optional(),
|
|
338
|
-
password: z.string().optional(),
|
|
338
|
+
token: z.string().optional().register(sensitive),
|
|
339
|
+
password: z.string().optional().register(sensitive),
|
|
339
340
|
tlsFingerprint: z.string().optional(),
|
|
340
341
|
sshTarget: z.string().optional(),
|
|
341
342
|
sshIdentity: z.string().optional(),
|
|
@@ -460,7 +461,7 @@ export const PoolBotSchema = z
|
|
|
460
461
|
.record(z.string(), z
|
|
461
462
|
.object({
|
|
462
463
|
enabled: z.boolean().optional(),
|
|
463
|
-
apiKey: z.string().optional(),
|
|
464
|
+
apiKey: z.string().optional().register(sensitive),
|
|
464
465
|
env: z.record(z.string(), z.string()).optional(),
|
|
465
466
|
config: z.record(z.string(), z.unknown()).optional(),
|
|
466
467
|
})
|
|
@@ -1679,6 +1679,7 @@ ${e.snapshot?JSON.stringify(e.snapshot,null,2):"No snapshot yet."}
|
|
|
1679
1679
|
>
|
|
1680
1680
|
<option value="announce">Announce summary (default)</option>
|
|
1681
1681
|
<option value="none">None (internal)</option>
|
|
1682
|
+
<option value="webhook">Webhook</option>
|
|
1682
1683
|
</select>
|
|
1683
1684
|
</label>
|
|
1684
1685
|
<label class="field">
|
|
@@ -3191,4 +3192,4 @@ ${e.snapshot?JSON.stringify(e.snapshot,null,2):"No snapshot yet."}
|
|
|
3191
3192
|
`}const qf={trace:!0,debug:!0,info:!0,warn:!0,error:!0,fatal:!0},Wf={name:"",description:"",agentId:"",enabled:!0,scheduleKind:"every",scheduleAt:"",everyAmount:"30",everyUnit:"minutes",cronExpr:"0 7 * * *",cronTz:"",sessionTarget:"main",wakeMode:"next-heartbeat",payloadKind:"systemEvent",payloadText:"",deliver:!1,channel:"last",to:"",timeoutSeconds:"",postToMainPrefix:""};async function Vf(e){if(!(!e.client||!e.connected)&&!e.agentsLoading){e.agentsLoading=!0,e.agentsError=null;try{const t=await e.client.request("agents.list",{});t&&(e.agentsList=t)}catch(t){e.agentsError=String(t)}finally{e.agentsLoading=!1}}}const $r={WEBCHAT_UI:"webchat-ui",CONTROL_UI:"poolbot-control-ui",WEBCHAT:"webchat",CLI:"cli",GATEWAY_CLIENT:"gateway-client",MACOS_APP:"poolbot-macos",IOS_APP:"poolbot-ios",ANDROID_APP:"poolbot-android",NODE_HOST:"node-host",TEST:"test",FINGERPRINT:"fingerprint",PROBE:"poolbot-probe"},Va=$r,Ts={WEBCHAT:"webchat",CLI:"cli",UI:"ui",BACKEND:"backend",NODE:"node",PROBE:"probe",TEST:"test"};new Set(Object.values($r));new Set(Object.values(Ts));function Gf(e){const t=e.version??(e.nonce?"v2":"v1"),n=e.scopes.join(","),s=e.token??"",i=[t,e.deviceId,e.clientId,e.clientMode,e.role,n,String(e.signedAtMs),s];return t==="v2"&&i.push(e.nonce??""),i.join("|")}const Yf=4008;class Qf{constructor(t){this.opts=t,this.ws=null,this.pending=new Map,this.closed=!1,this.lastSeq=null,this.connectNonce=null,this.connectSent=!1,this.connectTimer=null,this.backoffMs=800}start(){this.closed=!1,this.connect()}stop(){this.closed=!0,this.ws?.close(),this.ws=null,this.flushPending(new Error("gateway client stopped"))}get connected(){return this.ws?.readyState===WebSocket.OPEN}connect(){this.closed||(this.ws=new WebSocket(this.opts.url),this.ws.onopen=()=>this.queueConnect(),this.ws.onmessage=t=>this.handleMessage(String(t.data??"")),this.ws.onclose=t=>{const n=String(t.reason??"");this.ws=null,this.flushPending(new Error(`gateway closed (${t.code}): ${n}`)),this.opts.onClose?.({code:t.code,reason:n}),this.scheduleReconnect()},this.ws.onerror=()=>{})}scheduleReconnect(){if(this.closed)return;const t=this.backoffMs;this.backoffMs=Math.min(this.backoffMs*1.7,15e3),window.setTimeout(()=>this.connect(),t)}flushPending(t){for(const[,n]of this.pending)n.reject(t);this.pending.clear()}async sendConnect(){if(this.connectSent)return;this.connectSent=!0,this.connectTimer!==null&&(window.clearTimeout(this.connectTimer),this.connectTimer=null);const t=typeof crypto<"u"&&!!crypto.subtle,n=["operator.admin","operator.approvals","operator.pairing"],s="operator";let i=null,a=!1,o=this.opts.token;if(t){i=await Us();const d=Wc({deviceId:i.deviceId,role:s})?.token;o=d??this.opts.token,a=!!(d&&this.opts.token)}const l=o||this.opts.password?{token:o,password:this.opts.password}:void 0;let r;if(t&&i){const d=Date.now(),u=this.connectNonce??void 0,g=Gf({deviceId:i.deviceId,clientId:this.opts.clientName??Va.CONTROL_UI,clientMode:this.opts.mode??Ts.WEBCHAT,role:s,scopes:n,signedAtMs:d,token:o??null,nonce:u}),v=await jc(i.privateKey,g);r={id:i.deviceId,publicKey:i.publicKey,signature:v,signedAt:d,nonce:u}}const p={minProtocol:3,maxProtocol:3,client:{id:this.opts.clientName??Va.CONTROL_UI,version:this.opts.clientVersion??"dev",platform:this.opts.platform??navigator.platform??"web",mode:this.opts.mode??Ts.WEBCHAT,instanceId:this.opts.instanceId},role:s,scopes:n,device:r,caps:[],auth:l,userAgent:navigator.userAgent,locale:navigator.language};this.request("connect",p).then(d=>{d?.auth?.deviceToken&&i&&Ro({deviceId:i.deviceId,role:d.auth.role??s,token:d.auth.deviceToken,scopes:d.auth.scopes??[]}),this.backoffMs=800,this.opts.onHello?.(d)}).catch(()=>{a&&i&&Po({deviceId:i.deviceId,role:s}),this.ws?.close(Yf,"connect failed")})}handleMessage(t){let n;try{n=JSON.parse(t)}catch{return}const s=n;if(s.type==="event"){const i=n;if(i.event==="connect.challenge"){const o=i.payload,l=o&&typeof o.nonce=="string"?o.nonce:null;l&&(this.connectNonce=l,this.sendConnect());return}const a=typeof i.seq=="number"?i.seq:null;a!==null&&(this.lastSeq!==null&&a>this.lastSeq+1&&this.opts.onGap?.({expected:this.lastSeq+1,received:a}),this.lastSeq=a);try{this.opts.onEvent?.(i)}catch(o){console.error("[gateway] event handler error:",o)}return}if(s.type==="res"){const i=n,a=this.pending.get(i.id);if(!a)return;this.pending.delete(i.id),i.ok?a.resolve(i.payload):a.reject(new Error(i.error?.message??"request failed"));return}}request(t,n){if(!this.ws||this.ws.readyState!==WebSocket.OPEN)return Promise.reject(new Error("gateway not connected"));const s=Ns(),i={type:"req",id:s,method:t,params:n},a=new Promise((o,l)=>{this.pending.set(s,{resolve:r=>o(r),reject:l})});return this.ws.send(JSON.stringify(i)),a}queueConnect(){this.connectNonce=null,this.connectSent=!1,this.connectTimer!==null&&window.clearTimeout(this.connectTimer),this.connectTimer=window.setTimeout(()=>{this.sendConnect()},750)}}function Cs(e){return typeof e=="object"&&e!==null}function Zf(e){if(!Cs(e))return null;const t=typeof e.id=="string"?e.id.trim():"",n=e.request;if(!t||!Cs(n))return null;const s=typeof n.command=="string"?n.command.trim():"";if(!s)return null;const i=typeof e.createdAtMs=="number"?e.createdAtMs:0,a=typeof e.expiresAtMs=="number"?e.expiresAtMs:0;return!i||!a?null:{id:t,request:{command:s,cwd:typeof n.cwd=="string"?n.cwd:null,host:typeof n.host=="string"?n.host:null,security:typeof n.security=="string"?n.security:null,ask:typeof n.ask=="string"?n.ask:null,agentId:typeof n.agentId=="string"?n.agentId:null,resolvedPath:typeof n.resolvedPath=="string"?n.resolvedPath:null,sessionKey:typeof n.sessionKey=="string"?n.sessionKey:null},createdAtMs:i,expiresAtMs:a}}function Jf(e){if(!Cs(e))return null;const t=typeof e.id=="string"?e.id.trim():"";return t?{id:t,decision:typeof e.decision=="string"?e.decision:null,resolvedBy:typeof e.resolvedBy=="string"?e.resolvedBy:null,ts:typeof e.ts=="number"?e.ts:null}:null}function xr(e){const t=Date.now();return e.filter(n=>n.expiresAtMs>t)}function Xf(e,t){const n=xr(e).filter(s=>s.id!==t.id);return n.push(t),n}function Ga(e,t){return xr(e).filter(n=>n.id!==t)}async function kr(e,t){if(!e.client||!e.connected)return;const n=e.sessionKey.trim(),s=n?{sessionKey:n}:{};try{const i=await e.client.request("agent.identity.get",s);if(!i)return;const a=is(i);e.assistantName=a.name,e.assistantAvatar=a.avatar,e.assistantAgentId=a.agentId??null}catch{}}function ts(e,t){const n=(e??"").trim(),s=t.mainSessionKey?.trim();if(!s)return n;if(!n)return s;const i=t.mainKey?.trim()||"main",a=t.defaultAgentId?.trim();return n==="main"||n===i||a&&(n===`agent:${a}:main`||n===`agent:${a}:${i}`)?s:n}function eg(e,t){if(!t?.mainSessionKey)return;const n=ts(e.sessionKey,t),s=ts(e.settings.sessionKey,t),i=ts(e.settings.lastActiveSessionKey,t),a=n||s||e.sessionKey,o={...e.settings,sessionKey:s||a,lastActiveSessionKey:i||a},l=o.sessionKey!==e.settings.sessionKey||o.lastActiveSessionKey!==e.settings.lastActiveSessionKey;a!==e.sessionKey&&(e.sessionKey=a),l&&ke(e,o)}function Ar(e){e.lastError=null,e.hello=null,e.connected=!1,e.execApprovalQueue=[],e.execApprovalError=null,e.client?.stop(),e.client=new Qf({url:e.settings.gatewayUrl,token:e.settings.token.trim()?e.settings.token:void 0,password:e.password.trim()?e.password:void 0,clientName:"poolbot-control-ui",mode:"webchat",onHello:t=>{e.connected=!0,e.lastError=null,e.hello=t,sg(e,t),e.chatRunId=null,e.chatStream=null,e.chatStreamStartedAt=null,cn(e),kr(e),Vf(e),fn(e,{quiet:!0}),Te(e,{quiet:!0}),Qs(e)},onClose:({code:t,reason:n})=>{e.connected=!1,t!==1012&&(e.lastError=`disconnected (${t}): ${n||"no reason"}`)},onEvent:t=>tg(e,t),onGap:({expected:t,received:n})=>{e.lastError=`event gap detected (expected seq ${t}, got ${n}); refresh recommended`}}),e.client.start()}function tg(e,t){try{ng(e,t)}catch(n){console.error("[gateway] handleGatewayEvent error:",t.event,n)}}function ng(e,t){if(e.eventLogBuffer=[{ts:Date.now(),event:t.event,payload:t.payload},...e.eventLogBuffer].slice(0,250),e.tab==="debug"&&(e.eventLog=e.eventLogBuffer),t.event==="agent"){if(e.onboarding)return;Yl(e,t.payload);return}if(t.event==="chat"){const n=t.payload;n?.sessionKey&&No(e,n.sessionKey);const s=Dl(e,n);(s==="final"||s==="error"||s==="aborted")&&(cn(e),Cd(e)),s==="final"&&Xe(e);return}if(t.event==="presence"){const n=t.payload;n?.presence&&Array.isArray(n.presence)&&(e.presenceEntries=n.presence,e.presenceError=null,e.presenceStatus=null);return}if(t.event==="cron"&&e.tab==="cron"&&Zs(e),(t.event==="device.pair.requested"||t.event==="device.pair.resolved")&&Te(e,{quiet:!0}),t.event==="exec.approval.requested"){const n=Zf(t.payload);if(n){e.execApprovalQueue=Xf(e.execApprovalQueue,n),e.execApprovalError=null;const s=Math.max(0,n.expiresAtMs-Date.now()+500);window.setTimeout(()=>{e.execApprovalQueue=Ga(e.execApprovalQueue,n.id)},s)}return}if(t.event==="exec.approval.resolved"){const n=Jf(t.payload);n&&(e.execApprovalQueue=Ga(e.execApprovalQueue,n.id))}}function sg(e,t){const n=t.snapshot;n?.presence&&Array.isArray(n.presence)&&(e.presenceEntries=n.presence),n?.health&&(e.debugHealth=n.health),n?.sessionDefaults&&eg(e,n.sessionDefaults)}function ig(e){e.basePath=gd(),bd(e,!0),vd(e),md(e),window.addEventListener("popstate",e.popStateHandler),pd(e),Ar(e),dd(e),e.tab==="logs"&&Ws(e),e.tab==="debug"&&Gs(e)}function ag(e){ec(e)}function og(e){window.removeEventListener("popstate",e.popStateHandler),ud(e),Vs(e),Ys(e),yd(e),e.topbarObserver?.disconnect(),e.topbarObserver=null}function rg(e,t){if(e.tab==="chat"&&(t.has("chatMessages")||t.has("chatToolMessages")||t.has("chatStream")||t.has("chatLoading")||t.has("tab"))){const n=t.has("tab"),s=t.has("chatLoading")&&t.get("chatLoading")===!0&&e.chatLoading===!1;dn(e,n||s||!e.chatHasAutoScrolled)}e.tab==="logs"&&(t.has("logsEntries")||t.has("logsAutoFollow")||t.has("tab"))&&e.logsAutoFollow&&e.logsAtBottom&&po(e,t.has("tab")||t.has("logsAutoFollow"))}async function lg(e,t){await uc(e,t),await oe(e,!0)}async function cg(e){await pc(e),await oe(e,!0)}async function dg(e){await hc(e),await oe(e,!0)}async function ug(e){await ds(e),await ye(e),await oe(e,!0)}async function pg(e){await ye(e),await oe(e,!0)}function hg(e){if(!Array.isArray(e))return{};const t={};for(const n of e){if(typeof n!="string")continue;const[s,...i]=n.split(":");if(!s||i.length===0)continue;const a=s.trim(),o=i.join(":").trim();a&&o&&(t[a]=o)}return t}function Sr(e){return(e.channelsSnapshot?.channelAccounts?.nostr??[])[0]?.accountId??e.nostrProfileAccountId??"default"}function _r(e,t=""){return`/api/channels/nostr/${encodeURIComponent(e)}/profile${t}`}function fg(e,t,n){e.nostrProfileAccountId=t,e.nostrProfileFormState=uh(n??void 0)}function gg(e){e.nostrProfileFormState=null,e.nostrProfileAccountId=null}function vg(e,t,n){const s=e.nostrProfileFormState;s&&(e.nostrProfileFormState={...s,values:{...s.values,[t]:n},fieldErrors:{...s.fieldErrors,[t]:""}})}function mg(e){const t=e.nostrProfileFormState;t&&(e.nostrProfileFormState={...t,showAdvanced:!t.showAdvanced})}async function yg(e){const t=e.nostrProfileFormState;if(!t||t.saving)return;const n=Sr(e);e.nostrProfileFormState={...t,saving:!0,error:null,success:null,fieldErrors:{}};try{const s=await fetch(_r(n),{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t.values)}),i=await s.json().catch(()=>null);if(!s.ok||i?.ok===!1||!i){const a=i?.error??`Profile update failed (${s.status})`;e.nostrProfileFormState={...t,saving:!1,error:a,success:null,fieldErrors:hg(i?.details)};return}if(!i.persisted){e.nostrProfileFormState={...t,saving:!1,error:"Profile publish failed on all relays.",success:null};return}e.nostrProfileFormState={...t,saving:!1,error:null,success:"Profile published to relays.",fieldErrors:{},original:{...t.values}},await oe(e,!0)}catch(s){e.nostrProfileFormState={...t,saving:!1,error:`Profile update failed: ${String(s)}`,success:null}}}async function bg(e){const t=e.nostrProfileFormState;if(!t||t.importing)return;const n=Sr(e);e.nostrProfileFormState={...t,importing:!0,error:null,success:null};try{const s=await fetch(_r(n,"/import"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({autoMerge:!0})}),i=await s.json().catch(()=>null);if(!s.ok||i?.ok===!1||!i){const r=i?.error??`Profile import failed (${s.status})`;e.nostrProfileFormState={...t,importing:!1,error:r,success:null};return}const a=i.merged??i.imported??null,o=a?{...t.values,...a}:t.values,l=!!(o.banner||o.website||o.nip05||o.lud16);e.nostrProfileFormState={...t,importing:!1,values:o,error:null,success:i.saved?"Profile imported from relays. Review and publish.":"Profile imported. Review and publish.",showAdvanced:l},i.saved&&await oe(e,!0)}catch(s){e.nostrProfileFormState={...t,importing:!1,error:`Profile import failed: ${String(s)}`,success:null}}}var wg=Object.defineProperty,$g=Object.getOwnPropertyDescriptor,y=(e,t,n,s)=>{for(var i=s>1?void 0:s?$g(t,n):t,a=e.length-1,o;a>=0;a--)(o=e[a])&&(i=(s?o(t,n,i):o(i))||i);return s&&i&&wg(t,n,i),i};const ns=gl();function xg(){if(!window.location.search)return!1;const t=new URLSearchParams(window.location.search).get("onboarding");if(!t)return!1;const n=t.trim().toLowerCase();return n==="1"||n==="true"||n==="yes"||n==="on"}let m=class extends Ze{constructor(){super(...arguments),this.settings=vl(),this.password="",this.tab="chat",this.onboarding=xg(),this.connected=!1,this.theme=this.settings.theme??"system",this.themeResolved="dark",this.hello=null,this.lastError=null,this.eventLog=[],this.eventLogBuffer=[],this.toolStreamSyncTimer=null,this.sidebarCloseTimer=null,this.assistantName=ns.name,this.assistantAvatar=ns.avatar,this.assistantAgentId=ns.agentId??null,this.sessionKey=this.settings.sessionKey,this.chatLoading=!1,this.chatSending=!1,this.chatMessage="",this.chatMessages=[],this.chatToolMessages=[],this.chatStream=null,this.chatStreamStartedAt=null,this.chatRunId=null,this.compactionStatus=null,this.chatAvatarUrl=null,this.chatThinkingLevel=null,this.chatQueue=[],this.chatAttachments=[],this.sidebarOpen=!1,this.sidebarContent=null,this.sidebarError=null,this.splitRatio=this.settings.splitRatio,this.nodesLoading=!1,this.nodes=[],this.devicesLoading=!1,this.devicesError=null,this.devicesList=null,this.execApprovalsLoading=!1,this.execApprovalsSaving=!1,this.execApprovalsDirty=!1,this.execApprovalsSnapshot=null,this.execApprovalsForm=null,this.execApprovalsSelectedAgent=null,this.execApprovalsTarget="gateway",this.execApprovalsTargetNodeId=null,this.execApprovalQueue=[],this.execApprovalBusy=!1,this.execApprovalError=null,this.configLoading=!1,this.configRaw=`{
|
|
3192
3193
|
}
|
|
3193
3194
|
`,this.configRawOriginal="",this.configValid=null,this.configIssues=[],this.configSaving=!1,this.configApplying=!1,this.updateRunning=!1,this.applySessionKey=this.settings.lastActiveSessionKey,this.configSnapshot=null,this.configSchema=null,this.configSchemaVersion=null,this.configSchemaLoading=!1,this.configUiHints={},this.configForm=null,this.configFormOriginal=null,this.configFormDirty=!1,this.configFormMode="form",this.configSearchQuery="",this.configActiveSection=null,this.configActiveSubsection=null,this.channelsLoading=!1,this.channelsSnapshot=null,this.channelsError=null,this.channelsLastSuccess=null,this.whatsappLoginMessage=null,this.whatsappLoginQrDataUrl=null,this.whatsappLoginConnected=null,this.whatsappBusy=!1,this.nostrProfileFormState=null,this.nostrProfileAccountId=null,this.presenceLoading=!1,this.presenceEntries=[],this.presenceError=null,this.presenceStatus=null,this.agentsLoading=!1,this.agentsList=null,this.agentsError=null,this.sessionsLoading=!1,this.sessionsResult=null,this.sessionsError=null,this.sessionsFilterActive="",this.sessionsFilterLimit="120",this.sessionsIncludeGlobal=!0,this.sessionsIncludeUnknown=!1,this.cronLoading=!1,this.cronJobs=[],this.cronStatus=null,this.cronError=null,this.cronForm={...Wf},this.cronRunsJobId=null,this.cronRuns=[],this.cronBusy=!1,this.skillsLoading=!1,this.skillsReport=null,this.skillsError=null,this.skillsFilter="",this.skillEdits={},this.skillsBusyKey=null,this.skillMessages={},this.debugLoading=!1,this.debugStatus=null,this.debugHealth=null,this.debugModels=[],this.debugHeartbeat=null,this.debugCallMethod="",this.debugCallParams="{}",this.debugCallResult=null,this.debugCallError=null,this.logsLoading=!1,this.logsError=null,this.logsFile=null,this.logsEntries=[],this.logsFilterText="",this.logsLevelFilters={...qf},this.logsAutoFollow=!0,this.logsTruncated=!1,this.logsCursor=null,this.logsLastFetchAt=null,this.logsLimit=500,this.logsMaxBytes=25e4,this.logsAtBottom=!0,this.client=null,this.chatScrollFrame=null,this.chatScrollTimeout=null,this.chatHasAutoScrolled=!1,this.chatUserNearBottom=!0,this.nodesPollInterval=null,this.logsPollInterval=null,this.debugPollInterval=null,this.logsScrollFrame=null,this.toolStreamById=new Map,this.toolStreamOrder=[],this.basePath="",this.popStateHandler=()=>wd(this),this.themeMedia=null,this.themeMediaHandler=null,this.topbarObserver=null}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),ig(this)}firstUpdated(){ag(this)}disconnectedCallback(){og(this),super.disconnectedCallback()}updated(e){rg(this,e)}connect(){Ar(this)}handleChatScroll(e){Ql(this,e)}handleLogsScroll(e){Zl(this,e)}exportLogs(e,t){Xl(e,t)}resetToolStream(){cn(this)}resetChatScroll(){Jl(this)}async loadAssistantIdentity(){await kr(this)}applySettings(e){ke(this,e)}setTab(e){hd(this,e)}setTheme(e,t){fd(this,e,t)}async loadOverview(){await Bo(this)}async loadCron(){await Zs(this)}async handleAbortChat(){await Uo(this)}removeQueuedMessage(e){Sd(this,e)}async handleSendChat(e,t){await _d(this,e,t)}async handleWhatsAppStart(e){await lg(this,e)}async handleWhatsAppWait(){await cg(this)}async handleWhatsAppLogout(){await dg(this)}async handleChannelConfigSave(){await ug(this)}async handleChannelConfigReload(){await pg(this)}handleNostrProfileEdit(e,t){fg(this,e,t)}handleNostrProfileCancel(){gg(this)}handleNostrProfileFieldChange(e,t){vg(this,e,t)}async handleNostrProfileSave(){await yg(this)}async handleNostrProfileImport(){await bg(this)}handleNostrProfileToggleAdvanced(){mg(this)}async handleExecApprovalDecision(e){const t=this.execApprovalQueue[0];if(!(!t||!this.client||this.execApprovalBusy)){this.execApprovalBusy=!0,this.execApprovalError=null;try{await this.client.request("exec.approval.resolve",{id:t.id,decision:e}),this.execApprovalQueue=this.execApprovalQueue.filter(n=>n.id!==t.id)}catch(n){this.execApprovalError=`Exec approval failed: ${String(n)}`}finally{this.execApprovalBusy=!1}}}handleOpenSidebar(e){this.sidebarCloseTimer!=null&&(window.clearTimeout(this.sidebarCloseTimer),this.sidebarCloseTimer=null),this.sidebarContent=e,this.sidebarError=null,this.sidebarOpen=!0}handleCloseSidebar(){this.sidebarOpen=!1,this.sidebarCloseTimer!=null&&window.clearTimeout(this.sidebarCloseTimer),this.sidebarCloseTimer=window.setTimeout(()=>{this.sidebarOpen||(this.sidebarContent=null,this.sidebarError=null,this.sidebarCloseTimer=null)},200)}handleSplitRatioChange(e){const t=Math.max(.4,Math.min(.7,e));this.splitRatio=t,this.applySettings({...this.settings,splitRatio:t})}render(){return jf(this)}};y([b()],m.prototype,"settings",2);y([b()],m.prototype,"password",2);y([b()],m.prototype,"tab",2);y([b()],m.prototype,"onboarding",2);y([b()],m.prototype,"connected",2);y([b()],m.prototype,"theme",2);y([b()],m.prototype,"themeResolved",2);y([b()],m.prototype,"hello",2);y([b()],m.prototype,"lastError",2);y([b()],m.prototype,"eventLog",2);y([b()],m.prototype,"assistantName",2);y([b()],m.prototype,"assistantAvatar",2);y([b()],m.prototype,"assistantAgentId",2);y([b()],m.prototype,"sessionKey",2);y([b()],m.prototype,"chatLoading",2);y([b()],m.prototype,"chatSending",2);y([b()],m.prototype,"chatMessage",2);y([b()],m.prototype,"chatMessages",2);y([b()],m.prototype,"chatToolMessages",2);y([b()],m.prototype,"chatStream",2);y([b()],m.prototype,"chatStreamStartedAt",2);y([b()],m.prototype,"chatRunId",2);y([b()],m.prototype,"compactionStatus",2);y([b()],m.prototype,"chatAvatarUrl",2);y([b()],m.prototype,"chatThinkingLevel",2);y([b()],m.prototype,"chatQueue",2);y([b()],m.prototype,"chatAttachments",2);y([b()],m.prototype,"sidebarOpen",2);y([b()],m.prototype,"sidebarContent",2);y([b()],m.prototype,"sidebarError",2);y([b()],m.prototype,"splitRatio",2);y([b()],m.prototype,"nodesLoading",2);y([b()],m.prototype,"nodes",2);y([b()],m.prototype,"devicesLoading",2);y([b()],m.prototype,"devicesError",2);y([b()],m.prototype,"devicesList",2);y([b()],m.prototype,"execApprovalsLoading",2);y([b()],m.prototype,"execApprovalsSaving",2);y([b()],m.prototype,"execApprovalsDirty",2);y([b()],m.prototype,"execApprovalsSnapshot",2);y([b()],m.prototype,"execApprovalsForm",2);y([b()],m.prototype,"execApprovalsSelectedAgent",2);y([b()],m.prototype,"execApprovalsTarget",2);y([b()],m.prototype,"execApprovalsTargetNodeId",2);y([b()],m.prototype,"execApprovalQueue",2);y([b()],m.prototype,"execApprovalBusy",2);y([b()],m.prototype,"execApprovalError",2);y([b()],m.prototype,"configLoading",2);y([b()],m.prototype,"configRaw",2);y([b()],m.prototype,"configRawOriginal",2);y([b()],m.prototype,"configValid",2);y([b()],m.prototype,"configIssues",2);y([b()],m.prototype,"configSaving",2);y([b()],m.prototype,"configApplying",2);y([b()],m.prototype,"updateRunning",2);y([b()],m.prototype,"applySessionKey",2);y([b()],m.prototype,"configSnapshot",2);y([b()],m.prototype,"configSchema",2);y([b()],m.prototype,"configSchemaVersion",2);y([b()],m.prototype,"configSchemaLoading",2);y([b()],m.prototype,"configUiHints",2);y([b()],m.prototype,"configForm",2);y([b()],m.prototype,"configFormOriginal",2);y([b()],m.prototype,"configFormDirty",2);y([b()],m.prototype,"configFormMode",2);y([b()],m.prototype,"configSearchQuery",2);y([b()],m.prototype,"configActiveSection",2);y([b()],m.prototype,"configActiveSubsection",2);y([b()],m.prototype,"channelsLoading",2);y([b()],m.prototype,"channelsSnapshot",2);y([b()],m.prototype,"channelsError",2);y([b()],m.prototype,"channelsLastSuccess",2);y([b()],m.prototype,"whatsappLoginMessage",2);y([b()],m.prototype,"whatsappLoginQrDataUrl",2);y([b()],m.prototype,"whatsappLoginConnected",2);y([b()],m.prototype,"whatsappBusy",2);y([b()],m.prototype,"nostrProfileFormState",2);y([b()],m.prototype,"nostrProfileAccountId",2);y([b()],m.prototype,"presenceLoading",2);y([b()],m.prototype,"presenceEntries",2);y([b()],m.prototype,"presenceError",2);y([b()],m.prototype,"presenceStatus",2);y([b()],m.prototype,"agentsLoading",2);y([b()],m.prototype,"agentsList",2);y([b()],m.prototype,"agentsError",2);y([b()],m.prototype,"sessionsLoading",2);y([b()],m.prototype,"sessionsResult",2);y([b()],m.prototype,"sessionsError",2);y([b()],m.prototype,"sessionsFilterActive",2);y([b()],m.prototype,"sessionsFilterLimit",2);y([b()],m.prototype,"sessionsIncludeGlobal",2);y([b()],m.prototype,"sessionsIncludeUnknown",2);y([b()],m.prototype,"cronLoading",2);y([b()],m.prototype,"cronJobs",2);y([b()],m.prototype,"cronStatus",2);y([b()],m.prototype,"cronError",2);y([b()],m.prototype,"cronForm",2);y([b()],m.prototype,"cronRunsJobId",2);y([b()],m.prototype,"cronRuns",2);y([b()],m.prototype,"cronBusy",2);y([b()],m.prototype,"skillsLoading",2);y([b()],m.prototype,"skillsReport",2);y([b()],m.prototype,"skillsError",2);y([b()],m.prototype,"skillsFilter",2);y([b()],m.prototype,"skillEdits",2);y([b()],m.prototype,"skillsBusyKey",2);y([b()],m.prototype,"skillMessages",2);y([b()],m.prototype,"debugLoading",2);y([b()],m.prototype,"debugStatus",2);y([b()],m.prototype,"debugHealth",2);y([b()],m.prototype,"debugModels",2);y([b()],m.prototype,"debugHeartbeat",2);y([b()],m.prototype,"debugCallMethod",2);y([b()],m.prototype,"debugCallParams",2);y([b()],m.prototype,"debugCallResult",2);y([b()],m.prototype,"debugCallError",2);y([b()],m.prototype,"logsLoading",2);y([b()],m.prototype,"logsError",2);y([b()],m.prototype,"logsFile",2);y([b()],m.prototype,"logsEntries",2);y([b()],m.prototype,"logsFilterText",2);y([b()],m.prototype,"logsLevelFilters",2);y([b()],m.prototype,"logsAutoFollow",2);y([b()],m.prototype,"logsTruncated",2);y([b()],m.prototype,"logsCursor",2);y([b()],m.prototype,"logsLastFetchAt",2);y([b()],m.prototype,"logsLimit",2);y([b()],m.prototype,"logsMaxBytes",2);y([b()],m.prototype,"logsAtBottom",2);m=y([no("poolbot-app")],m);
|
|
3194
|
-
//# sourceMappingURL=index-
|
|
3195
|
+
//# sourceMappingURL=index-Dvkl4Xlx.js.map
|