mixdog 0.7.1
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/.claude-plugin/marketplace.json +31 -0
- package/.claude-plugin/plugin.json +20 -0
- package/.gitattributes +34 -0
- package/.mcp.json +14 -0
- package/ARCHITECTURE.md +77 -0
- package/CHANGELOG.md +7 -0
- package/CONTRIBUTING.md +45 -0
- package/DATA-FLOW.md +79 -0
- package/LICENSE +21 -0
- package/README.md +389 -0
- package/SECURITY.md +138 -0
- package/UNINSTALL.md +112 -0
- package/agents/maintenance.md +5 -0
- package/agents/memory-classification.md +30 -0
- package/agents/scheduler-task.md +18 -0
- package/agents/webhook-handler.md +27 -0
- package/agents/worker.md +24 -0
- package/bin/bridge +133 -0
- package/bin/statusline-launcher.mjs +78 -0
- package/bin/statusline-lib.mjs +550 -0
- package/bin/statusline.mjs +607 -0
- package/bun.lock +802 -0
- package/commands/config.md +16 -0
- package/commands/doctor.md +13 -0
- package/commands/setup.md +17 -0
- package/defaults/cycle3-review-prompt.md +90 -0
- package/defaults/hidden-roles.json +65 -0
- package/defaults/memory-chunk-prompt.md +63 -0
- package/defaults/memory-promote-prompt.md +135 -0
- package/defaults/mixdog-config.template.json +27 -0
- package/defaults/user-workflow.json +8 -0
- package/defaults/user-workflow.md +12 -0
- package/hooks/hooks.json +73 -0
- package/hooks/lib/active-instance.cjs +77 -0
- package/hooks/lib/permission-evaluator.cjs +411 -0
- package/hooks/lib/permission-route.cjs +63 -0
- package/hooks/lib/permission-rules.cjs +170 -0
- package/hooks/lib/settings-loader.cjs +116 -0
- package/hooks/post-tool-use.cjs +84 -0
- package/hooks/pre-mcp-sandbox.cjs +158 -0
- package/hooks/pre-tool-subagent.cjs +253 -0
- package/hooks/session-start.cjs +1372 -0
- package/hooks/turn-timer.cjs +82 -0
- package/lib/claude-md-writer.cjs +386 -0
- package/lib/config-cjs.cjs +61 -0
- package/lib/hook-pipe-path.cjs +10 -0
- package/lib/keychain-cjs.cjs +263 -0
- package/lib/plugin-paths.cjs +61 -0
- package/lib/rules-builder.cjs +241 -0
- package/lib/text-utils.cjs +61 -0
- package/native/README.md +117 -0
- package/native/prebuilt/linux-aarch64/mixdog-shim +0 -0
- package/native/prebuilt/linux-x86_64/mixdog-shim +0 -0
- package/native/prebuilt/macos-aarch64/mixdog-shim +0 -0
- package/native/prebuilt/macos-x86_64/mixdog-shim +0 -0
- package/native/prebuilt/windows-x86_64/mixdog-shim.exe +0 -0
- package/package.json +107 -0
- package/prompts/code-review.txt +16 -0
- package/prompts/security-audit.txt +17 -0
- package/rules/bridge/00-common.md +39 -0
- package/rules/bridge/20-skip-protocol.md +18 -0
- package/rules/bridge/30-explorer.md +33 -0
- package/rules/bridge/40-cycle1-agent.md +52 -0
- package/rules/bridge/41-cycle2-agent.md +62 -0
- package/rules/bridge/42-cycle3-agent.md +44 -0
- package/rules/lead/00-tool-lead.md +61 -0
- package/rules/lead/01-general.md +23 -0
- package/rules/lead/02-channels.md +49 -0
- package/rules/lead/03-team.md +27 -0
- package/rules/lead/04-workflow.md +20 -0
- package/rules/shared/00-language.md +14 -0
- package/rules/shared/01-tool.md +138 -0
- package/scripts/bootstrap.mjs +184 -0
- package/scripts/bridge-unify-smoke.mjs +308 -0
- package/scripts/build-runtime-linux.sh +348 -0
- package/scripts/build-runtime-macos.sh +217 -0
- package/scripts/build-runtime-windows.ps1 +242 -0
- package/scripts/builtin-utils-smoke.mjs +392 -0
- package/scripts/check-json.mjs +45 -0
- package/scripts/check-syntax-changed.mjs +102 -0
- package/scripts/check-syntax.mjs +58 -0
- package/scripts/code-graph-batch.test.mjs +33 -0
- package/scripts/config-preserve-smoke.mjs +180 -0
- package/scripts/doctor.mjs +484 -0
- package/scripts/edit-normalize-fuzz.mjs +130 -0
- package/scripts/edit-normalize-smoke.mjs +401 -0
- package/scripts/edit-operation-smoke.mjs +369 -0
- package/scripts/edit2-smoke.mjs +63 -0
- package/scripts/fuzzy-e2e.mjs +28 -0
- package/scripts/fuzzy-smoke.mjs +26 -0
- package/scripts/generate-runtime-manifest.mjs +166 -0
- package/scripts/guard-smoke.mjs +66 -0
- package/scripts/hidden-role-schema-smoke.mjs +162 -0
- package/scripts/hook-routing-smoke.mjs +29 -0
- package/scripts/inject-input.ps1 +204 -0
- package/scripts/io-complex-smoke.mjs +667 -0
- package/scripts/io-explore-bench.mjs +424 -0
- package/scripts/io-guardrails-smoke.mjs +205 -0
- package/scripts/io-mini-bench-baseline.json +11 -0
- package/scripts/io-mini-bench.mjs +216 -0
- package/scripts/io-route-harness.mjs +933 -0
- package/scripts/io-telemetry-report.mjs +691 -0
- package/scripts/mutation-bench.mjs +564 -0
- package/scripts/mutation-io-smoke.mjs +1081 -0
- package/scripts/native-patch-bridge-smoke.mjs +288 -0
- package/scripts/native-patch-smoke.mjs +304 -0
- package/scripts/patch-interior-context-smoke.mjs +49 -0
- package/scripts/patch-newline-utf8-smoke.mjs +157 -0
- package/scripts/perf-hook-smoke.mjs +71 -0
- package/scripts/permission-eval-smoke.mjs +426 -0
- package/scripts/prep-patch.mjs +53 -0
- package/scripts/prep-shim.mjs +96 -0
- package/scripts/provider-cache-smoke.mjs +687 -0
- package/scripts/report-runtime-health.mjs +132 -0
- package/scripts/run-mcp.mjs +1547 -0
- package/scripts/salvage-v4a-shatter.test.mjs +58 -0
- package/scripts/scoped-cache-io-smoke.mjs +103 -0
- package/scripts/shell-policy-round3-smoke.mjs +46 -0
- package/scripts/smoke-runtime-negative.ps1 +100 -0
- package/scripts/smoke-runtime-negative.sh +95 -0
- package/scripts/stall-policy-smoke.mjs +50 -0
- package/scripts/start-memory-worker.mjs +23 -0
- package/scripts/statusline-launcher-smoke.mjs +82 -0
- package/scripts/stress-atomic-write.mjs +1028 -0
- package/scripts/test-config-rmw-restore.mjs +122 -0
- package/scripts/test-fault-inject.mjs +164 -0
- package/scripts/test-large-file.mjs +174 -0
- package/scripts/tool-edge-smoke.mjs +209 -0
- package/scripts/uninstall.mjs +201 -0
- package/scripts/webhook-selfheal-smoke.mjs +29 -0
- package/scripts/write-overwrite-guard-smoke.mjs +56 -0
- package/server-main.mjs +3055 -0
- package/server.mjs +468 -0
- package/setup/config-merge.mjs +254 -0
- package/setup/install.mjs +120 -0
- package/setup/launch-core.mjs +507 -0
- package/setup/launch.mjs +101 -0
- package/setup/setup-server.mjs +3206 -0
- package/setup/setup.html +3693 -0
- package/skills/retro-skill-proposer/SKILL.md +92 -0
- package/skills/schedule-add/SKILL.md +77 -0
- package/skills/setup/SKILL.md +346 -0
- package/skills/webhook-add/SKILL.md +81 -0
- package/src/agent/bridge-stall-watchdog.mjs +337 -0
- package/src/agent/index.mjs +2138 -0
- package/src/agent/orchestrator/activity-bus.mjs +38 -0
- package/src/agent/orchestrator/ai-wrapped-dispatch.mjs +1010 -0
- package/src/agent/orchestrator/bridge-retry.mjs +220 -0
- package/src/agent/orchestrator/bridge-trace.mjs +583 -0
- package/src/agent/orchestrator/cache-mtime.mjs +58 -0
- package/src/agent/orchestrator/config.mjs +358 -0
- package/src/agent/orchestrator/context/collect.mjs +651 -0
- package/src/agent/orchestrator/dispatch-persist.mjs +549 -0
- package/src/agent/orchestrator/drain-registry.mjs +50 -0
- package/src/agent/orchestrator/explore-validator.mjs +8 -0
- package/src/agent/orchestrator/internal-roles.mjs +118 -0
- package/src/agent/orchestrator/internal-tools.mjs +88 -0
- package/src/agent/orchestrator/jobs.mjs +116 -0
- package/src/agent/orchestrator/mcp/client.mjs +364 -0
- package/src/agent/orchestrator/providers/anthropic-betas.mjs +21 -0
- package/src/agent/orchestrator/providers/anthropic-oauth.mjs +1745 -0
- package/src/agent/orchestrator/providers/anthropic.mjs +437 -0
- package/src/agent/orchestrator/providers/gemini.mjs +1175 -0
- package/src/agent/orchestrator/providers/grok-oauth.mjs +782 -0
- package/src/agent/orchestrator/providers/model-catalog.mjs +241 -0
- package/src/agent/orchestrator/providers/openai-compat.mjs +1467 -0
- package/src/agent/orchestrator/providers/openai-oauth-ws.mjs +1890 -0
- package/src/agent/orchestrator/providers/openai-oauth.mjs +1307 -0
- package/src/agent/orchestrator/providers/openai-ws.mjs +104 -0
- package/src/agent/orchestrator/providers/registry.mjs +192 -0
- package/src/agent/orchestrator/providers/retry-classifier.mjs +325 -0
- package/src/agent/orchestrator/session/abort-lookup.mjs +13 -0
- package/src/agent/orchestrator/session/cache/post-edit-marks.mjs +42 -0
- package/src/agent/orchestrator/session/cache/prefetch-cache.mjs +142 -0
- package/src/agent/orchestrator/session/cache/read-cache.mjs +319 -0
- package/src/agent/orchestrator/session/cache/scoped-cache-outcome.mjs +11 -0
- package/src/agent/orchestrator/session/cache/scoped-cache.mjs +361 -0
- package/src/agent/orchestrator/session/cache/util.mjs +49 -0
- package/src/agent/orchestrator/session/loop.mjs +1478 -0
- package/src/agent/orchestrator/session/manager.mjs +1975 -0
- package/src/agent/orchestrator/session/read-dedup.mjs +6 -0
- package/src/agent/orchestrator/session/result-classification.mjs +65 -0
- package/src/agent/orchestrator/session/save-session-worker.mjs +18 -0
- package/src/agent/orchestrator/session/store.mjs +624 -0
- package/src/agent/orchestrator/session/stream-watchdog.mjs +130 -0
- package/src/agent/orchestrator/session/tool-result-offload.mjs +166 -0
- package/src/agent/orchestrator/session/trim.mjs +491 -0
- package/src/agent/orchestrator/smart-bridge/CACHE-SHARD.md +115 -0
- package/src/agent/orchestrator/smart-bridge/bridge-llm.mjs +327 -0
- package/src/agent/orchestrator/smart-bridge/cache-obs.mjs +150 -0
- package/src/agent/orchestrator/smart-bridge/cache-strategy.mjs +228 -0
- package/src/agent/orchestrator/smart-bridge/index.mjs +215 -0
- package/src/agent/orchestrator/smart-bridge/profiles.mjs +37 -0
- package/src/agent/orchestrator/smart-bridge/registry.mjs +348 -0
- package/src/agent/orchestrator/smart-bridge/session-builder.mjs +116 -0
- package/src/agent/orchestrator/stall-policy.mjs +195 -0
- package/src/agent/orchestrator/tool-loop-guard.mjs +75 -0
- package/src/agent/orchestrator/tools/bash-policy-scan.mjs +77 -0
- package/src/agent/orchestrator/tools/bash-session.mjs +721 -0
- package/src/agent/orchestrator/tools/builtin/advisory-lock.mjs +171 -0
- package/src/agent/orchestrator/tools/builtin/arg-guard.mjs +455 -0
- package/src/agent/orchestrator/tools/builtin/atomic-write.mjs +236 -0
- package/src/agent/orchestrator/tools/builtin/bash-tool.mjs +480 -0
- package/src/agent/orchestrator/tools/builtin/binary-file.mjs +76 -0
- package/src/agent/orchestrator/tools/builtin/builtin-tools.mjs +256 -0
- package/src/agent/orchestrator/tools/builtin/cache-layers.mjs +386 -0
- package/src/agent/orchestrator/tools/builtin/cwd-utils.mjs +37 -0
- package/src/agent/orchestrator/tools/builtin/device-paths.mjs +154 -0
- package/src/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +292 -0
- package/src/agent/orchestrator/tools/builtin/diff-utils.mjs +109 -0
- package/src/agent/orchestrator/tools/builtin/edit-base-guard.mjs +58 -0
- package/src/agent/orchestrator/tools/builtin/edit-byte-plan.mjs +240 -0
- package/src/agent/orchestrator/tools/builtin/edit-byte-utils.mjs +113 -0
- package/src/agent/orchestrator/tools/builtin/edit-commit.mjs +74 -0
- package/src/agent/orchestrator/tools/builtin/edit-context-utils.mjs +242 -0
- package/src/agent/orchestrator/tools/builtin/edit-diagnostics.mjs +211 -0
- package/src/agent/orchestrator/tools/builtin/edit-engine.mjs +1364 -0
- package/src/agent/orchestrator/tools/builtin/edit-failure-context.mjs +126 -0
- package/src/agent/orchestrator/tools/builtin/edit-hint.mjs +141 -0
- package/src/agent/orchestrator/tools/builtin/edit-match-utils.mjs +194 -0
- package/src/agent/orchestrator/tools/builtin/edit-partial-write.mjs +60 -0
- package/src/agent/orchestrator/tools/builtin/edit-stale-refresh.mjs +168 -0
- package/src/agent/orchestrator/tools/builtin/edit-tool.mjs +173 -0
- package/src/agent/orchestrator/tools/builtin/edit-utf8-guard.mjs +48 -0
- package/src/agent/orchestrator/tools/builtin/fs-reachability.mjs +48 -0
- package/src/agent/orchestrator/tools/builtin/fuzzy-match.mjs +99 -0
- package/src/agent/orchestrator/tools/builtin/glob-walk.mjs +170 -0
- package/src/agent/orchestrator/tools/builtin/grep-formatting.mjs +113 -0
- package/src/agent/orchestrator/tools/builtin/hash-utils.mjs +6 -0
- package/src/agent/orchestrator/tools/builtin/list-formatting.mjs +7 -0
- package/src/agent/orchestrator/tools/builtin/list-tool.mjs +593 -0
- package/src/agent/orchestrator/tools/builtin/native-edit-runner.mjs +89 -0
- package/src/agent/orchestrator/tools/builtin/notebook-edit-tool.mjs +300 -0
- package/src/agent/orchestrator/tools/builtin/open-config-tool.mjs +26 -0
- package/src/agent/orchestrator/tools/builtin/path-diagnostics.mjs +152 -0
- package/src/agent/orchestrator/tools/builtin/path-locks.mjs +35 -0
- package/src/agent/orchestrator/tools/builtin/path-utils.mjs +201 -0
- package/src/agent/orchestrator/tools/builtin/read-args.mjs +103 -0
- package/src/agent/orchestrator/tools/builtin/read-batch.mjs +172 -0
- package/src/agent/orchestrator/tools/builtin/read-constants.mjs +40 -0
- package/src/agent/orchestrator/tools/builtin/read-formatting.mjs +118 -0
- package/src/agent/orchestrator/tools/builtin/read-image-resize.mjs +189 -0
- package/src/agent/orchestrator/tools/builtin/read-image.mjs +88 -0
- package/src/agent/orchestrator/tools/builtin/read-lines.mjs +12 -0
- package/src/agent/orchestrator/tools/builtin/read-mode-tool.mjs +455 -0
- package/src/agent/orchestrator/tools/builtin/read-open.mjs +190 -0
- package/src/agent/orchestrator/tools/builtin/read-range-index.mjs +271 -0
- package/src/agent/orchestrator/tools/builtin/read-ranges.mjs +26 -0
- package/src/agent/orchestrator/tools/builtin/read-single-tool.mjs +728 -0
- package/src/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +173 -0
- package/src/agent/orchestrator/tools/builtin/read-special-files.mjs +268 -0
- package/src/agent/orchestrator/tools/builtin/read-streaming.mjs +602 -0
- package/src/agent/orchestrator/tools/builtin/read-tool.mjs +530 -0
- package/src/agent/orchestrator/tools/builtin/read-windows.mjs +107 -0
- package/src/agent/orchestrator/tools/builtin/rename-tool.mjs +196 -0
- package/src/agent/orchestrator/tools/builtin/rg-runner.mjs +422 -0
- package/src/agent/orchestrator/tools/builtin/search-builders.mjs +158 -0
- package/src/agent/orchestrator/tools/builtin/search-tool.mjs +869 -0
- package/src/agent/orchestrator/tools/builtin/shell-analysis.mjs +653 -0
- package/src/agent/orchestrator/tools/builtin/shell-jobs.mjs +936 -0
- package/src/agent/orchestrator/tools/builtin/shell-output.mjs +36 -0
- package/src/agent/orchestrator/tools/builtin/shell-runtime.mjs +214 -0
- package/src/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +143 -0
- package/src/agent/orchestrator/tools/builtin/snapshot-store.mjs +206 -0
- package/src/agent/orchestrator/tools/builtin/snapshot-validation.mjs +98 -0
- package/src/agent/orchestrator/tools/builtin/text-stats.mjs +69 -0
- package/src/agent/orchestrator/tools/builtin/windows-roots.mjs +23 -0
- package/src/agent/orchestrator/tools/builtin/write-tool.mjs +401 -0
- package/src/agent/orchestrator/tools/builtin.mjs +500 -0
- package/src/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +39 -0
- package/src/agent/orchestrator/tools/code-graph-tool-defs.mjs +24 -0
- package/src/agent/orchestrator/tools/code-graph.mjs +4095 -0
- package/src/agent/orchestrator/tools/cwd-tool.mjs +298 -0
- package/src/agent/orchestrator/tools/destructive-warning.mjs +323 -0
- package/src/agent/orchestrator/tools/edit-normalize.mjs +603 -0
- package/src/agent/orchestrator/tools/env-scrub.mjs +100 -0
- package/src/agent/orchestrator/tools/graph-binary-fetcher.mjs +144 -0
- package/src/agent/orchestrator/tools/graph-manifest.json +26 -0
- package/src/agent/orchestrator/tools/host-input.mjs +204 -0
- package/src/agent/orchestrator/tools/mutation-content-cache.mjs +67 -0
- package/src/agent/orchestrator/tools/mutation-planner.mjs +75 -0
- package/src/agent/orchestrator/tools/next-call-utils.mjs +48 -0
- package/src/agent/orchestrator/tools/patch-binary-fetcher.mjs +133 -0
- package/src/agent/orchestrator/tools/patch-manifest.json +26 -0
- package/src/agent/orchestrator/tools/patch-tool-defs.mjs +20 -0
- package/src/agent/orchestrator/tools/patch.mjs +2754 -0
- package/src/agent/orchestrator/tools/progress-message.mjs +118 -0
- package/src/agent/orchestrator/tools/result-compression.mjs +279 -0
- package/src/agent/orchestrator/tools/shell-command.mjs +865 -0
- package/src/agent/orchestrator/tools/shell-exec-policy.mjs +89 -0
- package/src/agent/orchestrator/tools/shell-policy-danger-target.mjs +27 -0
- package/src/agent/orchestrator/tools/shell-policy-imports.mjs +7 -0
- package/src/agent/orchestrator/tools/shell-policy.mjs +345 -0
- package/src/agent/orchestrator/tools/shell-snapshot.mjs +313 -0
- package/src/agent/orchestrator/workflow-store.mjs +93 -0
- package/src/agent/tool-defs.mjs +103 -0
- package/src/channels/backends/discord.mjs +784 -0
- package/src/channels/data/voice-runtime-manifest.json +138 -0
- package/src/channels/index.mjs +3229 -0
- package/src/channels/lib/cli-worker-host.mjs +12 -0
- package/src/channels/lib/config-lock.mjs +13 -0
- package/src/channels/lib/config.mjs +292 -0
- package/src/channels/lib/drop-trace.mjs +71 -0
- package/src/channels/lib/event-pipeline.mjs +81 -0
- package/src/channels/lib/event-queue.mjs +345 -0
- package/src/channels/lib/executor.mjs +168 -0
- package/src/channels/lib/format.mjs +188 -0
- package/src/channels/lib/holidays.mjs +138 -0
- package/src/channels/lib/hook-pipe-server.mjs +802 -0
- package/src/channels/lib/interaction-workflows.mjs +184 -0
- package/src/channels/lib/memory-client.mjs +149 -0
- package/src/channels/lib/output-forwarder.mjs +765 -0
- package/src/channels/lib/runtime-paths.mjs +479 -0
- package/src/channels/lib/scheduler.mjs +723 -0
- package/src/channels/lib/session-control.mjs +36 -0
- package/src/channels/lib/session-discovery.mjs +103 -0
- package/src/channels/lib/settings.mjs +11 -0
- package/src/channels/lib/state-file.mjs +68 -0
- package/src/channels/lib/status-snapshot.mjs +219 -0
- package/src/channels/lib/tool-format.mjs +140 -0
- package/src/channels/lib/transcript-discovery.mjs +195 -0
- package/src/channels/lib/voice-runtime-fetcher.mjs +734 -0
- package/src/channels/lib/webhook.mjs +1179 -0
- package/src/channels/lib/whisper-server.mjs +477 -0
- package/src/channels/tool-defs.mjs +170 -0
- package/src/daemon/host.mjs +118 -0
- package/src/daemon/mcp-transport.mjs +47 -0
- package/src/daemon/session.mjs +100 -0
- package/src/daemon/thin-client.mjs +71 -0
- package/src/daemon/transport.mjs +163 -0
- package/src/memory/data/runtime-manifest.json +40 -0
- package/src/memory/index.mjs +3305 -0
- package/src/memory/lib/agent-ipc.mjs +93 -0
- package/src/memory/lib/bridge-trace-queries.mjs +120 -0
- package/src/memory/lib/core-memory-store.mjs +330 -0
- package/src/memory/lib/embedding-provider.mjs +269 -0
- package/src/memory/lib/embedding-worker.mjs +323 -0
- package/src/memory/lib/llm-worker-host.mjs +17 -0
- package/src/memory/lib/memory-cycle.mjs +11 -0
- package/src/memory/lib/memory-cycle1.mjs +641 -0
- package/src/memory/lib/memory-cycle2.mjs +1284 -0
- package/src/memory/lib/memory-cycle3.mjs +540 -0
- package/src/memory/lib/memory-embed.mjs +299 -0
- package/src/memory/lib/memory-extraction.mjs +5 -0
- package/src/memory/lib/memory-maintenance-store.mjs +32 -0
- package/src/memory/lib/memory-ops-policy.mjs +190 -0
- package/src/memory/lib/memory-recall-id-patch.mjs +15 -0
- package/src/memory/lib/memory-recall-read-query.mjs +7 -0
- package/src/memory/lib/memory-recall-scope-filter.mjs +63 -0
- package/src/memory/lib/memory-recall-store.mjs +621 -0
- package/src/memory/lib/memory-retrievers.mjs +112 -0
- package/src/memory/lib/memory-score.mjs +71 -0
- package/src/memory/lib/memory-text-utils.mjs +58 -0
- package/src/memory/lib/memory.mjs +412 -0
- package/src/memory/lib/model-profile.mjs +85 -0
- package/src/memory/lib/pg/adapter.mjs +308 -0
- package/src/memory/lib/pg/process.mjs +360 -0
- package/src/memory/lib/pg/supervisor.mjs +396 -0
- package/src/memory/lib/project-id-resolver.mjs +86 -0
- package/src/memory/lib/runtime-fetcher.mjs +442 -0
- package/src/memory/lib/trace-store.mjs +728 -0
- package/src/memory/tool-defs.mjs +79 -0
- package/src/search/index.mjs +1173 -0
- package/src/search/lib/backends/anthropic-oauth.mjs +98 -0
- package/src/search/lib/backends/exa.mjs +50 -0
- package/src/search/lib/backends/firecrawl.mjs +61 -0
- package/src/search/lib/backends/gemini-api.mjs +83 -0
- package/src/search/lib/backends/grok-oauth.mjs +86 -0
- package/src/search/lib/backends/index.mjs +150 -0
- package/src/search/lib/backends/openai-api.mjs +144 -0
- package/src/search/lib/backends/openai-oauth.mjs +98 -0
- package/src/search/lib/backends/openai-web-search.mjs +76 -0
- package/src/search/lib/backends/tavily.mjs +55 -0
- package/src/search/lib/backends/xai-api.mjs +113 -0
- package/src/search/lib/cache.mjs +131 -0
- package/src/search/lib/config.mjs +192 -0
- package/src/search/lib/formatter.mjs +115 -0
- package/src/search/lib/provider-usage.mjs +67 -0
- package/src/search/lib/providers.mjs +47 -0
- package/src/search/lib/search-intent.mjs +109 -0
- package/src/search/lib/setup-handler.mjs +261 -0
- package/src/search/lib/state.mjs +201 -0
- package/src/search/lib/web-tools.mjs +1207 -0
- package/src/search/tool-defs.mjs +83 -0
- package/src/setup/defender-exclusion.mjs +183 -0
- package/src/shared/abort-controller.mjs +15 -0
- package/src/shared/atomic-file.mjs +420 -0
- package/src/shared/config.mjs +350 -0
- package/src/shared/daemon-recycle.mjs +108 -0
- package/src/shared/disable-claude-builtins.mjs +88 -0
- package/src/shared/err-text.mjs +12 -0
- package/src/shared/llm/cost.mjs +66 -0
- package/src/shared/llm/http-agent.mjs +123 -0
- package/src/shared/llm/index.mjs +41 -0
- package/src/shared/llm/pid-cleanup.mjs +27 -0
- package/src/shared/llm/usage-log.mjs +47 -0
- package/src/shared/plugin-paths.mjs +58 -0
- package/src/shared/schedules-store.mjs +70 -0
- package/src/shared/seed.mjs +119 -0
- package/src/shared/user-cwd.mjs +213 -0
- package/src/shared/user-data-guard.mjs +238 -0
- package/src/status/aggregator.mjs +584 -0
- package/src/status/server.mjs +413 -0
- package/tools.json +1653 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// Cross-dispatch prefetch cache. Memory-first; disk-backed so a process
|
|
2
|
+
// restart (mcp child respawn / reload-plugins / dev-sync child kill) does
|
|
3
|
+
// not start cold. Keyed by canonical absolute path; stores raw read-tool
|
|
4
|
+
// output per file. Disk entries are stat-validated on read just like the
|
|
5
|
+
// memory entries, so an external write to the source file invalidates the
|
|
6
|
+
// cached slice automatically.
|
|
7
|
+
import { classifyResultKind } from '../result-classification.mjs';
|
|
8
|
+
import { _normalizeAbs, _normalizeCacheKey, _statTuple, _statEqual } from './util.mjs';
|
|
9
|
+
import { readFileSync, existsSync, mkdirSync, unlinkSync } from 'node:fs';
|
|
10
|
+
import { join, dirname } from 'node:path';
|
|
11
|
+
import { homedir } from 'node:os';
|
|
12
|
+
import { createHash } from 'node:crypto';
|
|
13
|
+
import { writeJsonAtomicSync } from '../../../../shared/atomic-file.mjs';
|
|
14
|
+
|
|
15
|
+
// I: cap is configurable via MIXDOG_PREFETCH_CACHE_MAX env var; default 200.
|
|
16
|
+
const _envCap = Number(process.env.MIXDOG_PREFETCH_CACHE_MAX);
|
|
17
|
+
const PREFETCH_CACHE_MAX = (Number.isFinite(_envCap) && _envCap > 0) ? _envCap : 200;
|
|
18
|
+
const PREFETCH_TTL_MS_DEFAULT = 60 * 60 * 1000; // 1 hour
|
|
19
|
+
let _prefetchTtlMs = PREFETCH_TTL_MS_DEFAULT;
|
|
20
|
+
|
|
21
|
+
// absPath → { content: string, stat: _statTuple, ts: number }
|
|
22
|
+
const _prefetchCache = new Map();
|
|
23
|
+
const _pendingDiskWrites = new Map();
|
|
24
|
+
let _diskWriteTimer = null;
|
|
25
|
+
|
|
26
|
+
const DISK_CACHE_DIR = join(homedir(), '.claude', 'plugins', 'data', 'mixdog-trib-plugin', 'cache', 'prefetch');
|
|
27
|
+
function _diskPath(absPath) {
|
|
28
|
+
const hash = createHash('sha256').update(absPath).digest('hex').slice(0, 16);
|
|
29
|
+
return join(DISK_CACHE_DIR, `${hash}.json`);
|
|
30
|
+
}
|
|
31
|
+
function _readDiskEntry(absPath) {
|
|
32
|
+
const p = _diskPath(absPath);
|
|
33
|
+
if (!existsSync(p)) return null;
|
|
34
|
+
try {
|
|
35
|
+
const parsed = JSON.parse(readFileSync(p, 'utf8'));
|
|
36
|
+
if (!parsed || typeof parsed.content !== 'string' || !parsed.stat) return null;
|
|
37
|
+
return { content: parsed.content, stat: parsed.stat, ts: parsed.ts };
|
|
38
|
+
} catch { return null; }
|
|
39
|
+
}
|
|
40
|
+
function _writeDiskEntryNow(absPath, entry) {
|
|
41
|
+
const p = _diskPath(absPath);
|
|
42
|
+
try {
|
|
43
|
+
mkdirSync(dirname(p), { recursive: true });
|
|
44
|
+
writeJsonAtomicSync(p, { absPath, ...entry }, { compact: true, fsync: false });
|
|
45
|
+
} catch { /* best-effort — disk persist failure must never break in-memory path */ }
|
|
46
|
+
}
|
|
47
|
+
function _flushDiskWrites() {
|
|
48
|
+
_diskWriteTimer = null;
|
|
49
|
+
if (_pendingDiskWrites.size === 0) return;
|
|
50
|
+
const batch = [..._pendingDiskWrites.entries()];
|
|
51
|
+
_pendingDiskWrites.clear();
|
|
52
|
+
for (const [absPath, entry] of batch) _writeDiskEntryNow(absPath, entry);
|
|
53
|
+
}
|
|
54
|
+
function _scheduleDiskWrite(absPath, entry) {
|
|
55
|
+
_pendingDiskWrites.set(absPath, entry);
|
|
56
|
+
if (_diskWriteTimer !== null) return;
|
|
57
|
+
const t = setTimeout(_flushDiskWrites, 100);
|
|
58
|
+
if (typeof t.unref === 'function') t.unref();
|
|
59
|
+
_diskWriteTimer = t;
|
|
60
|
+
}
|
|
61
|
+
function _deleteDiskEntry(absPath) {
|
|
62
|
+
_pendingDiskWrites.delete(absPath);
|
|
63
|
+
try { unlinkSync(_diskPath(absPath)); } catch { /* missing is fine */ }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Look up a cached prefetch result for `absPath`. Stat-validates the file on
|
|
68
|
+
* every hit. Returns null on miss, TTL expiry, or stat mismatch. Returns
|
|
69
|
+
* `{ content, ts }` on a fresh hit.
|
|
70
|
+
*/
|
|
71
|
+
export function tryPrefetchCached(absPath) {
|
|
72
|
+
if (typeof absPath !== 'string' || absPath.length === 0) return null;
|
|
73
|
+
absPath = _normalizeCacheKey(absPath);
|
|
74
|
+
let entry = _prefetchCache.get(absPath);
|
|
75
|
+
if (!entry) {
|
|
76
|
+
// Memory miss — fall through to disk so a fresh process can still hit.
|
|
77
|
+
const disk = _readDiskEntry(absPath);
|
|
78
|
+
if (!disk) return null;
|
|
79
|
+
entry = disk;
|
|
80
|
+
_prefetchCache.set(absPath, entry);
|
|
81
|
+
}
|
|
82
|
+
if (Date.now() - entry.ts > _prefetchTtlMs) {
|
|
83
|
+
_prefetchCache.delete(absPath);
|
|
84
|
+
_deleteDiskEntry(absPath);
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
const fresh = _statTuple(absPath);
|
|
88
|
+
if (!_statEqual(entry.stat, fresh)) {
|
|
89
|
+
_prefetchCache.delete(absPath);
|
|
90
|
+
_deleteDiskEntry(absPath);
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
// LRU touch: move to end of insertion-order sequence.
|
|
94
|
+
_prefetchCache.delete(absPath);
|
|
95
|
+
_prefetchCache.set(absPath, entry);
|
|
96
|
+
return { content: entry.content, ts: entry.ts };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Store a per-file prefetch result. Silently skips empty or error-prefixed
|
|
101
|
+
* content so only clean read output enters the cache.
|
|
102
|
+
*/
|
|
103
|
+
export function setPrefetchCached(absPath, content) {
|
|
104
|
+
if (typeof absPath !== 'string' || absPath.length === 0) return;
|
|
105
|
+
if (typeof content !== 'string' || content.length === 0) return;
|
|
106
|
+
if (classifyResultKind(content) === 'error') return;
|
|
107
|
+
absPath = _normalizeCacheKey(absPath);
|
|
108
|
+
const stat = _statTuple(absPath);
|
|
109
|
+
if (!stat) return;
|
|
110
|
+
if (_prefetchCache.size >= PREFETCH_CACHE_MAX) {
|
|
111
|
+
const firstKey = _prefetchCache.keys().next().value;
|
|
112
|
+
if (firstKey !== undefined) {
|
|
113
|
+
_prefetchCache.delete(firstKey);
|
|
114
|
+
_deleteDiskEntry(firstKey);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const entry = { content, stat, ts: Date.now() };
|
|
118
|
+
_prefetchCache.set(absPath, entry);
|
|
119
|
+
_scheduleDiskWrite(absPath, entry);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Drop the cache entry for `path` (cross-session). Called from loop.mjs
|
|
124
|
+
* wherever a write-class tool invalidates a path.
|
|
125
|
+
*/
|
|
126
|
+
export function invalidatePrefetchCache(path, cwd) {
|
|
127
|
+
if (typeof path !== 'string' || path.length === 0) return;
|
|
128
|
+
const abs = _normalizeAbs(path, cwd);
|
|
129
|
+
if (!abs) return;
|
|
130
|
+
_prefetchCache.delete(abs);
|
|
131
|
+
_deleteDiskEntry(abs);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function drainPrefetchDiskWrites() {
|
|
135
|
+
if (_diskWriteTimer !== null) {
|
|
136
|
+
clearTimeout(_diskWriteTimer);
|
|
137
|
+
_diskWriteTimer = null;
|
|
138
|
+
}
|
|
139
|
+
_flushDiskWrites();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
try { process.once('beforeExit', drainPrefetchDiskWrites); } catch {}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
// Session-scoped read result cache with stat-tuple invalidation.
|
|
2
|
+
// Scoped per sessionId; write-class tools explicitly invalidate touched paths.
|
|
3
|
+
import { statSync } from 'node:fs';
|
|
4
|
+
import { _normalizeAbs, _statTuple, _statEqual } from './util.mjs';
|
|
5
|
+
import { clearScopedToolsForSession, clearScopedCounters } from './scoped-cache.mjs';
|
|
6
|
+
import { clearPostEditMarks } from './post-edit-marks.mjs';
|
|
7
|
+
|
|
8
|
+
const MAX_PER_SESSION = 100;
|
|
9
|
+
|
|
10
|
+
// sessionId -> Map<key, { content, stat, ts, firstToolUseId }>
|
|
11
|
+
const _bySession = new Map();
|
|
12
|
+
|
|
13
|
+
// sessionId -> Map<absPath, Set<cacheKey>> — reverse index for O(1) path-targeted invalidation
|
|
14
|
+
const _reverseIdx = new Map();
|
|
15
|
+
|
|
16
|
+
// Normalize one element of an array-form path to { abs, off, lim, mode, n }.
|
|
17
|
+
// When top-level options (off/lim/mode/n) are supplied, they are applied as
|
|
18
|
+
// defaults to elements that don't specify their own.
|
|
19
|
+
function _normalizeArrayElem(elem, cwd) {
|
|
20
|
+
if (typeof elem === 'string') {
|
|
21
|
+
const abs = _normalizeAbs(elem, cwd);
|
|
22
|
+
return abs ? { abs, off: '', lim: '', mode: '', n: '', line: '', context: '', full: '' } : null;
|
|
23
|
+
}
|
|
24
|
+
if (elem && typeof elem === 'object' && (typeof elem.path === 'string' || typeof elem.file_path === 'string')) {
|
|
25
|
+
const abs = _normalizeAbs(elem.path || elem.file_path, cwd);
|
|
26
|
+
if (!abs) return null;
|
|
27
|
+
return {
|
|
28
|
+
abs,
|
|
29
|
+
off: elem.offset ?? '',
|
|
30
|
+
lim: elem.limit ?? '',
|
|
31
|
+
mode: elem.mode ?? '',
|
|
32
|
+
n: elem.n ?? '',
|
|
33
|
+
line: elem.line ?? '',
|
|
34
|
+
context: elem.context ?? '',
|
|
35
|
+
full: elem.full ?? '',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function _normalizeArrayElemWithDefaults(elem, cwd, topOff, topLim, topMode, topN, topLine, topContext, topFull) {
|
|
42
|
+
const n = _normalizeArrayElem(elem, cwd);
|
|
43
|
+
if (!n) return null;
|
|
44
|
+
// Apply top-level options as defaults only when element did not specify its own.
|
|
45
|
+
return {
|
|
46
|
+
abs: n.abs,
|
|
47
|
+
off: n.off !== '' ? n.off : topOff,
|
|
48
|
+
lim: n.lim !== '' ? n.lim : topLim,
|
|
49
|
+
mode: n.mode !== '' ? n.mode : topMode,
|
|
50
|
+
n: n.n !== '' ? n.n : topN,
|
|
51
|
+
line: n.line !== '' ? n.line : topLine,
|
|
52
|
+
context: n.context !== '' ? n.context : topContext,
|
|
53
|
+
full: n.full !== '' ? n.full : topFull,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Build cache key and statsByAbs map for array-form path args.
|
|
58
|
+
function _arrayKeyAndStats(args, cwd) {
|
|
59
|
+
const elems = args.path;
|
|
60
|
+
const pages = args?.pages ?? '';
|
|
61
|
+
const full = args?.full ?? '';
|
|
62
|
+
// Top-level options applied as per-element defaults (C: array-form parity).
|
|
63
|
+
const topOff = args?.offset ?? '';
|
|
64
|
+
const topLim = args?.limit ?? '';
|
|
65
|
+
const topMode = args?.mode ?? '';
|
|
66
|
+
const topN = args?.n ?? '';
|
|
67
|
+
const topLine = args?.line ?? '';
|
|
68
|
+
const topContext = args?.context ?? '';
|
|
69
|
+
const topFull = args?.full ?? '';
|
|
70
|
+
const parts = [];
|
|
71
|
+
const statsByAbs = {};
|
|
72
|
+
for (const elem of elems) {
|
|
73
|
+
const n = _normalizeArrayElemWithDefaults(elem, cwd, topOff, topLim, topMode, topN, topLine, topContext, topFull);
|
|
74
|
+
if (!n) return null;
|
|
75
|
+
parts.push(`${n.abs}|o=${n.off}|l=${n.lim}|m=${n.mode}|n=${n.n}|line=${n.line}|ctx=${n.context}|f=${n.full}`);
|
|
76
|
+
if (!statsByAbs[n.abs]) statsByAbs[n.abs] = _statTuple(n.abs);
|
|
77
|
+
}
|
|
78
|
+
const key = `[ARR]${parts.join('||')}|p=${pages}|f=${full}|to=${topOff}|tl=${topLim}|tm=${topMode}|tn=${topN}|tline=${topLine}|tctx=${topContext}|tf=${topFull}`;
|
|
79
|
+
return { key, statsByAbs };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function _keyFor(args, cwd) {
|
|
83
|
+
const p = args?.path ?? args?.file_path;
|
|
84
|
+
if (Array.isArray(p)) return null;
|
|
85
|
+
if (typeof p !== 'string') return null;
|
|
86
|
+
const abs = _normalizeAbs(p, cwd);
|
|
87
|
+
if (!abs) return null;
|
|
88
|
+
const usedFilePathAlias = typeof args?.file_path === 'string' && !args?.path;
|
|
89
|
+
const rawOff = args?.offset ?? '';
|
|
90
|
+
let off = rawOff;
|
|
91
|
+
if (usedFilePathAlias && rawOff !== '') {
|
|
92
|
+
const n = Number(rawOff);
|
|
93
|
+
off = Number.isFinite(n) ? Math.max(0, Math.trunc(n) - 1) : rawOff;
|
|
94
|
+
}
|
|
95
|
+
const lim = args?.limit ?? '';
|
|
96
|
+
const mode = args?.mode ?? '';
|
|
97
|
+
const n = args?.n ?? '';
|
|
98
|
+
const pages = args?.pages ?? '';
|
|
99
|
+
const full = args?.full ?? '';
|
|
100
|
+
const line = args?.line ?? '';
|
|
101
|
+
const context = args?.context ?? '';
|
|
102
|
+
return `${abs}|o=${off}|l=${lim}|m=${mode}|n=${n}|p=${pages}|f=${full}|line=${line}|ctx=${context}`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Re-stat every path in statsByAbs; return true only if ALL match stored tuples.
|
|
106
|
+
function _arrayStatsValid(statsByAbs) {
|
|
107
|
+
for (const [absPath, stored] of Object.entries(statsByAbs)) {
|
|
108
|
+
if (!_statEqual(stored, _statTuple(absPath))) return false;
|
|
109
|
+
}
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function _getOrCreate(sessionId) {
|
|
114
|
+
let m = _bySession.get(sessionId);
|
|
115
|
+
if (!m) { m = new Map(); _bySession.set(sessionId, m); }
|
|
116
|
+
return m;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function _ridxRegister(sessionId, absPath, key) {
|
|
120
|
+
let ridx = _reverseIdx.get(sessionId);
|
|
121
|
+
if (!ridx) { ridx = new Map(); _reverseIdx.set(sessionId, ridx); }
|
|
122
|
+
let s = ridx.get(absPath);
|
|
123
|
+
if (!s) { s = new Set(); ridx.set(absPath, s); }
|
|
124
|
+
s.add(key);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function _ridxPruneKey(sessionId, key) {
|
|
128
|
+
const ridx = _reverseIdx.get(sessionId);
|
|
129
|
+
if (!ridx) return;
|
|
130
|
+
for (const [absKey, keySet] of ridx) {
|
|
131
|
+
keySet.delete(key);
|
|
132
|
+
if (keySet.size === 0) ridx.delete(absKey);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function _absFromKey(key) {
|
|
137
|
+
const idx = key.indexOf('|');
|
|
138
|
+
return idx === -1 ? key : key.slice(0, idx);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Look up a cached read result for this session+args. Stats the file at
|
|
143
|
+
* lookup time and only returns when the stat tuple still matches. Returns
|
|
144
|
+
* null on miss, on path-form mismatch, or on stat failure. On hit returns
|
|
145
|
+
* the full entry { content, firstToolUseId, ts }.
|
|
146
|
+
*/
|
|
147
|
+
export function tryReadCached({ sessionId, args, cwd }) {
|
|
148
|
+
if (!sessionId) return null;
|
|
149
|
+
const key = _keyFor(args, cwd);
|
|
150
|
+
if (key === null && Array.isArray(args?.path)) {
|
|
151
|
+
const parsed = _arrayKeyAndStats(args, cwd);
|
|
152
|
+
if (!parsed) return null;
|
|
153
|
+
const map = _bySession.get(sessionId);
|
|
154
|
+
if (!map) return null;
|
|
155
|
+
const entry = map.get(parsed.key);
|
|
156
|
+
if (!entry || entry.kind !== 'array') return null;
|
|
157
|
+
if (!_arrayStatsValid(entry.statsByAbs)) {
|
|
158
|
+
map.delete(parsed.key);
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
map.delete(parsed.key);
|
|
162
|
+
map.set(parsed.key, entry);
|
|
163
|
+
return { content: entry.content, firstToolUseId: entry.firstToolUseId || null, ts: entry.ts };
|
|
164
|
+
}
|
|
165
|
+
if (!key) return null;
|
|
166
|
+
const map = _bySession.get(sessionId);
|
|
167
|
+
if (!map) return null;
|
|
168
|
+
const entry = map.get(key);
|
|
169
|
+
if (!entry) return null;
|
|
170
|
+
const fresh = _statTuple(_absFromKey(key));
|
|
171
|
+
if (!_statEqual(entry.stat, fresh)) {
|
|
172
|
+
map.delete(key);
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
map.delete(key);
|
|
176
|
+
map.set(key, entry);
|
|
177
|
+
return { content: entry.content, firstToolUseId: entry.firstToolUseId || null, ts: entry.ts };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Cache a successful read result. Skip caching if the file no longer exists.
|
|
182
|
+
* `toolUseId` is the tool_use id of the FIRST call that populated the entry.
|
|
183
|
+
*/
|
|
184
|
+
export function setReadCached({ sessionId, args, cwd, content, toolUseId }) {
|
|
185
|
+
if (!sessionId) return;
|
|
186
|
+
if (typeof content !== 'string' || content.length === 0) return;
|
|
187
|
+
const key = _keyFor(args, cwd);
|
|
188
|
+
if (key === null && Array.isArray(args?.path)) {
|
|
189
|
+
const parsed = _arrayKeyAndStats(args, cwd);
|
|
190
|
+
if (!parsed) return;
|
|
191
|
+
for (const st of Object.values(parsed.statsByAbs)) {
|
|
192
|
+
if (!st) return;
|
|
193
|
+
}
|
|
194
|
+
const map = _getOrCreate(sessionId);
|
|
195
|
+
if (map.size >= MAX_PER_SESSION) {
|
|
196
|
+
const firstKey = map.keys().next().value;
|
|
197
|
+
if (firstKey) { map.delete(firstKey); _ridxPruneKey(sessionId, firstKey); }
|
|
198
|
+
}
|
|
199
|
+
map.set(parsed.key, {
|
|
200
|
+
kind: 'array',
|
|
201
|
+
content,
|
|
202
|
+
statsByAbs: parsed.statsByAbs,
|
|
203
|
+
ts: Date.now(),
|
|
204
|
+
firstToolUseId: toolUseId || null,
|
|
205
|
+
});
|
|
206
|
+
// Register every constituent abs path in the reverse index.
|
|
207
|
+
for (const absPath of Object.keys(parsed.statsByAbs)) {
|
|
208
|
+
_ridxRegister(sessionId, absPath, parsed.key);
|
|
209
|
+
}
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (!key) return;
|
|
213
|
+
const fresh = _statTuple(_absFromKey(key));
|
|
214
|
+
if (!fresh) return;
|
|
215
|
+
const map = _getOrCreate(sessionId);
|
|
216
|
+
if (map.size >= MAX_PER_SESSION) {
|
|
217
|
+
const firstKey = map.keys().next().value;
|
|
218
|
+
if (firstKey) { map.delete(firstKey); _ridxPruneKey(sessionId, firstKey); }
|
|
219
|
+
}
|
|
220
|
+
map.set(key, { content, stat: fresh, ts: Date.now(), firstToolUseId: toolUseId || null });
|
|
221
|
+
_ridxRegister(sessionId, _absFromKey(key), key);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Invalidate all cache entries for `path` in the given session. Called when
|
|
226
|
+
* a write-class tool (write/edit/apply_patch) touches the path.
|
|
227
|
+
*/
|
|
228
|
+
export function invalidatePathForSession(sessionId, path, cwd) {
|
|
229
|
+
if (!sessionId) return;
|
|
230
|
+
const abs = _normalizeAbs(path, cwd);
|
|
231
|
+
if (!abs) return;
|
|
232
|
+
const map = _bySession.get(sessionId);
|
|
233
|
+
if (!map) return;
|
|
234
|
+
const ridx = _reverseIdx.get(sessionId);
|
|
235
|
+
const keys = ridx ? ridx.get(abs) : null;
|
|
236
|
+
if (keys && keys.size > 0) {
|
|
237
|
+
// O(1) lookup via reverse index.
|
|
238
|
+
const evicted = new Set(keys);
|
|
239
|
+
for (const k of evicted) map.delete(k);
|
|
240
|
+
keys.clear();
|
|
241
|
+
ridx.delete(abs);
|
|
242
|
+
// Clean evicted keys from other reverse-index sets; prune empty Sets.
|
|
243
|
+
for (const [absKey, keySet] of ridx) {
|
|
244
|
+
for (const k of evicted) keySet.delete(k);
|
|
245
|
+
if (keySet.size === 0) ridx.delete(absKey);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Index miss = entry has no path identity; no-op is correct.
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Drop everything for a session. Called when the session closes.
|
|
253
|
+
* Also clears scoped cache, counters, and post-edit marks for the session.
|
|
254
|
+
*/
|
|
255
|
+
export function clearReadDedupSession(sessionId) {
|
|
256
|
+
if (!sessionId) return;
|
|
257
|
+
_bySession.delete(sessionId);
|
|
258
|
+
_reverseIdx.delete(sessionId);
|
|
259
|
+
clearPostEditMarks(sessionId);
|
|
260
|
+
clearScopedToolsForSession(sessionId);
|
|
261
|
+
clearScopedCounters(sessionId);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Extract the set of touched filesystem paths from a unified-diff patch text.
|
|
266
|
+
* Handles git-style `--- a/<path>` / `+++ b/<path>` headers and `/dev/null` markers.
|
|
267
|
+
* Returns relative paths as written in the diff.
|
|
268
|
+
*/
|
|
269
|
+
export function extractTouchedPathsFromPatch(patchText) {
|
|
270
|
+
if (typeof patchText !== 'string' || patchText.length === 0) return [];
|
|
271
|
+
const lines = patchText.split('\n');
|
|
272
|
+
const out = [];
|
|
273
|
+
const seen = new Set();
|
|
274
|
+
const stripPathMetadata = (rawPath) => {
|
|
275
|
+
let text = String(rawPath || '').trim();
|
|
276
|
+
if (!text) return '';
|
|
277
|
+
const tabIdx = text.indexOf('\t');
|
|
278
|
+
if (tabIdx !== -1) text = text.slice(0, tabIdx).trimEnd();
|
|
279
|
+
const quote = text[0];
|
|
280
|
+
if ((quote === '"' || quote === "'") && text.length > 1) {
|
|
281
|
+
const end = text.indexOf(quote, 1);
|
|
282
|
+
if (end > 0) text = text.slice(1, end);
|
|
283
|
+
}
|
|
284
|
+
return text;
|
|
285
|
+
};
|
|
286
|
+
const push = (rawPath) => {
|
|
287
|
+
let touched = stripPathMetadata(rawPath);
|
|
288
|
+
if (!touched || touched === '/dev/null') return;
|
|
289
|
+
touched = touched.replace(/^["']|["']$/g, '').replace(/\\/g, '/');
|
|
290
|
+
if (touched.startsWith('a/') || touched.startsWith('b/')) touched = touched.slice(2);
|
|
291
|
+
if (!touched || touched === '/dev/null' || seen.has(touched)) return;
|
|
292
|
+
seen.add(touched);
|
|
293
|
+
out.push(touched);
|
|
294
|
+
};
|
|
295
|
+
for (const line of lines) {
|
|
296
|
+
if (line.startsWith('*** Update File:')) push(line.slice('*** Update File:'.length));
|
|
297
|
+
else if (line.startsWith('*** Add File:')) push(line.slice('*** Add File:'.length));
|
|
298
|
+
else if (line.startsWith('*** Delete File:')) push(line.slice('*** Delete File:'.length));
|
|
299
|
+
}
|
|
300
|
+
for (let i = 0; i < lines.length - 1; i += 1) {
|
|
301
|
+
const minus = lines[i];
|
|
302
|
+
const plus = lines[i + 1];
|
|
303
|
+
if (!minus.startsWith('--- ')) continue;
|
|
304
|
+
if (!plus.startsWith('+++ ')) continue;
|
|
305
|
+
const fromRaw = minus.slice(4).trim();
|
|
306
|
+
const toRaw = plus.slice(4).trim();
|
|
307
|
+
const fromStripped = fromRaw.startsWith('a/') ? fromRaw.slice(2) : fromRaw;
|
|
308
|
+
const toStripped = toRaw.startsWith('b/') ? toRaw.slice(2) : toRaw;
|
|
309
|
+
let touched;
|
|
310
|
+
if (toStripped === '/dev/null') {
|
|
311
|
+
touched = fromStripped === '/dev/null' ? null : fromStripped;
|
|
312
|
+
} else {
|
|
313
|
+
touched = toStripped;
|
|
314
|
+
}
|
|
315
|
+
push(touched);
|
|
316
|
+
i += 1;
|
|
317
|
+
}
|
|
318
|
+
return out;
|
|
319
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mutable outcome ref threaded from the agent loop into scoped-cacheable tools.
|
|
3
|
+
* Tools set `complete: false` only when the result is known incomplete/truncated.
|
|
4
|
+
*/
|
|
5
|
+
export function createScopedCacheOutcome() {
|
|
6
|
+
return { complete: true };
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function markScopedCacheIncomplete(outcome) {
|
|
10
|
+
if (outcome && typeof outcome === 'object') outcome.complete = false;
|
|
11
|
+
}
|