@poolzin/pool-bot 2026.2.21 → 2026.2.22
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 +17 -0
- package/dist/agents/api-key-rotation.js +47 -0
- package/dist/agents/apply-patch-update.js +19 -9
- package/dist/agents/apply-patch.js +72 -47
- package/dist/agents/bash-tools.exec.js +141 -559
- package/dist/agents/cli-backends.js +49 -6
- package/dist/agents/cli-runner/helpers.js +69 -152
- package/dist/agents/cli-runner.js +70 -19
- package/dist/agents/identity.js +20 -1
- package/dist/agents/image-sanitization.js +9 -0
- package/dist/agents/live-auth-keys.js +123 -26
- package/dist/agents/live-model-filter.js +13 -4
- package/dist/agents/model-catalog.js +40 -9
- package/dist/agents/model-forward-compat.js +60 -23
- package/dist/agents/model-selection.js +134 -41
- package/dist/agents/pi-auth-json.js +2 -2
- package/dist/agents/pi-embedded-helpers/bootstrap.js +65 -15
- package/dist/agents/pi-embedded-helpers/errors.js +140 -15
- package/dist/agents/pi-embedded-helpers/images.js +22 -12
- package/dist/agents/pi-embedded-helpers.js +2 -2
- package/dist/agents/pi-embedded-runner/abort.js +10 -3
- package/dist/agents/pi-embedded-runner/compact.js +230 -32
- package/dist/agents/pi-embedded-runner/extra-params.js +203 -12
- package/dist/agents/pi-embedded-runner/google.js +109 -19
- package/dist/agents/pi-embedded-runner/history.js +35 -17
- package/dist/agents/pi-embedded-runner/run/attempt.js +386 -95
- package/dist/agents/pi-embedded-runner/run/images.js +81 -55
- package/dist/agents/pi-embedded-runner/run/payloads.js +89 -39
- package/dist/agents/pi-embedded-runner/run.js +193 -25
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +2 -2
- package/dist/agents/pi-embedded-runner/runs.js +17 -8
- package/dist/agents/pi-embedded-runner/tool-result-context-guard.js +262 -0
- package/dist/agents/pi-embedded-runner.js +1 -1
- package/dist/agents/pi-embedded-subscribe.handlers.tools.js +180 -10
- package/dist/agents/pi-embedded-subscribe.js +37 -0
- package/dist/agents/pi-embedded-subscribe.tools.js +127 -30
- package/dist/agents/pi-model-discovery.js +9 -2
- package/dist/agents/pi-tool-definition-adapter.js +60 -8
- package/dist/agents/pi-tools.before-tool-call.js +1 -1
- package/dist/agents/pi-tools.js +113 -94
- package/dist/agents/pi-tools.read.js +337 -38
- package/dist/agents/poolbot-tools.js +14 -5
- package/dist/agents/sandbox/docker.js +10 -5
- package/dist/agents/sandbox/registry.js +96 -46
- package/dist/agents/sandbox/sanitize-env-vars.js +82 -0
- package/dist/agents/sandbox-paths.js +43 -10
- package/dist/agents/session-tool-result-guard-wrapper.js +23 -11
- package/dist/agents/session-tool-result-guard.js +39 -39
- package/dist/agents/session-transcript-repair.js +36 -33
- package/dist/agents/session-write-lock.js +62 -44
- package/dist/agents/skills/frontmatter.js +49 -88
- package/dist/agents/skills/workspace.js +335 -28
- package/dist/agents/subagent-announce.js +508 -174
- package/dist/agents/subagent-registry.js +45 -4
- package/dist/agents/subagent-spawn.js +16 -33
- package/dist/agents/system-prompt-report.js +27 -10
- package/dist/agents/system-prompt.js +26 -32
- package/dist/agents/tool-call-id.js +69 -17
- package/dist/agents/tool-display-common.js +1 -1
- package/dist/agents/tool-images.js +64 -31
- package/dist/agents/tools/canvas-tool.js +17 -11
- package/dist/agents/tools/common.js +37 -19
- package/dist/agents/tools/cron-tool.js +40 -38
- package/dist/agents/tools/gateway.js +70 -2
- package/dist/agents/tools/message-tool.js +181 -40
- package/dist/agents/tools/nodes-tool.js +128 -36
- package/dist/agents/tools/nodes-utils.js +12 -38
- package/dist/agents/tools/session-status-tool.js +24 -71
- package/dist/agents/tools/sessions-helpers.js +38 -210
- package/dist/agents/tools/sessions-spawn-tool.js +28 -198
- package/dist/agents/tools/telegram-actions.js +58 -7
- package/dist/agents/tools/web-fetch-utils.js +112 -7
- package/dist/agents/tools/web-fetch.js +279 -175
- package/dist/agents/tools/web-shared.js +71 -8
- package/dist/agents/usage.js +25 -16
- package/dist/auto-reply/commands-registry.data.js +85 -11
- package/dist/auto-reply/dispatch.js +40 -21
- package/dist/auto-reply/reply/abort.js +102 -33
- package/dist/auto-reply/reply/commands-core.js +82 -33
- package/dist/auto-reply/reply/commands-export-session.js +1 -1
- package/dist/auto-reply/reply/commands-info.js +41 -12
- package/dist/auto-reply/reply/commands-subagents.js +352 -100
- package/dist/auto-reply/reply/commands-system-prompt.js +2 -2
- package/dist/auto-reply/reply/dispatch-from-config.js +100 -29
- package/dist/auto-reply/reply/elevated-unavailable.js +1 -1
- package/dist/auto-reply/reply/inbound-meta.js +12 -1
- package/dist/auto-reply/reply/mentions.js +18 -11
- package/dist/auto-reply/reply/normalize-reply.js +17 -8
- package/dist/auto-reply/reply/reply-dispatcher.js +62 -10
- package/dist/auto-reply/reply/session.js +102 -21
- package/dist/auto-reply/reply/streaming-directives.js +16 -5
- package/dist/auto-reply/status.js +73 -50
- package/dist/browser/extension-relay.js +3 -3
- package/dist/browser/http-auth.js +1 -1
- package/dist/browser/paths.js +2 -2
- package/dist/build-info.json +3 -3
- package/dist/channels/allowlist-match.js +20 -0
- package/dist/channels/allowlists/resolve-utils.js +65 -2
- package/dist/channels/chat-type.js +8 -4
- package/dist/channels/dock.js +127 -35
- package/dist/channels/draft-stream-loop.js +6 -2
- package/dist/channels/plugins/actions/telegram.js +42 -18
- package/dist/channels/plugins/allowlist-match.js +1 -1
- package/dist/channels/plugins/group-mentions.js +51 -41
- package/dist/channels/plugins/message-action-names.js +2 -0
- package/dist/channels/plugins/message-actions.js +24 -5
- package/dist/channels/plugins/normalize/discord.js +26 -4
- package/dist/channels/plugins/normalize/signal.js +35 -22
- package/dist/channels/plugins/onboarding/helpers.js +8 -26
- package/dist/channels/plugins/outbound/imessage.js +15 -14
- package/dist/channels/registry.js +20 -7
- package/dist/cli/acp-cli.js +7 -5
- package/dist/cli/browser-cli-extension.js +25 -12
- package/dist/cli/browser-cli-state.cookies-storage.js +25 -6
- package/dist/cli/browser-cli-state.js +101 -145
- package/dist/cli/command-options.js +28 -0
- package/dist/cli/completion-cli.js +6 -6
- package/dist/cli/cron-cli/register.cron-add.js +25 -1
- package/dist/cli/cron-cli/register.cron-edit.js +44 -0
- package/dist/cli/cron-cli/shared.js +7 -1
- package/dist/cli/daemon-cli/lifecycle-core.js +23 -21
- package/dist/cli/daemon-cli/lifecycle.js +23 -247
- package/dist/cli/daemon-cli/register-service-commands.js +25 -4
- package/dist/cli/daemon-cli.js +1 -0
- package/dist/cli/devices-cli.js +33 -20
- package/dist/cli/gateway-cli/register.js +37 -105
- package/dist/cli/gateway-cli/run.js +49 -11
- package/dist/cli/nodes-camera.js +59 -4
- package/dist/cli/nodes-cli/register.camera.js +27 -24
- package/dist/cli/nodes-cli/rpc.js +21 -38
- package/dist/cli/qr-cli.js +2 -2
- package/dist/cli/skills-cli.format.js +2 -2
- package/dist/cli/update-cli/progress.js +2 -2
- package/dist/cli/update-cli/restart-helper.js +28 -7
- package/dist/cli/update-cli/shared.js +7 -7
- package/dist/cli/update-cli/status.js +1 -1
- package/dist/cli/update-cli/update-command.js +14 -8
- package/dist/cli/update-cli/wizard.js +2 -2
- package/dist/cli/update-cli.js +21 -1027
- package/dist/commands/auth-choice.apply.anthropic.js +10 -2
- package/dist/commands/channels/add-mutators.js +3 -35
- package/dist/commands/channels/add.js +39 -51
- package/dist/commands/config-validation.js +1 -1
- package/dist/commands/configure.gateway-auth.js +52 -15
- package/dist/commands/configure.gateway.js +84 -40
- package/dist/commands/doctor-completion.js +3 -3
- package/dist/commands/doctor-config-flow.js +536 -16
- package/dist/commands/doctor-gateway-services.js +103 -79
- package/dist/commands/doctor-memory-search.js +9 -9
- package/dist/commands/doctor-platform-notes.js +57 -30
- package/dist/commands/doctor-prompter.js +26 -15
- package/dist/commands/doctor-session-locks.js +1 -1
- package/dist/commands/doctor.js +21 -9
- package/dist/commands/model-picker.js +120 -95
- package/dist/commands/models/set.js +2 -21
- package/dist/commands/models/shared.js +65 -37
- package/dist/commands/onboard-helpers.js +81 -39
- package/dist/commands/openai-codex-oauth.js +1 -1
- package/dist/commands/sessions.js +52 -53
- package/dist/commands/status.summary.js +52 -34
- package/dist/commands/test-wizard-helpers.js +2 -2
- package/dist/config/defaults.js +79 -42
- package/dist/config/group-policy.js +50 -18
- package/dist/config/includes.js +37 -10
- package/dist/config/schema.help.js +5 -4
- package/dist/config/schema.hints.js +2 -2
- package/dist/config/schema.labels.js +1 -0
- package/dist/config/sessions/group.js +12 -11
- package/dist/config/sessions/paths.js +137 -11
- package/dist/config/sessions/store.js +185 -65
- package/dist/config/sessions/types.js +15 -1
- package/dist/config/sessions.js +1 -0
- package/dist/config/telegram-custom-commands.js +3 -2
- package/dist/config/types.js +2 -0
- package/dist/config/zod-schema.agent-defaults.js +6 -27
- package/dist/config/zod-schema.agent-runtime.js +171 -79
- package/dist/config/zod-schema.providers-core.js +138 -65
- package/dist/config/zod-schema.session.js +49 -22
- package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
- package/dist/cron/isolated-agent/run.js +224 -57
- package/dist/cron/normalize.js +48 -45
- package/dist/cron/run-log.js +14 -0
- package/dist/cron/service/jobs.js +190 -28
- package/dist/cron/service/normalize.js +29 -11
- package/dist/cron/service/store.js +30 -44
- package/dist/cron/service/timer.js +182 -96
- package/dist/cron/service.js +3 -0
- package/dist/cron/stagger.js +37 -0
- package/dist/daemon/inspect.js +132 -92
- package/dist/daemon/runtime-paths.js +25 -4
- package/dist/daemon/service-audit.js +47 -16
- package/dist/discord/accounts.js +23 -20
- package/dist/discord/monitor/agent-components.js +1115 -219
- package/dist/discord/monitor/allow-list.js +114 -34
- package/dist/discord/monitor/listeners.js +204 -97
- package/dist/discord/monitor/message-handler.js +21 -10
- package/dist/discord/monitor/message-handler.preflight.js +195 -101
- package/dist/discord/monitor/message-handler.process.js +384 -123
- package/dist/discord/monitor/message-utils.js +86 -23
- package/dist/discord/monitor/native-command.js +77 -57
- package/dist/discord/monitor/provider.js +122 -117
- package/dist/discord/monitor/reply-context.js +20 -16
- package/dist/discord/monitor/reply-delivery.js +40 -8
- package/dist/discord/monitor/rest-fetch.js +22 -0
- package/dist/discord/monitor/threading.js +117 -24
- package/dist/discord/send.js +2 -1
- package/dist/discord/send.outbound.js +124 -11
- package/dist/discord/send.shared.js +112 -72
- package/dist/discord/voice-message.js +3 -3
- package/dist/gateway/auth.js +119 -44
- package/dist/gateway/call.js +76 -34
- package/dist/gateway/channel-health-monitor.js +57 -50
- package/dist/gateway/client.js +63 -29
- package/dist/gateway/control-ui-contract.js +1 -1
- package/dist/gateway/gateway-config-prompts.shared.js +2 -2
- package/dist/gateway/net.js +109 -1
- package/dist/gateway/protocol/index.js +5 -8
- package/dist/gateway/protocol/schema/agent.js +19 -1
- package/dist/gateway/protocol/schema/channels.js +21 -0
- package/dist/gateway/protocol/schema/cron.js +43 -30
- package/dist/gateway/protocol/schema/protocol-schemas.js +6 -11
- package/dist/gateway/protocol/schema/sessions.js +5 -1
- package/dist/gateway/protocol/schema.js +0 -1
- package/dist/gateway/server/presence-events.js +12 -0
- package/dist/gateway/server/ws-connection/message-handler.js +203 -212
- package/dist/gateway/server/ws-connection.js +58 -21
- package/dist/gateway/server-broadcast.js +18 -13
- package/dist/gateway/server-cron.js +177 -10
- package/dist/gateway/server-methods/agent-job.js +131 -38
- package/dist/gateway/server-methods/send.js +60 -14
- package/dist/gateway/server-methods/sessions.js +160 -96
- package/dist/gateway/server-methods/system.js +5 -7
- package/dist/gateway/server-methods-list.js +8 -0
- package/dist/gateway/server-methods.js +24 -8
- package/dist/gateway/server-node-events.js +278 -68
- package/dist/gateway/session-utils.fs.js +316 -75
- package/dist/gateway/session-utils.js +224 -70
- package/dist/gateway/sessions-patch.js +63 -20
- package/dist/gateway/test-temp-config.js +1 -1
- package/dist/gateway/tools-invoke-http.js +118 -70
- package/dist/gateway/ws-log.js +135 -107
- package/dist/hooks/frontmatter.js +36 -82
- package/dist/hooks/install.js +149 -139
- package/dist/hooks/internal-hooks.js +29 -4
- package/dist/hooks/plugin-hooks.js +2 -1
- package/dist/imessage/monitor/deliver.js +10 -4
- package/dist/imessage/monitor/monitor-provider.js +138 -375
- package/dist/imessage/monitor/runtime.js +4 -8
- package/dist/imessage/send.js +65 -19
- package/dist/infra/exec-approvals-allowlist.js +7 -0
- package/dist/infra/exec-approvals.js +35 -920
- package/dist/infra/exec-safe-bin-trust.js +64 -0
- package/dist/infra/heartbeat-runner.js +207 -134
- package/dist/infra/heartbeat-wake.js +183 -22
- package/dist/infra/install-source-utils.js +47 -0
- package/dist/infra/net/ssrf.js +170 -36
- package/dist/infra/outbound/deliver.js +224 -58
- package/dist/infra/outbound/message-action-spec.js +12 -5
- package/dist/infra/outbound/outbound-session.js +27 -25
- package/dist/infra/poolbot-root.js +32 -22
- package/dist/infra/ports.js +14 -11
- package/dist/infra/skills-remote.js +48 -37
- package/dist/infra/system-events.js +25 -11
- package/dist/infra/system-presence.js +26 -33
- package/dist/infra/tmp-poolbot-dir.js +81 -2
- package/dist/infra/wsl.js +37 -1
- package/dist/line/bot-message-context.js +163 -191
- package/dist/logging/subsystem.js +59 -22
- package/dist/markdown/ir.js +124 -50
- package/dist/media/store.js +1 -1
- package/dist/media-understanding/runner.entries.js +42 -25
- package/dist/media-understanding/runner.js +53 -488
- package/dist/memory/embeddings-gemini.js +53 -38
- package/dist/memory/manager-embedding-ops.js +48 -69
- package/dist/pairing/pairing-store.js +178 -119
- package/dist/plugin-sdk/index.js +34 -6
- package/dist/plugins/hooks.js +135 -14
- package/dist/plugins/install.js +190 -152
- package/dist/polls.js +11 -0
- package/dist/routing/resolve-route.js +190 -56
- package/dist/routing/session-key.js +38 -22
- package/dist/runtime.js +35 -9
- package/dist/security/audit-channel.js +1 -1
- package/dist/sessions/session-key-utils.js +29 -11
- package/dist/shared/frontmatter.js +5 -5
- package/dist/shared/node-list-types.js +1 -0
- package/dist/shared/string-normalization.js +15 -0
- package/dist/signal/monitor/event-handler.js +68 -36
- package/dist/signal/send.js +29 -37
- package/dist/slack/monitor/allow-list.js +10 -11
- package/dist/slack/monitor/commands.js +14 -3
- package/dist/slack/monitor/events/interactions.js +4 -4
- package/dist/slack/monitor/media.js +224 -16
- package/dist/slack/monitor/message-handler/dispatch.js +247 -13
- package/dist/slack/monitor/message-handler/prepare.js +128 -45
- package/dist/slack/monitor/slash.js +357 -144
- package/dist/slack/streaming.js +77 -0
- package/dist/telegram/accounts.js +40 -13
- package/dist/telegram/allowed-updates.js +3 -0
- package/dist/telegram/bot/delivery.js +129 -66
- package/dist/telegram/bot/helpers.js +136 -122
- package/dist/telegram/bot-handlers.js +600 -339
- package/dist/telegram/bot-message-context.js +115 -73
- package/dist/telegram/bot-message-dispatch.js +235 -104
- package/dist/telegram/bot-native-command-menu.js +3 -1
- package/dist/telegram/bot-native-commands.js +213 -193
- package/dist/telegram/bot.js +24 -132
- package/dist/telegram/draft-stream.js +84 -75
- package/dist/telegram/format.js +150 -6
- package/dist/telegram/send.js +415 -255
- package/dist/telegram/targets.js +21 -2
- package/dist/telegram/update-offset-store.js +19 -3
- package/dist/terminal/restore.js +5 -2
- package/dist/test-utils/fetch-mock.js +5 -0
- package/dist/version.js +18 -5
- package/dist/web/auto-reply/monitor/broadcast.js +7 -3
- package/dist/web/auto-reply/monitor/on-message.js +6 -3
- package/dist/web/inbound/media.js +34 -8
- package/dist/web/inbound/monitor.js +34 -17
- package/dist/web/inbound/send-api.js +18 -17
- package/dist/web/outbound.js +12 -5
- package/dist/wizard/clack-prompter.js +40 -7
- 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/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/matrix/CHANGELOG.md +5 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- 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
- package/skills/apple-reminders/SKILL.md +100 -49
- package/skills/coding-agent/SKILL.md +34 -28
- package/skills/github/SKILL.md +131 -16
- package/skills/imsg/SKILL.md +112 -15
- package/skills/openhue/SKILL.md +101 -19
- package/skills/tmux/SKILL.md +111 -79
- package/skills/weather/SKILL.md +88 -25
|
@@ -8,38 +8,44 @@ import { CONFIG_PATH } from "../config/config.js";
|
|
|
8
8
|
import { resolveSessionTranscriptsDirForAgent } from "../config/sessions.js";
|
|
9
9
|
import { callGateway } from "../gateway/call.js";
|
|
10
10
|
import { normalizeControlUiBasePath } from "../gateway/control-ui-shared.js";
|
|
11
|
+
import { pickPrimaryLanIPv4, isValidIPv4 } from "../gateway/net.js";
|
|
11
12
|
import { isSafeExecutableValue } from "../infra/exec-safety.js";
|
|
12
13
|
import { pickPrimaryTailnetIPv4 } from "../infra/tailnet.js";
|
|
13
14
|
import { isWSL } from "../infra/wsl.js";
|
|
14
15
|
import { runCommandWithTimeout } from "../process/exec.js";
|
|
15
16
|
import { stylePromptTitle } from "../terminal/prompt-style.js";
|
|
16
|
-
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
|
|
17
17
|
import { CONFIG_DIR, resolveUserPath, shortenHomeInString, shortenHomePath, sleep, } from "../utils.js";
|
|
18
|
+
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
|
|
18
19
|
import { VERSION } from "../version.js";
|
|
19
20
|
export function guardCancel(value, runtime) {
|
|
20
21
|
if (isCancel(value)) {
|
|
21
22
|
cancel(stylePromptTitle("Setup cancelled.") ?? "Setup cancelled.");
|
|
22
23
|
runtime.exit(0);
|
|
24
|
+
throw new Error("unreachable");
|
|
23
25
|
}
|
|
24
26
|
return value;
|
|
25
27
|
}
|
|
26
28
|
export function summarizeExistingConfig(config) {
|
|
27
29
|
const rows = [];
|
|
28
30
|
const defaults = config.agents?.defaults;
|
|
29
|
-
if (defaults?.workspace)
|
|
31
|
+
if (defaults?.workspace) {
|
|
30
32
|
rows.push(shortenHomeInString(`workspace: ${defaults.workspace}`));
|
|
33
|
+
}
|
|
31
34
|
if (defaults?.model) {
|
|
32
35
|
const model = typeof defaults.model === "string" ? defaults.model : defaults.model.primary;
|
|
33
|
-
if (model)
|
|
36
|
+
if (model) {
|
|
34
37
|
rows.push(shortenHomeInString(`model: ${model}`));
|
|
38
|
+
}
|
|
35
39
|
}
|
|
36
|
-
if (config.gateway?.mode)
|
|
40
|
+
if (config.gateway?.mode) {
|
|
37
41
|
rows.push(shortenHomeInString(`gateway.mode: ${config.gateway.mode}`));
|
|
42
|
+
}
|
|
38
43
|
if (typeof config.gateway?.port === "number") {
|
|
39
44
|
rows.push(shortenHomeInString(`gateway.port: ${config.gateway.port}`));
|
|
40
45
|
}
|
|
41
|
-
if (config.gateway?.bind)
|
|
46
|
+
if (config.gateway?.bind) {
|
|
42
47
|
rows.push(shortenHomeInString(`gateway.bind: ${config.gateway.bind}`));
|
|
48
|
+
}
|
|
43
49
|
if (config.gateway?.remote?.url) {
|
|
44
50
|
rows.push(shortenHomeInString(`gateway.remote.url: ${config.gateway.remote.url}`));
|
|
45
51
|
}
|
|
@@ -51,14 +57,40 @@ export function summarizeExistingConfig(config) {
|
|
|
51
57
|
export function randomToken() {
|
|
52
58
|
return crypto.randomBytes(24).toString("hex");
|
|
53
59
|
}
|
|
60
|
+
export function normalizeGatewayTokenInput(value) {
|
|
61
|
+
if (typeof value !== "string") {
|
|
62
|
+
return "";
|
|
63
|
+
}
|
|
64
|
+
const trimmed = value.trim();
|
|
65
|
+
// Reject the literal string "undefined" — a common bug when JS undefined
|
|
66
|
+
// gets coerced to a string via template literals or String(undefined).
|
|
67
|
+
if (trimmed === "undefined" || trimmed === "null") {
|
|
68
|
+
return "";
|
|
69
|
+
}
|
|
70
|
+
return trimmed;
|
|
71
|
+
}
|
|
72
|
+
export function validateGatewayPasswordInput(value) {
|
|
73
|
+
if (typeof value !== "string") {
|
|
74
|
+
return "Required";
|
|
75
|
+
}
|
|
76
|
+
const trimmed = value.trim();
|
|
77
|
+
if (!trimmed) {
|
|
78
|
+
return "Required";
|
|
79
|
+
}
|
|
80
|
+
if (trimmed === "undefined" || trimmed === "null") {
|
|
81
|
+
return 'Cannot be the literal string "undefined" or "null"';
|
|
82
|
+
}
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
54
85
|
export function printWizardHeader(runtime) {
|
|
55
86
|
const header = [
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
87
|
+
"▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄",
|
|
88
|
+
"██░▄▄▄░██░▄▄░██░▄▄▄██░▀██░██░▄▄▀██░████░▄▄▀██░███░██",
|
|
89
|
+
"██░███░██░▀▀░██░▄▄▄██░█░█░██░█████░████░▀▀░██░█░█░██",
|
|
90
|
+
"██░▀▀▀░██░█████░▀▀▀██░██▄░██░▀▀▄██░▀▀░█░██░██▄▀▄▀▄██",
|
|
91
|
+
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀",
|
|
92
|
+
" 🦞 POOL BOT 🦞 ",
|
|
93
|
+
" ",
|
|
62
94
|
].join("\n");
|
|
63
95
|
runtime.log(header);
|
|
64
96
|
}
|
|
@@ -103,10 +135,12 @@ export async function resolveBrowserOpenCommand() {
|
|
|
103
135
|
}
|
|
104
136
|
if (wsl) {
|
|
105
137
|
const hasWslview = await detectBinary("wslview");
|
|
106
|
-
if (hasWslview)
|
|
138
|
+
if (hasWslview) {
|
|
107
139
|
return { argv: ["wslview"], command: "wslview" };
|
|
108
|
-
|
|
140
|
+
}
|
|
141
|
+
if (!hasDisplay) {
|
|
109
142
|
return { argv: null, reason: "wsl-no-wslview" };
|
|
143
|
+
}
|
|
110
144
|
}
|
|
111
145
|
const hasXdgOpen = await detectBinary("xdg-open");
|
|
112
146
|
return hasXdgOpen
|
|
@@ -117,16 +151,18 @@ export async function resolveBrowserOpenCommand() {
|
|
|
117
151
|
}
|
|
118
152
|
export async function detectBrowserOpenSupport() {
|
|
119
153
|
const resolved = await resolveBrowserOpenCommand();
|
|
120
|
-
if (!resolved.argv)
|
|
154
|
+
if (!resolved.argv) {
|
|
121
155
|
return { ok: false, reason: resolved.reason };
|
|
156
|
+
}
|
|
122
157
|
return { ok: true, command: resolved.command };
|
|
123
158
|
}
|
|
124
159
|
export function formatControlUiSshHint(params) {
|
|
125
160
|
const basePath = normalizeControlUiBasePath(params.basePath);
|
|
126
161
|
const uiPath = basePath ? `${basePath}/` : "/";
|
|
127
162
|
const localUrl = `http://localhost:${params.port}${uiPath}`;
|
|
128
|
-
const
|
|
129
|
-
|
|
163
|
+
const authedUrl = params.token
|
|
164
|
+
? `${localUrl}#token=${encodeURIComponent(params.token)}`
|
|
165
|
+
: undefined;
|
|
130
166
|
const sshTarget = resolveSshTargetHint();
|
|
131
167
|
return [
|
|
132
168
|
"No GUI detected. Open from your computer:",
|
|
@@ -135,8 +171,8 @@ export function formatControlUiSshHint(params) {
|
|
|
135
171
|
localUrl,
|
|
136
172
|
authedUrl,
|
|
137
173
|
"Docs:",
|
|
138
|
-
"https://docs.
|
|
139
|
-
"https://docs.
|
|
174
|
+
"https://docs.poolbot.ai/gateway/remote",
|
|
175
|
+
"https://docs.poolbot.ai/web/control-ui",
|
|
140
176
|
]
|
|
141
177
|
.filter(Boolean)
|
|
142
178
|
.join("\n");
|
|
@@ -148,11 +184,13 @@ function resolveSshTargetHint() {
|
|
|
148
184
|
return `${user}@${host}`;
|
|
149
185
|
}
|
|
150
186
|
export async function openUrl(url) {
|
|
151
|
-
if (shouldSkipBrowserOpenInTests())
|
|
187
|
+
if (shouldSkipBrowserOpenInTests()) {
|
|
152
188
|
return false;
|
|
189
|
+
}
|
|
153
190
|
const resolved = await resolveBrowserOpenCommand();
|
|
154
|
-
if (!resolved.argv)
|
|
191
|
+
if (!resolved.argv) {
|
|
155
192
|
return false;
|
|
193
|
+
}
|
|
156
194
|
const quoteUrl = resolved.quoteUrl === true;
|
|
157
195
|
const command = [...resolved.argv];
|
|
158
196
|
if (quoteUrl) {
|
|
@@ -178,13 +216,16 @@ export async function openUrl(url) {
|
|
|
178
216
|
}
|
|
179
217
|
}
|
|
180
218
|
export async function openUrlInBackground(url) {
|
|
181
|
-
if (shouldSkipBrowserOpenInTests())
|
|
219
|
+
if (shouldSkipBrowserOpenInTests()) {
|
|
182
220
|
return false;
|
|
183
|
-
|
|
221
|
+
}
|
|
222
|
+
if (process.platform !== "darwin") {
|
|
184
223
|
return false;
|
|
224
|
+
}
|
|
185
225
|
const resolved = await resolveBrowserOpenCommand();
|
|
186
|
-
if (!resolved.argv || resolved.command !== "open")
|
|
226
|
+
if (!resolved.argv || resolved.command !== "open") {
|
|
187
227
|
return false;
|
|
228
|
+
}
|
|
188
229
|
const command = ["open", "-g", url];
|
|
189
230
|
try {
|
|
190
231
|
await runCommandWithTimeout(command, { timeoutMs: 5_000 });
|
|
@@ -212,8 +253,9 @@ export function resolveNodeManagerOptions() {
|
|
|
212
253
|
];
|
|
213
254
|
}
|
|
214
255
|
export async function moveToTrash(pathname, runtime) {
|
|
215
|
-
if (!pathname)
|
|
256
|
+
if (!pathname) {
|
|
216
257
|
return;
|
|
258
|
+
}
|
|
217
259
|
try {
|
|
218
260
|
await fs.access(pathname);
|
|
219
261
|
}
|
|
@@ -230,8 +272,9 @@ export async function moveToTrash(pathname, runtime) {
|
|
|
230
272
|
}
|
|
231
273
|
export async function handleReset(scope, workspaceDir, runtime) {
|
|
232
274
|
await moveToTrash(CONFIG_PATH, runtime);
|
|
233
|
-
if (scope === "config")
|
|
275
|
+
if (scope === "config") {
|
|
234
276
|
return;
|
|
277
|
+
}
|
|
235
278
|
await moveToTrash(path.join(CONFIG_DIR, "credentials"), runtime);
|
|
236
279
|
await moveToTrash(resolveSessionTranscriptsDirForAgent(), runtime);
|
|
237
280
|
if (scope === "full") {
|
|
@@ -239,10 +282,12 @@ export async function handleReset(scope, workspaceDir, runtime) {
|
|
|
239
282
|
}
|
|
240
283
|
}
|
|
241
284
|
export async function detectBinary(name) {
|
|
242
|
-
if (!name?.trim())
|
|
285
|
+
if (!name?.trim()) {
|
|
243
286
|
return false;
|
|
244
|
-
|
|
287
|
+
}
|
|
288
|
+
if (!isSafeExecutableValue(name)) {
|
|
245
289
|
return false;
|
|
290
|
+
}
|
|
246
291
|
const resolved = name.startsWith("~") ? resolveUserPath(name) : name;
|
|
247
292
|
if (path.isAbsolute(resolved) ||
|
|
248
293
|
resolved.startsWith(".") ||
|
|
@@ -266,8 +311,9 @@ export async function detectBinary(name) {
|
|
|
266
311
|
}
|
|
267
312
|
}
|
|
268
313
|
function shouldSkipBrowserOpenInTests() {
|
|
269
|
-
if (process.env.VITEST)
|
|
314
|
+
if (process.env.VITEST) {
|
|
270
315
|
return true;
|
|
316
|
+
}
|
|
271
317
|
return process.env.NODE_ENV === "test";
|
|
272
318
|
}
|
|
273
319
|
export async function probeGatewayReachable(params) {
|
|
@@ -302,8 +348,9 @@ export async function waitForGatewayReachable(params) {
|
|
|
302
348
|
password: params.password,
|
|
303
349
|
timeoutMs: probeTimeoutMs,
|
|
304
350
|
});
|
|
305
|
-
if (probe.ok)
|
|
351
|
+
if (probe.ok) {
|
|
306
352
|
return probe;
|
|
353
|
+
}
|
|
307
354
|
lastDetail = probe.detail;
|
|
308
355
|
await sleep(pollMs);
|
|
309
356
|
}
|
|
@@ -336,8 +383,12 @@ export function resolveControlUiLinks(params) {
|
|
|
336
383
|
if (bind === "custom" && customBindHost && isValidIPv4(customBindHost)) {
|
|
337
384
|
return customBindHost;
|
|
338
385
|
}
|
|
339
|
-
if (bind === "tailnet" && tailnetIPv4)
|
|
386
|
+
if (bind === "tailnet" && tailnetIPv4) {
|
|
340
387
|
return tailnetIPv4 ?? "127.0.0.1";
|
|
388
|
+
}
|
|
389
|
+
if (bind === "lan") {
|
|
390
|
+
return pickPrimaryLanIPv4() ?? "127.0.0.1";
|
|
391
|
+
}
|
|
341
392
|
return "127.0.0.1";
|
|
342
393
|
})();
|
|
343
394
|
const basePath = normalizeControlUiBasePath(params.basePath);
|
|
@@ -348,12 +399,3 @@ export function resolveControlUiLinks(params) {
|
|
|
348
399
|
wsUrl: `ws://${host}:${port}${wsPath}`,
|
|
349
400
|
};
|
|
350
401
|
}
|
|
351
|
-
function isValidIPv4(host) {
|
|
352
|
-
const parts = host.split(".");
|
|
353
|
-
if (parts.length !== 4)
|
|
354
|
-
return false;
|
|
355
|
-
return parts.every((part) => {
|
|
356
|
-
const n = Number.parseInt(part, 10);
|
|
357
|
-
return !Number.isNaN(n) && n >= 0 && n <= 255 && part === String(n);
|
|
358
|
-
});
|
|
359
|
-
}
|
|
@@ -34,7 +34,7 @@ export async function loginOpenAICodexOAuth(params) {
|
|
|
34
34
|
catch (err) {
|
|
35
35
|
spin.stop("OpenAI OAuth failed");
|
|
36
36
|
runtime.error(String(err));
|
|
37
|
-
await prompter.note("Trouble with OAuth? See https://docs.
|
|
37
|
+
await prompter.note("Trouble with OAuth? See https://docs.poolbot.dev/start/faq", "OAuth help");
|
|
38
38
|
throw err;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -2,8 +2,11 @@ import { lookupContextTokens } from "../agents/context.js";
|
|
|
2
2
|
import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL, DEFAULT_PROVIDER } from "../agents/defaults.js";
|
|
3
3
|
import { resolveConfiguredModelRef } from "../agents/model-selection.js";
|
|
4
4
|
import { loadConfig } from "../config/config.js";
|
|
5
|
-
import { loadSessionStore, resolveStorePath } from "../config/sessions.js";
|
|
5
|
+
import { loadSessionStore, resolveFreshSessionTotalTokens, resolveStorePath, } from "../config/sessions.js";
|
|
6
|
+
import { classifySessionKey, resolveSessionModelRef } from "../gateway/session-utils.js";
|
|
6
7
|
import { info } from "../globals.js";
|
|
8
|
+
import { formatTimeAgo } from "../infra/format-time/format-relative.js";
|
|
9
|
+
import { parseAgentSessionKey } from "../routing/session-key.js";
|
|
7
10
|
import { isRich, theme } from "../terminal/theme.js";
|
|
8
11
|
const KIND_PAD = 6;
|
|
9
12
|
const KEY_PAD = 26;
|
|
@@ -12,25 +15,33 @@ const MODEL_PAD = 14;
|
|
|
12
15
|
const TOKENS_PAD = 20;
|
|
13
16
|
const formatKTokens = (value) => `${(value / 1000).toFixed(value >= 10_000 ? 0 : 1)}k`;
|
|
14
17
|
const truncateKey = (key) => {
|
|
15
|
-
if (key.length <= KEY_PAD)
|
|
18
|
+
if (key.length <= KEY_PAD) {
|
|
16
19
|
return key;
|
|
20
|
+
}
|
|
17
21
|
const head = Math.max(4, KEY_PAD - 10);
|
|
18
22
|
return `${key.slice(0, head)}...${key.slice(-6)}`;
|
|
19
23
|
};
|
|
20
24
|
const colorByPct = (label, pct, rich) => {
|
|
21
|
-
if (!rich || pct === null)
|
|
25
|
+
if (!rich || pct === null) {
|
|
22
26
|
return label;
|
|
23
|
-
|
|
27
|
+
}
|
|
28
|
+
if (pct >= 95) {
|
|
24
29
|
return theme.error(label);
|
|
25
|
-
|
|
30
|
+
}
|
|
31
|
+
if (pct >= 80) {
|
|
26
32
|
return theme.warn(label);
|
|
27
|
-
|
|
33
|
+
}
|
|
34
|
+
if (pct >= 60) {
|
|
28
35
|
return theme.success(label);
|
|
36
|
+
}
|
|
29
37
|
return theme.muted(label);
|
|
30
38
|
};
|
|
31
39
|
const formatTokensCell = (total, contextTokens, rich) => {
|
|
32
|
-
if (
|
|
33
|
-
|
|
40
|
+
if (total === undefined) {
|
|
41
|
+
const ctxLabel = contextTokens ? formatKTokens(contextTokens) : "?";
|
|
42
|
+
const label = `unknown/${ctxLabel} (?%)`;
|
|
43
|
+
return rich ? theme.muted(label.padEnd(TOKENS_PAD)) : label.padEnd(TOKENS_PAD);
|
|
44
|
+
}
|
|
34
45
|
const totalLabel = formatKTokens(total);
|
|
35
46
|
const ctxLabel = contextTokens ? formatKTokens(contextTokens) : "?";
|
|
36
47
|
const pct = contextTokens ? Math.min(999, Math.round((total / contextTokens) * 100)) : null;
|
|
@@ -40,18 +51,22 @@ const formatTokensCell = (total, contextTokens, rich) => {
|
|
|
40
51
|
};
|
|
41
52
|
const formatKindCell = (kind, rich) => {
|
|
42
53
|
const label = kind.padEnd(KIND_PAD);
|
|
43
|
-
if (!rich)
|
|
54
|
+
if (!rich) {
|
|
44
55
|
return label;
|
|
45
|
-
|
|
56
|
+
}
|
|
57
|
+
if (kind === "group") {
|
|
46
58
|
return theme.accentBright(label);
|
|
47
|
-
|
|
59
|
+
}
|
|
60
|
+
if (kind === "global") {
|
|
48
61
|
return theme.warn(label);
|
|
49
|
-
|
|
62
|
+
}
|
|
63
|
+
if (kind === "direct") {
|
|
50
64
|
return theme.accent(label);
|
|
65
|
+
}
|
|
51
66
|
return theme.muted(label);
|
|
52
67
|
};
|
|
53
68
|
const formatAgeCell = (updatedAt, rich) => {
|
|
54
|
-
const ageLabel = updatedAt ?
|
|
69
|
+
const ageLabel = updatedAt ? formatTimeAgo(Date.now() - updatedAt) : "unknown";
|
|
55
70
|
const padded = ageLabel.padEnd(AGE_PAD);
|
|
56
71
|
return rich ? theme.muted(padded) : padded;
|
|
57
72
|
};
|
|
@@ -74,40 +89,13 @@ const formatFlagsCell = (row, rich) => {
|
|
|
74
89
|
const label = flags.join(" ");
|
|
75
90
|
return label.length === 0 ? "" : rich ? theme.muted(label) : label;
|
|
76
91
|
};
|
|
77
|
-
const formatAge = (ms) => {
|
|
78
|
-
if (!ms || ms < 0)
|
|
79
|
-
return "unknown";
|
|
80
|
-
const minutes = Math.round(ms / 60_000);
|
|
81
|
-
if (minutes < 1)
|
|
82
|
-
return "just now";
|
|
83
|
-
if (minutes < 60)
|
|
84
|
-
return `${minutes}m ago`;
|
|
85
|
-
const hours = Math.round(minutes / 60);
|
|
86
|
-
if (hours < 48)
|
|
87
|
-
return `${hours}h ago`;
|
|
88
|
-
const days = Math.round(hours / 24);
|
|
89
|
-
return `${days}d ago`;
|
|
90
|
-
};
|
|
91
|
-
function classifyKey(key, entry) {
|
|
92
|
-
if (key === "global")
|
|
93
|
-
return "global";
|
|
94
|
-
if (key === "unknown")
|
|
95
|
-
return "unknown";
|
|
96
|
-
if (entry?.chatType === "group" || entry?.chatType === "channel") {
|
|
97
|
-
return "group";
|
|
98
|
-
}
|
|
99
|
-
if (key.includes(":group:") || key.includes(":channel:")) {
|
|
100
|
-
return "group";
|
|
101
|
-
}
|
|
102
|
-
return "direct";
|
|
103
|
-
}
|
|
104
92
|
function toRows(store) {
|
|
105
93
|
return Object.entries(store)
|
|
106
94
|
.map(([key, entry]) => {
|
|
107
95
|
const updatedAt = entry?.updatedAt ?? null;
|
|
108
96
|
return {
|
|
109
97
|
key,
|
|
110
|
-
kind:
|
|
98
|
+
kind: classifySessionKey(key, entry),
|
|
111
99
|
updatedAt,
|
|
112
100
|
ageMs: updatedAt ? Date.now() - updatedAt : null,
|
|
113
101
|
sessionId: entry?.sessionId,
|
|
@@ -122,11 +110,15 @@ function toRows(store) {
|
|
|
122
110
|
inputTokens: entry?.inputTokens,
|
|
123
111
|
outputTokens: entry?.outputTokens,
|
|
124
112
|
totalTokens: entry?.totalTokens,
|
|
113
|
+
totalTokensFresh: entry?.totalTokensFresh,
|
|
125
114
|
model: entry?.model,
|
|
115
|
+
modelProvider: entry?.modelProvider,
|
|
116
|
+
providerOverride: entry?.providerOverride,
|
|
117
|
+
modelOverride: entry?.modelOverride,
|
|
126
118
|
contextTokens: entry?.contextTokens,
|
|
127
119
|
};
|
|
128
120
|
})
|
|
129
|
-
.
|
|
121
|
+
.toSorted((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
|
|
130
122
|
}
|
|
131
123
|
export async function sessionsCommand(opts, runtime) {
|
|
132
124
|
const cfg = loadConfig();
|
|
@@ -152,10 +144,12 @@ export async function sessionsCommand(opts, runtime) {
|
|
|
152
144
|
activeMinutes = parsed;
|
|
153
145
|
}
|
|
154
146
|
const rows = toRows(store).filter((row) => {
|
|
155
|
-
if (activeMinutes === undefined)
|
|
147
|
+
if (activeMinutes === undefined) {
|
|
156
148
|
return true;
|
|
157
|
-
|
|
149
|
+
}
|
|
150
|
+
if (!row.updatedAt) {
|
|
158
151
|
return false;
|
|
152
|
+
}
|
|
159
153
|
return Date.now() - row.updatedAt <= activeMinutes * 60_000;
|
|
160
154
|
});
|
|
161
155
|
if (opts.json) {
|
|
@@ -163,11 +157,17 @@ export async function sessionsCommand(opts, runtime) {
|
|
|
163
157
|
path: storePath,
|
|
164
158
|
count: rows.length,
|
|
165
159
|
activeMinutes: activeMinutes ?? null,
|
|
166
|
-
sessions: rows.map((r) =>
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
160
|
+
sessions: rows.map((r) => {
|
|
161
|
+
const resolvedModel = resolveSessionModelRef(cfg, r, parseAgentSessionKey(r.key)?.agentId);
|
|
162
|
+
const model = resolvedModel.model ?? configModel;
|
|
163
|
+
return {
|
|
164
|
+
...r,
|
|
165
|
+
totalTokens: resolveFreshSessionTotalTokens(r) ?? null,
|
|
166
|
+
totalTokensFresh: typeof r.totalTokens === "number" ? r.totalTokensFresh !== false : false,
|
|
167
|
+
contextTokens: r.contextTokens ?? lookupContextTokens(model) ?? configContextTokens ?? null,
|
|
168
|
+
model,
|
|
169
|
+
};
|
|
170
|
+
}),
|
|
171
171
|
}, null, 2));
|
|
172
172
|
return;
|
|
173
173
|
}
|
|
@@ -191,11 +191,10 @@ export async function sessionsCommand(opts, runtime) {
|
|
|
191
191
|
].join(" ");
|
|
192
192
|
runtime.log(rich ? theme.heading(header) : header);
|
|
193
193
|
for (const row of rows) {
|
|
194
|
-
const
|
|
194
|
+
const resolvedModel = resolveSessionModelRef(cfg, row, parseAgentSessionKey(row.key)?.agentId);
|
|
195
|
+
const model = resolvedModel.model ?? configModel;
|
|
195
196
|
const contextTokens = row.contextTokens ?? lookupContextTokens(model) ?? configContextTokens;
|
|
196
|
-
const
|
|
197
|
-
const output = row.outputTokens ?? 0;
|
|
198
|
-
const total = row.totalTokens ?? input + output;
|
|
197
|
+
const total = resolveFreshSessionTotalTokens(row);
|
|
199
198
|
const keyLabel = truncateKey(row.key).padEnd(KEY_PAD);
|
|
200
199
|
const keyCell = rich ? theme.accent(keyLabel) : keyLabel;
|
|
201
200
|
const line = [
|
|
@@ -2,52 +2,67 @@ import { lookupContextTokens } from "../agents/context.js";
|
|
|
2
2
|
import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL, DEFAULT_PROVIDER } from "../agents/defaults.js";
|
|
3
3
|
import { resolveConfiguredModelRef } from "../agents/model-selection.js";
|
|
4
4
|
import { loadConfig } from "../config/config.js";
|
|
5
|
-
import { loadSessionStore, resolveMainSessionKey, resolveStorePath, } from "../config/sessions.js";
|
|
6
|
-
import { listAgentsForGateway } from "../gateway/session-utils.js";
|
|
5
|
+
import { loadSessionStore, resolveFreshSessionTotalTokens, resolveMainSessionKey, resolveStorePath, } from "../config/sessions.js";
|
|
6
|
+
import { classifySessionKey, listAgentsForGateway, resolveSessionModelRef, } from "../gateway/session-utils.js";
|
|
7
7
|
import { buildChannelSummary } from "../infra/channel-summary.js";
|
|
8
8
|
import { resolveHeartbeatSummaryForAgent } from "../infra/heartbeat-runner.js";
|
|
9
9
|
import { peekSystemEvents } from "../infra/system-events.js";
|
|
10
10
|
import { parseAgentSessionKey } from "../routing/session-key.js";
|
|
11
11
|
import { resolveLinkChannelContext } from "./status.link-channel.js";
|
|
12
|
-
const classifyKey = (key, entry) => {
|
|
13
|
-
if (key === "global")
|
|
14
|
-
return "global";
|
|
15
|
-
if (key === "unknown")
|
|
16
|
-
return "unknown";
|
|
17
|
-
if (entry?.chatType === "group" || entry?.chatType === "channel") {
|
|
18
|
-
return "group";
|
|
19
|
-
}
|
|
20
|
-
if (key.includes(":group:") || key.includes(":channel:")) {
|
|
21
|
-
return "group";
|
|
22
|
-
}
|
|
23
|
-
return "direct";
|
|
24
|
-
};
|
|
25
12
|
const buildFlags = (entry) => {
|
|
26
|
-
if (!entry)
|
|
13
|
+
if (!entry) {
|
|
27
14
|
return [];
|
|
15
|
+
}
|
|
28
16
|
const flags = [];
|
|
29
17
|
const think = entry?.thinkingLevel;
|
|
30
|
-
if (typeof think === "string" && think.length > 0)
|
|
18
|
+
if (typeof think === "string" && think.length > 0) {
|
|
31
19
|
flags.push(`think:${think}`);
|
|
20
|
+
}
|
|
32
21
|
const verbose = entry?.verboseLevel;
|
|
33
|
-
if (typeof verbose === "string" && verbose.length > 0)
|
|
22
|
+
if (typeof verbose === "string" && verbose.length > 0) {
|
|
34
23
|
flags.push(`verbose:${verbose}`);
|
|
24
|
+
}
|
|
35
25
|
const reasoning = entry?.reasoningLevel;
|
|
36
|
-
if (typeof reasoning === "string" && reasoning.length > 0)
|
|
26
|
+
if (typeof reasoning === "string" && reasoning.length > 0) {
|
|
37
27
|
flags.push(`reasoning:${reasoning}`);
|
|
28
|
+
}
|
|
38
29
|
const elevated = entry?.elevatedLevel;
|
|
39
|
-
if (typeof elevated === "string" && elevated.length > 0)
|
|
30
|
+
if (typeof elevated === "string" && elevated.length > 0) {
|
|
40
31
|
flags.push(`elevated:${elevated}`);
|
|
41
|
-
|
|
32
|
+
}
|
|
33
|
+
if (entry?.systemSent) {
|
|
42
34
|
flags.push("system");
|
|
43
|
-
|
|
35
|
+
}
|
|
36
|
+
if (entry?.abortedLastRun) {
|
|
44
37
|
flags.push("aborted");
|
|
38
|
+
}
|
|
45
39
|
const sessionId = entry?.sessionId;
|
|
46
|
-
if (typeof sessionId === "string" && sessionId.length > 0)
|
|
40
|
+
if (typeof sessionId === "string" && sessionId.length > 0) {
|
|
47
41
|
flags.push(`id:${sessionId}`);
|
|
42
|
+
}
|
|
48
43
|
return flags;
|
|
49
44
|
};
|
|
50
|
-
export
|
|
45
|
+
export function redactSensitiveStatusSummary(summary) {
|
|
46
|
+
return {
|
|
47
|
+
...summary,
|
|
48
|
+
sessions: {
|
|
49
|
+
...summary.sessions,
|
|
50
|
+
paths: [],
|
|
51
|
+
defaults: {
|
|
52
|
+
model: null,
|
|
53
|
+
contextTokens: null,
|
|
54
|
+
},
|
|
55
|
+
recent: [],
|
|
56
|
+
byAgent: summary.sessions.byAgent.map((entry) => ({
|
|
57
|
+
...entry,
|
|
58
|
+
path: "[redacted]",
|
|
59
|
+
recent: [],
|
|
60
|
+
})),
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export async function getStatusSummary(options = {}) {
|
|
65
|
+
const { includeSensitive = true } = options;
|
|
51
66
|
const cfg = loadConfig();
|
|
52
67
|
const linkContext = await resolveLinkChannelContext(cfg);
|
|
53
68
|
const agentList = listAgentsForGateway(cfg);
|
|
@@ -79,8 +94,9 @@ export async function getStatusSummary() {
|
|
|
79
94
|
const storeCache = new Map();
|
|
80
95
|
const loadStore = (storePath) => {
|
|
81
96
|
const cached = storeCache.get(storePath);
|
|
82
|
-
if (cached)
|
|
97
|
+
if (cached) {
|
|
83
98
|
return cached;
|
|
99
|
+
}
|
|
84
100
|
const store = loadSessionStore(storePath);
|
|
85
101
|
storeCache.set(storePath, store);
|
|
86
102
|
return store;
|
|
@@ -90,13 +106,13 @@ export async function getStatusSummary() {
|
|
|
90
106
|
.map(([key, entry]) => {
|
|
91
107
|
const updatedAt = entry?.updatedAt ?? null;
|
|
92
108
|
const age = updatedAt ? now - updatedAt : null;
|
|
93
|
-
const
|
|
109
|
+
const resolvedModel = resolveSessionModelRef(cfg, entry, opts.agentIdOverride);
|
|
110
|
+
const model = resolvedModel.model ?? configModel ?? null;
|
|
94
111
|
const contextTokens = entry?.contextTokens ?? lookupContextTokens(model) ?? configContextTokens ?? null;
|
|
95
|
-
const
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
const
|
|
99
|
-
const pct = contextTokens && contextTokens > 0
|
|
112
|
+
const total = resolveFreshSessionTotalTokens(entry);
|
|
113
|
+
const totalTokensFresh = typeof entry?.totalTokens === "number" ? entry?.totalTokensFresh !== false : false;
|
|
114
|
+
const remaining = contextTokens != null && total !== undefined ? Math.max(0, contextTokens - total) : null;
|
|
115
|
+
const pct = contextTokens && contextTokens > 0 && total !== undefined
|
|
100
116
|
? Math.min(999, Math.round((total / contextTokens) * 100))
|
|
101
117
|
: null;
|
|
102
118
|
const parsedAgentId = parseAgentSessionKey(key)?.agentId;
|
|
@@ -104,7 +120,7 @@ export async function getStatusSummary() {
|
|
|
104
120
|
return {
|
|
105
121
|
agentId,
|
|
106
122
|
key,
|
|
107
|
-
kind:
|
|
123
|
+
kind: classifySessionKey(key, entry),
|
|
108
124
|
sessionId: entry?.sessionId,
|
|
109
125
|
updatedAt,
|
|
110
126
|
age,
|
|
@@ -117,6 +133,7 @@ export async function getStatusSummary() {
|
|
|
117
133
|
inputTokens: entry?.inputTokens,
|
|
118
134
|
outputTokens: entry?.outputTokens,
|
|
119
135
|
totalTokens: total ?? null,
|
|
136
|
+
totalTokensFresh,
|
|
120
137
|
remainingTokens: remaining,
|
|
121
138
|
percentUsed: pct,
|
|
122
139
|
model,
|
|
@@ -140,10 +157,10 @@ export async function getStatusSummary() {
|
|
|
140
157
|
});
|
|
141
158
|
const allSessions = Array.from(paths)
|
|
142
159
|
.flatMap((storePath) => buildSessionRows(loadStore(storePath)))
|
|
143
|
-
.
|
|
160
|
+
.toSorted((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
|
|
144
161
|
const recent = allSessions.slice(0, 10);
|
|
145
162
|
const totalSessions = allSessions.length;
|
|
146
|
-
|
|
163
|
+
const summary = {
|
|
147
164
|
linkChannel: linkContext
|
|
148
165
|
? {
|
|
149
166
|
id: linkContext.plugin.id,
|
|
@@ -169,4 +186,5 @@ export async function getStatusSummary() {
|
|
|
169
186
|
byAgent,
|
|
170
187
|
},
|
|
171
188
|
};
|
|
189
|
+
return includeSensitive ? summary : redactSensitiveStatusSummary(summary);
|
|
172
190
|
}
|
|
@@ -27,7 +27,7 @@ export function createWizardPrompter(overrides, options) {
|
|
|
27
27
|
...overrides,
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
-
export async function setupAuthTestEnv(prefix = "
|
|
30
|
+
export async function setupAuthTestEnv(prefix = "poolbot-auth-", options) {
|
|
31
31
|
const stateDir = await makeTempWorkspace(prefix);
|
|
32
32
|
const agentDir = path.join(stateDir, options?.agentSubdir ?? "agent");
|
|
33
33
|
process.env.POOLBOT_STATE_DIR = stateDir;
|
|
@@ -52,7 +52,7 @@ export function createAuthTestLifecycle(envKeys) {
|
|
|
52
52
|
},
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
|
-
export function
|
|
55
|
+
export function requirePoolbotAgentDir() {
|
|
56
56
|
const agentDir = process.env.POOLBOT_AGENT_DIR;
|
|
57
57
|
if (!agentDir) {
|
|
58
58
|
throw new Error("POOLBOT_AGENT_DIR not set");
|