@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
package/dist/tui/tui.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CombinedAutocompleteProvider, Container, Loader, ProcessTerminal, Text, TUI,
|
|
1
|
+
import { CombinedAutocompleteProvider, Container, Loader, ProcessTerminal, Text, TUI, } from "@mariozechner/pi-tui";
|
|
2
2
|
import { resolveDefaultAgentId } from "../agents/agent-scope.js";
|
|
3
3
|
import { loadConfig } from "../config/config.js";
|
|
4
4
|
import { buildAgentMainSessionKey, normalizeAgentId, normalizeMainKey, parseAgentSessionKey, } from "../routing/session-key.js";
|
|
@@ -11,9 +11,9 @@ import { createCommandHandlers } from "./tui-command-handlers.js";
|
|
|
11
11
|
import { createEventHandlers } from "./tui-event-handlers.js";
|
|
12
12
|
import { formatTokens } from "./tui-formatters.js";
|
|
13
13
|
import { createLocalShellRunner } from "./tui-local-shell.js";
|
|
14
|
-
import { buildWaitingStatusMessage, defaultWaitingPhrases } from "./tui-waiting.js";
|
|
15
14
|
import { createOverlayHandlers } from "./tui-overlays.js";
|
|
16
15
|
import { createSessionActions } from "./tui-session-actions.js";
|
|
16
|
+
import { buildWaitingStatusMessage, defaultWaitingPhrases } from "./tui-waiting.js";
|
|
17
17
|
export { resolveFinalAssistantText } from "./tui-formatters.js";
|
|
18
18
|
export function createEditorSubmitHandler(params) {
|
|
19
19
|
return (text) => {
|
|
@@ -21,8 +21,9 @@ export function createEditorSubmitHandler(params) {
|
|
|
21
21
|
const value = raw.trim();
|
|
22
22
|
params.editor.setText("");
|
|
23
23
|
// Keep previous behavior: ignore empty/whitespace-only submissions.
|
|
24
|
-
if (!value)
|
|
24
|
+
if (!value) {
|
|
25
25
|
return;
|
|
26
|
+
}
|
|
26
27
|
// Bash mode: only if the very first character is '!' and it's not just '!'.
|
|
27
28
|
// IMPORTANT: use the raw (untrimmed) text so leading spaces do NOT trigger.
|
|
28
29
|
// Per requirement: a lone '!' should be treated as a normal message.
|
|
@@ -40,6 +41,102 @@ export function createEditorSubmitHandler(params) {
|
|
|
40
41
|
void params.sendMessage(value);
|
|
41
42
|
};
|
|
42
43
|
}
|
|
44
|
+
export function shouldEnableWindowsGitBashPasteFallback(params) {
|
|
45
|
+
const platform = params?.platform ?? process.platform;
|
|
46
|
+
if (platform !== "win32") {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const env = params?.env ?? process.env;
|
|
50
|
+
const msystem = (env.MSYSTEM ?? "").toUpperCase();
|
|
51
|
+
const shell = env.SHELL ?? "";
|
|
52
|
+
const termProgram = (env.TERM_PROGRAM ?? "").toLowerCase();
|
|
53
|
+
if (msystem.startsWith("MINGW") || msystem.startsWith("MSYS")) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
if (shell.toLowerCase().includes("bash")) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
return termProgram.includes("mintty");
|
|
60
|
+
}
|
|
61
|
+
export function createSubmitBurstCoalescer(params) {
|
|
62
|
+
const windowMs = Math.max(1, params.burstWindowMs ?? 50);
|
|
63
|
+
const now = params.now ?? (() => Date.now());
|
|
64
|
+
const setTimer = params.setTimer ?? setTimeout;
|
|
65
|
+
const clearTimer = params.clearTimer ?? clearTimeout;
|
|
66
|
+
let pending = null;
|
|
67
|
+
let pendingAt = 0;
|
|
68
|
+
let flushTimer = null;
|
|
69
|
+
const clearFlushTimer = () => {
|
|
70
|
+
if (!flushTimer) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
clearTimer(flushTimer);
|
|
74
|
+
flushTimer = null;
|
|
75
|
+
};
|
|
76
|
+
const flushPending = () => {
|
|
77
|
+
if (pending === null) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const value = pending;
|
|
81
|
+
pending = null;
|
|
82
|
+
pendingAt = 0;
|
|
83
|
+
clearFlushTimer();
|
|
84
|
+
params.submit(value);
|
|
85
|
+
};
|
|
86
|
+
const scheduleFlush = () => {
|
|
87
|
+
clearFlushTimer();
|
|
88
|
+
flushTimer = setTimer(() => {
|
|
89
|
+
flushPending();
|
|
90
|
+
}, windowMs);
|
|
91
|
+
};
|
|
92
|
+
return (value) => {
|
|
93
|
+
if (!params.enabled) {
|
|
94
|
+
params.submit(value);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (value.includes("\n")) {
|
|
98
|
+
flushPending();
|
|
99
|
+
params.submit(value);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const ts = now();
|
|
103
|
+
if (pending === null) {
|
|
104
|
+
pending = value;
|
|
105
|
+
pendingAt = ts;
|
|
106
|
+
scheduleFlush();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (ts - pendingAt <= windowMs) {
|
|
110
|
+
pending = `${pending}\n${value}`;
|
|
111
|
+
pendingAt = ts;
|
|
112
|
+
scheduleFlush();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
flushPending();
|
|
116
|
+
pending = value;
|
|
117
|
+
pendingAt = ts;
|
|
118
|
+
scheduleFlush();
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
export function resolveTuiSessionKey(params) {
|
|
122
|
+
const trimmed = (params.raw ?? "").trim();
|
|
123
|
+
if (!trimmed) {
|
|
124
|
+
if (params.sessionScope === "global") {
|
|
125
|
+
return "global";
|
|
126
|
+
}
|
|
127
|
+
return buildAgentMainSessionKey({
|
|
128
|
+
agentId: params.currentAgentId,
|
|
129
|
+
mainKey: params.sessionMainKey,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
if (trimmed === "global" || trimmed === "unknown") {
|
|
133
|
+
return trimmed;
|
|
134
|
+
}
|
|
135
|
+
if (trimmed.startsWith("agent:")) {
|
|
136
|
+
return trimmed;
|
|
137
|
+
}
|
|
138
|
+
return `agent:${params.currentAgentId}:${trimmed}`;
|
|
139
|
+
}
|
|
43
140
|
export async function runTui(opts) {
|
|
44
141
|
const config = loadConfig();
|
|
45
142
|
const initialSessionInput = (opts.session ?? "").trim();
|
|
@@ -58,6 +155,7 @@ export async function runTui(opts) {
|
|
|
58
155
|
let wasDisconnected = false;
|
|
59
156
|
let toolsExpanded = false;
|
|
60
157
|
let showThinking = false;
|
|
158
|
+
const localRunIds = new Set();
|
|
61
159
|
const deliverDefault = opts.deliver ?? false;
|
|
62
160
|
const autoMessage = opts.message?.trim();
|
|
63
161
|
let autoMessageSent = false;
|
|
@@ -185,6 +283,25 @@ export async function runTui(opts) {
|
|
|
185
283
|
lastCtrlCAt = value;
|
|
186
284
|
},
|
|
187
285
|
};
|
|
286
|
+
const noteLocalRunId = (runId) => {
|
|
287
|
+
if (!runId) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
localRunIds.add(runId);
|
|
291
|
+
if (localRunIds.size > 200) {
|
|
292
|
+
const [first] = localRunIds;
|
|
293
|
+
if (first) {
|
|
294
|
+
localRunIds.delete(first);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
const forgetLocalRunId = (runId) => {
|
|
299
|
+
localRunIds.delete(runId);
|
|
300
|
+
};
|
|
301
|
+
const isLocalRunId = (runId) => localRunIds.has(runId);
|
|
302
|
+
const clearLocalRunIds = () => {
|
|
303
|
+
localRunIds.clear();
|
|
304
|
+
};
|
|
188
305
|
const client = new GatewayChatClient({
|
|
189
306
|
url: opts.url,
|
|
190
307
|
token: opts.token,
|
|
@@ -212,8 +329,9 @@ export async function runTui(opts) {
|
|
|
212
329
|
tui.addChild(root);
|
|
213
330
|
tui.setFocus(editor);
|
|
214
331
|
const formatSessionKey = (key) => {
|
|
215
|
-
if (key === "global" || key === "unknown")
|
|
332
|
+
if (key === "global" || key === "unknown") {
|
|
216
333
|
return key;
|
|
334
|
+
}
|
|
217
335
|
const parsed = parseAgentSessionKey(key);
|
|
218
336
|
return parsed?.rest ?? key;
|
|
219
337
|
};
|
|
@@ -222,43 +340,35 @@ export async function runTui(opts) {
|
|
|
222
340
|
return name ? `${id} (${name})` : id;
|
|
223
341
|
};
|
|
224
342
|
const resolveSessionKey = (raw) => {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
mainKey: sessionMainKey,
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
if (trimmed === "global" || trimmed === "unknown")
|
|
235
|
-
return trimmed;
|
|
236
|
-
if (trimmed.startsWith("agent:"))
|
|
237
|
-
return trimmed;
|
|
238
|
-
return `agent:${currentAgentId}:${trimmed}`;
|
|
343
|
+
return resolveTuiSessionKey({
|
|
344
|
+
raw,
|
|
345
|
+
sessionScope,
|
|
346
|
+
currentAgentId,
|
|
347
|
+
sessionMainKey,
|
|
348
|
+
});
|
|
239
349
|
};
|
|
240
350
|
currentSessionKey = resolveSessionKey(initialSessionInput);
|
|
241
|
-
const getContentWidth = () => Math.max(20, (tui.terminal.columns ?? 80) - 2); // paddingX=1 each side
|
|
242
351
|
const updateHeader = () => {
|
|
243
352
|
const sessionLabel = formatSessionKey(currentSessionKey);
|
|
244
353
|
const agentLabel = formatAgentLabel(currentAgentId);
|
|
245
|
-
|
|
246
|
-
header.setText(theme.header(truncateToWidth(raw, getContentWidth())));
|
|
354
|
+
header.setText(theme.header(`poolbot tui - ${client.connection.url} - agent ${agentLabel} - session ${sessionLabel}`));
|
|
247
355
|
};
|
|
248
356
|
const busyStates = new Set(["sending", "waiting", "streaming", "running"]);
|
|
249
357
|
let statusText = null;
|
|
250
358
|
let statusLoader = null;
|
|
251
359
|
const formatElapsed = (startMs) => {
|
|
252
360
|
const totalSeconds = Math.max(0, Math.floor((Date.now() - startMs) / 1000));
|
|
253
|
-
if (totalSeconds < 60)
|
|
361
|
+
if (totalSeconds < 60) {
|
|
254
362
|
return `${totalSeconds}s`;
|
|
363
|
+
}
|
|
255
364
|
const minutes = Math.floor(totalSeconds / 60);
|
|
256
365
|
const seconds = totalSeconds % 60;
|
|
257
366
|
return `${minutes}m ${seconds}s`;
|
|
258
367
|
};
|
|
259
368
|
const ensureStatusText = () => {
|
|
260
|
-
if (statusText)
|
|
369
|
+
if (statusText) {
|
|
261
370
|
return;
|
|
371
|
+
}
|
|
262
372
|
statusContainer.clear();
|
|
263
373
|
statusLoader?.stop();
|
|
264
374
|
statusLoader = null;
|
|
@@ -266,8 +376,9 @@ export async function runTui(opts) {
|
|
|
266
376
|
statusContainer.addChild(statusText);
|
|
267
377
|
};
|
|
268
378
|
const ensureStatusLoader = () => {
|
|
269
|
-
if (statusLoader)
|
|
379
|
+
if (statusLoader) {
|
|
270
380
|
return;
|
|
381
|
+
}
|
|
271
382
|
statusContainer.clear();
|
|
272
383
|
statusText = null;
|
|
273
384
|
statusLoader = new Loader(tui, (spinner) => theme.accent(spinner), (text) => theme.bold(theme.accentSoft(text)), "");
|
|
@@ -277,44 +388,45 @@ export async function runTui(opts) {
|
|
|
277
388
|
let waitingTimer = null;
|
|
278
389
|
let waitingPhrase = null;
|
|
279
390
|
const updateBusyStatusMessage = () => {
|
|
280
|
-
if (!statusLoader || !statusStartedAt)
|
|
391
|
+
if (!statusLoader || !statusStartedAt) {
|
|
281
392
|
return;
|
|
393
|
+
}
|
|
282
394
|
const elapsed = formatElapsed(statusStartedAt);
|
|
283
|
-
// Truncate status messages to terminal width to prevent TUI crash
|
|
284
|
-
// (Loader adds spinner + space = 2 visible chars before the message)
|
|
285
|
-
const maxMsgWidth = Math.max(10, getContentWidth() - 4);
|
|
286
395
|
if (activityStatus === "waiting") {
|
|
287
396
|
waitingTick++;
|
|
288
|
-
|
|
397
|
+
statusLoader.setMessage(buildWaitingStatusMessage({
|
|
289
398
|
theme,
|
|
290
399
|
tick: waitingTick,
|
|
291
400
|
elapsed,
|
|
292
401
|
connectionStatus,
|
|
293
402
|
phrases: waitingPhrase ? [waitingPhrase] : undefined,
|
|
294
|
-
});
|
|
295
|
-
statusLoader.setMessage(truncateToWidth(msg, maxMsgWidth));
|
|
403
|
+
}));
|
|
296
404
|
return;
|
|
297
405
|
}
|
|
298
|
-
statusLoader.setMessage(
|
|
406
|
+
statusLoader.setMessage(`${activityStatus} • ${elapsed} | ${connectionStatus}`);
|
|
299
407
|
};
|
|
300
408
|
const startStatusTimer = () => {
|
|
301
|
-
if (statusTimer)
|
|
409
|
+
if (statusTimer) {
|
|
302
410
|
return;
|
|
411
|
+
}
|
|
303
412
|
statusTimer = setInterval(() => {
|
|
304
|
-
if (!busyStates.has(activityStatus))
|
|
413
|
+
if (!busyStates.has(activityStatus)) {
|
|
305
414
|
return;
|
|
415
|
+
}
|
|
306
416
|
updateBusyStatusMessage();
|
|
307
417
|
}, 1000);
|
|
308
418
|
};
|
|
309
419
|
const stopStatusTimer = () => {
|
|
310
|
-
if (!statusTimer)
|
|
420
|
+
if (!statusTimer) {
|
|
311
421
|
return;
|
|
422
|
+
}
|
|
312
423
|
clearInterval(statusTimer);
|
|
313
424
|
statusTimer = null;
|
|
314
425
|
};
|
|
315
426
|
const startWaitingTimer = () => {
|
|
316
|
-
if (waitingTimer)
|
|
427
|
+
if (waitingTimer) {
|
|
317
428
|
return;
|
|
429
|
+
}
|
|
318
430
|
// Pick a phrase once per waiting session.
|
|
319
431
|
if (!waitingPhrase) {
|
|
320
432
|
const idx = Math.floor(Math.random() * defaultWaitingPhrases.length);
|
|
@@ -322,14 +434,16 @@ export async function runTui(opts) {
|
|
|
322
434
|
}
|
|
323
435
|
waitingTick = 0;
|
|
324
436
|
waitingTimer = setInterval(() => {
|
|
325
|
-
if (activityStatus !== "waiting")
|
|
437
|
+
if (activityStatus !== "waiting") {
|
|
326
438
|
return;
|
|
439
|
+
}
|
|
327
440
|
updateBusyStatusMessage();
|
|
328
441
|
}, 120);
|
|
329
442
|
};
|
|
330
443
|
const stopWaitingTimer = () => {
|
|
331
|
-
if (!waitingTimer)
|
|
444
|
+
if (!waitingTimer) {
|
|
332
445
|
return;
|
|
446
|
+
}
|
|
333
447
|
clearInterval(waitingTimer);
|
|
334
448
|
waitingTimer = null;
|
|
335
449
|
waitingPhrase = null;
|
|
@@ -366,8 +480,9 @@ export async function runTui(opts) {
|
|
|
366
480
|
const setConnectionStatus = (text, ttlMs) => {
|
|
367
481
|
connectionStatus = text;
|
|
368
482
|
renderStatus();
|
|
369
|
-
if (statusTimeout)
|
|
483
|
+
if (statusTimeout) {
|
|
370
484
|
clearTimeout(statusTimeout);
|
|
485
|
+
}
|
|
371
486
|
if (ttlMs && ttlMs > 0) {
|
|
372
487
|
statusTimeout = setTimeout(() => {
|
|
373
488
|
connectionStatus = isConnected ? "connected" : "disconnected";
|
|
@@ -404,12 +519,13 @@ export async function runTui(opts) {
|
|
|
404
519
|
reasoningLabel,
|
|
405
520
|
tokens,
|
|
406
521
|
].filter(Boolean);
|
|
407
|
-
footer.setText(theme.dim(
|
|
522
|
+
footer.setText(theme.dim(footerParts.join(" | ")));
|
|
408
523
|
};
|
|
409
524
|
const { openOverlay, closeOverlay } = createOverlayHandlers(tui, editor);
|
|
410
525
|
const initialSessionAgentId = (() => {
|
|
411
|
-
if (!initialSessionInput)
|
|
526
|
+
if (!initialSessionInput) {
|
|
412
527
|
return null;
|
|
528
|
+
}
|
|
413
529
|
const parsed = parseAgentSessionKey(initialSessionInput);
|
|
414
530
|
return parsed ? normalizeAgentId(parsed.agentId) : null;
|
|
415
531
|
})();
|
|
@@ -427,14 +543,19 @@ export async function runTui(opts) {
|
|
|
427
543
|
updateFooter,
|
|
428
544
|
updateAutocompleteProvider,
|
|
429
545
|
setActivityStatus,
|
|
546
|
+
clearLocalRunIds,
|
|
430
547
|
});
|
|
431
|
-
const { refreshAgents, refreshSessionInfo, loadHistory, setSession, abortActive } = sessionActions;
|
|
548
|
+
const { refreshAgents, refreshSessionInfo, applySessionInfoFromPatch, loadHistory, setSession, abortActive, } = sessionActions;
|
|
432
549
|
const { handleChatEvent, handleAgentEvent } = createEventHandlers({
|
|
433
550
|
chatLog,
|
|
434
551
|
tui,
|
|
435
552
|
state,
|
|
436
553
|
setActivityStatus,
|
|
437
554
|
refreshSessionInfo,
|
|
555
|
+
loadHistory,
|
|
556
|
+
isLocalRunId,
|
|
557
|
+
forgetLocalRunId,
|
|
558
|
+
clearLocalRunIds,
|
|
438
559
|
});
|
|
439
560
|
const { handleCommand, sendMessage, openModelSelector, openAgentSelector, openSessionSelector } = createCommandHandlers({
|
|
440
561
|
client,
|
|
@@ -446,12 +567,15 @@ export async function runTui(opts) {
|
|
|
446
567
|
openOverlay,
|
|
447
568
|
closeOverlay,
|
|
448
569
|
refreshSessionInfo,
|
|
570
|
+
applySessionInfoFromPatch,
|
|
449
571
|
loadHistory,
|
|
450
572
|
setSession,
|
|
451
573
|
refreshAgents,
|
|
452
574
|
abortActive,
|
|
453
575
|
setActivityStatus,
|
|
454
576
|
formatSessionKey,
|
|
577
|
+
noteLocalRunId,
|
|
578
|
+
forgetLocalRunId,
|
|
455
579
|
});
|
|
456
580
|
const { runLocalShellLine } = createLocalShellRunner({
|
|
457
581
|
chatLog,
|
|
@@ -460,12 +584,16 @@ export async function runTui(opts) {
|
|
|
460
584
|
closeOverlay,
|
|
461
585
|
});
|
|
462
586
|
updateAutocompleteProvider();
|
|
463
|
-
|
|
587
|
+
const submitHandler = createEditorSubmitHandler({
|
|
464
588
|
editor,
|
|
465
589
|
handleCommand,
|
|
466
590
|
sendMessage,
|
|
467
591
|
handleBangLine: runLocalShellLine,
|
|
468
592
|
});
|
|
593
|
+
editor.onSubmit = createSubmitBurstCoalescer({
|
|
594
|
+
submit: submitHandler,
|
|
595
|
+
enabled: shouldEnableWindowsGitBashPasteFallback(),
|
|
596
|
+
});
|
|
469
597
|
editor.onEscape = () => {
|
|
470
598
|
void abortActive();
|
|
471
599
|
};
|
|
@@ -511,10 +639,12 @@ export async function runTui(opts) {
|
|
|
511
639
|
void loadHistory();
|
|
512
640
|
};
|
|
513
641
|
client.onEvent = (evt) => {
|
|
514
|
-
if (evt.event === "chat")
|
|
642
|
+
if (evt.event === "chat") {
|
|
515
643
|
handleChatEvent(evt.payload);
|
|
516
|
-
|
|
644
|
+
}
|
|
645
|
+
if (evt.event === "agent") {
|
|
517
646
|
handleAgentEvent(evt.payload);
|
|
647
|
+
}
|
|
518
648
|
};
|
|
519
649
|
client.onConnected = () => {
|
|
520
650
|
isConnected = true;
|
|
@@ -554,4 +684,10 @@ export async function runTui(opts) {
|
|
|
554
684
|
updateFooter();
|
|
555
685
|
tui.start();
|
|
556
686
|
client.start();
|
|
687
|
+
await new Promise((resolve) => {
|
|
688
|
+
const finish = () => resolve();
|
|
689
|
+
process.once("exit", finish);
|
|
690
|
+
process.once("SIGINT", finish);
|
|
691
|
+
process.once("SIGTERM", finish);
|
|
692
|
+
});
|
|
557
693
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export async function runTasksWithConcurrency(params) {
|
|
2
|
+
const { tasks, limit, onTaskError } = params;
|
|
3
|
+
const errorMode = params.errorMode ?? "continue";
|
|
4
|
+
if (tasks.length === 0) {
|
|
5
|
+
return { results: [], firstError: undefined, hasError: false };
|
|
6
|
+
}
|
|
7
|
+
const resolvedLimit = Math.max(1, Math.min(limit, tasks.length));
|
|
8
|
+
const results = Array.from({ length: tasks.length });
|
|
9
|
+
let next = 0;
|
|
10
|
+
let firstError = undefined;
|
|
11
|
+
let hasError = false;
|
|
12
|
+
const workers = Array.from({ length: resolvedLimit }, async () => {
|
|
13
|
+
while (true) {
|
|
14
|
+
if (errorMode === "stop" && hasError) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const index = next;
|
|
18
|
+
next += 1;
|
|
19
|
+
if (index >= tasks.length) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
results[index] = await tasks[index]();
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (!hasError) {
|
|
27
|
+
firstError = error;
|
|
28
|
+
hasError = true;
|
|
29
|
+
}
|
|
30
|
+
onTaskError?.(error, index);
|
|
31
|
+
if (errorMode === "stop") {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
await Promise.allSettled(workers);
|
|
38
|
+
return { results, firstError, hasError };
|
|
39
|
+
}
|
package/dist/web/media.js
CHANGED
|
@@ -5,8 +5,12 @@ import { logVerbose, shouldLogVerbose } from "../globals.js";
|
|
|
5
5
|
import { maxBytesForKind, mediaKindFromMime } from "../media/constants.js";
|
|
6
6
|
import { resolveUserPath } from "../utils.js";
|
|
7
7
|
import { fetchRemoteMedia } from "../media/fetch.js";
|
|
8
|
+
import { getDefaultMediaLocalRoots } from "../media/local-roots.js";
|
|
8
9
|
import { convertHeicToJpeg, hasAlphaChannel, optimizeImageToPng, resizeToJpeg, } from "../media/image-ops.js";
|
|
9
10
|
import { detectMime, extensionForMime } from "../media/mime.js";
|
|
11
|
+
export function getDefaultLocalRoots() {
|
|
12
|
+
return getDefaultMediaLocalRoots();
|
|
13
|
+
}
|
|
10
14
|
const HEIC_MIME_RE = /^image\/hei[cf]$/i;
|
|
11
15
|
const HEIC_EXT_RE = /\.(heic|heif)$/i;
|
|
12
16
|
const MB = 1024 * 1024;
|
|
@@ -3,6 +3,7 @@ summary: "Slash commands: text vs native, config, and supported commands"
|
|
|
3
3
|
read_when:
|
|
4
4
|
- Using or configuring chat commands
|
|
5
5
|
- Debugging command routing or permissions
|
|
6
|
+
title: "Slash Commands"
|
|
6
7
|
---
|
|
7
8
|
# Slash commands
|
|
8
9
|
|
|
@@ -65,8 +66,11 @@ Text + native (when enabled):
|
|
|
65
66
|
- `/allowlist` (list/add/remove allowlist entries)
|
|
66
67
|
- `/approve <id> allow-once|allow-always|deny` (resolve exec approval prompts)
|
|
67
68
|
- `/context [list|detail|json]` (explain “context”; `detail` shows per-file + per-tool + per-skill + system prompt size)
|
|
69
|
+
- `/export-session [path]` (export the current session; alias: `/export`)
|
|
68
70
|
- `/whoami` (show your sender id; alias: `/id`)
|
|
69
|
-
- `/subagents list|
|
|
71
|
+
- `/subagents list|kill|log|info|send|steer|spawn` (inspect, kill, log, or message sub-agent runs for the current session)
|
|
72
|
+
- `/kill <id|#|all>` (kill a sub-agent run)
|
|
73
|
+
- `/steer <id|#> <message>` (redirect a sub-agent; alias: `/tell`)
|
|
70
74
|
- `/config show|get|set|unset` (persist config to disk, owner-only; requires `commands.config: true`)
|
|
71
75
|
- `/debug show|set|unset|reset` (runtime overrides, owner-only; requires `commands.debug: true`)
|
|
72
76
|
- `/usage off|tokens|full|cost` (per-response usage footer or local cost summary)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const CONTROL_CHARS_RE = /[\u0000-\u001f\u007f]/;
|
|
2
|
+
const MAX_EXTERNAL_KEY_LENGTH = 512;
|
|
3
|
+
|
|
4
|
+
export function normalizeFeishuExternalKey(value: unknown): string | undefined {
|
|
5
|
+
if (typeof value !== "string") {
|
|
6
|
+
return undefined;
|
|
7
|
+
}
|
|
8
|
+
const normalized = value.trim();
|
|
9
|
+
if (!normalized || normalized.length > MAX_EXTERNAL_KEY_LENGTH) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
if (CONTROL_CHARS_RE.test(normalized)) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
if (normalized.includes("/") || normalized.includes("\\") || normalized.includes("..")) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
return normalized;
|
|
19
|
+
}
|