mixdog 0.9.1 → 0.9.3
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/package.json +9 -1
- package/scripts/_bench-cwc.json +20 -0
- package/scripts/agent-loop-policy-test.mjs +37 -0
- package/scripts/agent-parallel-smoke.mjs +54 -10
- package/scripts/anthropic-maxtokens-test.mjs +119 -0
- package/scripts/background-task-meta-smoke.mjs +1 -1
- package/scripts/bench-run.mjs +262 -0
- package/scripts/build-tui.mjs +13 -1
- package/scripts/compact-smoke.mjs +12 -0
- package/scripts/compact-trigger-migration-smoke.mjs +67 -1
- package/scripts/explore-bench.mjs +124 -0
- package/scripts/hook-bus-test.mjs +191 -0
- package/scripts/ingest-pure-conversation-smoke.mjs +148 -0
- package/scripts/internal-comms-bench.mjs +727 -0
- package/scripts/internal-comms-smoke.mjs +75 -0
- package/scripts/lead-workflow-smoke.mjs +4 -4
- package/scripts/live-worker-smoke.mjs +9 -9
- package/scripts/output-style-bench.mjs +285 -0
- package/scripts/output-style-smoke.mjs +13 -10
- package/scripts/patch-replay.mjs +90 -0
- package/scripts/path-suffix-test.mjs +57 -0
- package/scripts/provider-stream-stall-test.mjs +276 -0
- package/scripts/provider-toolcall-test.mjs +599 -1
- package/scripts/recall-bench.mjs +207 -0
- package/scripts/routing-corpus.mjs +281 -0
- package/scripts/session-bench.mjs +1526 -0
- package/scripts/session-diag.mjs +595 -0
- package/scripts/task-bench.mjs +207 -0
- package/scripts/tool-failures.mjs +6 -6
- package/scripts/tool-smoke.mjs +310 -67
- package/scripts/toolcall-args-test.mjs +81 -0
- package/src/agents/debugger/AGENT.md +4 -4
- package/src/agents/heavy-worker/AGENT.md +20 -9
- package/src/agents/reviewer/AGENT.md +4 -4
- package/src/agents/worker/AGENT.md +17 -9
- package/src/app.mjs +10 -6
- package/src/defaults/{hidden-roles.json → agents.json} +7 -7
- package/src/examples/schedules/SCHEDULE.example.md +32 -0
- package/src/examples/webhooks/WEBHOOK.example.md +40 -0
- package/src/headless-role.mjs +14 -14
- package/src/help.mjs +1 -0
- package/src/lib/rules-builder.cjs +32 -54
- package/src/mixdog-session-runtime.mjs +1040 -2036
- package/src/output-styles/default.md +12 -7
- package/src/output-styles/minimal.md +25 -0
- package/src/output-styles/oneline.md +21 -0
- package/src/output-styles/simple.md +10 -9
- package/src/repl.mjs +17 -7
- package/src/rules/agent/00-common.md +7 -5
- package/src/rules/agent/30-explorer.md +8 -12
- package/src/rules/lead/01-general.md +3 -1
- package/src/rules/lead/lead-tool.md +13 -2
- package/src/rules/shared/01-tool.md +23 -12
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +90 -32
- package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +32 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +18 -6
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +23 -20
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +48 -14
- package/src/runtime/agent/orchestrator/agent-trace.mjs +87 -12
- package/src/runtime/agent/orchestrator/config.mjs +3 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +182 -67
- package/src/runtime/agent/orchestrator/{internal-roles.mjs → internal-agents.mjs} +72 -72
- package/src/runtime/agent/orchestrator/internal-tools.mjs +13 -26
- package/src/runtime/agent/orchestrator/mcp/client.mjs +100 -18
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +188 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-leaked-toolcall.mjs +444 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +313 -84
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +104 -38
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +28 -33
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +184 -17
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +8 -1
- package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +18 -8
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +227 -31
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +83 -6
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +229 -115
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +213 -33
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +18 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +49 -17
- package/src/runtime/agent/orchestrator/providers/registry.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +22 -17
- package/src/runtime/agent/orchestrator/session/compact.mjs +560 -51
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +250 -3
- package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +262 -0
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
- package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +49 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
- package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
- package/src/runtime/agent/orchestrator/session/loop.mjs +513 -1000
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +227 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +137 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +232 -1152
- package/src/runtime/agent/orchestrator/session/store.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/tool-envelope.mjs +61 -0
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +5 -0
- package/src/runtime/agent/orchestrator/stall-policy.mjs +63 -15
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +194 -24
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +143 -0
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +34 -18
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.test.mjs +162 -0
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/list-formatting.mjs +10 -0
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +5 -4
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +15 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +9 -44
- package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +14 -5
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +10 -17
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +23 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +50 -39
- package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/builtin/tool-output-limit.mjs +10 -0
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +70 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +497 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1192 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +39 -4189
- package/src/runtime/agent/orchestrator/tools/patch.mjs +119 -5
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -2
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +1 -2
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
- package/src/runtime/channels/backends/discord.mjs +99 -9
- package/src/runtime/channels/backends/telegram.mjs +501 -0
- package/src/runtime/channels/index.mjs +437 -1439
- package/src/runtime/channels/lib/boot-profile.mjs +23 -0
- package/src/runtime/channels/lib/config.mjs +54 -2
- package/src/runtime/channels/lib/crash-log.mjs +106 -0
- package/src/runtime/channels/lib/format.mjs +4 -2
- package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
- package/src/runtime/channels/lib/output-forwarder.mjs +88 -67
- package/src/runtime/channels/lib/runtime-paths.mjs +29 -0
- package/src/runtime/channels/lib/scheduler.mjs +1 -1
- package/src/runtime/channels/lib/telegram-format.mjs +280 -0
- package/src/runtime/channels/lib/tool-format.mjs +1 -1
- package/src/runtime/channels/lib/transcript-discovery.mjs +19 -1
- package/src/runtime/channels/lib/webhook.mjs +59 -31
- package/src/runtime/channels/lib/whisper-language.mjs +42 -0
- package/src/runtime/channels/tool-defs.mjs +1 -1
- package/src/runtime/memory/index.mjs +465 -345
- package/src/runtime/memory/lib/agent-ipc.mjs +2 -2
- package/src/runtime/memory/lib/core-memory-store.mjs +352 -2
- package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
- package/src/runtime/memory/lib/http-wire.mjs +57 -0
- package/src/runtime/memory/lib/memory-cycle1.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2.mjs +65 -9
- package/src/runtime/memory/lib/memory-cycle3.mjs +1 -1
- package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
- package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
- package/src/runtime/memory/lib/memory.mjs +121 -4
- package/src/runtime/memory/lib/pg/adapter.mjs +139 -15
- package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
- package/src/runtime/memory/lib/recall-format.mjs +183 -0
- package/src/runtime/memory/lib/session-ingest.mjs +107 -0
- package/src/runtime/memory/lib/trace-store.mjs +69 -22
- package/src/runtime/memory/tool-defs.mjs +10 -7
- package/src/runtime/shared/abort-controller.mjs +1 -1
- package/src/runtime/shared/background-tasks.mjs +2 -3
- package/src/runtime/shared/buffered-appender.mjs +149 -0
- package/src/runtime/shared/channel-notification-routing.mjs +12 -0
- package/src/runtime/shared/channel-notification-routing.test.mjs +45 -0
- package/src/runtime/shared/config.mjs +9 -0
- package/src/runtime/shared/llm/http-agent.mjs +12 -5
- package/src/runtime/shared/schedules-store.mjs +21 -19
- package/src/runtime/shared/task-notification-envelope.mjs +98 -0
- package/src/runtime/shared/task-notification-envelope.test.mjs +107 -0
- package/src/runtime/shared/tool-execution-contract.mjs +2 -2
- package/src/runtime/shared/tool-surface.mjs +98 -13
- package/src/runtime/shared/transcript-writer.mjs +156 -0
- package/src/runtime/shared/update-checker.mjs +214 -0
- package/src/session-runtime/config-helpers.mjs +209 -0
- package/src/session-runtime/effort.mjs +128 -0
- package/src/session-runtime/fs-utils.mjs +10 -0
- package/src/session-runtime/model-capabilities.mjs +130 -0
- package/src/session-runtime/output-styles.mjs +124 -0
- package/src/session-runtime/plugin-mcp.mjs +114 -0
- package/src/session-runtime/session-text.mjs +100 -0
- package/src/session-runtime/statusline-route.mjs +35 -0
- package/src/session-runtime/tool-catalog.mjs +720 -0
- package/src/session-runtime/workflow.mjs +358 -0
- package/src/standalone/agent-tool.mjs +302 -117
- package/src/standalone/channel-admin.mjs +133 -40
- package/src/standalone/channel-worker.mjs +10 -292
- package/src/standalone/explore-tool.mjs +12 -5
- package/src/standalone/hook-bus.mjs +165 -8
- package/src/standalone/memory-runtime-proxy.mjs +3 -1
- package/src/standalone/opencode-go-login.mjs +121 -0
- package/src/standalone/provider-admin.mjs +25 -3
- package/src/standalone/usage-dashboard.mjs +1 -1
- package/src/tui/App.jsx +2883 -778
- package/src/tui/components/ConfirmBar.jsx +47 -0
- package/src/tui/components/ContextPanel.jsx +5 -3
- package/src/tui/components/ItemRightHintOverprint.jsx +54 -0
- package/src/tui/components/Markdown.jsx +22 -98
- package/src/tui/components/Message.jsx +14 -35
- package/src/tui/components/Picker.jsx +87 -12
- package/src/tui/components/PromptInput.jsx +355 -22
- package/src/tui/components/QueuedCommands.jsx +1 -1
- package/src/tui/components/SlashCommandPalette.jsx +8 -5
- package/src/tui/components/Spinner.jsx +7 -7
- package/src/tui/components/StatusLine.jsx +40 -21
- package/src/tui/components/TextEntryPanel.jsx +51 -7
- package/src/tui/components/ToolExecution.jsx +183 -101
- package/src/tui/components/TurnDone.jsx +4 -4
- package/src/tui/components/UsagePanel.jsx +1 -1
- package/src/tui/components/tool-output-format.mjs +161 -23
- package/src/tui/components/tool-output-format.test.mjs +87 -0
- package/src/tui/display-width.mjs +69 -0
- package/src/tui/display-width.test.mjs +35 -0
- package/src/tui/dist/index.mjs +6731 -2333
- package/src/tui/engine/agent-envelope.mjs +296 -0
- package/src/tui/engine/boot-profile.mjs +21 -0
- package/src/tui/engine/labels.mjs +67 -0
- package/src/tui/engine/notice-text.mjs +112 -0
- package/src/tui/engine/queue-helpers.mjs +161 -0
- package/src/tui/engine/session-stats.mjs +46 -0
- package/src/tui/engine/tool-call-fields.mjs +23 -0
- package/src/tui/engine/tool-result-text.mjs +126 -0
- package/src/tui/engine.mjs +569 -948
- package/src/tui/index.jsx +117 -7
- package/src/tui/input-editing.mjs +58 -8
- package/src/tui/input-editing.selection.test.mjs +75 -0
- package/src/tui/keyboard-protocol.mjs +42 -0
- package/src/tui/lib/voice-recorder.mjs +469 -0
- package/src/tui/markdown/format-token.mjs +128 -76
- package/src/tui/markdown/format-token.test.mjs +61 -19
- package/src/tui/markdown/measure-rendered-rows.mjs +85 -0
- package/src/tui/markdown/render-ansi.test.mjs +1 -1
- package/src/tui/markdown/streaming-markdown.mjs +167 -0
- package/src/tui/markdown/streaming-markdown.test.mjs +70 -0
- package/src/tui/markdown/table-layout.mjs +9 -9
- package/src/tui/paste-attachments.mjs +36 -9
- package/src/tui/paste-fix.test.mjs +119 -0
- package/src/tui/prompt-history-store.mjs +129 -0
- package/src/tui/prompt-history-store.test.mjs +52 -0
- package/src/tui/statusline-ansi-bridge.test.mjs +3 -3
- package/src/tui/theme.mjs +41 -657
- package/src/tui/themes/base.mjs +86 -0
- package/src/tui/themes/basic.mjs +85 -0
- package/src/tui/themes/catppuccin.mjs +72 -0
- package/src/tui/themes/dracula.mjs +70 -0
- package/src/tui/themes/everforest.mjs +71 -0
- package/src/tui/themes/gruvbox.mjs +71 -0
- package/src/tui/themes/index.mjs +71 -0
- package/src/tui/themes/indigo.mjs +78 -0
- package/src/tui/themes/kanagawa.mjs +80 -0
- package/src/tui/themes/light.mjs +81 -0
- package/src/tui/themes/nord.mjs +72 -0
- package/src/tui/themes/onedark.mjs +16 -0
- package/src/tui/themes/rosepine.mjs +70 -0
- package/src/tui/themes/teal.mjs +80 -0
- package/src/tui/themes/tokyonight.mjs +79 -0
- package/src/tui/themes/utils.mjs +106 -0
- package/src/tui/themes/warm.mjs +79 -0
- package/src/tui/transcript-tool-failures.mjs +13 -2
- package/src/ui/markdown.mjs +1 -1
- package/src/ui/model-display.mjs +2 -2
- package/src/ui/statusline.mjs +75 -27
- package/src/vendor/statusline/bin/statusline-route.mjs +5 -12
- package/src/vendor/statusline/src/gateway/claude-current.mjs +3 -3
- package/src/vendor/statusline/src/gateway/route-meta.mjs +30 -16
- package/src/workflows/default/WORKFLOW.md +46 -12
- package/src/workflows/sequential/WORKFLOW.md +51 -0
- package/src/workflows/solo/WORKFLOW.md +12 -1
- package/vendor/ink/build/display-width.js +62 -0
- package/vendor/ink/build/ink.js +100 -12
- package/vendor/ink/build/measure-text.js +4 -1
- package/vendor/ink/build/output.js +115 -9
- package/vendor/ink/build/render-node-to-output.js +4 -1
- package/vendor/ink/build/render.js +4 -0
- package/src/output-styles/extreme-simple.md +0 -20
- package/src/rules/lead/04-workflow.md +0 -51
- package/src/workflows/default/workflow.json +0 -13
- package/src/workflows/solo/workflow.json +0 -7
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
deleteSecret,
|
|
15
15
|
diagnoseDiscordTokenValue,
|
|
16
16
|
getDiscordToken,
|
|
17
|
+
getTelegramToken,
|
|
17
18
|
getWebhookAuthtoken,
|
|
18
19
|
hasStoredSecret,
|
|
19
20
|
readSection,
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
updateSection,
|
|
22
23
|
} from '../runtime/shared/config.mjs';
|
|
23
24
|
import { resolvePluginData } from '../runtime/shared/plugin-paths.mjs';
|
|
25
|
+
import { readMarkdownDocument } from '../runtime/shared/markdown-frontmatter.mjs';
|
|
24
26
|
|
|
25
27
|
const NAME_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
26
28
|
const DEFAULT_CHANNELS = Object.freeze({
|
|
@@ -48,10 +50,6 @@ function webhooksDir() {
|
|
|
48
50
|
return join(dataDir(), 'webhooks');
|
|
49
51
|
}
|
|
50
52
|
|
|
51
|
-
function readJson(path, fallback = {}) {
|
|
52
|
-
try { return JSON.parse(readFileSync(path, 'utf8')); } catch { return fallback; }
|
|
53
|
-
}
|
|
54
|
-
|
|
55
53
|
function readText(path, fallback = '') {
|
|
56
54
|
try { return readFileSync(path, 'utf8'); } catch { return fallback; }
|
|
57
55
|
}
|
|
@@ -63,8 +61,22 @@ function writeTextAtomic(path, text) {
|
|
|
63
61
|
renameSync(tmp, path);
|
|
64
62
|
}
|
|
65
63
|
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
// Serialize a single-file frontmatter markdown document:
|
|
65
|
+
// ---
|
|
66
|
+
// key: value
|
|
67
|
+
// ---
|
|
68
|
+
//
|
|
69
|
+
// <body>
|
|
70
|
+
// Values are stringified as-is (enabled:false -> "false"); the reader casts
|
|
71
|
+
// types back. Mirrors the WORKFLOW.md / SKILL.md single-file convention.
|
|
72
|
+
function serializeFrontmatterDoc(meta = {}, body = '') {
|
|
73
|
+
const lines = ['---'];
|
|
74
|
+
for (const [key, value] of Object.entries(meta)) {
|
|
75
|
+
if (value === undefined || value === null) continue;
|
|
76
|
+
lines.push(`${key}: ${value}`);
|
|
77
|
+
}
|
|
78
|
+
lines.push('---', '');
|
|
79
|
+
return `${lines.join('\n')}\n${String(body || '').trim()}\n`;
|
|
68
80
|
}
|
|
69
81
|
|
|
70
82
|
function assertName(name, kind = 'name') {
|
|
@@ -88,6 +100,22 @@ function normalizeChannelsConfig(raw = {}) {
|
|
|
88
100
|
};
|
|
89
101
|
}
|
|
90
102
|
|
|
103
|
+
function channelIdForBackend(entry = {}, backend = 'discord') {
|
|
104
|
+
if (backend === 'telegram') {
|
|
105
|
+
return String(entry?.telegramChatId || (entry?.discordChannelId ? '' : entry?.channelId) || '');
|
|
106
|
+
}
|
|
107
|
+
return String(entry?.discordChannelId || (entry?.telegramChatId ? '' : entry?.channelId) || '');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function seedBackendChannelIds(entry = {}, backend = 'discord') {
|
|
111
|
+
const next = { ...(entry || {}) };
|
|
112
|
+
if (next.channelId) {
|
|
113
|
+
if (backend === 'telegram' && !next.telegramChatId && !next.discordChannelId) next.telegramChatId = next.channelId;
|
|
114
|
+
if (backend !== 'telegram' && !next.discordChannelId && !next.telegramChatId) next.discordChannelId = next.channelId;
|
|
115
|
+
}
|
|
116
|
+
return next;
|
|
117
|
+
}
|
|
118
|
+
|
|
91
119
|
function updateChannelsSection(build) {
|
|
92
120
|
let next;
|
|
93
121
|
updateSection('channels', (current) => {
|
|
@@ -110,11 +138,14 @@ function listEntryDirs(dir) {
|
|
|
110
138
|
|
|
111
139
|
export function listChannels(config = {}) {
|
|
112
140
|
const cfg = normalizeChannelsConfig(config);
|
|
141
|
+
const backend = cfg.backend === 'telegram' ? 'telegram' : 'discord';
|
|
113
142
|
return Object.entries(cfg.channelsConfig || {})
|
|
114
143
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
115
144
|
.map(([name, value]) => ({
|
|
116
145
|
name,
|
|
117
|
-
channelId:
|
|
146
|
+
channelId: channelIdForBackend(value, backend),
|
|
147
|
+
discordChannelId: String(value?.discordChannelId || ''),
|
|
148
|
+
telegramChatId: String(value?.telegramChatId || ''),
|
|
118
149
|
mode: value?.mode || 'interactive',
|
|
119
150
|
main: cfg.mainChannel === name,
|
|
120
151
|
}));
|
|
@@ -132,6 +163,18 @@ export function forgetDiscordToken() {
|
|
|
132
163
|
return { ok: true };
|
|
133
164
|
}
|
|
134
165
|
|
|
166
|
+
export function saveTelegramToken(token) {
|
|
167
|
+
const value = String(token || '').trim();
|
|
168
|
+
if (!value) throw new Error('Telegram bot token is required');
|
|
169
|
+
saveSecret(SECRET_ACCOUNTS.telegramToken, value);
|
|
170
|
+
return { ok: true, configured: Boolean(getTelegramToken()) };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function forgetTelegramToken() {
|
|
174
|
+
deleteSecret(SECRET_ACCOUNTS.telegramToken);
|
|
175
|
+
return { ok: true };
|
|
176
|
+
}
|
|
177
|
+
|
|
135
178
|
export function saveWebhookAuthtoken(token) {
|
|
136
179
|
const value = String(token || '').trim();
|
|
137
180
|
if (!value) throw new Error('Webhook/ngrok authtoken is required');
|
|
@@ -144,19 +187,31 @@ export function forgetWebhookAuthtoken() {
|
|
|
144
187
|
return { ok: true };
|
|
145
188
|
}
|
|
146
189
|
|
|
147
|
-
export function saveChannel({ name, channelId, mode = 'interactive', main = false } = {}) {
|
|
190
|
+
export function saveChannel({ name, channelId, mode = 'interactive', main = false, backend = null } = {}) {
|
|
148
191
|
const label = assertName(name, 'channel name');
|
|
149
192
|
const id = String(channelId || '').trim();
|
|
150
193
|
if (!id) throw new Error('channelId is required');
|
|
151
194
|
const nextMode = mode === 'broadcast' ? 'broadcast' : 'interactive';
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
channelsConfig
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
195
|
+
const targetBackend = backend === 'telegram' || backend === 'discord' ? backend : null;
|
|
196
|
+
return updateChannelsSection((cfg) => {
|
|
197
|
+
const activeBackend = cfg.backend === 'telegram' ? 'telegram' : 'discord';
|
|
198
|
+
const current = seedBackendChannelIds(cfg.channelsConfig?.[label] || {}, activeBackend);
|
|
199
|
+
const nextEntry = { ...current, mode: nextMode };
|
|
200
|
+
if (targetBackend === 'telegram') nextEntry.telegramChatId = id;
|
|
201
|
+
else if (targetBackend === 'discord') nextEntry.discordChannelId = id;
|
|
202
|
+
else nextEntry.channelId = id;
|
|
203
|
+
nextEntry.channelId = targetBackend
|
|
204
|
+
? (channelIdForBackend(nextEntry, activeBackend) || (targetBackend === activeBackend ? id : ''))
|
|
205
|
+
: id;
|
|
206
|
+
return {
|
|
207
|
+
...cfg,
|
|
208
|
+
mainChannel: main || !cfg.mainChannel ? label : cfg.mainChannel,
|
|
209
|
+
channelsConfig: {
|
|
210
|
+
...(cfg.channelsConfig || {}),
|
|
211
|
+
[label]: nextEntry,
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
});
|
|
160
215
|
}
|
|
161
216
|
|
|
162
217
|
export function deleteChannel(name) {
|
|
@@ -183,6 +238,25 @@ export function setWebhookConfig(patch = {}) {
|
|
|
183
238
|
}));
|
|
184
239
|
}
|
|
185
240
|
|
|
241
|
+
export function setBackend(name) {
|
|
242
|
+
const value = String(name || '').trim();
|
|
243
|
+
if (value !== 'discord' && value !== 'telegram') {
|
|
244
|
+
throw new Error('backend must be discord or telegram');
|
|
245
|
+
}
|
|
246
|
+
updateChannelsSection((cfg) => {
|
|
247
|
+
const activeBackend = cfg.backend === 'telegram' ? 'telegram' : 'discord';
|
|
248
|
+
const channelsConfig = Object.fromEntries(Object.entries(cfg.channelsConfig || {}).map(([key, entry]) => [
|
|
249
|
+
key,
|
|
250
|
+
(() => {
|
|
251
|
+
const seeded = seedBackendChannelIds(entry, activeBackend);
|
|
252
|
+
return { ...seeded, channelId: channelIdForBackend(seeded, value) };
|
|
253
|
+
})(),
|
|
254
|
+
]));
|
|
255
|
+
return { ...cfg, channelsConfig, backend: value };
|
|
256
|
+
});
|
|
257
|
+
return { ok: true, backend: value };
|
|
258
|
+
}
|
|
259
|
+
|
|
186
260
|
function normalizeCron(time) {
|
|
187
261
|
const value = String(time || '').trim();
|
|
188
262
|
const parts = value.split(/\s+/).filter(Boolean);
|
|
@@ -195,12 +269,15 @@ function normalizeCron(time) {
|
|
|
195
269
|
export function listSchedules() {
|
|
196
270
|
return listEntryDirs(schedulesDir()).map((name) => {
|
|
197
271
|
const dir = join(schedulesDir(), name);
|
|
198
|
-
const
|
|
199
|
-
const
|
|
272
|
+
const { frontmatter, body } = readMarkdownDocument(readText(join(dir, 'SCHEDULE.md'), ''));
|
|
273
|
+
const config = { ...frontmatter };
|
|
274
|
+
if (Object.prototype.hasOwnProperty.call(config, 'enabled')) {
|
|
275
|
+
config.enabled = config.enabled !== 'false' && config.enabled !== false;
|
|
276
|
+
}
|
|
200
277
|
return {
|
|
201
278
|
name,
|
|
202
279
|
...config,
|
|
203
|
-
instructions,
|
|
280
|
+
instructions: body,
|
|
204
281
|
route: config.channel ? `channel:${config.channel}` : 'session',
|
|
205
282
|
};
|
|
206
283
|
});
|
|
@@ -231,8 +308,7 @@ export function saveSchedule({
|
|
|
231
308
|
if (channel) config.channel = String(channel).trim();
|
|
232
309
|
if (model) config.model = String(model).trim();
|
|
233
310
|
if (enabled === false) config.enabled = false;
|
|
234
|
-
|
|
235
|
-
writeTextAtomic(join(dir, 'instructions.md'), body + '\n');
|
|
311
|
+
writeTextAtomic(join(dir, 'SCHEDULE.md'), serializeFrontmatterDoc(config, body));
|
|
236
312
|
return { name: id, ...config, instructions: body };
|
|
237
313
|
}
|
|
238
314
|
|
|
@@ -245,24 +321,31 @@ export function deleteSchedule(name) {
|
|
|
245
321
|
export function setScheduleEnabled(name, enabled) {
|
|
246
322
|
const id = assertName(name, 'schedule name');
|
|
247
323
|
const dir = join(schedulesDir(), id);
|
|
248
|
-
const
|
|
249
|
-
if (!existsSync(
|
|
250
|
-
const
|
|
251
|
-
|
|
324
|
+
const mdPath = join(dir, 'SCHEDULE.md');
|
|
325
|
+
if (!existsSync(mdPath)) throw new Error(`schedule "${id}" does not exist`);
|
|
326
|
+
const { frontmatter, body } = readMarkdownDocument(readText(mdPath, ''));
|
|
327
|
+
writeTextAtomic(mdPath, serializeFrontmatterDoc({ ...frontmatter, enabled: enabled !== false }, body));
|
|
252
328
|
return { name: id, enabled: enabled !== false };
|
|
253
329
|
}
|
|
254
330
|
|
|
255
331
|
export function listWebhooks() {
|
|
256
332
|
return listEntryDirs(webhooksDir()).map((name) => {
|
|
257
333
|
const dir = join(webhooksDir(), name);
|
|
258
|
-
const
|
|
259
|
-
const
|
|
334
|
+
const { frontmatter, body } = readMarkdownDocument(readText(join(dir, 'WEBHOOK.md'), ''));
|
|
335
|
+
const config = { ...frontmatter };
|
|
336
|
+
if (Object.prototype.hasOwnProperty.call(config, 'enabled')) {
|
|
337
|
+
config.enabled = config.enabled !== 'false' && config.enabled !== false;
|
|
338
|
+
}
|
|
339
|
+
// Secret lives in a side file (<name>/secret), never in frontmatter, so
|
|
340
|
+
// an arbitrary user-supplied secret (quotes/colon/newline) round-trips
|
|
341
|
+
// losslessly and setWebhookEnabled cannot corrupt it.
|
|
342
|
+
const hasSecret = Boolean(readText(join(dir, 'secret'), '').trim());
|
|
260
343
|
return {
|
|
261
344
|
name,
|
|
262
345
|
...config,
|
|
263
|
-
secretSet:
|
|
346
|
+
secretSet: hasSecret,
|
|
264
347
|
secret: undefined,
|
|
265
|
-
instructions,
|
|
348
|
+
instructions: body,
|
|
266
349
|
route: config.channel ? `channel:${config.channel}` : 'session',
|
|
267
350
|
};
|
|
268
351
|
});
|
|
@@ -289,16 +372,17 @@ export function saveWebhook({
|
|
|
289
372
|
const dir = join(webhooksDir(), id);
|
|
290
373
|
if (existsSync(dir) && overwrite !== true) throw new Error(`webhook "${id}" already exists`);
|
|
291
374
|
mkdirSync(dir, { recursive: true });
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
parser: nextParser,
|
|
295
|
-
};
|
|
375
|
+
const secretValue = String(secret || randomBytes(24).toString('hex')).trim();
|
|
376
|
+
const config = { parser: nextParser };
|
|
296
377
|
if (channel) config.channel = String(channel).trim();
|
|
297
378
|
if (model) config.model = String(model).trim();
|
|
298
379
|
if (enabled === false) config.enabled = false;
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
380
|
+
// Secret to a side file (plaintext, same exposure level as the former
|
|
381
|
+
// config.json), kept OUT of the frontmatter to avoid unquote round-trip
|
|
382
|
+
// corruption. deleteWebhook rmSync's the whole dir, so this is removed too.
|
|
383
|
+
writeTextAtomic(join(dir, 'secret'), secretValue + '\n');
|
|
384
|
+
writeTextAtomic(join(dir, 'WEBHOOK.md'), serializeFrontmatterDoc(config, body));
|
|
385
|
+
return { name: id, ...config, secret: secretValue, instructions: body };
|
|
302
386
|
}
|
|
303
387
|
|
|
304
388
|
export function deleteWebhook(name) {
|
|
@@ -310,10 +394,10 @@ export function deleteWebhook(name) {
|
|
|
310
394
|
export function setWebhookEnabled(name, enabled) {
|
|
311
395
|
const id = assertName(name, 'webhook name');
|
|
312
396
|
const dir = join(webhooksDir(), id);
|
|
313
|
-
const
|
|
314
|
-
if (!existsSync(
|
|
315
|
-
const
|
|
316
|
-
|
|
397
|
+
const mdPath = join(dir, 'WEBHOOK.md');
|
|
398
|
+
if (!existsSync(mdPath)) throw new Error(`webhook "${id}" does not exist`);
|
|
399
|
+
const { frontmatter, body } = readMarkdownDocument(readText(mdPath, ''));
|
|
400
|
+
writeTextAtomic(mdPath, serializeFrontmatterDoc({ ...frontmatter, enabled: enabled !== false }, body));
|
|
317
401
|
return { name: id, enabled: enabled !== false };
|
|
318
402
|
}
|
|
319
403
|
|
|
@@ -322,7 +406,9 @@ export function channelSetup(config = null) {
|
|
|
322
406
|
const discordToken = getDiscordToken();
|
|
323
407
|
const discordProblem = diagnoseDiscordTokenValue(discordToken, cfg);
|
|
324
408
|
const webhookAuth = getWebhookAuthtoken();
|
|
409
|
+
const telegramToken = getTelegramToken();
|
|
325
410
|
return {
|
|
411
|
+
backend: cfg.backend || 'discord',
|
|
326
412
|
discord: {
|
|
327
413
|
backend: 'discord',
|
|
328
414
|
authenticated: Boolean(discordToken && !discordProblem),
|
|
@@ -330,6 +416,13 @@ export function channelSetup(config = null) {
|
|
|
330
416
|
status: discordToken ? (discordProblem ? 'Invalid' : 'Set') : 'Off',
|
|
331
417
|
problem: discordProblem || null,
|
|
332
418
|
},
|
|
419
|
+
telegram: {
|
|
420
|
+
backend: 'telegram',
|
|
421
|
+
authenticated: Boolean(telegramToken),
|
|
422
|
+
stored: hasStoredSecret(SECRET_ACCOUNTS.telegramToken),
|
|
423
|
+
status: telegramToken ? 'Set' : 'Off',
|
|
424
|
+
problem: null,
|
|
425
|
+
},
|
|
333
426
|
webhook: {
|
|
334
427
|
...(cfg.webhook || {}),
|
|
335
428
|
authenticated: Boolean(webhookAuth),
|