@poolzin/pool-bot 2026.2.0 → 2026.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +118 -0
- package/README-header.png +0 -0
- package/dist/agents/bash-tools.exec.js +76 -25
- package/dist/agents/cli-runner/helpers.js +9 -11
- package/dist/agents/context.js +1 -1
- package/dist/agents/identity.js +47 -7
- package/dist/agents/memory-search.js +25 -8
- package/dist/agents/model-catalog.js +1 -1
- package/dist/agents/model-selection.js +21 -0
- package/dist/agents/pi-embedded-block-chunker.js +117 -42
- package/dist/agents/pi-embedded-helpers/errors.js +183 -78
- package/dist/agents/pi-embedded-helpers.js +1 -1
- package/dist/agents/pi-embedded-runner/compact.js +8 -10
- package/dist/agents/pi-embedded-runner/model.js +62 -3
- package/dist/agents/pi-embedded-runner/run/attempt.js +21 -11
- package/dist/agents/pi-embedded-runner/run.js +199 -46
- package/dist/agents/pi-embedded-runner/system-prompt.js +10 -2
- package/dist/agents/pi-embedded-subscribe.js +118 -29
- package/dist/agents/pi-tools.js +10 -5
- package/dist/agents/poolbot-tools.js +15 -10
- package/dist/agents/sandbox-paths.js +31 -0
- package/dist/agents/session-tool-result-guard.js +94 -15
- package/dist/agents/shell-utils.js +51 -0
- package/dist/agents/skills/bundled-context.js +23 -0
- package/dist/agents/skills/bundled-dir.js +41 -7
- package/dist/agents/skills-install.js +60 -23
- package/dist/agents/subagent-announce.js +79 -34
- package/dist/agents/tool-policy.conformance.js +14 -0
- package/dist/agents/tool-policy.js +24 -0
- package/dist/agents/tools/cron-tool.js +166 -19
- package/dist/agents/tools/discord-actions-presence.js +78 -0
- package/dist/agents/tools/image-tool.js +1 -1
- package/dist/agents/tools/message-tool.js +56 -2
- package/dist/agents/tools/sessions-history-tool.js +69 -1
- package/dist/agents/tools/web-search.js +211 -42
- package/dist/agents/usage.js +23 -1
- package/dist/agents/workspace-run.js +67 -0
- package/dist/agents/workspace-templates.js +44 -0
- package/dist/auto-reply/command-auth.js +121 -6
- package/dist/auto-reply/envelope.js +74 -82
- package/dist/auto-reply/reply/commands-compact.js +1 -0
- package/dist/auto-reply/reply/commands-context-report.js +1 -0
- package/dist/auto-reply/reply/commands-context.js +1 -0
- package/dist/auto-reply/reply/commands-models.js +107 -60
- package/dist/auto-reply/reply/commands-ptt.js +171 -0
- package/dist/auto-reply/reply/get-reply-run.js +2 -1
- package/dist/auto-reply/reply/inbound-context.js +5 -1
- package/dist/auto-reply/reply/mentions.js +1 -1
- package/dist/auto-reply/reply/model-selection.js +3 -3
- package/dist/auto-reply/thinking.js +88 -43
- package/dist/browser/bridge-server.js +13 -0
- package/dist/browser/cdp.helpers.js +38 -24
- package/dist/browser/client-fetch.js +50 -7
- package/dist/browser/config.js +1 -10
- package/dist/browser/extension-relay.js +101 -40
- package/dist/browser/pw-ai.js +1 -1
- package/dist/browser/pw-session.js +143 -8
- package/dist/browser/pw-tools-core.interactions.js +125 -27
- package/dist/browser/pw-tools-core.responses.js +1 -1
- package/dist/browser/pw-tools-core.state.js +1 -1
- package/dist/browser/routes/agent.act.js +86 -41
- package/dist/browser/routes/dispatcher.js +4 -4
- package/dist/browser/screenshot.js +1 -1
- package/dist/browser/server.js +13 -0
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/index.html +28 -28
- package/dist/channels/reply-prefix.js +8 -1
- package/dist/cli/cron-cli/register.cron-add.js +61 -40
- package/dist/cli/cron-cli/register.cron-edit.js +60 -34
- package/dist/cli/cron-cli/shared.js +56 -41
- package/dist/cli/dns-cli.js +26 -14
- package/dist/cli/gateway-cli/register.js +37 -19
- package/dist/cli/memory-cli.js +5 -5
- package/dist/cli/parse-bytes.js +37 -0
- package/dist/cli/update-cli.js +173 -52
- package/dist/commands/agent.js +1 -0
- package/dist/commands/auth-choice.apply.oauth.js +1 -1
- package/dist/commands/doctor-config-flow.js +61 -5
- package/dist/commands/doctor-state-migrations.js +1 -1
- package/dist/commands/health.js +1 -1
- package/dist/commands/model-allowlist.js +29 -0
- package/dist/commands/model-picker.js +2 -1
- package/dist/commands/models/list.registry.js +1 -1
- package/dist/commands/models/list.status-command.js +43 -23
- package/dist/commands/models/shared.js +15 -0
- package/dist/commands/onboard-custom.js +384 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice-inference.js +35 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +6 -3
- package/dist/commands/onboard-skills.js +63 -38
- package/dist/commands/openai-model-default.js +41 -0
- package/dist/compat/legacy-names.js +2 -0
- package/dist/config/defaults.js +3 -2
- package/dist/config/paths.js +136 -35
- package/dist/config/plugin-auto-enable.js +21 -5
- package/dist/config/redact-snapshot.js +153 -0
- package/dist/config/schema.field-metadata.js +590 -0
- package/dist/config/schema.js +2 -2
- package/dist/config/sessions/store.js +291 -23
- package/dist/config/zod-schema.agent-defaults.js +3 -0
- package/dist/config/zod-schema.agent-runtime.js +13 -2
- package/dist/config/zod-schema.providers-core.js +142 -0
- package/dist/config/zod-schema.session.js +3 -0
- package/dist/control-ui/assets/{index-CIRDm-Lu.css → index-CSfXd2LO.css} +1 -1
- package/dist/control-ui/assets/{index-CmNMuoem.js → index-HRr1grwl.js} +446 -413
- package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -0
- package/dist/control-ui/index.html +4 -4
- package/dist/cron/delivery.js +57 -0
- package/dist/cron/isolated-agent/delivery-target.js +18 -3
- package/dist/cron/isolated-agent/helpers.js +22 -5
- package/dist/cron/isolated-agent/run.js +172 -63
- package/dist/cron/isolated-agent/session.js +2 -0
- package/dist/cron/normalize.js +356 -28
- package/dist/cron/parse.js +10 -5
- package/dist/cron/run-log.js +35 -10
- package/dist/cron/schedule.js +41 -6
- package/dist/cron/service/jobs.js +208 -35
- package/dist/cron/service/ops.js +72 -16
- package/dist/cron/service/state.js +2 -0
- package/dist/cron/service/store.js +386 -14
- package/dist/cron/service/timer.js +390 -147
- package/dist/cron/session-reaper.js +86 -0
- package/dist/cron/store.js +23 -8
- package/dist/cron/validate-timestamp.js +43 -0
- package/dist/discord/monitor/agent-components.js +438 -0
- package/dist/discord/monitor/allow-list.js +28 -5
- package/dist/discord/monitor/gateway-registry.js +29 -0
- package/dist/discord/monitor/native-command.js +44 -23
- package/dist/discord/monitor/sender-identity.js +45 -0
- package/dist/discord/pluralkit.js +27 -0
- package/dist/discord/send.outbound.js +92 -5
- package/dist/discord/send.shared.js +60 -23
- package/dist/discord/targets.js +84 -1
- package/dist/entry.js +15 -9
- package/dist/extensionAPI.js +8 -0
- package/dist/gateway/control-ui.js +8 -1
- package/dist/gateway/hooks-mapping.js +3 -0
- package/dist/gateway/hooks.js +65 -0
- package/dist/gateway/net.js +96 -31
- package/dist/gateway/node-command-policy.js +50 -15
- package/dist/gateway/origin-check.js +56 -0
- package/dist/gateway/protocol/client-info.js +9 -0
- package/dist/gateway/protocol/index.js +9 -2
- package/dist/gateway/protocol/schema/agents-models-skills.js +71 -1
- package/dist/gateway/protocol/schema/cron.js +22 -10
- package/dist/gateway/protocol/schema/protocol-schemas.js +16 -2
- package/dist/gateway/protocol/schema/sessions.js +12 -0
- package/dist/gateway/server/hooks.js +1 -1
- package/dist/gateway/server-broadcast.js +26 -9
- package/dist/gateway/server-chat.js +112 -23
- package/dist/gateway/server-discovery-runtime.js +10 -2
- package/dist/gateway/server-http.js +109 -11
- package/dist/gateway/server-methods/agent-timestamp.js +60 -0
- package/dist/gateway/server-methods/agents.js +321 -2
- package/dist/gateway/server-methods/usage.js +559 -16
- package/dist/gateway/server-runtime-state.js +22 -8
- package/dist/gateway/server-startup-memory.js +16 -0
- package/dist/gateway/server.impl.js +5 -1
- package/dist/gateway/session-utils.fs.js +23 -25
- package/dist/gateway/session-utils.js +20 -10
- package/dist/gateway/sessions-patch.js +7 -22
- package/dist/gateway/test-helpers.mocks.js +11 -7
- package/dist/gateway/test-helpers.server.js +35 -2
- package/dist/imessage/constants.js +2 -0
- package/dist/imessage/monitor/deliver.js +4 -1
- package/dist/imessage/monitor/monitor-provider.js +51 -1
- package/dist/infra/bonjour-discovery.js +131 -70
- package/dist/infra/control-ui-assets.js +134 -12
- package/dist/infra/errors.js +12 -0
- package/dist/infra/exec-approvals.js +266 -57
- package/dist/infra/format-time/format-datetime.js +79 -0
- package/dist/infra/format-time/format-duration.js +81 -0
- package/dist/infra/format-time/format-relative.js +80 -0
- package/dist/infra/heartbeat-runner.js +140 -49
- package/dist/infra/home-dir.js +54 -0
- package/dist/infra/net/fetch-guard.js +122 -0
- package/dist/infra/net/ssrf.js +65 -29
- package/dist/infra/outbound/abort.js +14 -0
- package/dist/infra/outbound/message-action-runner.js +77 -13
- package/dist/infra/outbound/outbound-session.js +143 -37
- package/dist/infra/poolbot-root.js +43 -1
- package/dist/infra/session-cost-usage.js +631 -41
- package/dist/infra/state-migrations.js +317 -47
- package/dist/infra/update-global.js +35 -0
- package/dist/infra/update-runner.js +149 -43
- package/dist/infra/warning-filter.js +65 -0
- package/dist/infra/widearea-dns.js +30 -9
- package/dist/logging/redact-identifier.js +12 -0
- package/dist/media/fetch.js +81 -58
- package/dist/media/store.js +2 -0
- package/dist/media-understanding/apply.js +403 -3
- package/dist/media-understanding/attachments.js +38 -27
- package/dist/media-understanding/defaults.js +16 -0
- package/dist/media-understanding/providers/deepgram/audio.js +22 -14
- package/dist/media-understanding/providers/google/audio.js +24 -17
- package/dist/media-understanding/providers/google/video.js +24 -17
- package/dist/media-understanding/providers/image.js +3 -3
- package/dist/media-understanding/providers/index.js +4 -1
- package/dist/media-understanding/providers/openai/audio.js +22 -14
- package/dist/media-understanding/providers/shared.js +16 -11
- package/dist/media-understanding/providers/zai/index.js +6 -0
- package/dist/media-understanding/runner.js +158 -90
- package/dist/memory/batch-voyage.js +277 -0
- package/dist/memory/embeddings-voyage.js +75 -0
- package/dist/memory/embeddings.js +28 -16
- package/dist/memory/internal.js +101 -18
- package/dist/memory/manager.js +154 -48
- package/dist/memory/search-manager.js +173 -0
- package/dist/memory/session-files.js +9 -3
- package/dist/node-host/runner.js +34 -24
- package/dist/node-host/with-timeout.js +27 -0
- package/dist/plugins/commands.js +5 -1
- package/dist/plugins/config-state.js +86 -7
- package/dist/plugins/source-display.js +51 -0
- package/dist/process/exec.js +20 -2
- package/dist/routing/resolve-route.js +12 -0
- package/dist/routing/session-key.js +15 -0
- package/dist/runtime.js +2 -0
- package/dist/security/audit-extra.async.js +601 -0
- package/dist/security/audit-extra.js +2 -830
- package/dist/security/audit-extra.sync.js +505 -0
- package/dist/security/channel-metadata.js +34 -0
- package/dist/security/external-content.js +88 -6
- package/dist/security/skill-scanner.js +330 -0
- package/dist/sessions/session-key-utils.js +7 -0
- package/dist/signal/monitor/event-handler.js +80 -1
- package/dist/slack/monitor/media.js +85 -15
- package/dist/tailscale/detect.js +1 -2
- package/dist/telegram/bot/helpers.js +109 -28
- package/dist/telegram/bot-handlers.js +144 -3
- package/dist/telegram/bot-message-context.js +37 -10
- package/dist/telegram/bot-message-dispatch.js +54 -17
- package/dist/telegram/bot-native-commands.js +86 -29
- package/dist/telegram/bot.js +30 -29
- package/dist/telegram/model-buttons.js +163 -0
- package/dist/telegram/monitor.js +110 -85
- package/dist/telegram/send.js +129 -47
- package/dist/terminal/restore.js +45 -0
- package/dist/test-helpers/state-dir-env.js +16 -0
- package/dist/tts/tts.js +12 -6
- package/dist/tui/tui-session-actions.js +166 -54
- package/dist/utils/fetch-timeout.js +20 -0
- package/dist/utils/normalize-secret-input.js +19 -0
- package/dist/utils/transcript-tools.js +58 -0
- package/dist/utils.js +45 -14
- package/dist/version.js +42 -5
- package/dist/wizard/clack-prompter.js +9 -6
- package/extensions/googlechat/node_modules/.bin/poolbot +21 -0
- package/extensions/googlechat/package.json +2 -2
- package/extensions/line/node_modules/.bin/poolbot +21 -0
- package/extensions/line/package.json +1 -1
- package/extensions/matrix/node_modules/.bin/poolbot +21 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/memory-core/node_modules/.bin/poolbot +21 -0
- package/extensions/memory-core/package.json +4 -1
- package/extensions/twitch/node_modules/.bin/poolbot +21 -0
- package/extensions/twitch/package.json +1 -1
- package/package.json +183 -24
- package/dist/control-ui/assets/index-CmNMuoem.js.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { listChannelPlugins } from "../../channels/plugins/index.js";
|
|
2
2
|
import { parseAbsoluteTimeMs } from "../../cron/parse.js";
|
|
3
|
+
import { formatDurationHuman } from "../../infra/format-time/format-duration.js";
|
|
3
4
|
import { defaultRuntime } from "../../runtime.js";
|
|
4
5
|
import { colorize, isRich, theme } from "../../terminal/theme.js";
|
|
5
6
|
import { callGatewayFromCli } from "../gateway-rpc.js";
|
|
@@ -7,8 +8,9 @@ export const getCronChannelOptions = () => ["last", ...listChannelPlugins().map(
|
|
|
7
8
|
export async function warnIfCronSchedulerDisabled(opts) {
|
|
8
9
|
try {
|
|
9
10
|
const res = (await callGatewayFromCli("cron.status", opts, {}));
|
|
10
|
-
if (res?.enabled === true)
|
|
11
|
+
if (res?.enabled === true) {
|
|
11
12
|
return;
|
|
13
|
+
}
|
|
12
14
|
const store = typeof res?.storePath === "string" ? res.storePath : "";
|
|
13
15
|
defaultRuntime.error([
|
|
14
16
|
"warning: cron scheduler is disabled in the Gateway; jobs are saved but will not run automatically.",
|
|
@@ -24,14 +26,17 @@ export async function warnIfCronSchedulerDisabled(opts) {
|
|
|
24
26
|
}
|
|
25
27
|
export function parseDurationMs(input) {
|
|
26
28
|
const raw = input.trim();
|
|
27
|
-
if (!raw)
|
|
29
|
+
if (!raw) {
|
|
28
30
|
return null;
|
|
31
|
+
}
|
|
29
32
|
const match = raw.match(/^(\d+(?:\.\d+)?)(ms|s|m|h|d)$/i);
|
|
30
|
-
if (!match)
|
|
33
|
+
if (!match) {
|
|
31
34
|
return null;
|
|
35
|
+
}
|
|
32
36
|
const n = Number.parseFloat(match[1] ?? "");
|
|
33
|
-
if (!Number.isFinite(n) || n <= 0)
|
|
37
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
34
38
|
return null;
|
|
39
|
+
}
|
|
35
40
|
const unit = (match[2] ?? "").toLowerCase();
|
|
36
41
|
const factor = unit === "ms"
|
|
37
42
|
? 1
|
|
@@ -44,16 +49,19 @@ export function parseDurationMs(input) {
|
|
|
44
49
|
: 86_400_000;
|
|
45
50
|
return Math.floor(n * factor);
|
|
46
51
|
}
|
|
47
|
-
export function
|
|
52
|
+
export function parseAt(input) {
|
|
48
53
|
const raw = input.trim();
|
|
49
|
-
if (!raw)
|
|
54
|
+
if (!raw) {
|
|
50
55
|
return null;
|
|
56
|
+
}
|
|
51
57
|
const absolute = parseAbsoluteTimeMs(raw);
|
|
52
|
-
if (absolute)
|
|
53
|
-
return absolute;
|
|
58
|
+
if (absolute !== null) {
|
|
59
|
+
return new Date(absolute).toISOString();
|
|
60
|
+
}
|
|
54
61
|
const dur = parseDurationMs(raw);
|
|
55
|
-
if (dur)
|
|
56
|
-
return Date.now() + dur;
|
|
62
|
+
if (dur !== null) {
|
|
63
|
+
return new Date(Date.now() + dur).toISOString();
|
|
64
|
+
}
|
|
57
65
|
return null;
|
|
58
66
|
}
|
|
59
67
|
const CRON_ID_PAD = 36;
|
|
@@ -66,56 +74,59 @@ const CRON_TARGET_PAD = 9;
|
|
|
66
74
|
const CRON_AGENT_PAD = 10;
|
|
67
75
|
const pad = (value, width) => value.padEnd(width);
|
|
68
76
|
const truncate = (value, width) => {
|
|
69
|
-
if (value.length <= width)
|
|
77
|
+
if (value.length <= width) {
|
|
70
78
|
return value;
|
|
71
|
-
|
|
79
|
+
}
|
|
80
|
+
if (width <= 3) {
|
|
72
81
|
return value.slice(0, width);
|
|
82
|
+
}
|
|
73
83
|
return `${value.slice(0, width - 3)}...`;
|
|
74
84
|
};
|
|
75
|
-
const formatIsoMinute = (
|
|
76
|
-
const
|
|
77
|
-
|
|
85
|
+
const formatIsoMinute = (iso) => {
|
|
86
|
+
const parsed = parseAbsoluteTimeMs(iso);
|
|
87
|
+
const d = new Date(parsed ?? NaN);
|
|
88
|
+
if (Number.isNaN(d.getTime())) {
|
|
78
89
|
return "-";
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
const formatDuration = (ms) => {
|
|
83
|
-
if (ms < 60_000)
|
|
84
|
-
return `${Math.max(1, Math.round(ms / 1000))}s`;
|
|
85
|
-
if (ms < 3_600_000)
|
|
86
|
-
return `${Math.round(ms / 60_000)}m`;
|
|
87
|
-
if (ms < 86_400_000)
|
|
88
|
-
return `${Math.round(ms / 3_600_000)}h`;
|
|
89
|
-
return `${Math.round(ms / 86_400_000)}d`;
|
|
90
|
+
}
|
|
91
|
+
const isoStr = d.toISOString();
|
|
92
|
+
return `${isoStr.slice(0, 10)} ${isoStr.slice(11, 16)}Z`;
|
|
90
93
|
};
|
|
91
94
|
const formatSpan = (ms) => {
|
|
92
|
-
if (ms < 60_000)
|
|
95
|
+
if (ms < 60_000) {
|
|
93
96
|
return "<1m";
|
|
94
|
-
|
|
97
|
+
}
|
|
98
|
+
if (ms < 3_600_000) {
|
|
95
99
|
return `${Math.round(ms / 60_000)}m`;
|
|
96
|
-
|
|
100
|
+
}
|
|
101
|
+
if (ms < 86_400_000) {
|
|
97
102
|
return `${Math.round(ms / 3_600_000)}h`;
|
|
103
|
+
}
|
|
98
104
|
return `${Math.round(ms / 86_400_000)}d`;
|
|
99
105
|
};
|
|
100
106
|
const formatRelative = (ms, nowMs) => {
|
|
101
|
-
if (!ms)
|
|
107
|
+
if (!ms) {
|
|
102
108
|
return "-";
|
|
109
|
+
}
|
|
103
110
|
const delta = ms - nowMs;
|
|
104
111
|
const label = formatSpan(Math.abs(delta));
|
|
105
112
|
return delta >= 0 ? `in ${label}` : `${label} ago`;
|
|
106
113
|
};
|
|
107
114
|
const formatSchedule = (schedule) => {
|
|
108
|
-
if (schedule.kind === "at")
|
|
109
|
-
return `at ${formatIsoMinute(schedule.
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
if (schedule.kind === "at") {
|
|
116
|
+
return `at ${formatIsoMinute(schedule.at)}`;
|
|
117
|
+
}
|
|
118
|
+
if (schedule.kind === "every") {
|
|
119
|
+
return `every ${formatDurationHuman(schedule.everyMs)}`;
|
|
120
|
+
}
|
|
112
121
|
return schedule.tz ? `cron ${schedule.expr} @ ${schedule.tz}` : `cron ${schedule.expr}`;
|
|
113
122
|
};
|
|
114
123
|
const formatStatus = (job) => {
|
|
115
|
-
if (!job.enabled)
|
|
124
|
+
if (!job.enabled) {
|
|
116
125
|
return "disabled";
|
|
117
|
-
|
|
126
|
+
}
|
|
127
|
+
if (job.state.runningAtMs) {
|
|
118
128
|
return "running";
|
|
129
|
+
}
|
|
119
130
|
return job.state.lastStatus ?? "idle";
|
|
120
131
|
};
|
|
121
132
|
export function printCronList(jobs, runtime = defaultRuntime) {
|
|
@@ -144,17 +155,21 @@ export function printCronList(jobs, runtime = defaultRuntime) {
|
|
|
144
155
|
const lastLabel = pad(formatRelative(job.state.lastRunAtMs, now), CRON_LAST_PAD);
|
|
145
156
|
const statusRaw = formatStatus(job);
|
|
146
157
|
const statusLabel = pad(statusRaw, CRON_STATUS_PAD);
|
|
147
|
-
const targetLabel = pad(job.sessionTarget, CRON_TARGET_PAD);
|
|
158
|
+
const targetLabel = pad(job.sessionTarget ?? "-", CRON_TARGET_PAD);
|
|
148
159
|
const agentLabel = pad(truncate(job.agentId ?? "default", CRON_AGENT_PAD), CRON_AGENT_PAD);
|
|
149
160
|
const coloredStatus = (() => {
|
|
150
|
-
if (statusRaw === "ok")
|
|
161
|
+
if (statusRaw === "ok") {
|
|
151
162
|
return colorize(rich, theme.success, statusLabel);
|
|
152
|
-
|
|
163
|
+
}
|
|
164
|
+
if (statusRaw === "error") {
|
|
153
165
|
return colorize(rich, theme.error, statusLabel);
|
|
154
|
-
|
|
166
|
+
}
|
|
167
|
+
if (statusRaw === "running") {
|
|
155
168
|
return colorize(rich, theme.warn, statusLabel);
|
|
156
|
-
|
|
169
|
+
}
|
|
170
|
+
if (statusRaw === "skipped") {
|
|
157
171
|
return colorize(rich, theme.muted, statusLabel);
|
|
172
|
+
}
|
|
158
173
|
return colorize(rich, theme.muted, statusLabel);
|
|
159
174
|
})();
|
|
160
175
|
const coloredTarget = job.sessionTarget === "isolated"
|
package/dist/cli/dns-cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import fs from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { loadConfig } from "../config/config.js";
|
|
5
5
|
import { pickPrimaryTailnetIPv4, pickPrimaryTailnetIPv6 } from "../infra/tailnet.js";
|
|
6
|
-
import { getWideAreaZonePath,
|
|
6
|
+
import { getWideAreaZonePath, resolveWideAreaDiscoveryDomain } from "../infra/widearea-dns.js";
|
|
7
7
|
import { defaultRuntime } from "../runtime.js";
|
|
8
8
|
import { formatDocsLink } from "../terminal/links.js";
|
|
9
9
|
import { renderTable } from "../terminal/table.js";
|
|
@@ -13,8 +13,9 @@ function run(cmd, args, opts) {
|
|
|
13
13
|
encoding: "utf-8",
|
|
14
14
|
stdio: opts?.inherit ? "inherit" : "pipe",
|
|
15
15
|
});
|
|
16
|
-
if (res.error)
|
|
16
|
+
if (res.error) {
|
|
17
17
|
throw res.error;
|
|
18
|
+
}
|
|
18
19
|
if (!opts?.allowFailure && res.status !== 0) {
|
|
19
20
|
const errText = typeof res.stderr === "string" && res.stderr.trim()
|
|
20
21
|
? res.stderr.trim()
|
|
@@ -39,8 +40,9 @@ function writeFileSudoIfNeeded(filePath, content) {
|
|
|
39
40
|
encoding: "utf-8",
|
|
40
41
|
stdio: ["pipe", "ignore", "inherit"],
|
|
41
42
|
});
|
|
42
|
-
if (res.error)
|
|
43
|
+
if (res.error) {
|
|
43
44
|
throw res.error;
|
|
45
|
+
}
|
|
44
46
|
if (res.status !== 0) {
|
|
45
47
|
throw new Error(`sudo tee ${filePath} failed: exit ${res.status ?? "unknown"}`);
|
|
46
48
|
}
|
|
@@ -59,8 +61,9 @@ function mkdirSudoIfNeeded(dirPath) {
|
|
|
59
61
|
run("sudo", ["mkdir", "-p", dirPath], { inherit: true });
|
|
60
62
|
}
|
|
61
63
|
function zoneFileNeedsBootstrap(zonePath) {
|
|
62
|
-
if (!fs.existsSync(zonePath))
|
|
64
|
+
if (!fs.existsSync(zonePath)) {
|
|
63
65
|
return true;
|
|
66
|
+
}
|
|
64
67
|
try {
|
|
65
68
|
const content = fs.readFileSync(zonePath, "utf-8");
|
|
66
69
|
return !/\bSOA\b/.test(content) || !/\bNS\b/.test(content);
|
|
@@ -72,14 +75,16 @@ function zoneFileNeedsBootstrap(zonePath) {
|
|
|
72
75
|
function detectBrewPrefix() {
|
|
73
76
|
const out = run("brew", ["--prefix"]);
|
|
74
77
|
const prefix = out.trim();
|
|
75
|
-
if (!prefix)
|
|
78
|
+
if (!prefix) {
|
|
76
79
|
throw new Error("failed to resolve Homebrew prefix");
|
|
80
|
+
}
|
|
77
81
|
return prefix;
|
|
78
82
|
}
|
|
79
83
|
function ensureImportLine(corefilePath, importGlob) {
|
|
80
84
|
const existing = fs.readFileSync(corefilePath, "utf-8");
|
|
81
|
-
if (existing.includes(importGlob))
|
|
85
|
+
if (existing.includes(importGlob)) {
|
|
82
86
|
return false;
|
|
87
|
+
}
|
|
83
88
|
const next = `${existing.replace(/\s*$/, "")}\n\nimport ${importGlob}\n`;
|
|
84
89
|
writeFileSudoIfNeeded(corefilePath, next);
|
|
85
90
|
return true;
|
|
@@ -91,13 +96,20 @@ export function registerDnsCli(program) {
|
|
|
91
96
|
.addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/dns", "docs.molt.bot/cli/dns")}\n`);
|
|
92
97
|
dns
|
|
93
98
|
.command("setup")
|
|
94
|
-
.description("Set up CoreDNS to serve
|
|
99
|
+
.description("Set up CoreDNS to serve your discovery domain for unicast DNS-SD (Wide-Area Bonjour)")
|
|
100
|
+
.option("--domain <domain>", "Wide-area discovery domain (e.g. poolbot.internal)")
|
|
95
101
|
.option("--apply", "Install/update CoreDNS config and (re)start the service (requires sudo)", false)
|
|
96
102
|
.action(async (opts) => {
|
|
97
103
|
const cfg = loadConfig();
|
|
98
104
|
const tailnetIPv4 = pickPrimaryTailnetIPv4();
|
|
99
105
|
const tailnetIPv6 = pickPrimaryTailnetIPv6();
|
|
100
|
-
const
|
|
106
|
+
const wideAreaDomain = resolveWideAreaDiscoveryDomain({
|
|
107
|
+
configDomain: opts.domain ?? cfg.discovery?.wideArea?.domain,
|
|
108
|
+
});
|
|
109
|
+
if (!wideAreaDomain) {
|
|
110
|
+
throw new Error("No wide-area domain configured. Set discovery.wideArea.domain or pass --domain.");
|
|
111
|
+
}
|
|
112
|
+
const zonePath = getWideAreaZonePath(wideAreaDomain);
|
|
101
113
|
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
|
|
102
114
|
defaultRuntime.log(theme.heading("DNS setup"));
|
|
103
115
|
defaultRuntime.log(renderTable({
|
|
@@ -107,7 +119,7 @@ export function registerDnsCli(program) {
|
|
|
107
119
|
{ key: "Value", header: "Value", minWidth: 24, flex: true },
|
|
108
120
|
],
|
|
109
121
|
rows: [
|
|
110
|
-
{ Key: "Domain", Value:
|
|
122
|
+
{ Key: "Domain", Value: wideAreaDomain },
|
|
111
123
|
{ Key: "Zone file", Value: zonePath },
|
|
112
124
|
{
|
|
113
125
|
Key: "Tailnet IP",
|
|
@@ -119,12 +131,12 @@ export function registerDnsCli(program) {
|
|
|
119
131
|
defaultRuntime.log(theme.heading("Recommended ~/.poolbot/poolbot.json:"));
|
|
120
132
|
defaultRuntime.log(JSON.stringify({
|
|
121
133
|
gateway: { bind: "auto" },
|
|
122
|
-
discovery: { wideArea: { enabled: true } },
|
|
134
|
+
discovery: { wideArea: { enabled: true, domain: wideAreaDomain } },
|
|
123
135
|
}, null, 2));
|
|
124
136
|
defaultRuntime.log("");
|
|
125
137
|
defaultRuntime.log(theme.heading("Tailscale admin (DNS → Nameservers):"));
|
|
126
138
|
defaultRuntime.log(theme.muted(`- Add nameserver: ${tailnetIPv4 ?? "<this machine's tailnet IPv4>"}`));
|
|
127
|
-
defaultRuntime.log(theme.muted(
|
|
139
|
+
defaultRuntime.log(theme.muted(`- Restrict to domain (Split DNS): ${wideAreaDomain.replace(/\.$/, "")}`));
|
|
128
140
|
if (!opts.apply) {
|
|
129
141
|
defaultRuntime.log("");
|
|
130
142
|
defaultRuntime.log(theme.muted("Run with --apply to install CoreDNS and configure it."));
|
|
@@ -141,7 +153,7 @@ export function registerDnsCli(program) {
|
|
|
141
153
|
const corefilePath = path.join(etcDir, "Corefile");
|
|
142
154
|
const confDir = path.join(etcDir, "conf.d");
|
|
143
155
|
const importGlob = path.join(confDir, "*.server");
|
|
144
|
-
const serverPath = path.join(confDir, "
|
|
156
|
+
const serverPath = path.join(confDir, `${wideAreaDomain.replace(/\.$/, "")}.server`);
|
|
145
157
|
run("brew", ["list", "coredns"], { allowFailure: true });
|
|
146
158
|
run("brew", ["install", "coredns"], {
|
|
147
159
|
inherit: true,
|
|
@@ -156,7 +168,7 @@ export function registerDnsCli(program) {
|
|
|
156
168
|
}
|
|
157
169
|
const bindArgs = [tailnetIPv4, tailnetIPv6].filter((v) => Boolean(v?.trim()));
|
|
158
170
|
const server = [
|
|
159
|
-
`${
|
|
171
|
+
`${wideAreaDomain.replace(/\.$/, "")}:53 {`,
|
|
160
172
|
` bind ${bindArgs.join(" ")}`,
|
|
161
173
|
` file ${zonePath} {`,
|
|
162
174
|
` reload 10s`,
|
|
@@ -176,7 +188,7 @@ export function registerDnsCli(program) {
|
|
|
176
188
|
const serial = `${y}${m}${d}01`;
|
|
177
189
|
const zoneLines = [
|
|
178
190
|
`; created by poolbot dns setup (will be overwritten by the gateway when wide-area discovery is enabled)`,
|
|
179
|
-
`$ORIGIN ${
|
|
191
|
+
`$ORIGIN ${wideAreaDomain}`,
|
|
180
192
|
`$TTL 60`,
|
|
181
193
|
`@ IN SOA ns1 hostmaster ${serial} 7200 3600 1209600 60`,
|
|
182
194
|
`@ IN NS ns1`,
|
|
@@ -1,41 +1,51 @@
|
|
|
1
1
|
import { gatewayStatusCommand } from "../../commands/gateway-status.js";
|
|
2
2
|
import { formatHealthChannelLines } from "../../commands/health.js";
|
|
3
|
+
import { loadConfig } from "../../config/config.js";
|
|
3
4
|
import { discoverGatewayBeacons } from "../../infra/bonjour-discovery.js";
|
|
4
|
-
import {
|
|
5
|
+
import { resolveWideAreaDiscoveryDomain } from "../../infra/widearea-dns.js";
|
|
5
6
|
import { defaultRuntime } from "../../runtime.js";
|
|
6
7
|
import { formatDocsLink } from "../../terminal/links.js";
|
|
7
8
|
import { colorize, isRich, theme } from "../../terminal/theme.js";
|
|
8
9
|
import { formatTokenCount, formatUsd } from "../../utils/usage-format.js";
|
|
9
|
-
import { withProgress } from "../progress.js";
|
|
10
10
|
import { runCommandWithRuntime } from "../cli-utils.js";
|
|
11
11
|
import { runDaemonInstall, runDaemonRestart, runDaemonStart, runDaemonStatus, runDaemonStop, runDaemonUninstall, } from "../daemon-cli.js";
|
|
12
|
+
import { withProgress } from "../progress.js";
|
|
12
13
|
import { callGatewayCli, gatewayCallOpts } from "./call.js";
|
|
13
14
|
import { dedupeBeacons, parseDiscoverTimeoutMs, pickBeaconHost, pickGatewayPort, renderBeaconLines, } from "./discover.js";
|
|
14
15
|
import { addGatewayRunCommand } from "./run.js";
|
|
15
16
|
function styleHealthChannelLine(line, rich) {
|
|
16
|
-
if (!rich)
|
|
17
|
+
if (!rich) {
|
|
17
18
|
return line;
|
|
19
|
+
}
|
|
18
20
|
const colon = line.indexOf(":");
|
|
19
|
-
if (colon === -1)
|
|
21
|
+
if (colon === -1) {
|
|
20
22
|
return line;
|
|
23
|
+
}
|
|
21
24
|
const label = line.slice(0, colon + 1);
|
|
22
25
|
const detail = line.slice(colon + 1).trimStart();
|
|
23
26
|
const normalized = detail.toLowerCase();
|
|
24
27
|
const applyPrefix = (prefix, color) => `${label} ${color(detail.slice(0, prefix.length))}${detail.slice(prefix.length)}`;
|
|
25
|
-
if (normalized.startsWith("failed"))
|
|
28
|
+
if (normalized.startsWith("failed")) {
|
|
26
29
|
return applyPrefix("failed", theme.error);
|
|
27
|
-
|
|
30
|
+
}
|
|
31
|
+
if (normalized.startsWith("ok")) {
|
|
28
32
|
return applyPrefix("ok", theme.success);
|
|
29
|
-
|
|
33
|
+
}
|
|
34
|
+
if (normalized.startsWith("linked")) {
|
|
30
35
|
return applyPrefix("linked", theme.success);
|
|
31
|
-
|
|
36
|
+
}
|
|
37
|
+
if (normalized.startsWith("configured")) {
|
|
32
38
|
return applyPrefix("configured", theme.success);
|
|
33
|
-
|
|
39
|
+
}
|
|
40
|
+
if (normalized.startsWith("not linked")) {
|
|
34
41
|
return applyPrefix("not linked", theme.warn);
|
|
35
|
-
|
|
42
|
+
}
|
|
43
|
+
if (normalized.startsWith("not configured")) {
|
|
36
44
|
return applyPrefix("not configured", theme.muted);
|
|
37
|
-
|
|
45
|
+
}
|
|
46
|
+
if (normalized.startsWith("unknown")) {
|
|
38
47
|
return applyPrefix("unknown", theme.warn);
|
|
48
|
+
}
|
|
39
49
|
return line;
|
|
40
50
|
}
|
|
41
51
|
function runGatewayCommand(action, label) {
|
|
@@ -46,12 +56,14 @@ function runGatewayCommand(action, label) {
|
|
|
46
56
|
});
|
|
47
57
|
}
|
|
48
58
|
function parseDaysOption(raw, fallback = 30) {
|
|
49
|
-
if (typeof raw === "number" && Number.isFinite(raw))
|
|
59
|
+
if (typeof raw === "number" && Number.isFinite(raw)) {
|
|
50
60
|
return Math.max(1, Math.floor(raw));
|
|
61
|
+
}
|
|
51
62
|
if (typeof raw === "string" && raw.trim() !== "") {
|
|
52
63
|
const parsed = Number(raw);
|
|
53
|
-
if (Number.isFinite(parsed))
|
|
64
|
+
if (Number.isFinite(parsed)) {
|
|
54
65
|
return Math.max(1, Math.floor(parsed));
|
|
66
|
+
}
|
|
55
67
|
}
|
|
56
68
|
return fallback;
|
|
57
69
|
}
|
|
@@ -213,19 +225,24 @@ export function registerGatewayCli(program) {
|
|
|
213
225
|
});
|
|
214
226
|
gateway
|
|
215
227
|
.command("discover")
|
|
216
|
-
.description(
|
|
228
|
+
.description("Discover gateways via Bonjour (local + wide-area if configured)")
|
|
217
229
|
.option("--timeout <ms>", "Per-command timeout in ms", "2000")
|
|
218
230
|
.option("--json", "Output JSON", false)
|
|
219
231
|
.action(async (opts) => {
|
|
220
232
|
await runGatewayCommand(async () => {
|
|
233
|
+
const cfg = loadConfig();
|
|
234
|
+
const wideAreaDomain = resolveWideAreaDiscoveryDomain({
|
|
235
|
+
configDomain: cfg.discovery?.wideArea?.domain,
|
|
236
|
+
});
|
|
221
237
|
const timeoutMs = parseDiscoverTimeoutMs(opts.timeout, 2000);
|
|
238
|
+
const domains = ["local.", ...(wideAreaDomain ? [wideAreaDomain] : [])];
|
|
222
239
|
const beacons = await withProgress({
|
|
223
240
|
label: "Scanning for gateways…",
|
|
224
241
|
indeterminate: true,
|
|
225
242
|
enabled: opts.json !== true,
|
|
226
243
|
delayMs: 0,
|
|
227
|
-
}, async () => await discoverGatewayBeacons({ timeoutMs }));
|
|
228
|
-
const deduped = dedupeBeacons(beacons).
|
|
244
|
+
}, async () => await discoverGatewayBeacons({ timeoutMs, wideAreaDomain }));
|
|
245
|
+
const deduped = dedupeBeacons(beacons).toSorted((a, b) => String(a.displayName || a.instanceName).localeCompare(String(b.displayName || b.instanceName)));
|
|
229
246
|
if (opts.json) {
|
|
230
247
|
const enriched = deduped.map((b) => {
|
|
231
248
|
const host = pickBeaconHost(b);
|
|
@@ -234,7 +251,7 @@ export function registerGatewayCli(program) {
|
|
|
234
251
|
});
|
|
235
252
|
defaultRuntime.log(JSON.stringify({
|
|
236
253
|
timeoutMs,
|
|
237
|
-
domains
|
|
254
|
+
domains,
|
|
238
255
|
count: enriched.length,
|
|
239
256
|
beacons: enriched,
|
|
240
257
|
}, null, 2));
|
|
@@ -242,9 +259,10 @@ export function registerGatewayCli(program) {
|
|
|
242
259
|
}
|
|
243
260
|
const rich = isRich();
|
|
244
261
|
defaultRuntime.log(colorize(rich, theme.heading, "Gateway Discovery"));
|
|
245
|
-
defaultRuntime.log(colorize(rich, theme.muted, `Found ${deduped.length} gateway(s) · domains:
|
|
246
|
-
if (deduped.length === 0)
|
|
262
|
+
defaultRuntime.log(colorize(rich, theme.muted, `Found ${deduped.length} gateway(s) · domains: ${domains.join(", ")}`));
|
|
263
|
+
if (deduped.length === 0) {
|
|
247
264
|
return;
|
|
265
|
+
}
|
|
248
266
|
for (const beacon of deduped) {
|
|
249
267
|
for (const line of renderBeaconLines(beacon, rich)) {
|
|
250
268
|
defaultRuntime.log(line);
|
package/dist/cli/memory-cli.js
CHANGED
|
@@ -161,7 +161,7 @@ export async function runMemoryStatus(opts) {
|
|
|
161
161
|
getManager: () => getMemorySearchManager({ cfg, agentId }),
|
|
162
162
|
onMissing: (error) => defaultRuntime.log(error ?? "Memory search disabled."),
|
|
163
163
|
onCloseError: (err) => defaultRuntime.error(`Memory manager close failed: ${formatErrorMessage(err)}`),
|
|
164
|
-
close: (manager) => manager.close(),
|
|
164
|
+
close: async (manager) => { await manager.close?.(); },
|
|
165
165
|
run: async (manager) => {
|
|
166
166
|
const deep = Boolean(opts.deep || opts.index);
|
|
167
167
|
let embeddingProbe;
|
|
@@ -182,7 +182,7 @@ export async function runMemoryStatus(opts) {
|
|
|
182
182
|
fallback: opts.verbose ? "line" : undefined,
|
|
183
183
|
}, async (update, progress) => {
|
|
184
184
|
try {
|
|
185
|
-
await manager.sync({
|
|
185
|
+
await manager.sync?.({
|
|
186
186
|
reason: "cli",
|
|
187
187
|
progress: (syncUpdate) => {
|
|
188
188
|
update({
|
|
@@ -387,7 +387,7 @@ export function registerMemoryCli(program) {
|
|
|
387
387
|
getManager: () => getMemorySearchManager({ cfg, agentId }),
|
|
388
388
|
onMissing: (error) => defaultRuntime.log(error ?? "Memory search disabled."),
|
|
389
389
|
onCloseError: (err) => defaultRuntime.error(`Memory manager close failed: ${formatErrorMessage(err)}`),
|
|
390
|
-
close: (manager) => manager.close(),
|
|
390
|
+
close: async (manager) => { await manager.close?.(); },
|
|
391
391
|
run: async (manager) => {
|
|
392
392
|
try {
|
|
393
393
|
if (opts.verbose) {
|
|
@@ -453,7 +453,7 @@ export function registerMemoryCli(program) {
|
|
|
453
453
|
progress.setLabel(buildLabel());
|
|
454
454
|
}, 1000);
|
|
455
455
|
try {
|
|
456
|
-
await manager.sync({
|
|
456
|
+
await manager.sync?.({
|
|
457
457
|
reason: "cli",
|
|
458
458
|
force: opts.force,
|
|
459
459
|
progress: (syncUpdate) => {
|
|
@@ -500,7 +500,7 @@ export function registerMemoryCli(program) {
|
|
|
500
500
|
getManager: () => getMemorySearchManager({ cfg, agentId }),
|
|
501
501
|
onMissing: (error) => defaultRuntime.log(error ?? "Memory search disabled."),
|
|
502
502
|
onCloseError: (err) => defaultRuntime.error(`Memory manager close failed: ${formatErrorMessage(err)}`),
|
|
503
|
-
close: (manager) => manager.close(),
|
|
503
|
+
close: async (manager) => { await manager.close?.(); },
|
|
504
504
|
run: async (manager) => {
|
|
505
505
|
let results;
|
|
506
506
|
try {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const UNIT_MULTIPLIERS = {
|
|
2
|
+
b: 1,
|
|
3
|
+
kb: 1024,
|
|
4
|
+
k: 1024,
|
|
5
|
+
mb: 1024 ** 2,
|
|
6
|
+
m: 1024 ** 2,
|
|
7
|
+
gb: 1024 ** 3,
|
|
8
|
+
g: 1024 ** 3,
|
|
9
|
+
tb: 1024 ** 4,
|
|
10
|
+
t: 1024 ** 4,
|
|
11
|
+
};
|
|
12
|
+
export function parseByteSize(raw, opts) {
|
|
13
|
+
const trimmed = String(raw ?? "")
|
|
14
|
+
.trim()
|
|
15
|
+
.toLowerCase();
|
|
16
|
+
if (!trimmed) {
|
|
17
|
+
throw new Error("invalid byte size (empty)");
|
|
18
|
+
}
|
|
19
|
+
const m = /^(\d+(?:\.\d+)?)([a-z]+)?$/.exec(trimmed);
|
|
20
|
+
if (!m) {
|
|
21
|
+
throw new Error(`invalid byte size: ${raw}`);
|
|
22
|
+
}
|
|
23
|
+
const value = Number(m[1]);
|
|
24
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
25
|
+
throw new Error(`invalid byte size: ${raw}`);
|
|
26
|
+
}
|
|
27
|
+
const unit = (m[2] ?? opts?.defaultUnit ?? "b").toLowerCase();
|
|
28
|
+
const multiplier = UNIT_MULTIPLIERS[unit];
|
|
29
|
+
if (!multiplier) {
|
|
30
|
+
throw new Error(`invalid byte size unit: ${raw}`);
|
|
31
|
+
}
|
|
32
|
+
const bytes = Math.round(value * multiplier);
|
|
33
|
+
if (!Number.isFinite(bytes)) {
|
|
34
|
+
throw new Error(`invalid byte size: ${raw}`);
|
|
35
|
+
}
|
|
36
|
+
return bytes;
|
|
37
|
+
}
|