mixdog 0.8.0 → 0.9.0
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/README.md +47 -23
- package/package.json +33 -27
- package/scripts/_test-folder-dialog.mjs +30 -0
- package/scripts/agent-parallel-smoke.mjs +388 -0
- package/scripts/agent-tag-reuse-smoke.mjs +183 -0
- package/scripts/background-task-meta-smoke.mjs +38 -0
- package/scripts/boot-smoke.mjs +52 -9
- package/scripts/build-runtime-linux.sh +348 -0
- package/scripts/build-runtime-macos.sh +217 -0
- package/scripts/build-runtime-windows.ps1 +242 -0
- package/scripts/compact-active-turn-test.mjs +68 -0
- package/scripts/compact-smoke.mjs +859 -129
- package/scripts/compact-trigger-migration-smoke.mjs +187 -0
- package/scripts/fix-brief-fn.mjs +35 -0
- package/scripts/fix-format-tool-surface.mjs +24 -0
- package/scripts/fix-tool-exec-visible.mjs +42 -0
- package/scripts/generate-runtime-manifest.mjs +166 -0
- package/scripts/hook-bus-test.mjs +330 -0
- package/scripts/lead-workflow-smoke.mjs +33 -39
- package/scripts/live-worker-smoke.mjs +43 -37
- package/scripts/llm-trace-summary.mjs +315 -0
- package/scripts/memory-meta-concurrency-test.mjs +20 -0
- package/scripts/output-style-smoke.mjs +56 -15
- package/scripts/parent-abort-link-test.mjs +44 -0
- package/scripts/patch-agent-brief.mjs +48 -0
- package/scripts/patch-app.mjs +21 -0
- package/scripts/patch-app2.mjs +18 -0
- package/scripts/patch-dist-brief.mjs +96 -0
- package/scripts/patch-tool-exec.mjs +70 -0
- package/scripts/pretool-ask-runtime-test.mjs +54 -0
- package/scripts/provider-toolcall-test.mjs +376 -0
- package/scripts/reactive-compact-persist-smoke.mjs +124 -0
- package/scripts/sanitize-tool-pairs-test.mjs +260 -0
- package/scripts/session-context-bench.mjs +344 -0
- package/scripts/session-ingest-smoke.mjs +177 -0
- package/scripts/set-effort-config-test.mjs +41 -0
- package/scripts/smoke-runtime-negative.ps1 +106 -0
- package/scripts/smoke-runtime-negative.sh +97 -0
- package/scripts/smoke.mjs +25 -0
- package/scripts/tool-result-hook-test.mjs +48 -0
- package/scripts/tool-smoke.mjs +1223 -95
- package/scripts/toolcall-args-test.mjs +150 -0
- package/scripts/tui-background-failure-smoke.mjs +73 -0
- package/scripts/usage-metrics-epoch-smoke.mjs +114 -0
- package/src/agents/debugger/AGENT.md +8 -0
- package/src/agents/explore/AGENT.md +4 -0
- package/src/agents/heavy-worker/AGENT.md +9 -3
- package/src/agents/maintainer/AGENT.md +4 -0
- package/src/agents/reviewer/AGENT.md +8 -0
- package/src/agents/scheduler-task/AGENT.md +12 -0
- package/src/agents/scheduler-task/agent.json +6 -0
- package/src/agents/webhook-handler/AGENT.md +12 -0
- package/src/agents/webhook-handler/agent.json +6 -0
- package/src/agents/worker/AGENT.md +9 -3
- package/src/app.mjs +77 -3
- package/src/defaults/hidden-roles.json +17 -12
- package/src/headless-role.mjs +117 -0
- package/src/help.mjs +30 -0
- package/src/hooks/lib/permission-evaluator.cjs +11 -475
- package/src/lib/keychain-cjs.cjs +9 -1
- package/src/lib/mixdog-debug.cjs +0 -7
- package/src/lib/rules-builder.cjs +240 -96
- package/src/lib/text-utils.cjs +1 -1
- package/src/mixdog-session-runtime.mjs +2325 -450
- package/src/output-styles/default.md +12 -28
- package/src/output-styles/extreme-simple.md +9 -6
- package/src/output-styles/simple.md +22 -9
- package/src/repl.mjs +118 -59
- package/src/rules/agent/00-common.md +15 -0
- package/src/rules/{bridge → agent}/20-skip-protocol.md +1 -2
- package/src/rules/agent/30-explorer.md +22 -0
- package/src/rules/{bridge → agent}/40-cycle1-agent.md +7 -0
- package/src/rules/{bridge → agent}/41-cycle2-agent.md +7 -0
- package/src/rules/{bridge → agent}/42-cycle3-agent.md +7 -0
- package/src/rules/lead/01-general.md +9 -5
- package/src/rules/lead/04-workflow.md +51 -12
- package/src/rules/lead/lead-tool.md +6 -0
- package/src/rules/shared/01-tool.md +12 -1
- package/src/runtime/agent/orchestrator/activity-bus.mjs +7 -18
- package/src/runtime/agent/orchestrator/agent-owner.mjs +11 -0
- package/src/runtime/agent/orchestrator/{smart-bridge/bridge-llm.mjs → agent-runtime/agent-dispatch.mjs} +138 -111
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +94 -0
- package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/cache-strategy.mjs +32 -23
- package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/session-builder.mjs +33 -27
- package/src/runtime/agent/orchestrator/{bridge-trace.mjs → agent-trace.mjs} +132 -81
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +0 -21
- package/src/runtime/agent/orchestrator/config.mjs +174 -55
- package/src/runtime/agent/orchestrator/context/collect.mjs +195 -487
- package/src/runtime/agent/orchestrator/dispatch-persist.mjs +1 -1
- package/src/runtime/agent/orchestrator/internal-roles.mjs +77 -29
- package/src/runtime/agent/orchestrator/internal-tools.mjs +5 -6
- package/src/runtime/agent/orchestrator/mcp/client.mjs +15 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +377 -243
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +146 -93
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +236 -4
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +49 -0
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +58 -13
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +67 -149
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +132 -2
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +45 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +61 -116
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +25 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +79 -255
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +221 -70
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +477 -147
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +343 -496
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +6 -6
- package/src/runtime/agent/orchestrator/providers/registry.mjs +88 -51
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +31 -11
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +41 -8
- package/src/runtime/agent/orchestrator/session/cache/post-edit-marks.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact.mjs +1173 -267
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +199 -36
- package/src/runtime/agent/orchestrator/session/loop.mjs +851 -674
- package/src/runtime/agent/orchestrator/session/manager.mjs +1593 -466
- package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +107 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +291 -46
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +2 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +31 -16
- package/src/runtime/agent/orchestrator/tool-loop-guard.mjs +3 -219
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +34 -7
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +19 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +9 -9
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +60 -37
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +21 -2
- package/src/runtime/agent/orchestrator/tools/builtin/device-paths.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -7
- package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +1 -3
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +36 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +5 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +4 -36
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +2 -40
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +148 -27
- package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +43 -75
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +90 -20
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +59 -5
- package/src/runtime/agent/orchestrator/tools/code-graph-state.mjs +86 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +11 -11
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4106 -4019
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +33 -4
- package/src/runtime/agent/orchestrator/tools/patch.mjs +90 -6
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +6 -4
- package/src/runtime/agent/orchestrator/tools/result-compression.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +8 -1
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -4
- package/src/runtime/channels/index.mjs +152 -24
- package/src/runtime/channels/lib/scheduler.mjs +18 -14
- package/src/runtime/channels/lib/session-discovery.mjs +3 -2
- package/src/runtime/channels/lib/tool-format.mjs +0 -2
- package/src/runtime/channels/lib/transcript-discovery.mjs +3 -2
- package/src/runtime/channels/lib/webhook.mjs +1 -1
- package/src/runtime/channels/tool-defs.mjs +29 -29
- package/src/runtime/memory/index.mjs +635 -107
- package/src/runtime/memory/lib/agent-ipc.mjs +29 -12
- package/src/runtime/memory/lib/core-memory-store.mjs +2 -2
- package/src/runtime/memory/lib/embedding-model-config.mjs +55 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +31 -4
- package/src/runtime/memory/lib/embedding-worker.mjs +19 -10
- package/src/runtime/memory/lib/memory-cycle1.mjs +38 -17
- package/src/runtime/memory/lib/memory-cycle2.mjs +6 -7
- package/src/runtime/memory/lib/memory-cycle3.mjs +4 -4
- package/src/runtime/memory/lib/memory-ops-policy.mjs +2 -1
- package/src/runtime/memory/lib/memory-session-merge.mjs +38 -0
- package/src/runtime/memory/lib/memory.mjs +88 -9
- package/src/runtime/memory/lib/model-profile.mjs +1 -1
- package/src/runtime/memory/lib/pg/adapter.mjs +15 -1
- package/src/runtime/memory/lib/pg/supervisor.mjs +12 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +37 -3
- package/src/runtime/memory/lib/session-ingest.mjs +194 -0
- package/src/runtime/memory/lib/trace-store.mjs +96 -51
- package/src/runtime/memory/tool-defs.mjs +46 -37
- package/src/runtime/search/index.mjs +102 -466
- package/src/runtime/search/lib/web-tools.mjs +45 -25
- package/src/runtime/search/tool-defs.mjs +16 -23
- package/src/runtime/shared/abort-controller.mjs +1 -1
- package/src/runtime/shared/atomic-file.mjs +4 -3
- package/src/runtime/shared/background-tasks.mjs +122 -11
- package/src/runtime/shared/child-spawn-gate.mjs +145 -0
- package/src/runtime/shared/config.mjs +7 -4
- package/src/runtime/shared/err-text.mjs +131 -4
- package/src/runtime/shared/llm/cost.mjs +2 -2
- package/src/runtime/shared/llm/http-agent.mjs +23 -7
- package/src/runtime/shared/llm/index.mjs +34 -11
- package/src/runtime/shared/llm/usage-log.mjs +4 -4
- package/src/runtime/shared/markdown-frontmatter.mjs +56 -0
- package/src/runtime/shared/singleton-owner.mjs +104 -0
- package/src/runtime/shared/tool-execution-contract.mjs +199 -20
- package/src/runtime/shared/tool-execution-contract.test.mjs +183 -0
- package/src/runtime/shared/tool-surface.mjs +624 -98
- package/src/runtime/shared/user-data-guard.mjs +0 -2
- package/src/standalone/agent-task-status.mjs +203 -0
- package/src/standalone/agent-task-status.test.mjs +76 -0
- package/src/standalone/agent-tool.mjs +1913 -0
- package/src/standalone/channel-worker.mjs +370 -14
- package/src/standalone/explore-tool.mjs +165 -70
- package/src/standalone/folder-dialog.mjs +314 -0
- package/src/standalone/hook-bus.mjs +898 -22
- package/src/standalone/memory-runtime-proxy.mjs +320 -0
- package/src/standalone/projects.mjs +226 -0
- package/src/standalone/provider-admin.mjs +41 -24
- package/src/standalone/seeds.mjs +2 -69
- package/src/standalone/usage-dashboard.mjs +96 -8
- package/src/tui/App.jsx +4798 -2153
- package/src/tui/components/AnsiText.jsx +39 -28
- package/src/tui/components/ContextPanel.jsx +87 -29
- package/src/tui/components/Markdown.jsx +43 -77
- package/src/tui/components/MarkdownTable.jsx +9 -184
- package/src/tui/components/Message.jsx +28 -11
- package/src/tui/components/Picker.jsx +95 -56
- package/src/tui/components/PromptInput.jsx +367 -239
- package/src/tui/components/QueuedCommands.jsx +1 -1
- package/src/tui/components/SlashCommandPalette.jsx +27 -21
- package/src/tui/components/Spinner.jsx +67 -38
- package/src/tui/components/StatusLine.jsx +606 -38
- package/src/tui/components/TextEntryPanel.jsx +128 -9
- package/src/tui/components/ToolExecution.jsx +617 -368
- package/src/tui/components/TurnDone.jsx +3 -3
- package/src/tui/components/UsagePanel.jsx +3 -5
- package/src/tui/components/tool-output-format.mjs +365 -0
- package/src/tui/components/tool-output-format.test.mjs +220 -0
- package/src/tui/dist/index.mjs +8915 -2418
- package/src/tui/engine-runtime-notification.test.mjs +115 -0
- package/src/tui/engine-tool-result-text.test.mjs +75 -0
- package/src/tui/engine.mjs +1455 -279
- package/src/tui/figures.mjs +21 -40
- package/src/tui/index.jsx +75 -31
- package/src/tui/input-editing.mjs +25 -0
- package/src/tui/markdown/format-token.mjs +511 -68
- package/src/tui/markdown/format-token.test.mjs +216 -0
- package/src/tui/markdown/render-ansi.mjs +94 -0
- package/src/tui/markdown/render-ansi.test.mjs +108 -0
- package/src/tui/markdown/stream-fence.mjs +34 -0
- package/src/tui/markdown/stream-fence.test.mjs +26 -0
- package/src/tui/markdown/table-layout.mjs +250 -0
- package/src/tui/paste-attachments.mjs +0 -7
- package/src/tui/spinner-verbs.mjs +1 -2
- package/src/tui/statusline-ansi-bridge.mjs +172 -0
- package/src/tui/statusline-ansi-bridge.test.mjs +159 -0
- package/src/tui/theme.mjs +746 -24
- package/src/tui/time-format.mjs +1 -1
- package/src/tui/transcript-tool-failures.mjs +67 -0
- package/src/tui/transcript-tool-failures.test.mjs +111 -0
- package/src/ui/ansi.mjs +1 -2
- package/src/ui/markdown.mjs +85 -26
- package/src/ui/markdown.test.mjs +70 -0
- package/src/ui/model-display.mjs +121 -0
- package/src/ui/session-stats.mjs +44 -0
- package/src/ui/statusline-context-label.test.mjs +15 -0
- package/src/ui/statusline.mjs +386 -178
- package/src/ui/tool-card.mjs +3 -16
- package/src/vendor/statusline/bin/statusline-lib.mjs +8 -4
- package/src/vendor/statusline/bin/statusline-route.mjs +169 -37
- package/src/vendor/statusline/bin/statusline-route.test.mjs +80 -0
- package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +3 -3
- package/src/vendor/statusline/src/gateway/claude-current.mjs +1 -1
- package/src/vendor/statusline/src/gateway/route-meta.mjs +44 -6
- package/src/vendor/statusline/src/gateway/session-routes.mjs +1 -1
- package/src/workflows/default/WORKFLOW.md +12 -5
- package/src/workflows/default/workflow.json +0 -1
- package/src/workflows/solo/WORKFLOW.md +15 -0
- package/src/workflows/solo/workflow.json +7 -0
- package/vendor/ink/build/output.js +6 -1
- package/src/agents/scheduler-task.md +0 -3
- package/src/agents/web-researcher/AGENT.md +0 -3
- package/src/agents/web-researcher/agent.json +0 -6
- package/src/agents/webhook-handler.md +0 -3
- package/src/rules/bridge/00-common.md +0 -5
- package/src/rules/bridge/30-explorer.md +0 -4
- package/src/rules/lead/00-tool-lead.md +0 -5
- package/src/rules/shared/00-language.md +0 -3
- package/src/runtime/agent/orchestrator/tools/builtin/native-edit-runner.mjs +0 -110
- package/src/runtime/agent/orchestrator/tools/mutation-content-cache.mjs +0 -67
- package/src/runtime/memory/lib/bridge-trace-queries.mjs +0 -120
- package/src/runtime/shared/llm/pid-cleanup.mjs +0 -27
- package/src/standalone/bridge-tool.mjs +0 -1414
- package/src/tui/runtime/shared/process-shutdown.mjs +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { spawn } from 'child_process';
|
|
1
|
+
import { spawn, spawnSync } from 'child_process';
|
|
2
2
|
import { closeSync, existsSync, mkdirSync, openSync, readFileSync, readSync, statSync, watch as fsWatch, writeFileSync } from 'fs';
|
|
3
3
|
import * as fsPromises from 'fs/promises';
|
|
4
4
|
import { basename, join } from 'path';
|
|
@@ -15,6 +15,8 @@ import {
|
|
|
15
15
|
} from '../../../../shared/background-tasks.mjs';
|
|
16
16
|
import { startChildGuardian } from '../../../../shared/child-guardian.mjs';
|
|
17
17
|
|
|
18
|
+
globalThis.__mixdogShellJobsRuntimeLoaded = true;
|
|
19
|
+
|
|
18
20
|
function sleep(ms) {
|
|
19
21
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
20
22
|
}
|
|
@@ -220,29 +222,62 @@ function killProcessTree(pid, signal = 'SIGTERM') {
|
|
|
220
222
|
// owned children. Async jobs are intentionally CLI-owned; no restart replay or
|
|
221
223
|
// daemon handoff is attempted.
|
|
222
224
|
const _liveJobPids = new Set();
|
|
225
|
+
const _liveJobIdsByPid = new Map();
|
|
223
226
|
let _shellJobsExitHookInstalled = false;
|
|
224
|
-
function _registerLiveJobPid(pid) {
|
|
225
|
-
if (Number.isFinite(pid) && pid > 0)
|
|
227
|
+
function _registerLiveJobPid(pid, jobId = null) {
|
|
228
|
+
if (Number.isFinite(pid) && pid > 0) {
|
|
229
|
+
_liveJobPids.add(pid);
|
|
230
|
+
if (jobId) _liveJobIdsByPid.set(pid, jobId);
|
|
231
|
+
}
|
|
226
232
|
}
|
|
227
233
|
function _unregisterLiveJobPid(pid) {
|
|
228
|
-
if (Number.isFinite(pid) && pid > 0)
|
|
234
|
+
if (Number.isFinite(pid) && pid > 0) {
|
|
235
|
+
_liveJobPids.delete(pid);
|
|
236
|
+
_liveJobIdsByPid.delete(pid);
|
|
237
|
+
}
|
|
229
238
|
}
|
|
230
|
-
function
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (
|
|
234
|
-
|
|
239
|
+
function _killLiveJobPid(pid, { sync = false } = {}) {
|
|
240
|
+
try {
|
|
241
|
+
if (process.platform === 'win32') {
|
|
242
|
+
if (sync) {
|
|
243
|
+
spawnSync('taskkill.exe', ['/pid', String(pid), '/t', '/f'], {
|
|
244
|
+
windowsHide: true,
|
|
245
|
+
stdio: 'ignore',
|
|
246
|
+
timeout: 1500,
|
|
247
|
+
});
|
|
235
248
|
} else {
|
|
236
|
-
|
|
237
|
-
catch { try { process.kill(pid, 'SIGKILL'); } catch { /* ignore */ } }
|
|
249
|
+
spawn('taskkill', ['/pid', String(pid), '/t', '/f'], { windowsHide: true, stdio: 'ignore' });
|
|
238
250
|
}
|
|
239
|
-
}
|
|
251
|
+
} else {
|
|
252
|
+
try { process.kill(-pid, 'SIGKILL'); }
|
|
253
|
+
catch { try { process.kill(pid, 'SIGKILL'); } catch { /* ignore */ } }
|
|
254
|
+
}
|
|
255
|
+
return true;
|
|
256
|
+
} catch {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function _sweepLiveJobsSync() {
|
|
261
|
+
for (const pid of _liveJobPids) {
|
|
262
|
+
_killLiveJobPid(pid, { sync: true });
|
|
240
263
|
}
|
|
241
264
|
_liveJobPids.clear();
|
|
265
|
+
_liveJobIdsByPid.clear();
|
|
266
|
+
}
|
|
267
|
+
function _ensureProcessListenerHeadroom(events, extra = 1) {
|
|
268
|
+
try {
|
|
269
|
+
if (typeof process.getMaxListeners !== 'function' || typeof process.setMaxListeners !== 'function') return;
|
|
270
|
+
const current = process.getMaxListeners();
|
|
271
|
+
if (current === 0) return;
|
|
272
|
+
let needed = current;
|
|
273
|
+
for (const event of events) needed = Math.max(needed, process.listenerCount(event) + extra);
|
|
274
|
+
if (needed > current) process.setMaxListeners(needed);
|
|
275
|
+
} catch { /* ignore */ }
|
|
242
276
|
}
|
|
243
277
|
function _installShellJobsExitHook() {
|
|
244
278
|
if (_shellJobsExitHookInstalled) return;
|
|
245
279
|
_shellJobsExitHookInstalled = true;
|
|
280
|
+
_ensureProcessListenerHeadroom(['exit', 'SIGTERM', 'SIGINT', 'SIGHUP'], 1);
|
|
246
281
|
try { process.on('exit', _sweepLiveJobsSync); } catch { /* ignore */ }
|
|
247
282
|
try { process.on('SIGTERM', _sweepLiveJobsSync); } catch { /* ignore */ }
|
|
248
283
|
try { process.on('SIGINT', _sweepLiveJobsSync); } catch { /* ignore */ }
|
|
@@ -538,8 +573,8 @@ function refreshShellJob(jobId) {
|
|
|
538
573
|
return detail;
|
|
539
574
|
}
|
|
540
575
|
|
|
541
|
-
export function startBackgroundShellJob({ command, timeoutMs, workDir, mergeStderr, spawnEnv, shell, shellArg, shellType, clientHostPid }) {
|
|
542
|
-
return _startBackgroundShellJobImpl({ command, timeoutMs, workDir, mergeStderr, spawnEnv, shell, shellArg, shellType, clientHostPid });
|
|
576
|
+
export function startBackgroundShellJob({ command, timeoutMs, workDir, mergeStderr, spawnEnv, shell, shellArg, shellArgs, shellType, clientHostPid }) {
|
|
577
|
+
return _startBackgroundShellJobImpl({ command, timeoutMs, workDir, mergeStderr, spawnEnv, shell, shellArg, shellArgs, shellType, clientHostPid });
|
|
543
578
|
}
|
|
544
579
|
|
|
545
580
|
// In-process completion watcher. After a background shell task is spawned the
|
|
@@ -572,6 +607,20 @@ const jobNotifyCtxByJobId = new Map();
|
|
|
572
607
|
// consuming the outcome, so the watcher must stay cancelled; the last waiter to
|
|
573
608
|
// leave (count===0) owns the decision to re-arm a still-running job.
|
|
574
609
|
const jobWaitWaiterCountByJobId = new Map();
|
|
610
|
+
function markShellJobCancelledByShutdown(jobId, reason = 'shutdown') {
|
|
611
|
+
const detail = readShellJobDetail(jobId);
|
|
612
|
+
if (!detail || detail.status !== 'running') return false;
|
|
613
|
+
detail.status = 'cancelled';
|
|
614
|
+
detail.exitCode = 137;
|
|
615
|
+
detail.killed = true;
|
|
616
|
+
detail.error = `cancelled by runtime shutdown (${reason})`;
|
|
617
|
+
detail.finishedAt = new Date().toISOString();
|
|
618
|
+
try { writeFileSync(detail.exitPath || shellJobExitPath(jobId), '137'); } catch { /* ignore */ }
|
|
619
|
+
try { writeFileSync(detail.donePath || shellJobDonePath(jobId), ''); } catch { /* ignore */ }
|
|
620
|
+
writeShellJobDetail(detail);
|
|
621
|
+
_unregisterLiveJobPid(detail.pid);
|
|
622
|
+
return true;
|
|
623
|
+
}
|
|
575
624
|
// Register a synchronous task waiter. Paired with endShellJobWait in a
|
|
576
625
|
// finally so the count can't leak on throw.
|
|
577
626
|
export function beginShellJobWait(jobId) {
|
|
@@ -590,6 +639,26 @@ export function endShellJobWait(jobId) {
|
|
|
590
639
|
export function clearShellJobNotifyCtx(jobId) {
|
|
591
640
|
jobNotifyCtxByJobId.delete(jobId);
|
|
592
641
|
}
|
|
642
|
+
export function shutdownShellJobs(reason = 'runtime-close', { sync = false } = {}) {
|
|
643
|
+
const livePids = [..._liveJobPids];
|
|
644
|
+
const jobIds = new Set([..._liveJobIdsByPid.values()].filter(Boolean));
|
|
645
|
+
const watcherJobIds = [...backgroundShellJobWatchers.keys()];
|
|
646
|
+
for (const jobId of watcherJobIds) {
|
|
647
|
+
jobIds.add(jobId);
|
|
648
|
+
try { cancelBackgroundShellJobWatch(jobId); } catch { /* ignore */ }
|
|
649
|
+
}
|
|
650
|
+
for (const pid of livePids) _killLiveJobPid(pid, { sync });
|
|
651
|
+
_liveJobPids.clear();
|
|
652
|
+
_liveJobIdsByPid.clear();
|
|
653
|
+
let marked = 0;
|
|
654
|
+
for (const jobId of jobIds) {
|
|
655
|
+
try { if (markShellJobCancelledByShutdown(jobId, reason)) marked += 1; } catch { /* ignore */ }
|
|
656
|
+
}
|
|
657
|
+
backgroundShellJobWatchers.clear();
|
|
658
|
+
jobNotifyCtxByJobId.clear();
|
|
659
|
+
jobWaitWaiterCountByJobId.clear();
|
|
660
|
+
return { killed: livePids.length, cancelledJobs: marked, cancelledWatchers: watcherJobIds.length };
|
|
661
|
+
}
|
|
593
662
|
// Cancel (and unregister) an armed watcher without notifying. Idempotent: a
|
|
594
663
|
// no-op when no watcher is armed, and the per-watcher cancel respects the
|
|
595
664
|
// `settled` guard so it cannot race a real completion notify. The persistent
|
|
@@ -824,12 +893,12 @@ export function adoptForegroundShellJob({ command, cwd, pid, timeoutMs, mergeStd
|
|
|
824
893
|
writeShellJobDetail(detail);
|
|
825
894
|
if (Number.isFinite(pid) && pid > 0) {
|
|
826
895
|
_installShellJobsExitHook();
|
|
827
|
-
_registerLiveJobPid(pid);
|
|
896
|
+
_registerLiveJobPid(pid, jobId);
|
|
828
897
|
}
|
|
829
898
|
return { ...detail, exitPath, donePath };
|
|
830
899
|
}
|
|
831
900
|
|
|
832
|
-
function _startBackgroundShellJobImpl({ command, timeoutMs, workDir, mergeStderr, spawnEnv, shell, shellArg, shellType, clientHostPid }) {
|
|
901
|
+
function _startBackgroundShellJobImpl({ command, timeoutMs, workDir, mergeStderr, spawnEnv, shell, shellArg, shellArgs, shellType, clientHostPid }) {
|
|
833
902
|
// Route ANY PowerShell shell to the PS wrapper, regardless of platform.
|
|
834
903
|
// Gating on win32 sent shell:'powershell' on macOS/Linux down the POSIX
|
|
835
904
|
// path below, which spawns `pwsh <wrapper>.sh` — pwsh then tries to run a
|
|
@@ -871,7 +940,8 @@ function _startBackgroundShellJobImpl({ command, timeoutMs, workDir, mergeStderr
|
|
|
871
940
|
// it trivial to distinguish a timeout (124) from a user-side
|
|
872
941
|
// SIGTERM exit (143).
|
|
873
942
|
const innerShellQ = shellQuoteSingle(shell);
|
|
874
|
-
const
|
|
943
|
+
const innerArgs = Array.isArray(shellArgs) && shellArgs.length > 0 ? shellArgs : [shellArg];
|
|
944
|
+
const innerArgsQ = innerArgs.filter((arg) => arg != null && String(arg).length > 0).map(shellQuoteSingle).join(' ');
|
|
875
945
|
// Runtime enforcement proof: the wrapper touches <jobId>.enforced right
|
|
876
946
|
// before exec'ing `timeout`, so the marker exists iff the timeout branch
|
|
877
947
|
// actually ran under the wrapper's own env/cwd. A spawn-time probe can't
|
|
@@ -885,7 +955,7 @@ function _startBackgroundShellJobImpl({ command, timeoutMs, workDir, mergeStderr
|
|
|
885
955
|
// status for processes that actually exited 0. `rm -- "$0"` removes
|
|
886
956
|
// the staged wrapper .cmd.sh after donePath is published so a host
|
|
887
957
|
// crash before this point still leaves the file for the sweep to GC.
|
|
888
|
-
const wrapped = `{ if command -v timeout >/dev/null 2>&1; then _to=timeout; elif command -v gtimeout >/dev/null 2>&1; then _to=gtimeout; else _to=; fi; if [ -n "$_to" ]; then touch ${shellQuoteSingle(enforcedPath)}; "$_to" ${timeoutSeconds} ${innerShellQ} ${
|
|
958
|
+
const wrapped = `{ if command -v timeout >/dev/null 2>&1; then _to=timeout; elif command -v gtimeout >/dev/null 2>&1; then _to=gtimeout; else _to=; fi; if [ -n "$_to" ]; then touch ${shellQuoteSingle(enforcedPath)}; "$_to" ${timeoutSeconds} ${innerShellQ} ${innerArgsQ} ${userCmdQuoted}; else ${innerShellQ} ${innerArgsQ} ${userCmdQuoted}; fi; rc=$?; printf '%s' "$rc" > ${shellQuoteSingle(exitPath)}; touch ${shellQuoteSingle(donePath)}; rm -- "$0" 2>/dev/null; exit $rc; }`;
|
|
889
959
|
// Stage the wrapped command to a .sh and let the script open its own
|
|
890
960
|
// output files via `exec > … 2> …`. The parent does NOT pass file
|
|
891
961
|
// descriptors via stdio inheritance (`stdio: 'ignore'` for all three).
|
|
@@ -919,7 +989,7 @@ function _startBackgroundShellJobImpl({ command, timeoutMs, workDir, mergeStderr
|
|
|
919
989
|
label: 'shell-job',
|
|
920
990
|
});
|
|
921
991
|
_installShellJobsExitHook();
|
|
922
|
-
_registerLiveJobPid(child.pid);
|
|
992
|
+
_registerLiveJobPid(child.pid, jobId);
|
|
923
993
|
const detail = {
|
|
924
994
|
jobId,
|
|
925
995
|
kind: 'bash',
|
|
@@ -1056,7 +1126,7 @@ function startBackgroundPowerShellJob({ command, timeoutMs, workDir, mergeStderr
|
|
|
1056
1126
|
return { jobId, kind: 'bash', status: 'failed', error: 'PowerShell background task spawn returned no pid' };
|
|
1057
1127
|
}
|
|
1058
1128
|
_installShellJobsExitHook();
|
|
1059
|
-
_registerLiveJobPid(childPid);
|
|
1129
|
+
_registerLiveJobPid(childPid, jobId);
|
|
1060
1130
|
const detail = {
|
|
1061
1131
|
jobId,
|
|
1062
1132
|
kind: 'bash',
|
|
@@ -3,7 +3,7 @@ import { join } from 'path';
|
|
|
3
3
|
import { writeJsonAtomicSync } from '../../../../shared/atomic-file.mjs';
|
|
4
4
|
import { resolvePluginData } from '../../../../shared/plugin-paths.mjs';
|
|
5
5
|
|
|
6
|
-
// Mixdog read/
|
|
6
|
+
// Mixdog read/patch paths share a scoped snapshot store. Value stores the
|
|
7
7
|
// mtime + size at read-time. A missing scope is fail-closed: snapshots without
|
|
8
8
|
// a real scope id are NOT recorded under a shared default bucket (would let
|
|
9
9
|
// worker A's read satisfy worker B's edit-gate across sessions via a persisted
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
} from './builtin/bash-tool.mjs';
|
|
20
20
|
import {
|
|
21
21
|
executeFindFilesTool,
|
|
22
|
+
executeFuzzyFindTool,
|
|
22
23
|
executeListTool,
|
|
23
24
|
executeTreeTool,
|
|
24
25
|
} from './builtin/list-tool.mjs';
|
|
@@ -129,7 +130,7 @@ export {
|
|
|
129
130
|
} from './builtin/cache-layers.mjs';
|
|
130
131
|
export { atomicWrite } from './builtin/atomic-write.mjs';
|
|
131
132
|
// ---------------------------------------------------------------------------
|
|
132
|
-
// User-cwd persistence
|
|
133
|
+
// User-cwd persistence hook: writes user-cwd.txt on SessionStart so
|
|
133
134
|
// the MCP server (spawned from cache dir) resolves the correct sandbox root.
|
|
134
135
|
// Helper extracted to src/shared/user-cwd.mjs so server-main.mjs can import
|
|
135
136
|
// the same primitive without circular-import risk.
|
|
@@ -252,9 +253,54 @@ const BUILTIN_TOOL_ALIASES = new Map([
|
|
|
252
253
|
['golb', 'glob'],
|
|
253
254
|
]);
|
|
254
255
|
|
|
256
|
+
// Case-insensitive lookup of canonical builtin names, built once from the
|
|
257
|
+
// declarative BUILTIN_TOOLS registry. Models trained on other coding-agent
|
|
258
|
+
// CLIs frequently emit PascalCase tool names ("Read", "Shell", "Grep",
|
|
259
|
+
// "List") for tools mixdog exposes in lowercase. Those calls used to fall
|
|
260
|
+
// through to formatUnknownBuiltinToolMessage and, because the error did not
|
|
261
|
+
// resolve the case mismatch, the model re-issued the SAME capitalised call
|
|
262
|
+
// every iteration until the loop cap. A lowercase→canonical map makes the
|
|
263
|
+
// dispatcher accept the case variant directly.
|
|
264
|
+
const _BUILTIN_LOWER_TO_CANONICAL = new Map(
|
|
265
|
+
BUILTIN_TOOLS.map((t) => [String(t.name || '').toLowerCase(), t.name]).filter(([k]) => k),
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
// Well-known tool names from OTHER agent CLIs that have no mixdog builtin.
|
|
269
|
+
// They cannot be silently remapped (their argument shapes differ — e.g.
|
|
270
|
+
// Write{path,contents} vs apply_patch{patch}) so the unknown-tool error
|
|
271
|
+
// surfaces a concrete redirect instead of a bare "unknown tool", which is
|
|
272
|
+
// what kept models looping on a non-existent tool.
|
|
273
|
+
const EXTERNAL_TOOL_REDIRECTS = new Map([
|
|
274
|
+
['write', 'use `apply_patch` with an `*** Add File:` V4A section to create a file'],
|
|
275
|
+
['edit', 'use `apply_patch` with a `*** Update File:` V4A section'],
|
|
276
|
+
['multiedit', 'use a single `apply_patch` call with multiple `*** Update File:` sections'],
|
|
277
|
+
['strreplace', 'use `apply_patch` with a `*** Update File:` V4A section'],
|
|
278
|
+
['str_replace', 'use `apply_patch` with a `*** Update File:` V4A section'],
|
|
279
|
+
['str_replace_editor', 'use `apply_patch` with a `*** Update File:` V4A section'],
|
|
280
|
+
['createfile', 'use `apply_patch` with an `*** Add File:` V4A section'],
|
|
281
|
+
['create_file', 'use `apply_patch` with an `*** Add File:` V4A section'],
|
|
282
|
+
['deletefile', 'use `apply_patch` with a `*** Delete File:` V4A section'],
|
|
283
|
+
['delete_file', 'use `apply_patch` with a `*** Delete File:` V4A section'],
|
|
284
|
+
['bash', 'use the `shell` tool'],
|
|
285
|
+
['run', 'use the `shell` tool'],
|
|
286
|
+
['runcommand', 'use the `shell` tool'],
|
|
287
|
+
['terminal', 'use the `shell` tool'],
|
|
288
|
+
['view', 'use the `read` tool'],
|
|
289
|
+
['cat', 'use the `read` tool'],
|
|
290
|
+
['ls', 'use the `list` tool'],
|
|
291
|
+
['searchfiles', 'use the `grep` tool'],
|
|
292
|
+
['codebase_search', 'use the `grep` or `code_graph` tool'],
|
|
293
|
+
]);
|
|
294
|
+
|
|
255
295
|
export function canonicalizeBuiltinToolName(name) {
|
|
256
296
|
if (typeof name !== 'string') return name;
|
|
257
|
-
|
|
297
|
+
const aliased = BUILTIN_TOOL_ALIASES.get(name);
|
|
298
|
+
if (aliased) return aliased;
|
|
299
|
+
// Exact match wins (cheapest, most common path).
|
|
300
|
+
if (_BUILTIN_LOWER_TO_CANONICAL.get(name) === name) return name;
|
|
301
|
+
// Case-insensitive fall-through: "Read"/"SHELL"/"Grep" → canonical.
|
|
302
|
+
const lowerCanonical = _BUILTIN_LOWER_TO_CANONICAL.get(name.toLowerCase());
|
|
303
|
+
return lowerCanonical || name;
|
|
258
304
|
}
|
|
259
305
|
|
|
260
306
|
function editDistance(a, b) {
|
|
@@ -294,6 +340,12 @@ export function suggestBuiltinToolName(name) {
|
|
|
294
340
|
}
|
|
295
341
|
|
|
296
342
|
export function formatUnknownBuiltinToolMessage(name, _args = {}, noun = 'builtin tool') {
|
|
343
|
+
// Concrete redirect for a well-known tool from another agent CLI whose
|
|
344
|
+
// argument shape differs from any mixdog builtin (so it cannot be
|
|
345
|
+
// case-normalised into one). Without this, the model re-issues the same
|
|
346
|
+
// non-existent tool every iteration until the loop cap.
|
|
347
|
+
const redirect = typeof name === 'string' ? EXTERNAL_TOOL_REDIRECTS.get(name.toLowerCase()) : null;
|
|
348
|
+
if (redirect) return `Error: unknown ${noun} "${name}" — ${redirect}.`;
|
|
297
349
|
const suggestion = suggestBuiltinToolName(name);
|
|
298
350
|
if (!suggestion) return `Error: unknown ${noun} "${name}"`;
|
|
299
351
|
return `Error: unknown ${noun} "${name}". Did you mean "${suggestion}"?`;
|
|
@@ -308,7 +360,7 @@ process.on('exit', flushReadRangeIndexesSync);
|
|
|
308
360
|
|
|
309
361
|
configureReadRangeIndexTelemetry({ trace: _ioTrace, hashText: _hashText });
|
|
310
362
|
|
|
311
|
-
// Uniform tool-output cap (
|
|
363
|
+
// Uniform tool-output cap (`tool_output_token_limit` analogue): a SINGLE
|
|
312
364
|
// optional knob that bounds EVERY builtin string result before it enters the
|
|
313
365
|
// lead context, on top of each tool's own caps. Default 0 = OFF (per-tool caps
|
|
314
366
|
// only, no behaviour change). Set MIXDOG_TOOL_OUTPUT_MAX_BYTES (or pass
|
|
@@ -342,7 +394,7 @@ function capToolOutput(result, options = {}) {
|
|
|
342
394
|
const bytes = Buffer.byteLength(result, 'utf8');
|
|
343
395
|
if (bytes <= cap) return result;
|
|
344
396
|
// Middle-truncate: keep head + tail (byte-accurate), drop the middle. Mirrors
|
|
345
|
-
//
|
|
397
|
+
// Middle truncation so the model still sees both ends of a runaway.
|
|
346
398
|
const half = Math.max(1, Math.floor(cap / 2) - 64);
|
|
347
399
|
const head = _sliceToBytesFromStart(result, half);
|
|
348
400
|
const tail = _sliceToBytesFromEnd(result, half);
|
|
@@ -371,7 +423,7 @@ export async function executeBuiltinTool(name, args, cwd, options = {}) {
|
|
|
371
423
|
const readStateScope = options?.readStateScope ?? options?.sessionId ?? null;
|
|
372
424
|
const executeChildBuiltinTool = (childName, childArgs, childCwd = workDir, childOptions = null) =>
|
|
373
425
|
executeBuiltinTool(childName, childArgs, childCwd, childOptions ? { ...options, ...childOptions } : options);
|
|
374
|
-
// Path policy:
|
|
426
|
+
// Path policy: host settings.json permissions (mcp__* allow) are the
|
|
375
427
|
// sole arbiter for workspace-boundary decisions.
|
|
376
428
|
const _toolResult = await (async () => {
|
|
377
429
|
switch (toolName) {
|
|
@@ -389,6 +441,8 @@ export async function executeBuiltinTool(name, args, cwd, options = {}) {
|
|
|
389
441
|
return executeGrepTool(args, workDir, executeChildBuiltinTool, readStateScope, options);
|
|
390
442
|
case 'glob':
|
|
391
443
|
return executeGlobTool(args, workDir, options);
|
|
444
|
+
case 'find':
|
|
445
|
+
return executeFuzzyFindTool(args, workDir, options);
|
|
392
446
|
case 'list':
|
|
393
447
|
return executeListTool(args, workDir, options);
|
|
394
448
|
case 'tree':
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, resolve as pathResolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
export const codeGraphCache = new Map();
|
|
5
|
+
export const codeGraphDirtyPaths = new Map();
|
|
6
|
+
|
|
7
|
+
const codeGraphDirtyGen = new Map();
|
|
8
|
+
let drainCodeGraphCacheFn = null;
|
|
9
|
+
|
|
10
|
+
export function canonicalGraphCwd(cwd) {
|
|
11
|
+
if (!cwd) throw new Error('code_graph requires cwd - caller did not provide a working directory');
|
|
12
|
+
const full = pathResolve(cwd);
|
|
13
|
+
return process.platform === 'win32' ? full.toLowerCase() : full;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function canonicalGraphPath(p) {
|
|
17
|
+
const full = pathResolve(String(p || ''));
|
|
18
|
+
return process.platform === 'win32' ? full.toLowerCase() : full;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function getCodeGraphGen(graphCwd) {
|
|
22
|
+
return codeGraphDirtyGen.get(graphCwd) || 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function bumpCodeGraphGen(graphCwd) {
|
|
26
|
+
codeGraphDirtyGen.set(graphCwd, (codeGraphDirtyGen.get(graphCwd) || 0) + 1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function consumeCodeGraphDirtyPaths(cwd) {
|
|
30
|
+
const key = canonicalGraphCwd(cwd);
|
|
31
|
+
const set = codeGraphDirtyPaths.get(key);
|
|
32
|
+
if (!set || set.size === 0) return [];
|
|
33
|
+
codeGraphDirtyPaths.delete(key);
|
|
34
|
+
return [...set];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Accept absolute written paths only; resolve affected indexed roots centrally.
|
|
38
|
+
export function markCodeGraphDirtyPaths(paths) {
|
|
39
|
+
const values = Array.isArray(paths) ? paths : [paths];
|
|
40
|
+
const cleaned = values
|
|
41
|
+
.filter(Boolean)
|
|
42
|
+
.map((p) => canonicalGraphPath(p));
|
|
43
|
+
if (cleaned.length === 0) return;
|
|
44
|
+
|
|
45
|
+
const knownRoots = new Set([...codeGraphDirtyPaths.keys(), ...codeGraphCache.keys()]);
|
|
46
|
+
const affectedRoots = new Set();
|
|
47
|
+
for (const absPath of cleaned) {
|
|
48
|
+
let matchedThisPath = false;
|
|
49
|
+
for (const root of knownRoots) {
|
|
50
|
+
const canonRoot = canonicalGraphPath(root);
|
|
51
|
+
if (absPath.startsWith(canonRoot + '/') || absPath.startsWith(canonRoot + '\\') || absPath === canonRoot) {
|
|
52
|
+
affectedRoots.add(root);
|
|
53
|
+
matchedThisPath = true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (!matchedThisPath) {
|
|
57
|
+
let dir = dirname(absPath);
|
|
58
|
+
while (dir && dir !== dirname(dir)) {
|
|
59
|
+
if (existsSync(join(dir, 'package.json')) || existsSync(join(dir, '.git'))) {
|
|
60
|
+
affectedRoots.add(canonicalGraphCwd(dir));
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
dir = dirname(dir);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
for (const root of affectedRoots) {
|
|
69
|
+
if (!codeGraphDirtyPaths.has(root)) codeGraphDirtyPaths.set(root, new Set());
|
|
70
|
+
const set = codeGraphDirtyPaths.get(root);
|
|
71
|
+
for (const p of cleaned) set.add(p);
|
|
72
|
+
|
|
73
|
+
const canonRoot = canonicalGraphCwd(root);
|
|
74
|
+
codeGraphCache.delete(canonRoot);
|
|
75
|
+
bumpCodeGraphGen(canonRoot);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function registerCodeGraphDrain(fn) {
|
|
80
|
+
drainCodeGraphCacheFn = typeof fn === 'function' ? fn : null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function drainCodeGraphCache() {
|
|
84
|
+
if (!drainCodeGraphCacheFn) return;
|
|
85
|
+
drainCodeGraphCacheFn();
|
|
86
|
+
}
|
|
@@ -3,20 +3,20 @@ export const CODE_GRAPH_TOOL_DEFS = [
|
|
|
3
3
|
name: 'code_graph',
|
|
4
4
|
title: 'Code Graph',
|
|
5
5
|
annotations: { title: 'Code Graph', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, compressible: false, compressibleLossless: true },
|
|
6
|
-
description: '
|
|
6
|
+
description: 'Code structure: symbols, refs, calls, imports, impact.',
|
|
7
7
|
inputSchema: {
|
|
8
8
|
type: 'object',
|
|
9
9
|
properties: {
|
|
10
|
-
mode: { type: 'string', enum: ['overview', 'imports', 'dependents', 'related', 'impact', 'symbols', 'find_symbol', 'search', 'references', 'callers', 'callees', 'prewarm'], description: 'Operation
|
|
11
|
-
file: { type: 'string', description: '
|
|
12
|
-
symbol: { type: 'string', description: 'Identifier or
|
|
13
|
-
symbols: { type: 'array', items: { type: 'string' }, description: 'Batch identifiers
|
|
14
|
-
body: { type: 'boolean', description: '
|
|
15
|
-
language: { type: 'string', description: '
|
|
16
|
-
limit: { type: 'number', minimum: 1, description: 'Max results
|
|
17
|
-
depth: { type: 'number', minimum: 1, maximum: 5, description: '
|
|
18
|
-
page: { type: 'number', minimum: 1, description: '
|
|
19
|
-
cwd: { type: 'string', description: 'Project root
|
|
10
|
+
mode: { type: 'string', enum: ['overview', 'imports', 'dependents', 'related', 'impact', 'symbols', 'find_symbol', 'search', 'references', 'callers', 'callees', 'prewarm'], description: 'Operation.' },
|
|
11
|
+
file: { type: 'string', description: 'Source file.' },
|
|
12
|
+
symbol: { type: 'string', description: 'Identifier or symbol keyword.' },
|
|
13
|
+
symbols: { type: 'array', items: { type: 'string' }, description: 'Batch identifiers.' },
|
|
14
|
+
body: { type: 'boolean', description: 'Include body.' },
|
|
15
|
+
language: { type: 'string', description: 'Language hint.' },
|
|
16
|
+
limit: { type: 'number', minimum: 1, description: 'Max results.' },
|
|
17
|
+
depth: { type: 'number', minimum: 1, maximum: 5, description: 'Caller depth.' },
|
|
18
|
+
page: { type: 'number', minimum: 1, description: 'Caller page.' },
|
|
19
|
+
cwd: { type: 'string', description: 'Project root.' },
|
|
20
20
|
},
|
|
21
21
|
required: ['mode'],
|
|
22
22
|
},
|