@poolzin/pool-bot 2026.3.25 → 2026.3.27
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/dist/agents/model-fallback.js +5 -4
- package/dist/agents/tools/common.js +16 -201
- package/dist/auto-reply/auto-reply/reply/agent-runner-execution.js +502 -0
- package/dist/auto-reply/auto-reply/reply/agent-runner-helpers.js +65 -0
- package/dist/auto-reply/auto-reply/reply/agent-runner-memory.js +160 -0
- package/dist/auto-reply/auto-reply/reply/agent-runner-payloads.js +85 -0
- package/dist/auto-reply/auto-reply/reply/agent-runner-utils.js +101 -0
- package/dist/auto-reply/auto-reply/reply/bash-command.js +338 -0
- package/dist/auto-reply/auto-reply/reply/block-streaming.js +91 -0
- package/dist/auto-reply/auto-reply/reply/commands-approve.js +88 -0
- package/dist/auto-reply/auto-reply/reply/commands-bash.js +26 -0
- package/dist/auto-reply/auto-reply/reply/commands-compact.js +107 -0
- package/dist/auto-reply/auto-reply/reply/commands-config.js +241 -0
- package/dist/auto-reply/auto-reply/reply/commands-context-report.js +295 -0
- package/dist/auto-reply/auto-reply/reply/commands-context.js +30 -0
- package/dist/auto-reply/auto-reply/reply/commands-core.js +151 -0
- package/dist/auto-reply/auto-reply/reply/commands-export-session.js +163 -0
- package/dist/auto-reply/auto-reply/reply/commands-info.js +184 -0
- package/dist/auto-reply/auto-reply/reply/commands-models.js +299 -0
- package/dist/auto-reply/auto-reply/reply/commands-plugin.js +35 -0
- package/dist/auto-reply/auto-reply/reply/commands-ptt.js +171 -0
- package/dist/auto-reply/auto-reply/reply/commands-setunset-standard.js +13 -0
- package/dist/auto-reply/auto-reply/reply/commands-setunset.js +73 -0
- package/dist/auto-reply/auto-reply/reply/commands-slash-parse.js +31 -0
- package/dist/auto-reply/auto-reply/reply/commands-status.js +178 -0
- package/dist/auto-reply/auto-reply/reply/commands-subagents.js +73 -0
- package/dist/auto-reply/auto-reply/reply/commands-system-prompt.js +117 -0
- package/dist/auto-reply/auto-reply/reply/commands-tts.js +231 -0
- package/dist/auto-reply/auto-reply/reply/directive-handling.impl.js +380 -0
- package/dist/auto-reply/auto-reply/reply/followup-runner.js +227 -0
- package/dist/auto-reply/auto-reply/reply/get-reply-directives-apply.js +201 -0
- package/dist/auto-reply/auto-reply/reply/get-reply-directives-utils.js +54 -0
- package/dist/auto-reply/auto-reply/reply/get-reply-directives.js +332 -0
- package/dist/auto-reply/auto-reply/reply/get-reply-inline-actions.js +258 -0
- package/dist/auto-reply/auto-reply/reply/get-reply-run.js +297 -0
- package/dist/auto-reply/auto-reply/reply/groups.js +102 -0
- package/dist/auto-reply/auto-reply/reply/mentions.js +129 -0
- package/dist/auto-reply/auto-reply/reply/reply-delivery.js +92 -0
- package/dist/auto-reply/auto-reply/reply/reply-directives.js +30 -0
- package/dist/auto-reply/auto-reply/reply/reply-dispatcher.js +152 -0
- package/dist/auto-reply/auto-reply/reply/reply-elevated.js +166 -0
- package/dist/auto-reply/auto-reply/reply/reply-inline.js +28 -0
- package/dist/auto-reply/auto-reply/reply/reply-payloads.js +114 -0
- package/dist/auto-reply/auto-reply/reply/reply-reference.js +36 -0
- package/dist/auto-reply/auto-reply/reply/reply-tags.js +13 -0
- package/dist/auto-reply/auto-reply/reply/reply-threading.js +41 -0
- package/dist/auto-reply/auto-reply/reply/session-updates.js +233 -0
- package/dist/auto-reply/auto-reply/reply/stage-sandbox-media.js +146 -0
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/canvas-host/a2ui/a2ui.bundle.js +2 -17772
- package/dist/canvas-host/a2ui/index.html +1 -307
- package/dist/channels/channels/directory-config.js +185 -0
- package/dist/channels/channels/discord/handle-action.guild-admin.js +332 -0
- package/dist/channels/channels/discord/handle-action.js +165 -0
- package/dist/channels/channels/discord.js +413 -0
- package/dist/channels/channels/dock.js +436 -0
- package/dist/channels/channels/index.js +51 -0
- package/dist/channels/channels/plugins/outbound/discord.js +101 -0
- package/dist/channels/channels/whatsapp.js +17 -0
- package/dist/channels/plugins/types.js +1 -1
- package/dist/channels/run-state-machine.js +7 -0
- package/dist/commands/models/auth.js +47 -1
- package/dist/commands-subagents/action-agents.js +44 -0
- package/dist/commands-subagents/action-focus.js +64 -0
- package/dist/commands-subagents/action-help.js +4 -0
- package/dist/commands-subagents/action-info.js +45 -0
- package/dist/commands-subagents/action-kill.js +60 -0
- package/dist/commands-subagents/action-list.js +44 -0
- package/dist/commands-subagents/action-log.js +29 -0
- package/dist/commands-subagents/action-send.js +119 -0
- package/dist/commands-subagents/action-spawn.js +52 -0
- package/dist/commands-subagents/action-unfocus.js +30 -0
- package/dist/commands-subagents/shared.js +303 -0
- package/dist/config/config.js +1 -8
- package/dist/config/types.secrets.js +61 -0
- package/dist/control-ui/assets/{index-D7shnQwQ.js → index-umCsvrWy.js} +884 -741
- package/dist/control-ui/assets/index-umCsvrWy.js.map +1 -0
- package/dist/control-ui/assets/pt-BR-DedEVAvY.js +2 -0
- package/dist/control-ui/assets/pt-BR-DedEVAvY.js.map +1 -0
- package/dist/control-ui/assets/zh-CN-CDzeklK-.js +2 -0
- package/dist/control-ui/assets/zh-CN-CDzeklK-.js.map +1 -0
- package/dist/control-ui/assets/zh-TW-BJCRYNWH.js +2 -0
- package/dist/control-ui/assets/zh-TW-BJCRYNWH.js.map +1 -0
- package/dist/control-ui/index.html +1 -1
- package/dist/gateway/method-scopes.js +9 -1
- package/dist/gateway/node-pending-work.js +142 -0
- package/dist/gateway/protocol/index.js +5 -1
- package/dist/gateway/protocol/schema/nodes.js +18 -0
- package/dist/gateway/server-methods/nodes-pending.js +96 -0
- package/dist/gateway/server-methods-list.js +4 -0
- package/dist/gateway/server-methods.js +2 -0
- package/dist/imessage/channel.js +253 -0
- package/dist/imessage/monitor/echo-cache.js +70 -0
- package/dist/imessage/monitor/loop-rate-limiter.js +51 -0
- package/dist/imessage/monitor/reflection-guard.js +50 -0
- package/dist/imessage/monitor/sanitize-outbound.js +25 -0
- package/dist/imessage/monitor/self-chat-cache.js +75 -0
- package/dist/imessage/runtime.js +3 -0
- package/dist/infra/exec-approval-reply.js +7 -0
- package/dist/infra/tmp-openclaw-dir.js +84 -0
- package/dist/pairing/pairing-challenge.js +15 -0
- package/dist/plugin-sdk/account-id.d.ts +1 -0
- package/dist/plugin-sdk/agent-media-payload.d.ts +12 -0
- package/dist/plugin-sdk/allow-from.d.ts +27 -0
- package/dist/plugin-sdk/command-auth.d.ts +25 -0
- package/dist/plugin-sdk/command-auth.js +3 -1
- package/dist/plugin-sdk/config-paths.d.ts +6 -0
- package/dist/plugin-sdk/file-lock.d.ts +16 -0
- package/dist/plugin-sdk/index.d.ts +428 -0
- package/dist/plugin-sdk/index.js +237 -103
- package/dist/plugin-sdk/json-store.d.ts +5 -0
- package/dist/plugin-sdk/keyed-async-queue.d.ts +12 -0
- package/dist/plugin-sdk/onboarding.d.ts +11 -0
- package/dist/plugin-sdk/provider-auth-result.d.ts +14 -0
- package/dist/plugin-sdk/slack-message-actions.d.ts +11 -0
- package/dist/plugin-sdk/status-helpers.d.ts +25 -0
- package/dist/plugin-sdk/temp-path.d.ts +12 -0
- package/dist/plugin-sdk/text-chunking.d.ts +1 -0
- package/dist/plugin-sdk/tool-send.d.ts +4 -0
- package/dist/plugin-sdk/webhook-path.d.ts +6 -0
- package/dist/plugin-sdk/webhook-targets.d.ts +23 -0
- package/dist/plugin-sdk/windows-spawn.d.ts +39 -0
- package/dist/plugin-sdk-internal/accounts.js +6 -0
- package/dist/plugin-sdk-internal/discord.js +23 -0
- package/dist/plugin-sdk-internal/imessage.js +13 -0
- package/dist/plugin-sdk-internal/setup.js +9 -0
- package/dist/plugin-sdk-internal/signal.js +13 -0
- package/dist/plugin-sdk-internal/slack.js +22 -0
- package/dist/plugin-sdk-internal/telegram.js +32 -0
- package/dist/plugin-sdk-internal/whatsapp.js +29 -0
- package/dist/routing/session-key.js +4 -185
- package/dist/shared/pid-alive.js +2 -61
- package/dist/shared/process-scoped-map.js +5 -7
- package/dist/signal/channel.js +264 -0
- package/dist/signal/monitor/access-policy.js +60 -0
- package/dist/signal/runtime.js +3 -0
- package/dist/slack/account-inspect.js +135 -0
- package/dist/slack/blocks-input.js +7 -38
- package/dist/slack/channel.js +394 -0
- package/dist/slack/interactive-replies.js +28 -0
- package/dist/slack/monitor/channel-type.js +31 -0
- package/dist/slack/monitor/dm-auth.js +49 -0
- package/dist/slack/monitor/events/interactions.modal.js +137 -0
- package/dist/slack/monitor/events/message-subtype-handlers.js +68 -0
- package/dist/slack/monitor/events/system-event-context.js +29 -0
- package/dist/slack/monitor/events/system-event-test-harness.js +41 -0
- package/dist/slack/monitor/external-arg-menu-store.js +46 -0
- package/dist/slack/monitor/message-handler/prepare-content.js +69 -0
- package/dist/slack/monitor/message-handler/prepare-thread-context.js +91 -0
- package/dist/slack/monitor/message-handler/prepare.test-helpers.js +55 -0
- package/dist/slack/monitor/reconnect-policy.js +78 -0
- package/dist/slack/monitor/slash-commands.runtime.js +1 -0
- package/dist/slack/monitor/slash-dispatch.runtime.js +9 -0
- package/dist/slack/monitor/slash-skill-commands.runtime.js +1 -0
- package/dist/slack/resolve-allowlist-common.js +36 -0
- package/dist/slack/runtime.js +3 -0
- package/dist/slack/sent-thread-cache.js +61 -0
- package/dist/slack/truncate.js +10 -0
- package/dist/telegram/account-inspect.js +175 -0
- package/dist/telegram/allow-from.js +10 -0
- package/dist/telegram/api-fetch.js +18 -0
- package/dist/telegram/approval-buttons.js +30 -0
- package/dist/telegram/audit-membership-runtime.js +61 -0
- package/dist/telegram/bot/delivery.replies.js +508 -0
- package/dist/telegram/bot/delivery.resolve-media.js +227 -0
- package/dist/telegram/bot/delivery.send.js +132 -0
- package/dist/telegram/bot/reply-threading.js +46 -0
- package/dist/telegram/bot-message-context.body.js +186 -0
- package/dist/telegram/bot-message-context.session.js +207 -0
- package/dist/telegram/bot-message-context.types.js +1 -0
- package/dist/telegram/bot-native-commands.test-helpers.js +117 -0
- package/dist/telegram/bot.media.e2e-harness.js +81 -0
- package/dist/telegram/bot.media.test-utils.js +81 -0
- package/dist/telegram/channel-actions.js +225 -0
- package/dist/telegram/channel.js +515 -0
- package/dist/telegram/conversation-route.js +107 -0
- package/dist/telegram/delivery.js +2 -0
- package/dist/telegram/delivery.replies.js +508 -0
- package/dist/telegram/dm-access.js +86 -0
- package/dist/telegram/draft-stream.test-helpers.js +62 -0
- package/dist/telegram/exec-approvals-handler.js +281 -0
- package/dist/telegram/exec-approvals.js +62 -0
- package/dist/telegram/forum-service-message.js +22 -0
- package/dist/telegram/group-config-helpers.js +10 -0
- package/dist/telegram/lane-delivery-state.js +19 -0
- package/dist/telegram/lane-delivery-text-deliverer.js +357 -0
- package/dist/telegram/lane-delivery.js +2 -0
- package/dist/telegram/normalize.js +37 -0
- package/dist/telegram/onboarding.js +192 -0
- package/dist/telegram/outbound-adapter.js +100 -0
- package/dist/telegram/polling-session.js +275 -0
- package/dist/telegram/runtime.js +3 -0
- package/dist/telegram/sendchataction-401-backoff.js +71 -0
- package/dist/telegram/sequential-key.js +46 -0
- package/dist/telegram/status-issues.js +105 -0
- package/dist/telegram/target-writeback.js +165 -0
- package/dist/telegram/thread-bindings.js +560 -0
- package/dist/utils.js +32 -257
- package/dist/wizard/prompts.js +5 -5
- package/extensions/feishu/src/policy.ts +1 -1
- package/extensions/firecrawl/index.test.ts +82 -0
- package/extensions/firecrawl/index.ts +20 -0
- package/extensions/firecrawl/openclaw.plugin.json +8 -0
- package/extensions/firecrawl/package.json +12 -0
- package/extensions/firecrawl/src/config.ts +159 -0
- package/extensions/firecrawl/src/firecrawl-client.ts +446 -0
- package/extensions/firecrawl/src/firecrawl-scrape-tool.ts +89 -0
- package/extensions/firecrawl/src/firecrawl-search-provider.ts +63 -0
- package/extensions/firecrawl/src/firecrawl-search-tool.ts +76 -0
- package/package.json +1 -1
- package/dist/.buildstamp +0 -1
- package/dist/acp/bindings-store.js +0 -209
- package/dist/acp/control-plane/runtime-cache.js +0 -54
- package/dist/acp/control-plane/runtime-options.js +0 -215
- package/dist/acp/control-plane/session-actor-queue.js +0 -36
- package/dist/acp/index.js +0 -2
- package/dist/acp/runtime/errors.js +0 -47
- package/dist/acp/runtime/registry.js +0 -86
- package/dist/acp/secret-file.js +0 -22
- package/dist/agents/auth-profiles.resolve-auth-profile-order.fixtures.js +0 -23
- package/dist/agents/bash-process-registry.test-helpers.js +0 -29
- package/dist/agents/bash-tools.exec-approval-request.js +0 -20
- package/dist/agents/bash-tools.exec-host-gateway.js +0 -240
- package/dist/agents/bash-tools.exec-host-node.js +0 -235
- package/dist/agents/checkpoint-manager.js +0 -290
- package/dist/agents/claude-cli-runner.js +0 -3
- package/dist/agents/error-classifier.js +0 -251
- package/dist/agents/live-model-filter.js +0 -84
- package/dist/agents/nvidia-models.js +0 -228
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +0 -34
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +0 -156
- package/dist/agents/pi-embedded-subscribe.handlers.tools.media.test-helpers.js +0 -30
- package/dist/agents/provider/config-loader.js +0 -76
- package/dist/agents/provider/index.js +0 -15
- package/dist/agents/provider/models-dev.js +0 -129
- package/dist/agents/provider/session-binding.js +0 -376
- package/dist/agents/queued-file-writer.js +0 -22
- package/dist/agents/skills/bundled-context.js +0 -23
- package/dist/agents/skills/security.js +0 -211
- package/dist/agents/skills/tools-dir.js +0 -9
- package/dist/agents/skills-install-download.js +0 -290
- package/dist/agents/skills-install-output.js +0 -30
- package/dist/agents/skills-install.download-test-utils.js +0 -36
- package/dist/agents/skills.test-helpers.js +0 -13
- package/dist/agents/subagent-announce-reliability.js +0 -160
- package/dist/agents/subagent-registry.mocks.shared.js +0 -12
- package/dist/agents/test-helpers/assistant-message-fixtures.js +0 -29
- package/dist/agents/test-helpers/fast-coding-tools.js +0 -1
- package/dist/agents/test-helpers/fast-core-tools.js +0 -8
- package/dist/agents/test-helpers/fast-tool-stubs.js +0 -18
- package/dist/agents/test-helpers/host-sandbox-fs-bridge.js +0 -74
- package/dist/agents/test-helpers/pi-tools-sandbox-context.js +0 -27
- package/dist/agents/tool-display-common.js +0 -915
- package/dist/agents/tool-policy-shared.js +0 -108
- package/dist/agents/tool-policy.conformance.js +0 -14
- package/dist/agents/tool-result-truncation.js +0 -299
- package/dist/agents/tools/cron-tool.test-helpers.js +0 -12
- package/dist/agents/tools/discord-actions-moderation-shared.js +0 -27
- package/dist/agents/tools/discord-actions-presence.js +0 -78
- package/dist/control-ui/assets/index-D7shnQwQ.js.map +0 -1
- package/dist/discord/discord-improvements.js +0 -167
- package/dist/discord/index.js +0 -2
- package/dist/hooks/bundled/boot-md/HOOK.md +0 -19
- package/dist/hooks/bundled/command-logger/HOOK.md +0 -122
- package/dist/hooks/bundled/session-memory/HOOK.md +0 -86
- package/dist/hooks/bundled/soul-evil/HOOK.md +0 -71
- package/dist/whatsapp/normalize.js +0 -66
- package/dist/whatsapp/resolve-outbound-target.js +0 -42
- /package/dist/{acp/runtime/types.js → auto-reply/auto-reply/reply/commands-types.js} +0 -0
- /package/dist/{agents/pi-embedded-payloads.js → slack/account-surface-fields.js} +0 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { getChannelDock } from "../../channels/dock.js";
|
|
2
|
+
import { normalizeChannelId } from "../../channels/plugins/index.js";
|
|
3
|
+
import { normalizeAccountId } from "../../routing/session-key.js";
|
|
4
|
+
import { INTERNAL_MESSAGE_CHANNEL, listDeliverableMessageChannels, } from "../../utils/message-channel.js";
|
|
5
|
+
import { resolveTextChunkLimit } from "../chunk.js";
|
|
6
|
+
const DEFAULT_BLOCK_STREAM_MIN = 800;
|
|
7
|
+
const DEFAULT_BLOCK_STREAM_MAX = 1200;
|
|
8
|
+
const DEFAULT_BLOCK_STREAM_COALESCE_IDLE_MS = 1000;
|
|
9
|
+
const getBlockChunkProviders = () => new Set([...listDeliverableMessageChannels(), INTERNAL_MESSAGE_CHANNEL]);
|
|
10
|
+
function normalizeChunkProvider(provider) {
|
|
11
|
+
if (!provider)
|
|
12
|
+
return undefined;
|
|
13
|
+
const cleaned = provider.trim().toLowerCase();
|
|
14
|
+
return getBlockChunkProviders().has(cleaned)
|
|
15
|
+
? cleaned
|
|
16
|
+
: undefined;
|
|
17
|
+
}
|
|
18
|
+
function resolveProviderBlockStreamingCoalesce(params) {
|
|
19
|
+
const { cfg, providerKey, accountId } = params;
|
|
20
|
+
if (!cfg || !providerKey)
|
|
21
|
+
return undefined;
|
|
22
|
+
const providerCfg = cfg[providerKey];
|
|
23
|
+
if (!providerCfg || typeof providerCfg !== "object")
|
|
24
|
+
return undefined;
|
|
25
|
+
const normalizedAccountId = normalizeAccountId(accountId);
|
|
26
|
+
const typed = providerCfg;
|
|
27
|
+
const accountCfg = typed.accounts?.[normalizedAccountId];
|
|
28
|
+
return accountCfg?.blockStreamingCoalesce ?? typed.blockStreamingCoalesce;
|
|
29
|
+
}
|
|
30
|
+
export function resolveBlockStreamingChunking(cfg, provider, accountId) {
|
|
31
|
+
const providerKey = normalizeChunkProvider(provider);
|
|
32
|
+
const providerId = providerKey ? normalizeChannelId(providerKey) : null;
|
|
33
|
+
const providerChunkLimit = providerId
|
|
34
|
+
? getChannelDock(providerId)?.outbound?.textChunkLimit
|
|
35
|
+
: undefined;
|
|
36
|
+
const textLimit = resolveTextChunkLimit(cfg, providerKey, accountId, {
|
|
37
|
+
fallbackLimit: providerChunkLimit,
|
|
38
|
+
});
|
|
39
|
+
const chunkCfg = cfg?.agents?.defaults?.blockStreamingChunk;
|
|
40
|
+
// Note: chunkMode="newline" used to imply splitting on each newline, but outbound
|
|
41
|
+
// delivery now treats it as paragraph-aware chunking (only split on blank lines).
|
|
42
|
+
// Block streaming should follow the same rule, so we do NOT special-case newline
|
|
43
|
+
// mode here.
|
|
44
|
+
// (chunkMode no longer alters block streaming behavior)
|
|
45
|
+
const maxRequested = Math.max(1, Math.floor(chunkCfg?.maxChars ?? DEFAULT_BLOCK_STREAM_MAX));
|
|
46
|
+
const maxChars = Math.max(1, Math.min(maxRequested, textLimit));
|
|
47
|
+
const minFallback = DEFAULT_BLOCK_STREAM_MIN;
|
|
48
|
+
const minRequested = Math.max(1, Math.floor(chunkCfg?.minChars ?? minFallback));
|
|
49
|
+
const minChars = Math.min(minRequested, maxChars);
|
|
50
|
+
const breakPreference = chunkCfg?.breakPreference === "newline" || chunkCfg?.breakPreference === "sentence"
|
|
51
|
+
? chunkCfg.breakPreference
|
|
52
|
+
: "paragraph";
|
|
53
|
+
return { minChars, maxChars, breakPreference };
|
|
54
|
+
}
|
|
55
|
+
export function resolveBlockStreamingCoalescing(cfg, provider, accountId, chunking) {
|
|
56
|
+
const providerKey = normalizeChunkProvider(provider);
|
|
57
|
+
// Note: chunkMode="newline" is paragraph-aware in outbound delivery (blank-line splits),
|
|
58
|
+
// so block streaming should not disable coalescing or flush per single newline.
|
|
59
|
+
const providerId = providerKey ? normalizeChannelId(providerKey) : null;
|
|
60
|
+
const providerChunkLimit = providerId
|
|
61
|
+
? getChannelDock(providerId)?.outbound?.textChunkLimit
|
|
62
|
+
: undefined;
|
|
63
|
+
const textLimit = resolveTextChunkLimit(cfg, providerKey, accountId, {
|
|
64
|
+
fallbackLimit: providerChunkLimit,
|
|
65
|
+
});
|
|
66
|
+
const providerDefaults = providerId
|
|
67
|
+
? getChannelDock(providerId)?.streaming?.blockStreamingCoalesceDefaults
|
|
68
|
+
: undefined;
|
|
69
|
+
const providerCfg = resolveProviderBlockStreamingCoalesce({
|
|
70
|
+
cfg,
|
|
71
|
+
providerKey,
|
|
72
|
+
accountId,
|
|
73
|
+
});
|
|
74
|
+
const coalesceCfg = providerCfg ?? cfg?.agents?.defaults?.blockStreamingCoalesce;
|
|
75
|
+
const minRequested = Math.max(1, Math.floor(coalesceCfg?.minChars ??
|
|
76
|
+
providerDefaults?.minChars ??
|
|
77
|
+
chunking?.minChars ??
|
|
78
|
+
DEFAULT_BLOCK_STREAM_MIN));
|
|
79
|
+
const maxRequested = Math.max(1, Math.floor(coalesceCfg?.maxChars ?? textLimit));
|
|
80
|
+
const maxChars = Math.max(1, Math.min(maxRequested, textLimit));
|
|
81
|
+
const minChars = Math.min(minRequested, maxChars);
|
|
82
|
+
const idleMs = Math.max(0, Math.floor(coalesceCfg?.idleMs ?? providerDefaults?.idleMs ?? DEFAULT_BLOCK_STREAM_COALESCE_IDLE_MS));
|
|
83
|
+
const preference = chunking?.breakPreference ?? "paragraph";
|
|
84
|
+
const joiner = preference === "sentence" ? " " : preference === "newline" ? "\n" : "\n\n";
|
|
85
|
+
return {
|
|
86
|
+
minChars,
|
|
87
|
+
maxChars,
|
|
88
|
+
idleMs,
|
|
89
|
+
joiner,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { callGateway } from "../../gateway/call.js";
|
|
2
|
+
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../../utils/message-channel.js";
|
|
3
|
+
import { logVerbose } from "../../globals.js";
|
|
4
|
+
const COMMAND = "/approve";
|
|
5
|
+
const DECISION_ALIASES = {
|
|
6
|
+
allow: "allow-once",
|
|
7
|
+
once: "allow-once",
|
|
8
|
+
"allow-once": "allow-once",
|
|
9
|
+
allowonce: "allow-once",
|
|
10
|
+
always: "allow-always",
|
|
11
|
+
"allow-always": "allow-always",
|
|
12
|
+
allowalways: "allow-always",
|
|
13
|
+
deny: "deny",
|
|
14
|
+
reject: "deny",
|
|
15
|
+
block: "deny",
|
|
16
|
+
};
|
|
17
|
+
function parseApproveCommand(raw) {
|
|
18
|
+
const trimmed = raw.trim();
|
|
19
|
+
if (!trimmed.toLowerCase().startsWith(COMMAND))
|
|
20
|
+
return null;
|
|
21
|
+
const rest = trimmed.slice(COMMAND.length).trim();
|
|
22
|
+
if (!rest) {
|
|
23
|
+
return { ok: false, error: "Usage: /approve <id> allow-once|allow-always|deny" };
|
|
24
|
+
}
|
|
25
|
+
const tokens = rest.split(/\s+/).filter(Boolean);
|
|
26
|
+
if (tokens.length < 2) {
|
|
27
|
+
return { ok: false, error: "Usage: /approve <id> allow-once|allow-always|deny" };
|
|
28
|
+
}
|
|
29
|
+
const first = tokens[0].toLowerCase();
|
|
30
|
+
const second = tokens[1].toLowerCase();
|
|
31
|
+
if (DECISION_ALIASES[first]) {
|
|
32
|
+
return {
|
|
33
|
+
ok: true,
|
|
34
|
+
decision: DECISION_ALIASES[first],
|
|
35
|
+
id: tokens.slice(1).join(" ").trim(),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (DECISION_ALIASES[second]) {
|
|
39
|
+
return {
|
|
40
|
+
ok: true,
|
|
41
|
+
decision: DECISION_ALIASES[second],
|
|
42
|
+
id: tokens[0],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return { ok: false, error: "Usage: /approve <id> allow-once|allow-always|deny" };
|
|
46
|
+
}
|
|
47
|
+
function buildResolvedByLabel(params) {
|
|
48
|
+
const channel = params.command.channel;
|
|
49
|
+
const sender = params.command.senderId ?? "unknown";
|
|
50
|
+
return `${channel}:${sender}`;
|
|
51
|
+
}
|
|
52
|
+
export const handleApproveCommand = async (params, allowTextCommands) => {
|
|
53
|
+
if (!allowTextCommands)
|
|
54
|
+
return null;
|
|
55
|
+
const normalized = params.command.commandBodyNormalized;
|
|
56
|
+
const parsed = parseApproveCommand(normalized);
|
|
57
|
+
if (!parsed)
|
|
58
|
+
return null;
|
|
59
|
+
if (!params.command.isAuthorizedSender) {
|
|
60
|
+
logVerbose(`Ignoring /approve from unauthorized sender: ${params.command.senderId || "<unknown>"}`);
|
|
61
|
+
return { shouldContinue: false };
|
|
62
|
+
}
|
|
63
|
+
if (!parsed.ok) {
|
|
64
|
+
return { shouldContinue: false, reply: { text: parsed.error } };
|
|
65
|
+
}
|
|
66
|
+
const resolvedBy = buildResolvedByLabel(params);
|
|
67
|
+
try {
|
|
68
|
+
await callGateway({
|
|
69
|
+
method: "exec.approval.resolve",
|
|
70
|
+
params: { id: parsed.id, decision: parsed.decision },
|
|
71
|
+
clientName: GATEWAY_CLIENT_NAMES.GATEWAY_CLIENT,
|
|
72
|
+
clientDisplayName: `Chat approval (${resolvedBy})`,
|
|
73
|
+
mode: GATEWAY_CLIENT_MODES.BACKEND,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
return {
|
|
78
|
+
shouldContinue: false,
|
|
79
|
+
reply: {
|
|
80
|
+
text: `❌ Failed to submit approval: ${String(err)}`,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
shouldContinue: false,
|
|
86
|
+
reply: { text: `✅ Exec approval ${parsed.decision} submitted for ${parsed.id}.` },
|
|
87
|
+
};
|
|
88
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { handleBashChatCommand } from "./bash-command.js";
|
|
2
|
+
import { rejectUnauthorizedCommand } from "./command-gates.js";
|
|
3
|
+
export const handleBashCommand = async (params, allowTextCommands) => {
|
|
4
|
+
if (!allowTextCommands) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
const { command } = params;
|
|
8
|
+
const bashSlashRequested = command.commandBodyNormalized === "/bash" || command.commandBodyNormalized.startsWith("/bash ");
|
|
9
|
+
const bashBangRequested = command.commandBodyNormalized.startsWith("!");
|
|
10
|
+
if (!bashSlashRequested && !(bashBangRequested && command.isAuthorizedSender)) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
const unauthorized = rejectUnauthorizedCommand(params, "/bash");
|
|
14
|
+
if (unauthorized) {
|
|
15
|
+
return unauthorized;
|
|
16
|
+
}
|
|
17
|
+
const reply = await handleBashChatCommand({
|
|
18
|
+
ctx: params.ctx,
|
|
19
|
+
cfg: params.cfg,
|
|
20
|
+
agentId: params.agentId,
|
|
21
|
+
sessionKey: params.sessionKey,
|
|
22
|
+
isGroup: params.isGroup,
|
|
23
|
+
elevated: params.elevated,
|
|
24
|
+
});
|
|
25
|
+
return { shouldContinue: false, reply };
|
|
26
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { abortEmbeddedPiRun, compactEmbeddedPiSession, isEmbeddedPiRunActive, waitForEmbeddedPiRunEnd, } from "../../agents/pi-embedded.js";
|
|
2
|
+
import { resolveSessionFilePath } from "../../config/sessions.js";
|
|
3
|
+
import { logVerbose } from "../../globals.js";
|
|
4
|
+
import { enqueueSystemEvent } from "../../infra/system-events.js";
|
|
5
|
+
import { formatContextUsageShort, formatTokenCount } from "../status.js";
|
|
6
|
+
import { stripMentions, stripStructuralPrefixes } from "./mentions.js";
|
|
7
|
+
import { incrementCompactionCount } from "./session-updates.js";
|
|
8
|
+
function extractCompactInstructions(params) {
|
|
9
|
+
const raw = stripStructuralPrefixes(params.rawBody ?? "");
|
|
10
|
+
const stripped = params.isGroup
|
|
11
|
+
? stripMentions(raw, params.ctx, params.cfg, params.agentId)
|
|
12
|
+
: raw;
|
|
13
|
+
const trimmed = stripped.trim();
|
|
14
|
+
if (!trimmed)
|
|
15
|
+
return undefined;
|
|
16
|
+
const lowered = trimmed.toLowerCase();
|
|
17
|
+
const prefix = lowered.startsWith("/compact") ? "/compact" : null;
|
|
18
|
+
if (!prefix)
|
|
19
|
+
return undefined;
|
|
20
|
+
let rest = trimmed.slice(prefix.length).trimStart();
|
|
21
|
+
if (rest.startsWith(":"))
|
|
22
|
+
rest = rest.slice(1).trimStart();
|
|
23
|
+
return rest.length ? rest : undefined;
|
|
24
|
+
}
|
|
25
|
+
export const handleCompactCommand = async (params) => {
|
|
26
|
+
const compactRequested = params.command.commandBodyNormalized === "/compact" ||
|
|
27
|
+
params.command.commandBodyNormalized.startsWith("/compact ");
|
|
28
|
+
if (!compactRequested)
|
|
29
|
+
return null;
|
|
30
|
+
if (!params.command.isAuthorizedSender) {
|
|
31
|
+
logVerbose(`Ignoring /compact from unauthorized sender: ${params.command.senderId || "<unknown>"}`);
|
|
32
|
+
return { shouldContinue: false };
|
|
33
|
+
}
|
|
34
|
+
if (!params.sessionEntry?.sessionId) {
|
|
35
|
+
return {
|
|
36
|
+
shouldContinue: false,
|
|
37
|
+
reply: { text: "⚙️ Compaction unavailable (missing session id)." },
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const sessionId = params.sessionEntry.sessionId;
|
|
41
|
+
if (isEmbeddedPiRunActive(sessionId)) {
|
|
42
|
+
abortEmbeddedPiRun(sessionId);
|
|
43
|
+
await waitForEmbeddedPiRunEnd(sessionId, 15_000);
|
|
44
|
+
}
|
|
45
|
+
const customInstructions = extractCompactInstructions({
|
|
46
|
+
rawBody: params.ctx.CommandBody ?? params.ctx.RawBody ?? params.ctx.Body,
|
|
47
|
+
ctx: params.ctx,
|
|
48
|
+
cfg: params.cfg,
|
|
49
|
+
agentId: params.agentId,
|
|
50
|
+
isGroup: params.isGroup,
|
|
51
|
+
});
|
|
52
|
+
const result = await compactEmbeddedPiSession({
|
|
53
|
+
sessionId,
|
|
54
|
+
sessionKey: params.sessionKey,
|
|
55
|
+
messageChannel: params.command.channel,
|
|
56
|
+
groupId: params.sessionEntry.groupId,
|
|
57
|
+
groupChannel: params.sessionEntry.groupChannel,
|
|
58
|
+
groupSpace: params.sessionEntry.space,
|
|
59
|
+
spawnedBy: params.sessionEntry.spawnedBy,
|
|
60
|
+
sessionFile: resolveSessionFilePath(sessionId, params.sessionEntry),
|
|
61
|
+
workspaceDir: params.workspaceDir,
|
|
62
|
+
config: params.cfg,
|
|
63
|
+
skillsSnapshot: params.sessionEntry.skillsSnapshot,
|
|
64
|
+
provider: params.provider,
|
|
65
|
+
model: params.model,
|
|
66
|
+
thinkLevel: params.resolvedThinkLevel ?? (await params.resolveDefaultThinkingLevel()),
|
|
67
|
+
bashElevated: {
|
|
68
|
+
enabled: false,
|
|
69
|
+
allowed: false,
|
|
70
|
+
defaultLevel: "off",
|
|
71
|
+
},
|
|
72
|
+
customInstructions,
|
|
73
|
+
senderIsOwner: params.command.senderIsOwner,
|
|
74
|
+
ownerNumbers: params.command.ownerList.length > 0 ? params.command.ownerList : undefined,
|
|
75
|
+
});
|
|
76
|
+
const compactLabel = result.ok
|
|
77
|
+
? result.compacted
|
|
78
|
+
? result.result?.tokensBefore != null && result.result?.tokensAfter != null
|
|
79
|
+
? `Compacted (${formatTokenCount(result.result.tokensBefore)} → ${formatTokenCount(result.result.tokensAfter)})`
|
|
80
|
+
: result.result?.tokensBefore
|
|
81
|
+
? `Compacted (${formatTokenCount(result.result.tokensBefore)} before)`
|
|
82
|
+
: "Compacted"
|
|
83
|
+
: "Compaction skipped"
|
|
84
|
+
: "Compaction failed";
|
|
85
|
+
if (result.ok && result.compacted) {
|
|
86
|
+
await incrementCompactionCount({
|
|
87
|
+
sessionEntry: params.sessionEntry,
|
|
88
|
+
sessionStore: params.sessionStore,
|
|
89
|
+
sessionKey: params.sessionKey,
|
|
90
|
+
storePath: params.storePath,
|
|
91
|
+
// Update token counts after compaction
|
|
92
|
+
tokensAfter: result.result?.tokensAfter,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// Use the post-compaction token count for context summary if available
|
|
96
|
+
const tokensAfterCompaction = result.result?.tokensAfter;
|
|
97
|
+
const totalTokens = tokensAfterCompaction ??
|
|
98
|
+
params.sessionEntry.totalTokens ??
|
|
99
|
+
(params.sessionEntry.inputTokens ?? 0) + (params.sessionEntry.outputTokens ?? 0);
|
|
100
|
+
const contextSummary = formatContextUsageShort(totalTokens > 0 ? totalTokens : null, params.contextTokens ?? params.sessionEntry.contextTokens ?? null);
|
|
101
|
+
const reason = result.reason?.trim();
|
|
102
|
+
const line = reason
|
|
103
|
+
? `${compactLabel}: ${reason} • ${contextSummary}`
|
|
104
|
+
: `${compactLabel} • ${contextSummary}`;
|
|
105
|
+
enqueueSystemEvent(line, { sessionKey: params.sessionKey });
|
|
106
|
+
return { shouldContinue: false, reply: { text: `⚙️ ${line}` } };
|
|
107
|
+
};
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { resolveChannelConfigWrites } from "../../channels/plugins/config-writes.js";
|
|
2
|
+
import { normalizeChannelId } from "../../channels/registry.js";
|
|
3
|
+
import { getConfigValueAtPath, parseConfigPath, setConfigValueAtPath, unsetConfigValueAtPath, } from "../../config/config-paths.js";
|
|
4
|
+
import { readConfigFileSnapshot, validateConfigObjectWithPlugins, writeConfigFile, } from "../../config/config.js";
|
|
5
|
+
import { getConfigOverrides, resetConfigOverrides, setConfigOverride, unsetConfigOverride, } from "../../config/runtime-overrides.js";
|
|
6
|
+
import { rejectUnauthorizedCommand, requireCommandFlagEnabled } from "./command-gates.js";
|
|
7
|
+
import { parseConfigCommand } from "./config-commands.js";
|
|
8
|
+
import { parseDebugCommand } from "./debug-commands.js";
|
|
9
|
+
export const handleConfigCommand = async (params, allowTextCommands) => {
|
|
10
|
+
if (!allowTextCommands) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
const configCommand = parseConfigCommand(params.command.commandBodyNormalized);
|
|
14
|
+
if (!configCommand) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const unauthorized = rejectUnauthorizedCommand(params, "/config");
|
|
18
|
+
if (unauthorized) {
|
|
19
|
+
return unauthorized;
|
|
20
|
+
}
|
|
21
|
+
const disabled = requireCommandFlagEnabled(params.cfg, {
|
|
22
|
+
label: "/config",
|
|
23
|
+
configKey: "config",
|
|
24
|
+
});
|
|
25
|
+
if (disabled) {
|
|
26
|
+
return disabled;
|
|
27
|
+
}
|
|
28
|
+
if (configCommand.action === "error") {
|
|
29
|
+
return {
|
|
30
|
+
shouldContinue: false,
|
|
31
|
+
reply: { text: `⚠️ ${configCommand.message}` },
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (configCommand.action === "set" || configCommand.action === "unset") {
|
|
35
|
+
const channelId = params.command.channelId ?? normalizeChannelId(params.command.channel);
|
|
36
|
+
const allowWrites = resolveChannelConfigWrites({
|
|
37
|
+
cfg: params.cfg,
|
|
38
|
+
channelId,
|
|
39
|
+
accountId: params.ctx.AccountId,
|
|
40
|
+
});
|
|
41
|
+
if (!allowWrites) {
|
|
42
|
+
const channelLabel = channelId ?? "this channel";
|
|
43
|
+
const hint = channelId
|
|
44
|
+
? `channels.${channelId}.configWrites=true`
|
|
45
|
+
: "channels.<channel>.configWrites=true";
|
|
46
|
+
return {
|
|
47
|
+
shouldContinue: false,
|
|
48
|
+
reply: {
|
|
49
|
+
text: `⚠️ Config writes are disabled for ${channelLabel}. Set ${hint} to enable.`,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const snapshot = await readConfigFileSnapshot();
|
|
55
|
+
if (!snapshot.valid || !snapshot.parsed || typeof snapshot.parsed !== "object") {
|
|
56
|
+
return {
|
|
57
|
+
shouldContinue: false,
|
|
58
|
+
reply: {
|
|
59
|
+
text: "⚠️ Config file is invalid; fix it before using /config.",
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const parsedBase = structuredClone(snapshot.parsed);
|
|
64
|
+
if (configCommand.action === "show") {
|
|
65
|
+
const pathRaw = configCommand.path?.trim();
|
|
66
|
+
if (pathRaw) {
|
|
67
|
+
const parsedPath = parseConfigPath(pathRaw);
|
|
68
|
+
if (!parsedPath.ok || !parsedPath.path) {
|
|
69
|
+
return {
|
|
70
|
+
shouldContinue: false,
|
|
71
|
+
reply: { text: `⚠️ ${parsedPath.error ?? "Invalid path."}` },
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const value = getConfigValueAtPath(parsedBase, parsedPath.path);
|
|
75
|
+
const rendered = JSON.stringify(value ?? null, null, 2);
|
|
76
|
+
return {
|
|
77
|
+
shouldContinue: false,
|
|
78
|
+
reply: {
|
|
79
|
+
text: `⚙️ Config ${pathRaw}:\n\`\`\`json\n${rendered}\n\`\`\``,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const json = JSON.stringify(parsedBase, null, 2);
|
|
84
|
+
return {
|
|
85
|
+
shouldContinue: false,
|
|
86
|
+
reply: { text: `⚙️ Config (raw):\n\`\`\`json\n${json}\n\`\`\`` },
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (configCommand.action === "unset") {
|
|
90
|
+
const parsedPath = parseConfigPath(configCommand.path);
|
|
91
|
+
if (!parsedPath.ok || !parsedPath.path) {
|
|
92
|
+
return {
|
|
93
|
+
shouldContinue: false,
|
|
94
|
+
reply: { text: `⚠️ ${parsedPath.error ?? "Invalid path."}` },
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const removed = unsetConfigValueAtPath(parsedBase, parsedPath.path);
|
|
98
|
+
if (!removed) {
|
|
99
|
+
return {
|
|
100
|
+
shouldContinue: false,
|
|
101
|
+
reply: { text: `⚙️ No config value found for ${configCommand.path}.` },
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
const validated = validateConfigObjectWithPlugins(parsedBase);
|
|
105
|
+
if (!validated.ok) {
|
|
106
|
+
const issue = validated.issues[0];
|
|
107
|
+
return {
|
|
108
|
+
shouldContinue: false,
|
|
109
|
+
reply: {
|
|
110
|
+
text: `⚠️ Config invalid after unset (${issue.path}: ${issue.message}).`,
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
await writeConfigFile(validated.config);
|
|
115
|
+
return {
|
|
116
|
+
shouldContinue: false,
|
|
117
|
+
reply: { text: `⚙️ Config updated: ${configCommand.path} removed.` },
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (configCommand.action === "set") {
|
|
121
|
+
const parsedPath = parseConfigPath(configCommand.path);
|
|
122
|
+
if (!parsedPath.ok || !parsedPath.path) {
|
|
123
|
+
return {
|
|
124
|
+
shouldContinue: false,
|
|
125
|
+
reply: { text: `⚠️ ${parsedPath.error ?? "Invalid path."}` },
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
setConfigValueAtPath(parsedBase, parsedPath.path, configCommand.value);
|
|
129
|
+
const validated = validateConfigObjectWithPlugins(parsedBase);
|
|
130
|
+
if (!validated.ok) {
|
|
131
|
+
const issue = validated.issues[0];
|
|
132
|
+
return {
|
|
133
|
+
shouldContinue: false,
|
|
134
|
+
reply: {
|
|
135
|
+
text: `⚠️ Config invalid after set (${issue.path}: ${issue.message}).`,
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
await writeConfigFile(validated.config);
|
|
140
|
+
const valueLabel = typeof configCommand.value === "string"
|
|
141
|
+
? `"${configCommand.value}"`
|
|
142
|
+
: JSON.stringify(configCommand.value);
|
|
143
|
+
return {
|
|
144
|
+
shouldContinue: false,
|
|
145
|
+
reply: {
|
|
146
|
+
text: `⚙️ Config updated: ${configCommand.path}=${valueLabel ?? "null"}`,
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return null;
|
|
151
|
+
};
|
|
152
|
+
export const handleDebugCommand = async (params, allowTextCommands) => {
|
|
153
|
+
if (!allowTextCommands) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
const debugCommand = parseDebugCommand(params.command.commandBodyNormalized);
|
|
157
|
+
if (!debugCommand) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
const unauthorized = rejectUnauthorizedCommand(params, "/debug");
|
|
161
|
+
if (unauthorized) {
|
|
162
|
+
return unauthorized;
|
|
163
|
+
}
|
|
164
|
+
const disabled = requireCommandFlagEnabled(params.cfg, {
|
|
165
|
+
label: "/debug",
|
|
166
|
+
configKey: "debug",
|
|
167
|
+
});
|
|
168
|
+
if (disabled) {
|
|
169
|
+
return disabled;
|
|
170
|
+
}
|
|
171
|
+
if (debugCommand.action === "error") {
|
|
172
|
+
return {
|
|
173
|
+
shouldContinue: false,
|
|
174
|
+
reply: { text: `⚠️ ${debugCommand.message}` },
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
if (debugCommand.action === "show") {
|
|
178
|
+
const overrides = getConfigOverrides();
|
|
179
|
+
const hasOverrides = Object.keys(overrides).length > 0;
|
|
180
|
+
if (!hasOverrides) {
|
|
181
|
+
return {
|
|
182
|
+
shouldContinue: false,
|
|
183
|
+
reply: { text: "⚙️ Debug overrides: (none)" },
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const json = JSON.stringify(overrides, null, 2);
|
|
187
|
+
return {
|
|
188
|
+
shouldContinue: false,
|
|
189
|
+
reply: {
|
|
190
|
+
text: `⚙️ Debug overrides (memory-only):\n\`\`\`json\n${json}\n\`\`\``,
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
if (debugCommand.action === "reset") {
|
|
195
|
+
resetConfigOverrides();
|
|
196
|
+
return {
|
|
197
|
+
shouldContinue: false,
|
|
198
|
+
reply: { text: "⚙️ Debug overrides cleared; using config on disk." },
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
if (debugCommand.action === "unset") {
|
|
202
|
+
const result = unsetConfigOverride(debugCommand.path);
|
|
203
|
+
if (!result.ok) {
|
|
204
|
+
return {
|
|
205
|
+
shouldContinue: false,
|
|
206
|
+
reply: { text: `⚠️ ${result.error ?? "Invalid path."}` },
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
if (!result.removed) {
|
|
210
|
+
return {
|
|
211
|
+
shouldContinue: false,
|
|
212
|
+
reply: {
|
|
213
|
+
text: `⚙️ No debug override found for ${debugCommand.path}.`,
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
shouldContinue: false,
|
|
219
|
+
reply: { text: `⚙️ Debug override removed for ${debugCommand.path}.` },
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
if (debugCommand.action === "set") {
|
|
223
|
+
const result = setConfigOverride(debugCommand.path, debugCommand.value);
|
|
224
|
+
if (!result.ok) {
|
|
225
|
+
return {
|
|
226
|
+
shouldContinue: false,
|
|
227
|
+
reply: { text: `⚠️ ${result.error ?? "Invalid override."}` },
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
const valueLabel = typeof debugCommand.value === "string"
|
|
231
|
+
? `"${debugCommand.value}"`
|
|
232
|
+
: JSON.stringify(debugCommand.value);
|
|
233
|
+
return {
|
|
234
|
+
shouldContinue: false,
|
|
235
|
+
reply: {
|
|
236
|
+
text: `⚙️ Debug override set: ${debugCommand.path}=${valueLabel ?? "null"}`,
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
return null;
|
|
241
|
+
};
|