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
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { execFile, fork, spawnSync } from 'node:child_process';
|
|
2
|
-
import {
|
|
3
|
-
import http from 'node:http';
|
|
2
|
+
import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
4
3
|
import { tmpdir } from 'node:os';
|
|
5
4
|
import { dirname, join, resolve } from 'node:path';
|
|
6
5
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
7
6
|
import { startChildGuardian } from '../runtime/shared/child-guardian.mjs';
|
|
8
|
-
import {
|
|
7
|
+
import { appendBuffered } from '../runtime/shared/buffered-appender.mjs';
|
|
9
8
|
|
|
10
9
|
const CHANNEL_TOOLS = new Set([
|
|
11
10
|
'reply',
|
|
@@ -26,7 +25,7 @@ const WORKER_PRELOAD = fileURLToPath(new URL('./channel-worker-preload.cjs', imp
|
|
|
26
25
|
function logLine(path, line) {
|
|
27
26
|
try {
|
|
28
27
|
mkdirSync(dirname(path), { recursive: true });
|
|
29
|
-
|
|
28
|
+
appendBuffered(path, `[${new Date().toISOString()}] ${line}\n`);
|
|
30
29
|
} catch {
|
|
31
30
|
// Logging must never break the TUI.
|
|
32
31
|
}
|
|
@@ -56,67 +55,6 @@ function runtimeRoot() {
|
|
|
56
55
|
return process.env.MIXDOG_RUNTIME_ROOT ? resolve(process.env.MIXDOG_RUNTIME_ROOT) : join(tmpdir(), 'mixdog');
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
function readJson(path) {
|
|
60
|
-
try { return JSON.parse(readFileSync(path, 'utf8')); } catch { return null; }
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function parsePort(value) {
|
|
64
|
-
const port = Number(value);
|
|
65
|
-
return Number.isInteger(port) && port > 0 && port < 65536 ? port : null;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function readActiveInstance() {
|
|
69
|
-
return readJson(join(runtimeRoot(), 'active-instance.json'));
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function readOwnerSecret(instanceId) {
|
|
73
|
-
const parsed = readJson(join(runtimeRoot(), `owner-secret-${String(instanceId)}.json`));
|
|
74
|
-
return typeof parsed?.secret === 'string' ? parsed.secret : '';
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function requestJson({ port, method = 'GET', path = '/', body = null, headers = {}, timeoutMs = 120_000 }) {
|
|
78
|
-
return new Promise((resolvePromise, reject) => {
|
|
79
|
-
const payload = body == null ? null : JSON.stringify(body);
|
|
80
|
-
const req = http.request({
|
|
81
|
-
hostname: '127.0.0.1',
|
|
82
|
-
port,
|
|
83
|
-
path,
|
|
84
|
-
method,
|
|
85
|
-
headers: {
|
|
86
|
-
...headers,
|
|
87
|
-
...(payload
|
|
88
|
-
? { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) }
|
|
89
|
-
: {}),
|
|
90
|
-
},
|
|
91
|
-
timeout: timeoutMs,
|
|
92
|
-
}, (res) => {
|
|
93
|
-
let data = '';
|
|
94
|
-
res.setEncoding('utf8');
|
|
95
|
-
res.on('data', chunk => { data += chunk; });
|
|
96
|
-
res.on('end', () => {
|
|
97
|
-
let parsed = null;
|
|
98
|
-
try { parsed = data ? JSON.parse(data) : null; } catch {}
|
|
99
|
-
if (res.statusCode && res.statusCode >= 400) {
|
|
100
|
-
reject(new Error(parsed?.error || data || `HTTP ${res.statusCode}`));
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
resolvePromise(parsed ?? { raw: data });
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
req.on('error', reject);
|
|
107
|
-
req.on('timeout', () => {
|
|
108
|
-
req.destroy();
|
|
109
|
-
reject(new Error(`channel owner request timed out: ${method} ${path}`));
|
|
110
|
-
});
|
|
111
|
-
if (payload) req.write(payload);
|
|
112
|
-
req.end();
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function textResult(text, isError = false) {
|
|
117
|
-
return { content: [{ type: 'text', text: String(text ?? '') }], ...(isError ? { isError: true } : {}) };
|
|
118
|
-
}
|
|
119
|
-
|
|
120
58
|
export function createStandaloneChannelWorker({
|
|
121
59
|
entry,
|
|
122
60
|
rootDir,
|
|
@@ -141,16 +79,8 @@ export function createStandaloneChannelWorker({
|
|
|
141
79
|
const ownedChildPids = new Set();
|
|
142
80
|
const logPath = join(dataDir, 'channels-worker-standalone.log');
|
|
143
81
|
const useProcessWorker = process.env.MIXDOG_CHANNEL_WORKER_PROCESS !== '0';
|
|
144
|
-
const singletonEnabled = process.env.MIXDOG_CHANNEL_SINGLETON !== '0';
|
|
145
|
-
const daemonEnabled = process.env.MIXDOG_CHANNEL_DAEMON !== '0';
|
|
146
|
-
const ownerPath = join(dataDir, 'channels-worker-owner.json');
|
|
147
|
-
const notifyBusPath = join(runtimeRoot(), 'channel-notifications.jsonl');
|
|
148
82
|
const clientDir = join(runtimeRoot(), 'channel-clients');
|
|
149
83
|
const clientPath = join(clientDir, `${process.pid}.json`);
|
|
150
|
-
let ownerClaim = null;
|
|
151
|
-
let ownerPid = process.pid;
|
|
152
|
-
let notifyBusTimer = null;
|
|
153
|
-
let notifyBusOffset = 0;
|
|
154
84
|
let clientHeartbeatTimer = null;
|
|
155
85
|
let clientHeartbeatExitCleanup = null;
|
|
156
86
|
|
|
@@ -186,56 +116,9 @@ export function createStandaloneChannelWorker({
|
|
|
186
116
|
try { rmSync(clientPath, { force: true }); } catch {}
|
|
187
117
|
}
|
|
188
118
|
|
|
189
|
-
function startNotifyBus() {
|
|
190
|
-
if (!onNotify || notifyBusTimer) return;
|
|
191
|
-
try { notifyBusOffset = statSync(notifyBusPath).size; } catch { notifyBusOffset = 0; }
|
|
192
|
-
notifyBusTimer = setInterval(pollNotifyBus, 500);
|
|
193
|
-
notifyBusTimer.unref?.();
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function stopNotifyBus() {
|
|
197
|
-
if (!notifyBusTimer) return;
|
|
198
|
-
clearInterval(notifyBusTimer);
|
|
199
|
-
notifyBusTimer = null;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function pollNotifyBus() {
|
|
203
|
-
let size = 0;
|
|
204
|
-
try { size = statSync(notifyBusPath).size; } catch { return; }
|
|
205
|
-
if (size < notifyBusOffset) notifyBusOffset = 0;
|
|
206
|
-
if (size === notifyBusOffset) return;
|
|
207
|
-
let chunk;
|
|
208
|
-
try {
|
|
209
|
-
const data = readFileSync(notifyBusPath);
|
|
210
|
-
chunk = data.subarray(notifyBusOffset, size).toString('utf8');
|
|
211
|
-
notifyBusOffset = size;
|
|
212
|
-
} catch {
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
for (const line of chunk.split(/\r?\n/)) {
|
|
216
|
-
if (!line.trim()) continue;
|
|
217
|
-
try {
|
|
218
|
-
const msg = JSON.parse(line);
|
|
219
|
-
if (!msg || typeof msg !== 'object') continue;
|
|
220
|
-
onNotify({ type: 'notify', method: msg.method, params: msg.params, busId: msg.id, busPid: msg.pid });
|
|
221
|
-
} catch {}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
startNotifyBus();
|
|
226
119
|
startClientHeartbeat();
|
|
227
120
|
|
|
228
121
|
function status() {
|
|
229
|
-
const external = externalOwner();
|
|
230
|
-
if (external) {
|
|
231
|
-
return {
|
|
232
|
-
running: false,
|
|
233
|
-
pid: null,
|
|
234
|
-
pending: pending.size,
|
|
235
|
-
mode: 'external-owner',
|
|
236
|
-
ownerPid: Number(external.pid) || null,
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
122
|
if (!useProcessWorker) {
|
|
240
123
|
return {
|
|
241
124
|
running: Boolean(inProcessMod),
|
|
@@ -252,36 +135,6 @@ export function createStandaloneChannelWorker({
|
|
|
252
135
|
};
|
|
253
136
|
}
|
|
254
137
|
|
|
255
|
-
function externalOwner() {
|
|
256
|
-
if (!singletonEnabled || ownerClaim?.owned) return null;
|
|
257
|
-
const current = readSingletonOwner(ownerPath);
|
|
258
|
-
if (current.alive && current.owner?.pid && Number(current.owner.pid) !== process.pid) return current.owner;
|
|
259
|
-
return null;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
function ensureOwner() {
|
|
263
|
-
if (!singletonEnabled || ownerClaim?.owned) return true;
|
|
264
|
-
ownerClaim = claimSingletonOwner(ownerPath, {
|
|
265
|
-
kind: 'channel-worker-host',
|
|
266
|
-
pid: process.pid,
|
|
267
|
-
meta: { cwd },
|
|
268
|
-
});
|
|
269
|
-
if (!ownerClaim.owned) {
|
|
270
|
-
logLine(logPath, `runtime owned by pid ${ownerClaim.owner?.pid || 'unknown'}; skipping local channel worker`);
|
|
271
|
-
return false;
|
|
272
|
-
}
|
|
273
|
-
installParentExitHook();
|
|
274
|
-
return true;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function releaseOwner() {
|
|
278
|
-
if (!singletonEnabled || !ownerClaim?.owned) return;
|
|
279
|
-
releaseSingletonOwner(ownerPath, ownerPid);
|
|
280
|
-
ownerClaim = null;
|
|
281
|
-
ownerPid = process.pid;
|
|
282
|
-
uninstallParentExitHook();
|
|
283
|
-
}
|
|
284
|
-
|
|
285
138
|
function rejectPending(error) {
|
|
286
139
|
for (const [, item] of pending) {
|
|
287
140
|
clearTimeout(item.timer);
|
|
@@ -292,7 +145,6 @@ export function createStandaloneChannelWorker({
|
|
|
292
145
|
|
|
293
146
|
function start() {
|
|
294
147
|
if (!useProcessWorker) return startInProcess();
|
|
295
|
-
if (!ensureOwner()) return Promise.resolve(status());
|
|
296
148
|
if (stopPromise) {
|
|
297
149
|
return stopPromise.then(() => start());
|
|
298
150
|
}
|
|
@@ -306,35 +158,21 @@ export function createStandaloneChannelWorker({
|
|
|
306
158
|
cwd,
|
|
307
159
|
execArgv: ['--require', WORKER_PRELOAD],
|
|
308
160
|
stdio: ['ignore', 'ignore', 'pipe', 'ipc'],
|
|
309
|
-
detached:
|
|
161
|
+
detached: false,
|
|
310
162
|
env: {
|
|
311
163
|
...process.env,
|
|
312
164
|
MIXDOG_ROOT: rootDir,
|
|
313
165
|
MIXDOG_DATA_DIR: dataDir,
|
|
314
166
|
MIXDOG_STANDALONE: '1',
|
|
315
167
|
MIXDOG_WORKER_MODE: '1',
|
|
316
|
-
MIXDOG_CLI_OWNED:
|
|
317
|
-
MIXDOG_CHANNEL_DAEMON: daemonEnabled ? '1' : '0',
|
|
318
|
-
MIXDOG_CHANNELS_AUTO_BOOT: '0',
|
|
319
|
-
MIXDOG_CHANNEL_FLAG: '1',
|
|
168
|
+
MIXDOG_CLI_OWNED: '0',
|
|
320
169
|
MIXDOG_QUIET_SESSION_LOG: process.env.MIXDOG_QUIET_SESSION_LOG ?? '1',
|
|
321
170
|
},
|
|
322
171
|
windowsHide: true,
|
|
323
172
|
});
|
|
324
173
|
const spawnedPid = child.pid;
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
ownerClaim = claimSingletonOwner(ownerPath, {
|
|
328
|
-
kind: 'channel-worker-daemon',
|
|
329
|
-
pid: spawnedPid,
|
|
330
|
-
meta: { cwd, launcherPid: process.pid },
|
|
331
|
-
});
|
|
332
|
-
ownerPid = spawnedPid;
|
|
333
|
-
}
|
|
334
|
-
if (!daemonEnabled) {
|
|
335
|
-
startChildGuardian({ childPid: spawnedPid, label: 'channel-worker', orphanGraceMs: 8000, forceGraceMs: 3000 });
|
|
336
|
-
if (spawnedPid) ownedChildPids.add(spawnedPid);
|
|
337
|
-
}
|
|
174
|
+
startChildGuardian({ childPid: spawnedPid, label: 'channel-worker', orphanGraceMs: 8000, forceGraceMs: 3000 });
|
|
175
|
+
if (spawnedPid) ownedChildPids.add(spawnedPid);
|
|
338
176
|
installParentExitHook();
|
|
339
177
|
|
|
340
178
|
child.stderr?.on('data', (chunk) => {
|
|
@@ -360,19 +198,12 @@ export function createStandaloneChannelWorker({
|
|
|
360
198
|
return;
|
|
361
199
|
}
|
|
362
200
|
if (msg.type === 'notify') {
|
|
363
|
-
|
|
364
|
-
try { onNotify?.(msg); } catch {}
|
|
365
|
-
}
|
|
201
|
+
try { onNotify?.(msg); } catch {}
|
|
366
202
|
}
|
|
367
203
|
});
|
|
368
204
|
|
|
369
205
|
child.on('exit', (code, signal) => {
|
|
370
206
|
if (spawnedPid) ownedChildPids.delete(spawnedPid);
|
|
371
|
-
if (daemonEnabled && spawnedPid) releaseSingletonOwner(ownerPath, spawnedPid);
|
|
372
|
-
if (daemonEnabled && ownerPid === spawnedPid) {
|
|
373
|
-
ownerClaim = null;
|
|
374
|
-
ownerPid = process.pid;
|
|
375
|
-
}
|
|
376
207
|
const error = new Error(`channels runtime exited (${signal || (code ?? 'unknown')})`);
|
|
377
208
|
if (readyReject) readyReject(error);
|
|
378
209
|
readyResolve = null;
|
|
@@ -394,16 +225,12 @@ export function createStandaloneChannelWorker({
|
|
|
394
225
|
}
|
|
395
226
|
|
|
396
227
|
async function startInProcess() {
|
|
397
|
-
if (!ensureOwner()) return status();
|
|
398
228
|
if (inProcessMod) return status();
|
|
399
229
|
if (inProcessStartPromise) return inProcessStartPromise;
|
|
400
230
|
inProcessStartPromise = (async () => {
|
|
401
231
|
process.env.MIXDOG_ROOT = rootDir;
|
|
402
232
|
process.env.MIXDOG_DATA_DIR = dataDir;
|
|
403
233
|
process.env.MIXDOG_STANDALONE ??= '1';
|
|
404
|
-
process.env.MIXDOG_CHANNEL_FLAG ??= '1';
|
|
405
|
-
process.env.MIXDOG_CHANNELS_AUTO_BOOT = '0';
|
|
406
|
-
process.env.MIXDOG_CLI_OWNED = '1';
|
|
407
234
|
const mod = await import(pathToFileURL(entry).href);
|
|
408
235
|
if (typeof mod?.start !== 'function') throw new Error('channels runtime does not export start()');
|
|
409
236
|
await mod.start();
|
|
@@ -417,9 +244,6 @@ export function createStandaloneChannelWorker({
|
|
|
417
244
|
|
|
418
245
|
async function execute(name, args = {}, { timeoutMs = 120_000 } = {}) {
|
|
419
246
|
if (!CHANNEL_TOOLS.has(name)) throw new Error(`unknown channel tool: ${name}`);
|
|
420
|
-
if (!ensureOwner()) {
|
|
421
|
-
return await executeViaOwnerHttp(name, args || {}, timeoutMs);
|
|
422
|
-
}
|
|
423
247
|
await start();
|
|
424
248
|
if (!useProcessWorker) {
|
|
425
249
|
const call = inProcessMod?.handleToolCallWithBridgeRetry || inProcessMod?.handleToolCall;
|
|
@@ -453,91 +277,6 @@ export function createStandaloneChannelWorker({
|
|
|
453
277
|
});
|
|
454
278
|
}
|
|
455
279
|
|
|
456
|
-
async function executeViaOwnerHttp(name, args, timeoutMs) {
|
|
457
|
-
const active = readActiveInstance();
|
|
458
|
-
const port = parsePort(active?.httpPort);
|
|
459
|
-
const instanceId = active?.instanceId;
|
|
460
|
-
const token = readOwnerSecret(instanceId);
|
|
461
|
-
if (!port || !token) {
|
|
462
|
-
const owner = externalOwner();
|
|
463
|
-
throw new Error(`channels runtime is owned by pid ${owner?.pid || 'unknown'} but owner HTTP is unavailable`);
|
|
464
|
-
}
|
|
465
|
-
const headers = {
|
|
466
|
-
'x-owner-token': token,
|
|
467
|
-
'x-owner-instance': String(instanceId || ''),
|
|
468
|
-
};
|
|
469
|
-
const post = (path, body) => requestJson({ port, method: 'POST', path, body, headers, timeoutMs });
|
|
470
|
-
const get = (path) => requestJson({ port, method: 'GET', path, headers, timeoutMs });
|
|
471
|
-
|
|
472
|
-
switch (name) {
|
|
473
|
-
case 'reply': {
|
|
474
|
-
const result = await post('/send', {
|
|
475
|
-
chatId: args.chat_id,
|
|
476
|
-
text: args.text,
|
|
477
|
-
opts: {
|
|
478
|
-
replyTo: args.reply_to,
|
|
479
|
-
files: args.files ?? [],
|
|
480
|
-
embeds: args.embeds ?? [],
|
|
481
|
-
components: args.components ?? [],
|
|
482
|
-
},
|
|
483
|
-
});
|
|
484
|
-
const ids = Array.isArray(result?.sentIds) ? result.sentIds : [];
|
|
485
|
-
return textResult(ids.length === 1 ? `sent (id: ${ids[0]})` : `sent ${ids.length} parts (ids: ${ids.join(', ')})`);
|
|
486
|
-
}
|
|
487
|
-
case 'fetch': {
|
|
488
|
-
const channel = encodeURIComponent(String(args.channel || ''));
|
|
489
|
-
const limit = Math.max(1, Number(args.limit) || 20);
|
|
490
|
-
const result = await get(`/fetch?channel=${channel}&limit=${limit}`);
|
|
491
|
-
const msgs = Array.isArray(result?.messages) ? result.messages : [];
|
|
492
|
-
const text = msgs.length === 0 ? '(no messages)' : msgs.map((m) => {
|
|
493
|
-
const atts = Number(m.attachmentCount) > 0 ? ` +${m.attachmentCount}att` : '';
|
|
494
|
-
return `[${m.ts}] ${m.user}: ${m.text} (id: ${m.id}${atts})`;
|
|
495
|
-
}).join('\n');
|
|
496
|
-
return textResult(text);
|
|
497
|
-
}
|
|
498
|
-
case 'react':
|
|
499
|
-
await post('/react', { chatId: args.chat_id, messageId: args.message_id, emoji: args.emoji });
|
|
500
|
-
return textResult('reacted');
|
|
501
|
-
case 'edit_message': {
|
|
502
|
-
const result = await post('/edit', {
|
|
503
|
-
chatId: args.chat_id,
|
|
504
|
-
messageId: args.message_id,
|
|
505
|
-
text: args.text,
|
|
506
|
-
opts: { embeds: args.embeds ?? [], components: args.components ?? [] },
|
|
507
|
-
});
|
|
508
|
-
return textResult(`edited (id: ${result?.id ?? ''})`);
|
|
509
|
-
}
|
|
510
|
-
case 'download_attachment': {
|
|
511
|
-
const result = await post('/download', { chatId: args.chat_id, messageId: args.message_id });
|
|
512
|
-
const files = Array.isArray(result?.files) ? result.files : [];
|
|
513
|
-
if (files.length === 0) return textResult('message has no attachments');
|
|
514
|
-
return textResult(`downloaded ${files.length} attachment(s):\n${files.map((f) => ` ${f.path} (${f.name}, ${f.contentType}, ${(Number(f.size || 0) / 1024).toFixed(0)}KB)`).join('\n')}`);
|
|
515
|
-
}
|
|
516
|
-
case 'schedule_status': {
|
|
517
|
-
const result = await get('/schedule-status');
|
|
518
|
-
return result?.result ?? textResult('no schedules configured');
|
|
519
|
-
}
|
|
520
|
-
case 'trigger_schedule': {
|
|
521
|
-
const result = await post('/trigger-schedule', { name: args.name });
|
|
522
|
-
return textResult(result?.result == null ? '' : String(result.result));
|
|
523
|
-
}
|
|
524
|
-
case 'schedule_control': {
|
|
525
|
-
const result = await post('/schedule-control', { name: args.name, action: args.action, minutes: args.minutes });
|
|
526
|
-
return result?.result ?? textResult(`unknown action: ${args.action}`, true);
|
|
527
|
-
}
|
|
528
|
-
case 'activate_channel_bridge':
|
|
529
|
-
await post('/bridge/activate', { active: args.active === true });
|
|
530
|
-
return textResult(`channel bridge ${args.active ? 'activated' : 'deactivated'}`);
|
|
531
|
-
case 'inject_command':
|
|
532
|
-
await post('/inject', { content: `/${String(args.command || '').trim()}`, source: 'mixdog-agent', type: 'command' });
|
|
533
|
-
return textResult(`queued /${String(args.command || '').trim()} via channel owner`);
|
|
534
|
-
case 'reload_config':
|
|
535
|
-
return textResult('reload_config must run in the channel owner process', true);
|
|
536
|
-
default:
|
|
537
|
-
return textResult(`unknown channel tool: ${name}`, true);
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
280
|
function forceKillTree(pid) {
|
|
542
281
|
if (!pid) return;
|
|
543
282
|
if (process.platform === 'win32') {
|
|
@@ -565,11 +304,8 @@ export function createStandaloneChannelWorker({
|
|
|
565
304
|
if (parentExitCleanup) return;
|
|
566
305
|
parentExitCleanup = registerChannelWorkerExitCleanup(() => {
|
|
567
306
|
parentExitCleanup = null;
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
forceKillTreeSync(pid);
|
|
571
|
-
}
|
|
572
|
-
releaseOwner();
|
|
307
|
+
for (const pid of Array.from(ownedChildPids)) {
|
|
308
|
+
forceKillTreeSync(pid);
|
|
573
309
|
}
|
|
574
310
|
ownedChildPids.clear();
|
|
575
311
|
});
|
|
@@ -592,12 +328,10 @@ export function createStandaloneChannelWorker({
|
|
|
592
328
|
|
|
593
329
|
function stop(reason = 'standalone shutdown', options = {}) {
|
|
594
330
|
const waitForExit = options?.waitForExit !== false;
|
|
595
|
-
stopNotifyBus();
|
|
596
331
|
stopClientHeartbeat();
|
|
597
332
|
if (stopPromise) return stopPromise;
|
|
598
333
|
if (!useProcessWorker) {
|
|
599
334
|
if (!inProcessMod && !inProcessStartPromise) {
|
|
600
|
-
releaseOwner();
|
|
601
335
|
return Promise.resolve(false);
|
|
602
336
|
}
|
|
603
337
|
stopPromise = Promise.resolve(inProcessStartPromise)
|
|
@@ -605,7 +339,6 @@ export function createStandaloneChannelWorker({
|
|
|
605
339
|
.then(async () => {
|
|
606
340
|
try { await inProcessMod?.stop?.(reason); } catch {}
|
|
607
341
|
inProcessMod = null;
|
|
608
|
-
releaseOwner();
|
|
609
342
|
return true;
|
|
610
343
|
})
|
|
611
344
|
.finally(() => {
|
|
@@ -614,23 +347,11 @@ export function createStandaloneChannelWorker({
|
|
|
614
347
|
return stopPromise;
|
|
615
348
|
}
|
|
616
349
|
if (!child) {
|
|
617
|
-
stopNotifyBus();
|
|
618
|
-
releaseOwner();
|
|
619
350
|
return Promise.resolve(false);
|
|
620
351
|
}
|
|
621
352
|
const target = child;
|
|
622
353
|
const targetPid = target.pid;
|
|
623
354
|
child = null;
|
|
624
|
-
if (daemonEnabled && options?.force !== true) {
|
|
625
|
-
rejectPending(new Error(`channels runtime detached (${reason})`));
|
|
626
|
-
if (targetPid) ownedChildPids.delete(targetPid);
|
|
627
|
-
try { target.disconnect?.(); } catch {}
|
|
628
|
-
unrefChildHandles(target);
|
|
629
|
-
ownerClaim = null;
|
|
630
|
-
ownerPid = process.pid;
|
|
631
|
-
uninstallParentExitHook();
|
|
632
|
-
return Promise.resolve(true);
|
|
633
|
-
}
|
|
634
355
|
if (!waitForExit) {
|
|
635
356
|
rejectPending(new Error(`channels runtime shutdown requested (${reason})`));
|
|
636
357
|
if (targetPid) ownedChildPids.delete(targetPid);
|
|
@@ -642,7 +363,6 @@ export function createStandaloneChannelWorker({
|
|
|
642
363
|
clearTimeout(sendTimer);
|
|
643
364
|
stopPromise = null;
|
|
644
365
|
unrefChildHandles(target);
|
|
645
|
-
releaseOwner();
|
|
646
366
|
uninstallParentExitHook();
|
|
647
367
|
resolve(ok);
|
|
648
368
|
};
|
|
@@ -667,8 +387,6 @@ export function createStandaloneChannelWorker({
|
|
|
667
387
|
clearTimeout(termTimer);
|
|
668
388
|
clearTimeout(killTimer);
|
|
669
389
|
stopPromise = null;
|
|
670
|
-
stopNotifyBus();
|
|
671
|
-
releaseOwner();
|
|
672
390
|
uninstallParentExitHook();
|
|
673
391
|
resolve(ok);
|
|
674
392
|
};
|
|
@@ -14,7 +14,7 @@ export const EXPLORE_TOOL = {
|
|
|
14
14
|
name: 'explore',
|
|
15
15
|
title: 'Explore',
|
|
16
16
|
annotations: { title: 'Explore', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
17
|
-
description: 'Repo anchor locator.
|
|
17
|
+
description: 'Repo anchor locator. LLM-backed; broad/uncertain only. Array only for independent targets.',
|
|
18
18
|
inputSchema: {
|
|
19
19
|
type: 'object',
|
|
20
20
|
properties: {
|
|
@@ -170,8 +170,12 @@ function findConfigPreset(config, presetName) {
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
async function ensureExploreProviderReady(config) {
|
|
173
|
-
const
|
|
174
|
-
|
|
173
|
+
const route = config?.maintenance?.explore;
|
|
174
|
+
// Route object ({provider,model}) is the current shape; a string is a
|
|
175
|
+
// legacy preset NAME resolved against config.presets.
|
|
176
|
+
const provider = (route && typeof route === 'object')
|
|
177
|
+
? clean(route.provider)
|
|
178
|
+
: clean(findConfigPreset(config, route)?.provider);
|
|
175
179
|
if (!provider) return;
|
|
176
180
|
const providers = { ...(config?.providers || {}) };
|
|
177
181
|
providers[provider] = { ...(providers[provider] || {}), enabled: true };
|
|
@@ -303,9 +307,12 @@ async function runExploreSync(args = {}, ctx = {}) {
|
|
|
303
307
|
scheduleExploreCodeGraphPrewarm(resolvedCwd);
|
|
304
308
|
const config = loadConfig();
|
|
305
309
|
await ensureExploreProviderReady(config);
|
|
306
|
-
const
|
|
310
|
+
const route = config?.maintenance?.explore;
|
|
311
|
+
const presetName = (route && typeof route === 'object')
|
|
312
|
+
? `${clean(route.provider)}/${clean(route.model)}`
|
|
313
|
+
: (route || '');
|
|
307
314
|
const llm = makeAgentDispatch({
|
|
308
|
-
|
|
315
|
+
agent: 'explorer',
|
|
309
316
|
cwd: resolvedCwd,
|
|
310
317
|
brief: true,
|
|
311
318
|
parentSessionId: ctx.callerSessionId || null,
|