mixdog 0.9.2 → 0.9.4
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 +8 -3
- package/scripts/anthropic-maxtokens-test.mjs +119 -0
- package/scripts/bench/lead-review-tasks-r3.json +20 -0
- package/scripts/bench/lead-review-tasks.json +20 -0
- package/scripts/bench/r4-mixed-tasks.json +20 -0
- package/scripts/bench/review-tasks.json +20 -0
- package/scripts/bench/round-codex.json +114 -0
- package/scripts/bench/round-mixdog-lead-r3.json +269 -0
- package/scripts/bench/round-mixdog-lead.json +269 -0
- package/scripts/bench/round-mixdog.json +126 -0
- package/scripts/bench/round-r10-bigsample.json +679 -0
- package/scripts/bench/round-r11-codexalign.json +257 -0
- package/scripts/bench/round-r4-codex.json +114 -0
- package/scripts/bench/round-r4-mixed.json +225 -0
- package/scripts/bench/round-r5-gpt-lead.json +259 -0
- package/scripts/bench/round-r6-codex.json +114 -0
- package/scripts/bench/round-r6-solo.json +257 -0
- package/scripts/bench/round-r7-full.json +254 -0
- package/scripts/bench/round-r8-fulldefault.json +255 -0
- package/scripts/bench-run.mjs +215 -29
- package/scripts/build-tui.mjs +13 -1
- package/scripts/explore-bench.mjs +124 -0
- package/scripts/freevar-smoke.mjs +95 -0
- package/scripts/hook-bus-test.mjs +191 -0
- package/scripts/internal-comms-bench.mjs +1 -0
- package/scripts/internal-comms-smoke.mjs +10 -9
- package/scripts/mouse-probe.mjs +45 -0
- package/scripts/output-style-bench.mjs +13 -6
- package/scripts/output-style-smoke.mjs +4 -4
- package/scripts/path-suffix-test.mjs +57 -0
- package/scripts/provider-toolcall-test.mjs +7 -3
- package/scripts/recall-bench.mjs +207 -0
- package/scripts/recall-usecase-cases.json +18 -0
- package/scripts/recall-usecase-probe.json +6 -0
- package/scripts/session-bench.mjs +152 -6
- package/scripts/tool-smoke.mjs +30 -67
- package/scripts/tui-render-smoke.mjs +90 -0
- package/scripts/webhook-smoke.mjs +208 -0
- package/src/agents/debugger/AGENT.md +5 -2
- package/src/agents/heavy-worker/AGENT.md +21 -11
- package/src/agents/maintainer/AGENT.md +4 -0
- package/src/agents/reviewer/AGENT.md +3 -2
- package/src/agents/worker/AGENT.md +21 -11
- package/src/lib/rules-builder.cjs +4 -0
- package/src/mixdog-session-runtime.mjs +933 -3731
- package/src/output-styles/default.md +34 -9
- package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
- package/src/output-styles/minimal.md +4 -1
- package/src/output-styles/simple.md +22 -7
- package/src/repl.mjs +5 -5
- package/src/rules/agent/00-common.md +2 -0
- package/src/rules/agent/30-explorer.md +8 -11
- package/src/rules/lead/lead-brief.md +12 -0
- package/src/rules/lead/lead-tool.md +2 -9
- package/src/rules/shared/01-tool.md +11 -5
- package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
- package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
- package/src/runtime/agent/orchestrator/config.mjs +69 -2
- package/src/runtime/agent/orchestrator/context/collect.mjs +51 -0
- package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +63 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +97 -1343
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +78 -10
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +1 -13
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +44 -1014
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +18 -4
- package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +86 -11
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +348 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
- package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +19 -12
- package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +41 -1142
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +732 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +303 -2119
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +140 -995
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +227 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +436 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +38 -12
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +7 -8
- package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
- package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
- package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
- package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
- package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
- package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +274 -0
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -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 +47 -0
- package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +182 -0
- package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -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/termination.mjs +58 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -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 +409 -1304
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +230 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +149 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +226 -2114
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
- package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +33 -42
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -87
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +78 -304
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +11 -6
- 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 +551 -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/keyword-match.mjs +82 -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 +1080 -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-columns.mjs +45 -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 +6 -6
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +36 -4277
- package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
- package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
- package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
- package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
- package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -23
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +10 -74
- package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
- package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
- package/src/runtime/channels/backends/discord-access.mjs +32 -0
- package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
- package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
- package/src/runtime/channels/backends/discord.mjs +12 -292
- package/src/runtime/channels/index.mjs +241 -894
- package/src/runtime/channels/lib/backend-dispatch.mjs +44 -0
- package/src/runtime/channels/lib/boot-profile.mjs +23 -0
- package/src/runtime/channels/lib/crash-log.mjs +106 -0
- package/src/runtime/channels/lib/event-pipeline.mjs +18 -1
- package/src/runtime/channels/lib/event-queue.mjs +63 -4
- package/src/runtime/channels/lib/inbound-routing.mjs +111 -0
- package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
- package/src/runtime/channels/lib/output-forwarder.mjs +9 -1
- package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
- package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
- package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
- package/src/runtime/channels/lib/session-discovery.mjs +56 -4
- package/src/runtime/channels/lib/telegram-format.mjs +19 -22
- package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
- package/src/runtime/channels/lib/tool-format.mjs +1 -1
- package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
- package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
- package/src/runtime/channels/lib/webhook/deliveries.mjs +312 -0
- package/src/runtime/channels/lib/webhook/log.mjs +42 -0
- package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
- package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
- package/src/runtime/channels/lib/webhook.mjs +36 -570
- package/src/runtime/channels/lib/whisper-language.mjs +42 -0
- package/src/runtime/channels/tool-defs.mjs +11 -130
- package/src/runtime/memory/index.mjs +258 -2050
- package/src/runtime/memory/lib/core-memory-store.mjs +351 -1
- package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
- package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
- package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
- package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
- package/src/runtime/memory/lib/http-wire.mjs +57 -0
- package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
- package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
- package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
- package/src/runtime/memory/lib/memory-cycle2.mjs +72 -837
- package/src/runtime/memory/lib/memory-embed.mjs +149 -0
- package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
- package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
- package/src/runtime/memory/lib/memory-recall-store.mjs +22 -2
- package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
- package/src/runtime/memory/lib/memory.mjs +20 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
- package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
- package/src/runtime/memory/lib/query-handlers.mjs +780 -0
- package/src/runtime/memory/lib/recall-format.mjs +238 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
- package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
- package/src/runtime/memory/tool-defs.mjs +6 -14
- package/src/runtime/search/lib/http-fetch.mjs +274 -0
- package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
- package/src/runtime/search/lib/web-tools.mjs +24 -602
- package/src/runtime/shared/abort-controller.mjs +1 -1
- package/src/runtime/shared/atomic-file.mjs +26 -1
- package/src/runtime/shared/background-tasks.mjs +2 -3
- package/src/runtime/shared/buffered-appender.mjs +149 -0
- package/src/runtime/shared/launcher-control.mjs +2 -2
- package/src/runtime/shared/task-notification-envelope.mjs +98 -0
- package/src/runtime/shared/tool-execution-contract.mjs +2 -2
- package/src/runtime/shared/tool-primitives.mjs +308 -0
- package/src/runtime/shared/tool-result-summary.mjs +515 -0
- package/src/runtime/shared/tool-surface.mjs +80 -898
- package/src/runtime/shared/transcript-writer.mjs +52 -2
- package/src/runtime/shared/update-checker.mjs +7 -4
- package/src/session-runtime/config-helpers.mjs +291 -0
- package/src/session-runtime/config-lifecycle.mjs +232 -0
- package/src/session-runtime/cwd-plugins.mjs +226 -0
- package/src/session-runtime/effort.mjs +128 -0
- package/src/session-runtime/fs-utils.mjs +10 -0
- package/src/session-runtime/mcp-glue.mjs +177 -0
- package/src/session-runtime/model-capabilities.mjs +130 -0
- package/src/session-runtime/model-recency.mjs +111 -0
- package/src/session-runtime/native-search.mjs +247 -0
- package/src/session-runtime/output-styles.mjs +126 -0
- package/src/session-runtime/plugin-mcp.mjs +114 -0
- package/src/session-runtime/prewarm.mjs +142 -0
- package/src/session-runtime/provider-models.mjs +278 -0
- package/src/session-runtime/provider-usage.mjs +120 -0
- package/src/session-runtime/quick-model-rows.mjs +170 -0
- package/src/session-runtime/quick-search-models.mjs +46 -0
- package/src/session-runtime/session-hooks.mjs +93 -0
- package/src/session-runtime/session-text.mjs +100 -0
- package/src/session-runtime/settings-api.mjs +319 -0
- package/src/session-runtime/statusline-route.mjs +35 -0
- package/src/session-runtime/tool-catalog.mjs +720 -0
- package/src/session-runtime/tool-defs.mjs +84 -0
- package/src/session-runtime/warmup-schedulers.mjs +201 -0
- package/src/session-runtime/workflow.mjs +358 -0
- package/src/standalone/agent-tool/helpers.mjs +237 -0
- package/src/standalone/agent-tool/notify.mjs +107 -0
- package/src/standalone/agent-tool/provider-init.mjs +143 -0
- package/src/standalone/agent-tool/render.mjs +152 -0
- package/src/standalone/agent-tool/tool-def.mjs +55 -0
- package/src/standalone/agent-tool.mjs +155 -677
- package/src/standalone/channel-worker.mjs +7 -9
- package/src/standalone/explore-tool.mjs +40 -12
- package/src/standalone/hook-bus/config.mjs +207 -0
- package/src/standalone/hook-bus/constants.mjs +90 -0
- package/src/standalone/hook-bus/handlers.mjs +481 -0
- package/src/standalone/hook-bus/payload.mjs +31 -0
- package/src/standalone/hook-bus/rules.mjs +77 -0
- package/src/standalone/hook-bus.mjs +110 -746
- package/src/standalone/memory-runtime-proxy.mjs +7 -0
- package/src/standalone/opencode-go-login.mjs +125 -0
- package/src/standalone/provider-admin.mjs +15 -19
- package/src/standalone/usage-dashboard.mjs +3 -1
- package/src/tui/App.jsx +1163 -7571
- package/src/tui/app/app-format.mjs +206 -0
- package/src/tui/app/channel-pickers.mjs +510 -0
- package/src/tui/app/clipboard.mjs +67 -0
- package/src/tui/app/core-memory-picker.mjs +210 -0
- package/src/tui/app/extension-pickers.mjs +506 -0
- package/src/tui/app/input-parsers.mjs +193 -0
- package/src/tui/app/maintenance-pickers.mjs +324 -0
- package/src/tui/app/model-options.mjs +330 -0
- package/src/tui/app/model-picker.mjs +365 -0
- package/src/tui/app/onboarding-steps.mjs +400 -0
- package/src/tui/app/project-picker.mjs +247 -0
- package/src/tui/app/provider-setup-picker.mjs +580 -0
- package/src/tui/app/resume-picker.mjs +55 -0
- package/src/tui/app/route-pickers.mjs +419 -0
- package/src/tui/app/settings-picker.mjs +490 -0
- package/src/tui/app/slash-commands.mjs +101 -0
- package/src/tui/app/slash-dispatch.mjs +427 -0
- package/src/tui/app/text-layout.mjs +46 -0
- package/src/tui/app/theme-effort-pickers.mjs +154 -0
- package/src/tui/app/transcript-window.mjs +671 -0
- package/src/tui/app/use-mouse-input.mjs +460 -0
- package/src/tui/app/use-prompt-handlers.mjs +310 -0
- package/src/tui/app/use-transcript-scroll.mjs +510 -0
- package/src/tui/app/use-transcript-window.mjs +589 -0
- package/src/tui/components/ConfirmBar.jsx +1 -1
- package/src/tui/components/Picker.jsx +32 -4
- package/src/tui/components/PromptInput.jsx +259 -80
- package/src/tui/components/SlashCommandPalette.jsx +8 -1
- package/src/tui/components/StatusLine.jsx +63 -12
- package/src/tui/components/TextEntryPanel.jsx +11 -0
- package/src/tui/components/ToolExecution.jsx +56 -588
- package/src/tui/components/TranscriptItem.jsx +105 -0
- package/src/tui/components/UsagePanel.jsx +18 -4
- package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
- package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
- package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
- package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
- package/src/tui/components/tool-execution/text-format.mjs +161 -0
- package/src/tui/components/tool-output-format.mjs +2 -2
- package/src/tui/display-width.mjs +20 -3
- package/src/tui/dist/index.mjs +18034 -17188
- package/src/tui/engine/agent-envelope.mjs +296 -0
- package/src/tui/engine/agent-job-feed.mjs +133 -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/notification-plan.mjs +76 -0
- package/src/tui/engine/queue-helpers.mjs +161 -0
- package/src/tui/engine/render-timing.mjs +17 -0
- package/src/tui/engine/session-stats.mjs +46 -0
- package/src/tui/engine/tool-approval.mjs +94 -0
- package/src/tui/engine/tool-call-fields.mjs +23 -0
- package/src/tui/engine/tool-card-results.mjs +234 -0
- package/src/tui/engine/tool-result-status.mjs +135 -0
- package/src/tui/engine/tool-result-text.mjs +126 -0
- package/src/tui/engine.mjs +405 -1385
- package/src/tui/figures.mjs +5 -0
- package/src/tui/index.jsx +105 -0
- package/src/tui/input-editing.mjs +60 -10
- package/src/tui/keyboard-protocol.mjs +2 -2
- package/src/tui/lib/voice-recorder.mjs +35 -19
- package/src/tui/markdown/format-token.mjs +11 -9
- package/src/tui/paste-attachments.mjs +38 -0
- package/src/tui/statusline-ansi-bridge.mjs +11 -3
- package/src/tui/theme.mjs +6 -0
- package/src/tui/themes/base.mjs +2 -2
- package/src/tui/themes/kanagawa.mjs +4 -4
- package/src/tui/themes/teal.mjs +4 -5
- package/src/tui/themes/utils.mjs +1 -1
- package/src/ui/statusline-agents.mjs +213 -0
- package/src/ui/statusline-format.mjs +146 -0
- package/src/ui/statusline-segments.mjs +148 -0
- package/src/ui/statusline.mjs +77 -462
- package/src/ui/tool-card.mjs +0 -1
- package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
- package/src/workflows/default/WORKFLOW.md +16 -9
- package/src/workflows/sequential/WORKFLOW.md +16 -11
- package/src/workflows/solo/WORKFLOW.md +5 -1
- package/vendor/ink/build/display-width.js +19 -3
- package/vendor/ink/build/ink.js +103 -6
- package/vendor/ink/build/log-update.js +17 -3
- package/vendor/ink/build/wrap-text.js +125 -0
- package/scripts/_test-folder-dialog.mjs +0 -30
- package/scripts/fix-brief-fn.mjs +0 -35
- package/scripts/fix-format-tool-surface.mjs +0 -24
- package/scripts/fix-tool-exec-visible.mjs +0 -42
- package/scripts/patch-agent-brief.mjs +0 -48
- package/scripts/patch-app.mjs +0 -21
- package/scripts/patch-app2.mjs +0 -18
- package/scripts/patch-dist-brief.mjs +0 -96
- package/scripts/patch-tool-exec.mjs +0 -70
- package/src/examples/schedules/SCHEDULE.example.md +0 -32
- package/src/examples/webhooks/WEBHOOK.example.md +0 -40
- package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
- package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
- package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
- package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
- package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
- package/src/standalone/agent-task-status.test.mjs +0 -76
- package/src/tui/components/tool-output-format.test.mjs +0 -399
- package/src/tui/display-width.test.mjs +0 -35
- package/src/tui/engine-runtime-notification.test.mjs +0 -115
- package/src/tui/engine-tool-result-text.test.mjs +0 -75
- package/src/tui/markdown/format-token.test.mjs +0 -354
- package/src/tui/markdown/render-ansi.test.mjs +0 -108
- package/src/tui/markdown/stream-fence.test.mjs +0 -26
- package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
- package/src/tui/prompt-history-store.test.mjs +0 -52
- package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
- package/src/tui/transcript-tool-failures.test.mjs +0 -111
- package/src/ui/markdown.test.mjs +0 -70
- package/src/ui/statusline-context-label.test.mjs +0 -15
- package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
- package/src/vendor/statusline/bin/statusline-route.test.mjs +0 -80
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
// Tool dispatch layer: codeGraph (mode router), findSymbolTool,
|
|
2
|
+
// resolveSymbolReadSpan, executeCodeGraphTool (entry with cwd re-rooting +
|
|
3
|
+
// batch fan-out + abort race), isCodeGraphTool. Extracted verbatim from
|
|
4
|
+
// code-graph.mjs.
|
|
5
|
+
import { resolve as pathResolve, isAbsolute, relative as pathRelative } from 'node:path';
|
|
6
|
+
import { readFileSync, existsSync, statSync } from 'node:fs';
|
|
7
|
+
import { normalizeInputPath, toDisplayPath } from '../builtin.mjs';
|
|
8
|
+
import { findFileByBasename } from '../builtin/path-diagnostics.mjs';
|
|
9
|
+
import { markScopedCacheIncomplete } from '../../session/cache/scoped-cache-outcome.mjs';
|
|
10
|
+
import { CODE_GRAPH_TOOL_DEFS } from '../code-graph-tool-defs.mjs';
|
|
11
|
+
import { CODE_GRAPH_MAX_FILES } from './constants.mjs';
|
|
12
|
+
import { _graphRel, _getSourceTextForNode, _appendSameBasenameHint } from './source-access.mjs';
|
|
13
|
+
import { _extractSymbolsCheap, _buildExplainerFileSummary } from './symbol-index.mjs';
|
|
14
|
+
import { _inferSpanEndByIndent } from './span.mjs';
|
|
15
|
+
import {
|
|
16
|
+
_PROJECT_ROOT_SENTINELS,
|
|
17
|
+
_resolveFileProjectRoot,
|
|
18
|
+
_findDirProjectRoot,
|
|
19
|
+
_stripEmptyArgs,
|
|
20
|
+
} from './project-root.mjs';
|
|
21
|
+
import { buildCodeGraphAsync, prewarmCodeGraph, prewarmCodeGraphSymbols } from './build.mjs';
|
|
22
|
+
import {
|
|
23
|
+
_findSymbolHits,
|
|
24
|
+
_findSymbolAcrossGraph,
|
|
25
|
+
_searchSymbolsByKeyword,
|
|
26
|
+
_extractCallees,
|
|
27
|
+
_formatCalleeRow,
|
|
28
|
+
_CALLEES_BRACE_LANGS,
|
|
29
|
+
_formatRelated,
|
|
30
|
+
_formatImpact,
|
|
31
|
+
_resolveReferenceLanguageNode,
|
|
32
|
+
_prewarmReferenceSourceText,
|
|
33
|
+
_cheapReferenceSearch,
|
|
34
|
+
_formatCallerReferences,
|
|
35
|
+
_formatTransitiveCallers,
|
|
36
|
+
_augmentNoHitDiagnostic,
|
|
37
|
+
_pickCalleeDeclHit,
|
|
38
|
+
} from './search.mjs';
|
|
39
|
+
|
|
40
|
+
const CODE_GRAPH_BATCHABLE_MODES = new Set(['symbol', 'find_symbol', 'symbol_search', 'callers', 'callees', 'references']);
|
|
41
|
+
const CODE_GRAPH_FILE_BATCHABLE_MODES = new Set(['imports', 'dependents', 'related', 'impact', 'symbols', 'overview']);
|
|
42
|
+
|
|
43
|
+
function _collectGraphSymbolList(args) {
|
|
44
|
+
const split = (s) => String(s || '').split(/[,\s]+/).map((t) => t.trim()).filter(Boolean);
|
|
45
|
+
return [...new Set([
|
|
46
|
+
...(Array.isArray(args?.symbols) ? args.symbols.map((s) => String(s || '').trim()).filter(Boolean) : []),
|
|
47
|
+
...(typeof args?.symbols === 'string' ? split(args.symbols) : []),
|
|
48
|
+
...(typeof args?.symbol === 'string' ? split(args.symbol) : []),
|
|
49
|
+
])];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const CODE_GRAPH_FILE_BATCH_CAP = 20;
|
|
53
|
+
|
|
54
|
+
function _collectGraphFileList(args) {
|
|
55
|
+
const split = (s) => String(s || '').split(/,+/).map((t) => t.trim()).filter(Boolean);
|
|
56
|
+
const list = [...new Set([
|
|
57
|
+
...(Array.isArray(args?.files) ? args.files.map((f) => String(f || '').trim()).filter(Boolean) : []),
|
|
58
|
+
...(typeof args?.files === 'string' ? split(args.files) : []),
|
|
59
|
+
...(typeof args?.file === 'string' && args.file.trim() ? [args.file.trim()] : []),
|
|
60
|
+
])];
|
|
61
|
+
if (list.length > CODE_GRAPH_FILE_BATCH_CAP) {
|
|
62
|
+
const capped = list.slice(0, CODE_GRAPH_FILE_BATCH_CAP);
|
|
63
|
+
capped._capped = true;
|
|
64
|
+
return capped;
|
|
65
|
+
}
|
|
66
|
+
return list;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function codeGraph(args, cwd, signal = null, options = {}) {
|
|
70
|
+
let mode = String(args?.mode || '').trim();
|
|
71
|
+
if (!mode) throw new Error('code_graph: "mode" is required');
|
|
72
|
+
if (mode === 'search') mode = 'symbol_search';
|
|
73
|
+
|
|
74
|
+
if (mode === 'prewarm') {
|
|
75
|
+
const _splitMulti = (s) => String(s || '').split(/[,\s]+/).map((t) => t.trim()).filter(Boolean);
|
|
76
|
+
const fromSymbolsArr = Array.isArray(args?.symbols)
|
|
77
|
+
? args.symbols.map((s) => String(s || '').trim()).filter(Boolean)
|
|
78
|
+
: [];
|
|
79
|
+
const fromSymbolsStr = typeof args?.symbols === 'string' ? _splitMulti(args.symbols) : [];
|
|
80
|
+
const fromSymbolField = typeof args?.symbol === 'string' ? _splitMulti(args.symbol) : [];
|
|
81
|
+
const symbols = [...new Set([...fromSymbolsArr, ...fromSymbolsStr, ...fromSymbolField])];
|
|
82
|
+
if (symbols.length > 0) prewarmCodeGraphSymbols(cwd, symbols);
|
|
83
|
+
else prewarmCodeGraph(cwd);
|
|
84
|
+
return `prewarm scheduled: cwd=${cwd} symbols=${symbols.length}${symbols.length ? ` (${symbols.slice(0, 5).join(',')}${symbols.length > 5 ? `,+${symbols.length - 5}` : ''})` : ''}`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const graph = await buildCodeGraphAsync(cwd, signal);
|
|
88
|
+
if (!graph || graph.nodes.size === 0) {
|
|
89
|
+
throw new Error(`code_graph: cwd '${cwd}' is not an indexed/known project root or contains zero eligible files`);
|
|
90
|
+
}
|
|
91
|
+
if (options?.scopedCacheOutcome && graph.truncated) {
|
|
92
|
+
markScopedCacheIncomplete(options.scopedCacheOutcome);
|
|
93
|
+
}
|
|
94
|
+
const normFile = normalizeInputPath(args?.file);
|
|
95
|
+
const abs = normFile ? (isAbsolute(normFile) ? pathResolve(normFile) : pathResolve(cwd, normFile)) : null;
|
|
96
|
+
let fileIsDirectory = false;
|
|
97
|
+
if (abs) {
|
|
98
|
+
try { fileIsDirectory = statSync(abs).isDirectory(); } catch { fileIsDirectory = false; }
|
|
99
|
+
}
|
|
100
|
+
const rel = abs && !fileIsDirectory ? _graphRel(abs, cwd) : null;
|
|
101
|
+
const scopeRelPrefix = abs && fileIsDirectory
|
|
102
|
+
? (() => {
|
|
103
|
+
const r = _graphRel(abs, cwd).replace(/\\/g, '/').replace(/\/+$/, '');
|
|
104
|
+
return (!r || r === '.') ? null : `${r}/`;
|
|
105
|
+
})()
|
|
106
|
+
: null;
|
|
107
|
+
const node = rel ? graph.nodes.get(rel) : null;
|
|
108
|
+
|
|
109
|
+
if (mode === 'overview') {
|
|
110
|
+
if (rel && !node) return _appendSameBasenameHint(`Error: code_graph overview: file not found in graph: ${normFile}`, normFile, graph);
|
|
111
|
+
if (node) return _buildExplainerFileSummary(node, graph, cwd);
|
|
112
|
+
const byLang = new Map();
|
|
113
|
+
for (const node of graph.nodes.values()) {
|
|
114
|
+
byLang.set(node.lang, (byLang.get(node.lang) || 0) + 1);
|
|
115
|
+
}
|
|
116
|
+
const lines = [
|
|
117
|
+
`files\t${graph.nodes.size}`,
|
|
118
|
+
`edges\t${Array.from(graph.nodes.values()).reduce((sum, n) => sum + n.resolvedImports.length, 0)}`,
|
|
119
|
+
];
|
|
120
|
+
for (const [lang, count] of [...byLang.entries()].sort((a, b) => b[1] - a[1])) {
|
|
121
|
+
lines.push(`${lang}\t${count}`);
|
|
122
|
+
}
|
|
123
|
+
if (graph?.truncated) {
|
|
124
|
+
lines.push(`WARN: graph truncated at CODE_GRAPH_MAX_FILES=${CODE_GRAPH_MAX_FILES} — some files under cwd were not indexed`);
|
|
125
|
+
}
|
|
126
|
+
return lines.join('\n');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (mode === 'imports') {
|
|
130
|
+
if (!node) return _appendSameBasenameHint(`Error: code_graph imports: file not found in graph: ${normFile || '(missing file)'}`, normFile, graph);
|
|
131
|
+
const GRAPH_LIST_CAP = 200;
|
|
132
|
+
const resolvedAll = node.resolvedImports.map((p) => _graphRel(p, cwd));
|
|
133
|
+
const rawAll = node.rawImports;
|
|
134
|
+
const resolved = resolvedAll.slice(0, GRAPH_LIST_CAP);
|
|
135
|
+
const raw = rawAll.slice(0, GRAPH_LIST_CAP);
|
|
136
|
+
const parts = [];
|
|
137
|
+
if (resolved.length) parts.push(resolved.join('\n'));
|
|
138
|
+
if (raw.length) parts.push(`# raw\n${raw.join('\n')}`);
|
|
139
|
+
if (resolvedAll.length > resolved.length || rawAll.length > raw.length) {
|
|
140
|
+
parts.push(`[truncated — showing first ${GRAPH_LIST_CAP} of ${resolvedAll.length} resolved / ${rawAll.length} raw imports]`);
|
|
141
|
+
}
|
|
142
|
+
return parts.join('\n\n') || '(no imports)';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (mode === 'dependents') {
|
|
146
|
+
if (!rel) throw new Error('code_graph dependents: "file" is required');
|
|
147
|
+
if (!node) return _appendSameBasenameHint(`Error: code_graph dependents: file not found in graph: ${normFile || '(missing file)'}`, normFile, graph);
|
|
148
|
+
const GRAPH_LIST_CAP = 200;
|
|
149
|
+
const depsAll = [...(graph.reverse.get(rel) || [])].sort();
|
|
150
|
+
if (!depsAll.length) return '(no dependents)';
|
|
151
|
+
const deps = depsAll.slice(0, GRAPH_LIST_CAP);
|
|
152
|
+
const basename = rel.split('/').pop();
|
|
153
|
+
const stem = basename.replace(/\.[^/.]+$/, '');
|
|
154
|
+
const enriched = deps.map((dep) => {
|
|
155
|
+
const depNode = graph.nodes.get(dep);
|
|
156
|
+
if (!depNode) return dep;
|
|
157
|
+
let text;
|
|
158
|
+
try { text = readFileSync(depNode.abs, 'utf8'); } catch { return dep; }
|
|
159
|
+
const linesArr = text.split(/\r?\n/);
|
|
160
|
+
for (let i = 0; i < linesArr.length; i++) {
|
|
161
|
+
const ln = linesArr[i];
|
|
162
|
+
if (!/(?:^|\W)(?:import|require)\b|\bfrom\s*['"]/.test(ln)) continue;
|
|
163
|
+
if (ln.includes(`/${basename}`) || ln.includes(`/${stem}`) || ln.includes(`'${basename}'`) || ln.includes(`"${basename}"`)) {
|
|
164
|
+
return `${dep}:${i + 1}`;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return dep;
|
|
168
|
+
});
|
|
169
|
+
const out = enriched.join('\n');
|
|
170
|
+
return depsAll.length > deps.length
|
|
171
|
+
? `${out}\n[truncated — showing first ${GRAPH_LIST_CAP} of ${depsAll.length} dependents]`
|
|
172
|
+
: out;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (mode === 'related') {
|
|
176
|
+
if (!node) return _appendSameBasenameHint(`Error: code_graph related: file not found in graph: ${normFile || '(missing file)'}`, normFile, graph);
|
|
177
|
+
return _formatRelated(node, graph, cwd);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (mode === 'impact') {
|
|
181
|
+
if (!node) return _appendSameBasenameHint(`Error: code_graph impact: file not found in graph: ${normFile || '(missing file)'}`, normFile, graph);
|
|
182
|
+
const targetSymbol = String(args?.symbol || '').trim();
|
|
183
|
+
return _formatImpact(node, graph, cwd, targetSymbol);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (mode === 'callees') {
|
|
187
|
+
const symbol = String(args?.symbol || '').trim();
|
|
188
|
+
if (!symbol) throw new Error('code_graph callees: "symbol" is required.');
|
|
189
|
+
const explicitLanguage = String(args?.language || '').trim() || null;
|
|
190
|
+
if (rel && !node) return _appendSameBasenameHint(`Error: code_graph callees: file not found in graph: ${normFile || '(missing file)'}`, normFile, graph);
|
|
191
|
+
const allHits = _findSymbolHits(graph, symbol, { language: explicitLanguage });
|
|
192
|
+
const hits = rel ? allHits.filter((h) => h.rel === rel) : allHits;
|
|
193
|
+
const declHit = hits.find((h) => h.declarationLike) || hits[0];
|
|
194
|
+
if (!declHit) {
|
|
195
|
+
const scopeNote = rel ? ` file=${rel}` : '';
|
|
196
|
+
return `(no symbol matches in cwd=${cwd}${scopeNote})`;
|
|
197
|
+
}
|
|
198
|
+
if (!_CALLEES_BRACE_LANGS.has(declHit.lang)) {
|
|
199
|
+
return `(callees unsupported for ${declHit.lang})`;
|
|
200
|
+
}
|
|
201
|
+
const rows = _extractCallees(graph, declHit, cwd, {
|
|
202
|
+
cap: 200,
|
|
203
|
+
callerSymbol: symbol,
|
|
204
|
+
language: explicitLanguage,
|
|
205
|
+
});
|
|
206
|
+
if (!rows.length) return `(no callees)`;
|
|
207
|
+
const out = ['# callees'];
|
|
208
|
+
for (const row of rows) out.push(_formatCalleeRow(row));
|
|
209
|
+
return out.join('\n');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (mode === 'symbols') {
|
|
213
|
+
if (!node) return _appendSameBasenameHint(`Error: code_graph symbols: file not found in graph: ${normFile || '(missing file)'}`, normFile, graph);
|
|
214
|
+
let text = '';
|
|
215
|
+
try { text = readFileSync(node.abs, 'utf8'); } catch { return '(no symbols)'; }
|
|
216
|
+
return _extractSymbolsCheap(text, node.lang);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (mode === 'find_symbol') {
|
|
220
|
+
const symbol = String(args?.symbol || '').trim();
|
|
221
|
+
if (!symbol) throw new Error('code_graph find_symbol: "symbol" is required.');
|
|
222
|
+
const language = String(args?.language || '').trim() || null;
|
|
223
|
+
const limit = Math.max(1, Math.min(50, Number(args?.limit || 20)));
|
|
224
|
+
if (rel && !node) return _appendSameBasenameHint(`Error: code_graph find_symbol: file not found in graph: ${normFile || '(missing file)'}`, normFile, graph);
|
|
225
|
+
return _findSymbolAcrossGraph(graph, symbol, cwd, { language, limit, fileRel: rel, body: args?.body !== false });
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (mode === 'symbol_search') {
|
|
229
|
+
const language = String(args?.language || '').trim() || null;
|
|
230
|
+
const limit = Math.max(1, Math.min(100, Number(args?.limit || 30)));
|
|
231
|
+
const symbolsList = Array.isArray(args?.symbols)
|
|
232
|
+
? args.symbols.map((s) => String(s || '').trim()).filter(Boolean)
|
|
233
|
+
: [];
|
|
234
|
+
const keyword = String(args?.symbol || '').trim();
|
|
235
|
+
const keywords = symbolsList.length ? symbolsList : (keyword ? [keyword] : []);
|
|
236
|
+
if (!keywords.length) throw new Error('code_graph symbol_search: "symbol" (or "symbols[]") is required.');
|
|
237
|
+
if (keywords.length === 1) {
|
|
238
|
+
return _searchSymbolsByKeyword(graph, keywords[0], cwd, { language, limit });
|
|
239
|
+
}
|
|
240
|
+
// Batch: merge results across symbols, dedupe identical result blocks.
|
|
241
|
+
const seen = new Set();
|
|
242
|
+
const sections = [];
|
|
243
|
+
for (const kw of keywords) {
|
|
244
|
+
const result = _searchSymbolsByKeyword(graph, kw, cwd, { language, limit });
|
|
245
|
+
if (seen.has(result)) continue;
|
|
246
|
+
seen.add(result);
|
|
247
|
+
sections.push(`# symbol_search: ${kw}\n${result}`);
|
|
248
|
+
}
|
|
249
|
+
return sections.join('\n\n');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (mode === 'references') {
|
|
253
|
+
const symbol = String(args?.symbol || '').trim();
|
|
254
|
+
if (!symbol) throw new Error('code_graph references: "symbol" is required.');
|
|
255
|
+
const explicitLanguage = String(args?.language || '').trim() || null;
|
|
256
|
+
if (explicitLanguage) {
|
|
257
|
+
const langHasFiles = [...graph.nodes.values()].some((n) => n.lang === explicitLanguage);
|
|
258
|
+
if (!langHasFiles) {
|
|
259
|
+
throw new Error(`code_graph references: language '${explicitLanguage}' has no adapter topLevelTypes and is not in supportedRegexLangs for this project`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
const narrowedByCaller = Boolean(rel || scopeRelPrefix || explicitLanguage);
|
|
263
|
+
const resolved = _resolveReferenceLanguageNode(graph, symbol, rel, cwd, explicitLanguage);
|
|
264
|
+
if (rel && resolved.kind === 'file-not-found') {
|
|
265
|
+
return _appendSameBasenameHint(`Error: code_graph references: file not found in graph: ${normFile || '(missing file)'}`, normFile, graph);
|
|
266
|
+
}
|
|
267
|
+
if (rel && resolved.kind === 'symbol-not-present') {
|
|
268
|
+
return `Error: code_graph references: symbol "${symbol}" not found in ${normFile || rel}`;
|
|
269
|
+
}
|
|
270
|
+
const resolvedNode = resolved.kind === 'ok' ? resolved.node : null;
|
|
271
|
+
const lang = explicitLanguage
|
|
272
|
+
|| ((narrowedByCaller && resolvedNode) ? resolvedNode.lang : null);
|
|
273
|
+
const rawLimit = Number(args?.limit);
|
|
274
|
+
const userLimit = Number.isFinite(rawLimit) && rawLimit > 0
|
|
275
|
+
? Math.min(500, Math.floor(rawLimit))
|
|
276
|
+
: null;
|
|
277
|
+
await _prewarmReferenceSourceText(graph, symbol, lang);
|
|
278
|
+
const refResult = _cheapReferenceSearch(graph, symbol, cwd, { language: lang, limit: userLimit, fileRel: rel, scopeRelPrefix });
|
|
279
|
+
return narrowedByCaller ? refResult : _augmentNoHitDiagnostic(refResult, '(no references)', graph, cwd, symbol);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (mode === 'callers') {
|
|
283
|
+
const symbol = String(args?.symbol || '').trim();
|
|
284
|
+
if (!symbol) throw new Error('code_graph callers: "symbol" is required.');
|
|
285
|
+
const explicitLanguage = String(args?.language || '').trim() || null;
|
|
286
|
+
if (explicitLanguage) {
|
|
287
|
+
const langHasFiles = [...graph.nodes.values()].some((n) => n.lang === explicitLanguage);
|
|
288
|
+
if (!langHasFiles) {
|
|
289
|
+
throw new Error(`code_graph callers: language '${explicitLanguage}' has no adapter topLevelTypes and is not in supportedRegexLangs for this project`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const narrowedByCaller = Boolean(rel || scopeRelPrefix || explicitLanguage);
|
|
293
|
+
const resolved = _resolveReferenceLanguageNode(graph, symbol, rel, cwd, explicitLanguage);
|
|
294
|
+
if (rel && resolved.kind === 'file-not-found') {
|
|
295
|
+
return _appendSameBasenameHint(`Error: code_graph callers: file not found in graph: ${normFile || '(missing file)'}`, normFile, graph);
|
|
296
|
+
}
|
|
297
|
+
if (rel && resolved.kind === 'symbol-not-present') {
|
|
298
|
+
return `Error: code_graph callers: symbol "${symbol}" not found in ${normFile || rel}`;
|
|
299
|
+
}
|
|
300
|
+
const resolvedNode = resolved.kind === 'ok' ? resolved.node : null;
|
|
301
|
+
const lang = explicitLanguage
|
|
302
|
+
|| ((narrowedByCaller && resolvedNode) ? resolvedNode.lang : null);
|
|
303
|
+
const rawLimit = Number(args?.limit);
|
|
304
|
+
const userLimit = Number.isFinite(rawLimit) && rawLimit > 0
|
|
305
|
+
? Math.min(500, Math.floor(rawLimit))
|
|
306
|
+
: null;
|
|
307
|
+
await _prewarmReferenceSourceText(graph, symbol, lang);
|
|
308
|
+
const depth = Math.max(1, Math.min(5, Math.floor(Number(args?.depth) || 1)));
|
|
309
|
+
if (depth > 1) {
|
|
310
|
+
return _formatTransitiveCallers(graph, symbol, cwd, { language: lang, depth, page: args?.page });
|
|
311
|
+
}
|
|
312
|
+
const refs = _cheapReferenceSearch(graph, symbol, cwd, { language: lang, limit: userLimit, fileRel: rel, scopeRelPrefix });
|
|
313
|
+
const callerResult = _formatCallerReferences(graph, symbol, refs, userLimit ? { limit: userLimit } : undefined);
|
|
314
|
+
return narrowedByCaller ? callerResult : _augmentNoHitDiagnostic(callerResult, '(no callers)', graph, cwd, symbol);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
throw new Error(`code_graph: unknown mode "${mode}"`);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
async function findSymbolTool(args, cwd, signal = null, options = {}) {
|
|
321
|
+
if (args?.mode === 'prewarm') {
|
|
322
|
+
const _splitMulti = (s) => String(s || '').split(/[,\s]+/).map((t) => t.trim()).filter(Boolean);
|
|
323
|
+
const fromSymbolsArr = Array.isArray(args?.symbols)
|
|
324
|
+
? args.symbols.map((s) => String(s || '').trim()).filter(Boolean)
|
|
325
|
+
: [];
|
|
326
|
+
const fromSymbolsStr = typeof args?.symbols === 'string' ? _splitMulti(args.symbols) : [];
|
|
327
|
+
const fromSymbolField = typeof args?.symbol === 'string' ? _splitMulti(args.symbol) : [];
|
|
328
|
+
const symbols = [...new Set([...fromSymbolsArr, ...fromSymbolsStr, ...fromSymbolField])];
|
|
329
|
+
if (symbols.length > 0) prewarmCodeGraphSymbols(cwd, symbols);
|
|
330
|
+
else prewarmCodeGraph(cwd);
|
|
331
|
+
return `prewarm scheduled: cwd=${cwd} symbols=${symbols.length}${symbols.length ? ` (${symbols.slice(0, 5).join(',')}${symbols.length > 5 ? `,+${symbols.length - 5}` : ''})` : ''}`;
|
|
332
|
+
}
|
|
333
|
+
const graph = await buildCodeGraphAsync(cwd, signal);
|
|
334
|
+
if (!graph) throw new Error(`find_symbol: cwd '${cwd}' is not an indexed/known project root or contains zero eligible files`);
|
|
335
|
+
if (options?.scopedCacheOutcome && graph.truncated) {
|
|
336
|
+
markScopedCacheIncomplete(options.scopedCacheOutcome);
|
|
337
|
+
}
|
|
338
|
+
const symbol = String(args?.symbol || '').trim();
|
|
339
|
+
const language = String(args?.language || '').trim() || null;
|
|
340
|
+
const limit = Math.max(1, Math.min(50, Number(args?.limit || 20)));
|
|
341
|
+
const normFile = normalizeInputPath(args?.file);
|
|
342
|
+
const abs = normFile ? (isAbsolute(normFile) ? pathResolve(normFile) : pathResolve(cwd, normFile)) : null;
|
|
343
|
+
const fileRel = abs ? _graphRel(abs, cwd) : null;
|
|
344
|
+
if (fileRel && !graph.nodes.get(fileRel)) {
|
|
345
|
+
return _appendSameBasenameHint(`Error: find_symbol: file not found in graph: ${normFile}`, normFile, graph);
|
|
346
|
+
}
|
|
347
|
+
if (!symbol) {
|
|
348
|
+
if (fileRel) {
|
|
349
|
+
const node = graph.nodes.get(fileRel);
|
|
350
|
+
let text = '';
|
|
351
|
+
try { text = readFileSync(node.abs, 'utf8'); } catch { return '(no symbols)'; }
|
|
352
|
+
return _extractSymbolsCheap(text, node.lang);
|
|
353
|
+
}
|
|
354
|
+
throw new Error('find_symbol: provide "symbol" (to locate) or "file" (to list its symbols).');
|
|
355
|
+
}
|
|
356
|
+
return _findSymbolAcrossGraph(graph, symbol, cwd, { language, limit, fileRel, body: args?.body !== false });
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Resolve a symbol name to a 1-based [startLine, endLine] declaration span for read().
|
|
361
|
+
* Returns `{ offset, limit, startLine, endLine, rel, note? }` or `{ error }`.
|
|
362
|
+
*/
|
|
363
|
+
export async function resolveSymbolReadSpan(cwd, { symbol, path = null, language = null, line = null } = {}) {
|
|
364
|
+
const cleanSymbol = String(symbol || '').trim();
|
|
365
|
+
if (!cleanSymbol) return { error: 'symbol is required' };
|
|
366
|
+
let graph;
|
|
367
|
+
try {
|
|
368
|
+
graph = await buildCodeGraphAsync(cwd);
|
|
369
|
+
} catch (err) {
|
|
370
|
+
return { error: `symbol read: code graph unavailable (${err?.message || err})` };
|
|
371
|
+
}
|
|
372
|
+
if (!graph) return { error: 'symbol read: code graph could not be built for cwd' };
|
|
373
|
+
|
|
374
|
+
const normFile = path ? normalizeInputPath(path) : null;
|
|
375
|
+
const abs = normFile ? (isAbsolute(normFile) ? pathResolve(normFile) : pathResolve(cwd, normFile)) : null;
|
|
376
|
+
const fileRel = abs ? _graphRel(abs, cwd) : null;
|
|
377
|
+
if (fileRel && !graph.nodes.get(fileRel)) {
|
|
378
|
+
return { error: `symbol '${cleanSymbol}' not found — file not indexed: ${path}; use find_symbol` };
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
let hits = _findSymbolHits(graph, cleanSymbol, { language });
|
|
382
|
+
if (fileRel) hits = hits.filter((h) => h.rel === fileRel);
|
|
383
|
+
if (!hits.length) {
|
|
384
|
+
const scope = fileRel ? ` in ${fileRel}` : '';
|
|
385
|
+
return { error: `symbol '${cleanSymbol}' not found${scope}; use find_symbol to locate it` };
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const disambigLine = Number(line);
|
|
389
|
+
let primary;
|
|
390
|
+
if (Number.isFinite(disambigLine) && disambigLine > 0) {
|
|
391
|
+
const onLine = hits.filter((h) => h.line === disambigLine);
|
|
392
|
+
primary = _pickCalleeDeclHit(onLine.length ? onLine : hits, fileRel);
|
|
393
|
+
} else {
|
|
394
|
+
primary = _pickCalleeDeclHit(hits, fileRel);
|
|
395
|
+
}
|
|
396
|
+
if (!primary) return { error: `symbol '${cleanSymbol}' not found; use find_symbol` };
|
|
397
|
+
|
|
398
|
+
const startLine = Number(primary.line);
|
|
399
|
+
let endLine = Number(primary.endLine);
|
|
400
|
+
let approximate = false;
|
|
401
|
+
if (!Number.isFinite(startLine) || startLine < 1) {
|
|
402
|
+
return { error: `symbol '${cleanSymbol}' has no valid declaration line; use find_symbol` };
|
|
403
|
+
}
|
|
404
|
+
if (!Number.isFinite(endLine) || endLine < startLine) {
|
|
405
|
+
const node = graph.nodes.get(primary.rel);
|
|
406
|
+
const srcText = node ? _getSourceTextForNode(graph, node) : null;
|
|
407
|
+
const inferred = srcText ? _inferSpanEndByIndent(srcText.split('\n'), startLine) : null;
|
|
408
|
+
if (inferred) {
|
|
409
|
+
endLine = inferred;
|
|
410
|
+
} else {
|
|
411
|
+
endLine = startLine + 79;
|
|
412
|
+
approximate = true;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const declCount = hits.filter((h) => h.declarationLike).length;
|
|
416
|
+
const notes = [];
|
|
417
|
+
if (approximate) notes.push('end line unknown — approximate range from declaration line');
|
|
418
|
+
if (!fileRel && (hits.length > 1 || declCount > 1)) {
|
|
419
|
+
notes.push('other matches exist — pass path= (and line= to disambiguate) to scope');
|
|
420
|
+
} else if (fileRel && declCount > 1) {
|
|
421
|
+
notes.push(
|
|
422
|
+
`${declCount} declarations of '${cleanSymbol}' in this file — reading the first; pass line= to pick another`,
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return {
|
|
427
|
+
rel: primary.rel,
|
|
428
|
+
startLine,
|
|
429
|
+
endLine,
|
|
430
|
+
offset: startLine - 1,
|
|
431
|
+
limit: endLine - startLine + 1,
|
|
432
|
+
approximate,
|
|
433
|
+
note: notes.length ? notes.join('; ') : undefined,
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
export async function executeCodeGraphTool(name, args, cwd, signal = null, options = {}) {
|
|
438
|
+
if (!cwd) throw new Error('find_symbol/code_graph requires cwd — caller did not provide a working directory');
|
|
439
|
+
const fileArg = (args && typeof args.file === 'string' && args.file.trim()) ? args.file.trim() : '';
|
|
440
|
+
const baseCwd = (args && typeof args.cwd === 'string' && args.cwd.trim()) ? args.cwd.trim() : cwd;
|
|
441
|
+
let effectiveCwd = baseCwd;
|
|
442
|
+
if (fileArg) {
|
|
443
|
+
const abs = isAbsolute(fileArg) ? pathResolve(fileArg) : pathResolve(baseCwd, fileArg);
|
|
444
|
+
if (!existsSync(abs)) {
|
|
445
|
+
const elsewhere = findFileByBasename(pathResolve(baseCwd), abs);
|
|
446
|
+
const hint = elsewhere.length
|
|
447
|
+
? ` Same filename exists at: ${elsewhere.map((p) => `"${toDisplayPath(p, baseCwd).replace(/\\/g, '/')}"`).join(', ')}. Use that path.`
|
|
448
|
+
: '';
|
|
449
|
+
return `Error: ${name}: file not found: ${fileArg}${hint}`;
|
|
450
|
+
}
|
|
451
|
+
let fileArgIsDirectory = false;
|
|
452
|
+
try { fileArgIsDirectory = statSync(abs).isDirectory(); } catch { fileArgIsDirectory = false; }
|
|
453
|
+
const rel = pathRelative(pathResolve(baseCwd), abs);
|
|
454
|
+
const insideCwd = rel === '' || (!!rel && !rel.startsWith('..') && !isAbsolute(rel));
|
|
455
|
+
if (!insideCwd) {
|
|
456
|
+
const hasExplicitCwd = args && typeof args.cwd === 'string' && args.cwd.trim();
|
|
457
|
+
if (!hasExplicitCwd) {
|
|
458
|
+
const fileRoot = fileArgIsDirectory ? _findDirProjectRoot(abs) : _resolveFileProjectRoot(abs);
|
|
459
|
+
if (!fileRoot) {
|
|
460
|
+
throw new Error(`find_symbol: file '${fileArg}' is outside cwd '${baseCwd}' and has no detectable project root (no package.json/.git ancestor). Provide an explicit cwd.`);
|
|
461
|
+
}
|
|
462
|
+
effectiveCwd = fileRoot;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
if (!fileArg && !(args && typeof args.cwd === 'string' && args.cwd.trim())) {
|
|
467
|
+
const projectRoot = _findDirProjectRoot(effectiveCwd);
|
|
468
|
+
if (!projectRoot) {
|
|
469
|
+
throw new Error(
|
|
470
|
+
`${name}: cwd '${effectiveCwd}' is not inside a project (no `
|
|
471
|
+
+ `${_PROJECT_ROOT_SENTINELS.join('/')} at it or any ancestor). Refusing to `
|
|
472
|
+
+ `index an arbitrary tree. Run 'cwd set <repo>', or pass an explicit `
|
|
473
|
+
+ `'cwd' (repo root) or a 'file' anchor.`);
|
|
474
|
+
}
|
|
475
|
+
effectiveCwd = projectRoot;
|
|
476
|
+
}
|
|
477
|
+
if (signal?.aborted) throw new Error('aborted');
|
|
478
|
+
const _work = (() => {
|
|
479
|
+
switch (name) {
|
|
480
|
+
case 'code_graph': {
|
|
481
|
+
const rawMode = String(args?.mode || '').trim();
|
|
482
|
+
const batchMode = rawMode === 'search' ? 'symbol_search' : rawMode;
|
|
483
|
+
const declModes = new Set(['symbol', 'find_symbol']);
|
|
484
|
+
const dispatchOne = (a) => (declModes.has(rawMode)
|
|
485
|
+
? findSymbolTool(_stripEmptyArgs(a), effectiveCwd, signal, options)
|
|
486
|
+
: codeGraph(a, effectiveCwd, signal, options));
|
|
487
|
+
if (CODE_GRAPH_BATCHABLE_MODES.has(batchMode)) {
|
|
488
|
+
const symbolList = _collectGraphSymbolList(args);
|
|
489
|
+
if (symbolList.length > 1) {
|
|
490
|
+
return (async () => {
|
|
491
|
+
const sections = [];
|
|
492
|
+
for (const sym of symbolList) {
|
|
493
|
+
let body;
|
|
494
|
+
try { body = await dispatchOne({ ...args, symbol: sym, symbols: undefined }); }
|
|
495
|
+
catch (e) { body = `Error: ${e?.message || String(e)}`; }
|
|
496
|
+
sections.push(`# ${batchMode} ${sym}\n${body}`);
|
|
497
|
+
}
|
|
498
|
+
return sections.join('\n\n');
|
|
499
|
+
})();
|
|
500
|
+
}
|
|
501
|
+
if (symbolList.length === 1 && args?.symbol !== symbolList[0]) {
|
|
502
|
+
return dispatchOne({ ...args, symbol: symbolList[0], symbols: undefined });
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
if (CODE_GRAPH_FILE_BATCHABLE_MODES.has(batchMode)) {
|
|
506
|
+
const fileList = _collectGraphFileList(args);
|
|
507
|
+
if (fileList.length > 1) {
|
|
508
|
+
const capped = fileList._capped;
|
|
509
|
+
return (async () => {
|
|
510
|
+
const sections = [];
|
|
511
|
+
for (const f of fileList) {
|
|
512
|
+
let body;
|
|
513
|
+
try { body = await dispatchOne({ ...args, file: f, files: undefined }); }
|
|
514
|
+
catch (e) { body = `Error: ${e?.message || String(e)}`; }
|
|
515
|
+
sections.push(`# ${batchMode} ${f}\n${body}`);
|
|
516
|
+
}
|
|
517
|
+
if (capped) sections.push(`Note: file list capped at ${CODE_GRAPH_FILE_BATCH_CAP} entries.`);
|
|
518
|
+
return sections.join('\n\n');
|
|
519
|
+
})();
|
|
520
|
+
}
|
|
521
|
+
if (fileList.length === 1 && args?.file !== fileList[0]) {
|
|
522
|
+
return dispatchOne({ ...args, file: fileList[0], files: undefined });
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return dispatchOne(args);
|
|
526
|
+
}
|
|
527
|
+
default: throw new Error(`Unknown code-graph tool: ${name}`);
|
|
528
|
+
}
|
|
529
|
+
})();
|
|
530
|
+
if (!signal) return _work;
|
|
531
|
+
let onAbort = null;
|
|
532
|
+
const abortP = new Promise((_, reject) => {
|
|
533
|
+
if (signal.aborted) { reject(new Error('aborted')); return; }
|
|
534
|
+
onAbort = () => reject(new Error('aborted'));
|
|
535
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
536
|
+
});
|
|
537
|
+
const cleanup = () => {
|
|
538
|
+
if (onAbort) {
|
|
539
|
+
try { signal.removeEventListener('abort', onAbort); } catch {}
|
|
540
|
+
onAbort = null;
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
return Promise.race([_work, abortP]).then(
|
|
544
|
+
(v) => { cleanup(); return v; },
|
|
545
|
+
(e) => { cleanup(); throw e; },
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
export function isCodeGraphTool(name) {
|
|
550
|
+
return CODE_GRAPH_TOOL_DEFS.some((t) => t.name === name);
|
|
551
|
+
}
|