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,382 @@
|
|
|
1
|
+
// Per-cwd on-disk code-graph cache: manifest + <hash>.json layout, legacy
|
|
2
|
+
// single-file migration, budget pruning, orphan sweep, and a debounced
|
|
3
|
+
// atomic flush. Owns its own module-level state (the in-memory disk map,
|
|
4
|
+
// manifest, flush timer). Extracted verbatim from code-graph.mjs.
|
|
5
|
+
import { createHash } from 'node:crypto';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import {
|
|
8
|
+
readdirSync, readFileSync, statSync, existsSync, mkdirSync, renameSync, unlinkSync,
|
|
9
|
+
} from 'node:fs';
|
|
10
|
+
import { getPluginData } from '../../config.mjs';
|
|
11
|
+
import { writeJsonAtomicSync } from '../../../../shared/atomic-file.mjs';
|
|
12
|
+
import {
|
|
13
|
+
canonicalGraphCwd as _canonicalGraphCwd,
|
|
14
|
+
registerCodeGraphDrain,
|
|
15
|
+
drainCodeGraphCache as drainCodeGraphCacheState,
|
|
16
|
+
} from '../code-graph-state.mjs';
|
|
17
|
+
import {
|
|
18
|
+
CODE_GRAPH_DISK_FILE,
|
|
19
|
+
CODE_GRAPH_DISK_DIR,
|
|
20
|
+
CODE_GRAPH_DISK_MAX_ENTRIES,
|
|
21
|
+
CODE_GRAPH_DISK_MAX_BYTES,
|
|
22
|
+
ORPHAN_TMP_MIN_AGE_MS,
|
|
23
|
+
RE_CACHE_TMP,
|
|
24
|
+
RE_MANIFEST_TMP,
|
|
25
|
+
RE_CACHE_LOCK,
|
|
26
|
+
} from './constants.mjs';
|
|
27
|
+
import { _serializeGraph, _deserializeGraph } from './graph-model.mjs';
|
|
28
|
+
|
|
29
|
+
const _diskCodeGraphCache = new Map();
|
|
30
|
+
let _diskCodeGraphCacheLoaded = false;
|
|
31
|
+
let _diskCodeGraphCacheFlushTimer = null;
|
|
32
|
+
// Per-cwd manifest read at boot; per-cwd entries load on demand via
|
|
33
|
+
// _ensureCwdLoaded(cwd). Avoids the cold-start I/O spike that hit every
|
|
34
|
+
// fresh process when the legacy single-file cache grew unbounded.
|
|
35
|
+
let _diskManifest = null;
|
|
36
|
+
|
|
37
|
+
function _codeGraphDiskDir() {
|
|
38
|
+
return join(getPluginData(), CODE_GRAPH_DISK_DIR);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const _HASH_CWD_CACHE_MAX = 50;
|
|
42
|
+
const _hashCwdCache = new Map();
|
|
43
|
+
|
|
44
|
+
function _hashCwd(cwd) {
|
|
45
|
+
// Memoize SHA256(canonical cwd) — the same canonical cwd is hashed
|
|
46
|
+
// repeatedly on persist/sweep hot paths. Keyed by canonical cwd; capped
|
|
47
|
+
// so a long-lived process cycling through many cwds can't grow unbounded.
|
|
48
|
+
const canon = _canonicalGraphCwd(cwd);
|
|
49
|
+
const cached = _hashCwdCache.get(canon);
|
|
50
|
+
if (cached !== undefined) return cached;
|
|
51
|
+
const hash = createHash('sha256').update(canon).digest('hex').slice(0, 16);
|
|
52
|
+
if (_hashCwdCache.size >= _HASH_CWD_CACHE_MAX) {
|
|
53
|
+
// Evict oldest insertion (Map preserves insertion order).
|
|
54
|
+
_hashCwdCache.delete(_hashCwdCache.keys().next().value);
|
|
55
|
+
}
|
|
56
|
+
_hashCwdCache.set(canon, hash);
|
|
57
|
+
return hash;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function _migrateLegacyDiskCache() {
|
|
61
|
+
const legacy = join(getPluginData(), CODE_GRAPH_DISK_FILE);
|
|
62
|
+
if (!existsSync(legacy)) return;
|
|
63
|
+
try {
|
|
64
|
+
const parsed = JSON.parse(readFileSync(legacy, 'utf8'));
|
|
65
|
+
if (parsed && typeof parsed === 'object') {
|
|
66
|
+
for (const [cwd, entry] of Object.entries(parsed)) {
|
|
67
|
+
if (!entry || typeof entry !== 'object') continue;
|
|
68
|
+
_diskCodeGraphCache.set(_canonicalGraphCwd(cwd), entry);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Rename rather than delete so a rollback can recover the blob if the
|
|
72
|
+
// per-cwd layout misbehaves. Next persist round writes the new layout
|
|
73
|
+
// and the legacy path no longer exists, so this branch is a one-shot.
|
|
74
|
+
renameSync(legacy, `${legacy}.bak-${Date.now()}`);
|
|
75
|
+
// Schedule an immediate flush so the in-memory entries we just loaded
|
|
76
|
+
// get written out as per-cwd files now, instead of waiting for the
|
|
77
|
+
// next graph rebuild to trigger _setDiskCodeGraphEntry. Without this,
|
|
78
|
+
// the layout transition is half-complete (legacy renamed, new layout
|
|
79
|
+
// empty) until an unrelated build happens to land.
|
|
80
|
+
_scheduleDiskCodeGraphCacheFlush();
|
|
81
|
+
} catch (err) {
|
|
82
|
+
process.stderr.write(`[code-graph] legacy cache migration failed: ${err?.message || err}\n`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function _pruneDiskCodeGraphEntries(_now = Date.now()) {
|
|
87
|
+
for (const [cwd, entry] of _diskCodeGraphCache) {
|
|
88
|
+
if (!entry || typeof entry !== 'object') {
|
|
89
|
+
_diskCodeGraphCache.delete(cwd);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
// Disk entries are not TTL-evicted: signature validation on load/build
|
|
93
|
+
// plus _pruneCodeGraphManifestForBudget (MIXDOG_CODE_GRAPH_CACHE_MAX_MB)
|
|
94
|
+
// govern freshness and size. Memory cache keeps CODE_GRAPH_TTL_MS.
|
|
95
|
+
}
|
|
96
|
+
while (_diskCodeGraphCache.size > CODE_GRAPH_DISK_MAX_ENTRIES) {
|
|
97
|
+
const oldest = _diskCodeGraphCache.keys().next().value;
|
|
98
|
+
if (!oldest) break;
|
|
99
|
+
_diskCodeGraphCache.delete(oldest);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function _isCodeGraphCacheHash(value) {
|
|
104
|
+
return /^[0-9a-f]{8,64}$/i.test(String(value || ''));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function _pruneCodeGraphManifestForBudget(manifest, dir, options = {}) {
|
|
108
|
+
const maxEntries = Number.isFinite(options.maxEntries)
|
|
109
|
+
? Math.max(0, Math.floor(options.maxEntries))
|
|
110
|
+
: CODE_GRAPH_DISK_MAX_ENTRIES;
|
|
111
|
+
const maxBytes = Number.isFinite(options.maxBytes)
|
|
112
|
+
? Math.max(0, Math.floor(options.maxBytes))
|
|
113
|
+
: CODE_GRAPH_DISK_MAX_BYTES;
|
|
114
|
+
const rows = [];
|
|
115
|
+
for (const [cwd, meta] of Object.entries(manifest || {})) {
|
|
116
|
+
const hash = String(meta?.hash || '');
|
|
117
|
+
if (!cwd || !_isCodeGraphCacheHash(hash)) continue;
|
|
118
|
+
const file = join(dir, `${hash}.json`);
|
|
119
|
+
let size = 0;
|
|
120
|
+
try { size = statSync(file).size; } catch { continue; }
|
|
121
|
+
rows.push({
|
|
122
|
+
cwd,
|
|
123
|
+
hash,
|
|
124
|
+
builtAt: Number(meta?.builtAt) || 0,
|
|
125
|
+
size: Math.max(0, Number(size) || 0),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
rows.sort((a, b) => (a.builtAt - b.builtAt) || a.cwd.localeCompare(b.cwd));
|
|
129
|
+
const keep = new Set(rows.map((row) => row.cwd));
|
|
130
|
+
let totalBytes = rows.reduce((sum, row) => sum + row.size, 0);
|
|
131
|
+
const evicted = [];
|
|
132
|
+
|
|
133
|
+
const evict = (row, reason) => {
|
|
134
|
+
if (!row || !keep.has(row.cwd)) return false;
|
|
135
|
+
keep.delete(row.cwd);
|
|
136
|
+
totalBytes -= row.size;
|
|
137
|
+
evicted.push({ ...row, reason });
|
|
138
|
+
return true;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
for (const row of rows) {
|
|
142
|
+
if (keep.size <= maxEntries) break;
|
|
143
|
+
evict(row, 'max-entries');
|
|
144
|
+
}
|
|
145
|
+
for (const row of rows) {
|
|
146
|
+
if (totalBytes <= maxBytes) break;
|
|
147
|
+
evict(row, 'max-bytes');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const pruned = {};
|
|
151
|
+
for (const row of rows) {
|
|
152
|
+
if (!keep.has(row.cwd)) continue;
|
|
153
|
+
pruned[row.cwd] = { hash: row.hash, builtAt: row.builtAt };
|
|
154
|
+
}
|
|
155
|
+
return { manifest: pruned, evicted, totalBytes: Math.max(0, totalBytes) };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function _readCacheLockOwnerPid(lockPath) {
|
|
159
|
+
try {
|
|
160
|
+
const raw = readFileSync(lockPath, 'utf8');
|
|
161
|
+
const tok = String(raw).trim().split(/\s+/)[0];
|
|
162
|
+
const pid = Number.parseInt(tok, 10);
|
|
163
|
+
return Number.isFinite(pid) && pid > 0 ? pid : null;
|
|
164
|
+
} catch {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function _cacheLockOwnerIsDead(lockPath) {
|
|
170
|
+
const pid = _readCacheLockOwnerPid(lockPath);
|
|
171
|
+
// Unparseable/unreadable owner pid: keep the lock (conservative). Truly stale
|
|
172
|
+
// locks are reclaimed on the next writeJsonAtomicSync via atomic-file.mjs
|
|
173
|
+
// stale-lock recovery (mtime > staleMs, dead owner pid).
|
|
174
|
+
if (pid === null) return false;
|
|
175
|
+
if (pid === process.pid) return false;
|
|
176
|
+
try {
|
|
177
|
+
process.kill(pid, 0);
|
|
178
|
+
return false;
|
|
179
|
+
} catch (err) {
|
|
180
|
+
return err?.code === 'ESRCH';
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function _cacheFileOlderThanGuard(fullPath, now, minAgeMs) {
|
|
185
|
+
try {
|
|
186
|
+
const st = statSync(fullPath);
|
|
187
|
+
return now - st.mtimeMs > minAgeMs;
|
|
188
|
+
} catch {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Best-effort orphan cleanup: evicted <hash>.json plus aged atomic-write .tmp/.lock
|
|
194
|
+
// left by crash/kill between temp write and rename (writeFileAtomicSync). Young temps
|
|
195
|
+
// are kept because a live persist may still hold the matching .lock while writing.
|
|
196
|
+
function _sweepCodeGraphCacheDir(dir, validHashes, opts = {}) {
|
|
197
|
+
const now = Number.isFinite(opts.now) ? opts.now : Date.now();
|
|
198
|
+
const sweepJson = opts.sweepJson !== false;
|
|
199
|
+
try {
|
|
200
|
+
for (const f of readdirSync(dir)) {
|
|
201
|
+
const full = join(dir, f);
|
|
202
|
+
if (f === 'manifest.json') continue;
|
|
203
|
+
if (f.endsWith('.json')) {
|
|
204
|
+
if (!sweepJson) continue;
|
|
205
|
+
const hash = f.slice(0, -5);
|
|
206
|
+
if (!validHashes.has(hash)) {
|
|
207
|
+
try { unlinkSync(full); } catch { /* best-effort */ }
|
|
208
|
+
}
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (RE_CACHE_TMP.test(f) || RE_MANIFEST_TMP.test(f)) {
|
|
212
|
+
if (!_cacheFileOlderThanGuard(full, now, ORPHAN_TMP_MIN_AGE_MS)) continue;
|
|
213
|
+
try { unlinkSync(full); } catch { /* best-effort */ }
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (f === 'manifest.json.lock' || RE_CACHE_LOCK.test(f)) {
|
|
217
|
+
if (!_cacheFileOlderThanGuard(full, now, ORPHAN_TMP_MIN_AGE_MS)) continue;
|
|
218
|
+
if (!_cacheLockOwnerIsDead(full)) continue;
|
|
219
|
+
try { unlinkSync(full); } catch { /* best-effort */ }
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
} catch { /* sweep best-effort */ }
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function _loadDiskCodeGraphCache(now = Date.now()) {
|
|
226
|
+
if (_diskCodeGraphCacheLoaded) return;
|
|
227
|
+
_diskCodeGraphCacheLoaded = true;
|
|
228
|
+
|
|
229
|
+
// One-shot migration from the legacy single-file cache. Subsequent boots
|
|
230
|
+
// skip this branch because the source file was renamed to .bak.
|
|
231
|
+
_migrateLegacyDiskCache();
|
|
232
|
+
|
|
233
|
+
// Manifest-only load: per-cwd entries are picked up by _ensureCwdLoaded()
|
|
234
|
+
// at lookup time. Cold start now pays a single small JSON.parse instead
|
|
235
|
+
// of reading every per-cwd file (~24 × ~2 MB on long-running workspaces).
|
|
236
|
+
let manifestTrusted = false;
|
|
237
|
+
try {
|
|
238
|
+
const manifestFile = join(_codeGraphDiskDir(), 'manifest.json');
|
|
239
|
+
if (existsSync(manifestFile)) {
|
|
240
|
+
const parsed = JSON.parse(readFileSync(manifestFile, 'utf8'));
|
|
241
|
+
if (parsed && typeof parsed === 'object') {
|
|
242
|
+
_diskManifest = parsed;
|
|
243
|
+
manifestTrusted = true;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
} catch (err) {
|
|
247
|
+
process.stderr.write(`[code-graph] disk manifest load failed: ${err?.message || err}\n`);
|
|
248
|
+
}
|
|
249
|
+
if (!_diskManifest) _diskManifest = {};
|
|
250
|
+
_pruneDiskCodeGraphEntries(now);
|
|
251
|
+
try {
|
|
252
|
+
const dir = _codeGraphDiskDir();
|
|
253
|
+
mkdirSync(dir, { recursive: true });
|
|
254
|
+
const validHashes = new Set();
|
|
255
|
+
for (const meta of Object.values(_diskManifest)) {
|
|
256
|
+
if (meta && typeof meta === 'object' && meta.hash) validHashes.add(meta.hash);
|
|
257
|
+
}
|
|
258
|
+
// Without a successfully loaded manifest we must not delete <hash>.json
|
|
259
|
+
// files (validHashes would be empty or incomplete after a parse failure).
|
|
260
|
+
_sweepCodeGraphCacheDir(dir, validHashes, { now, sweepJson: manifestTrusted });
|
|
261
|
+
} catch { /* boot sweep best-effort */ }
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Demand-load one cwd's per-file entry. Callers invoke this right before
|
|
265
|
+
// reading the disk cache so the in-memory cache stays populated only for
|
|
266
|
+
// cwds actually looked up in this process lifetime.
|
|
267
|
+
function _ensureCwdLoaded(cwd) {
|
|
268
|
+
const key = _canonicalGraphCwd(cwd);
|
|
269
|
+
if (_diskCodeGraphCache.has(key)) return;
|
|
270
|
+
if (!_diskManifest) return;
|
|
271
|
+
const meta = _diskManifest[key];
|
|
272
|
+
if (!meta || typeof meta !== 'object' || !meta.hash) return;
|
|
273
|
+
try {
|
|
274
|
+
const file = join(_codeGraphDiskDir(), `${meta.hash}.json`);
|
|
275
|
+
if (!existsSync(file)) return;
|
|
276
|
+
const entry = JSON.parse(readFileSync(file, 'utf8'));
|
|
277
|
+
if (entry && typeof entry === 'object') _diskCodeGraphCache.set(key, entry);
|
|
278
|
+
} catch { /* skip corrupt per-cwd file */ }
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function _persistDiskCodeGraphCacheNow() {
|
|
282
|
+
try {
|
|
283
|
+
_loadDiskCodeGraphCache();
|
|
284
|
+
_pruneDiskCodeGraphEntries();
|
|
285
|
+
const dir = _codeGraphDiskDir();
|
|
286
|
+
mkdirSync(dir, { recursive: true });
|
|
287
|
+
|
|
288
|
+
// Read the on-disk manifest BEFORE writing so cwd entries owned by
|
|
289
|
+
// other instances (MIXDOG_MULTI_INSTANCE=1) survive. Without this,
|
|
290
|
+
// our orphan sweep below would happily unlink another instance's
|
|
291
|
+
// per-cwd files just because we don't have them in our in-memory map.
|
|
292
|
+
let preserved = {};
|
|
293
|
+
try {
|
|
294
|
+
const raw = readFileSync(join(dir, 'manifest.json'), 'utf8');
|
|
295
|
+
const parsed = JSON.parse(raw);
|
|
296
|
+
if (parsed && typeof parsed === 'object') preserved = parsed;
|
|
297
|
+
} catch { /* no existing manifest yet */ }
|
|
298
|
+
|
|
299
|
+
let manifest = { ...preserved };
|
|
300
|
+
const validHashes = new Set();
|
|
301
|
+
for (const [cwd, entry] of _diskCodeGraphCache) {
|
|
302
|
+
const hash = _hashCwd(cwd);
|
|
303
|
+
const file = join(dir, `${hash}.json`);
|
|
304
|
+
writeJsonAtomicSync(file, entry, { compact: true, lock: true });
|
|
305
|
+
manifest[cwd] = { hash, builtAt: entry.builtAt || Date.now() };
|
|
306
|
+
}
|
|
307
|
+
const pruned = _pruneCodeGraphManifestForBudget(manifest, dir);
|
|
308
|
+
manifest = pruned.manifest;
|
|
309
|
+
for (const row of pruned.evicted) {
|
|
310
|
+
_diskCodeGraphCache.delete(row.cwd);
|
|
311
|
+
}
|
|
312
|
+
for (const meta of Object.values(manifest)) {
|
|
313
|
+
if (meta && typeof meta === 'object' && meta.hash) validHashes.add(meta.hash);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const manifestFile = join(dir, 'manifest.json');
|
|
317
|
+
writeJsonAtomicSync(manifestFile, manifest, { compact: true, lock: true });
|
|
318
|
+
_diskManifest = manifest;
|
|
319
|
+
|
|
320
|
+
// Sweep orphan per-cwd files. validHashes now includes every hash in
|
|
321
|
+
// the merged manifest (preserved + ours) so cross-instance cache files
|
|
322
|
+
// are never collateral damage.
|
|
323
|
+
_sweepCodeGraphCacheDir(dir, validHashes, { sweepJson: true });
|
|
324
|
+
} catch (err) {
|
|
325
|
+
process.stderr.write(`[code-graph] disk cache persist failed (target: ${_codeGraphDiskDir()}): ${err?.message || err}\n`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function _scheduleDiskCodeGraphCacheFlush() {
|
|
330
|
+
if (_diskCodeGraphCacheFlushTimer) return;
|
|
331
|
+
_diskCodeGraphCacheFlushTimer = setTimeout(() => {
|
|
332
|
+
_diskCodeGraphCacheFlushTimer = null;
|
|
333
|
+
_persistDiskCodeGraphCacheNow();
|
|
334
|
+
}, 250);
|
|
335
|
+
if (typeof _diskCodeGraphCacheFlushTimer.unref === 'function') _diskCodeGraphCacheFlushTimer.unref();
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Sync-flush any pending code-graph disk cache write before process exit.
|
|
340
|
+
* Cancels the 250ms scheduled-flush timer and runs _persistDiskCodeGraphCacheNow
|
|
341
|
+
* directly so newly-built graphs land on disk regardless of exit timing.
|
|
342
|
+
*/
|
|
343
|
+
function drainCodeGraphCacheNow() {
|
|
344
|
+
if (_diskCodeGraphCacheFlushTimer) {
|
|
345
|
+
clearTimeout(_diskCodeGraphCacheFlushTimer);
|
|
346
|
+
_diskCodeGraphCacheFlushTimer = null;
|
|
347
|
+
_persistDiskCodeGraphCacheNow();
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
registerCodeGraphDrain(drainCodeGraphCacheNow);
|
|
351
|
+
|
|
352
|
+
// Public: delegate to the state module's drain hook (which invokes the
|
|
353
|
+
// registered drainCodeGraphCacheNow). Preserves the original facade behavior.
|
|
354
|
+
export function drainCodeGraphCache() {
|
|
355
|
+
drainCodeGraphCacheState();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Read a demand-loaded disk entry for `cwd` (loads it first). Returns the
|
|
359
|
+
// serialized payload or undefined. Callers deserialize via graph-model.
|
|
360
|
+
export function getDiskCodeGraphEntry(cwd) {
|
|
361
|
+
const key = _canonicalGraphCwd(cwd);
|
|
362
|
+
_ensureCwdLoaded(key);
|
|
363
|
+
return _diskCodeGraphCache.get(key);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Ensure the on-disk manifest/sweep boot pass has run (idempotent).
|
|
367
|
+
export function ensureDiskCodeGraphLoaded(now = Date.now()) {
|
|
368
|
+
_loadDiskCodeGraphCache(now);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export function _setDiskCodeGraphEntry(cwd, graph) {
|
|
372
|
+
_loadDiskCodeGraphCache();
|
|
373
|
+
// Stamp the cache entry with the persistence timestamp (not the build
|
|
374
|
+
// start) so manifest/signature metadata stays fresh. Disk retention is
|
|
375
|
+
// governed by signature validation and MIXDOG_CODE_GRAPH_CACHE_MAX_MB,
|
|
376
|
+
// not CODE_GRAPH_TTL_MS (memory cache only).
|
|
377
|
+
const serialized = _serializeGraph(graph);
|
|
378
|
+
serialized.builtAt = Date.now();
|
|
379
|
+
_diskCodeGraphCache.set(_canonicalGraphCwd(cwd), serialized);
|
|
380
|
+
_pruneDiskCodeGraphEntries();
|
|
381
|
+
_scheduleDiskCodeGraphCacheFlush();
|
|
382
|
+
}
|