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,583 @@
|
|
|
1
|
+
import { readFileSync, existsSync, mkdirSync, appendFileSync, statSync, renameSync } from 'fs';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { createHash } from 'crypto';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import { getPluginData } from './config.mjs';
|
|
6
|
+
import { normalizeUsage } from './smart-bridge/cache-obs.mjs';
|
|
7
|
+
import { isInclusiveProvider } from '../../shared/llm/cost.mjs';
|
|
8
|
+
import { countJsonNextCalls } from './tools/next-call-utils.mjs';
|
|
9
|
+
|
|
10
|
+
const WARNED_KEYS = new Set();
|
|
11
|
+
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// In-memory buffer + HTTP flush to memory-service /admin/trace-record
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
let _buffer = [];
|
|
16
|
+
const _BUFFER_MAX = 2000;
|
|
17
|
+
const _FLUSH_INTERVAL_MS = 5000;
|
|
18
|
+
const _FLUSH_BATCH_SIZE = 500;
|
|
19
|
+
let _flushTimer = null;
|
|
20
|
+
let _serviceUrl = null;
|
|
21
|
+
let _flushInFlight = false;
|
|
22
|
+
let _localTracePath = null;
|
|
23
|
+
let _localTraceBuffer = [];
|
|
24
|
+
let _localTraceTimer = null;
|
|
25
|
+
const _LOCAL_TRACE_FLUSH_LINES = 100;
|
|
26
|
+
const _LOCAL_TRACE_FLUSH_MS = 1000;
|
|
27
|
+
const _LOCAL_TRACE_MAX_BYTES = 10 * 1024 * 1024; // 10 MB — rotate to .1 above this.
|
|
28
|
+
|
|
29
|
+
function _rotateLocalTraceIfNeeded(path) {
|
|
30
|
+
try {
|
|
31
|
+
const stat = statSync(path);
|
|
32
|
+
if (stat && stat.size > _LOCAL_TRACE_MAX_BYTES) {
|
|
33
|
+
try { renameSync(path, `${path}.1`); }
|
|
34
|
+
catch (err) {
|
|
35
|
+
warnBridgeOnce('bridge-trace:local-rotate', `[bridge-trace] local rotate failed (${err?.message})`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
// File missing or unstattable — nothing to rotate.
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function _resolveLocalTracePath() {
|
|
44
|
+
if (process.env.MIXDOG_BRIDGE_TRACE_LOCAL_DISABLE === '1') return null;
|
|
45
|
+
if (_localTracePath) return _localTracePath;
|
|
46
|
+
try {
|
|
47
|
+
_localTracePath = process.env.MIXDOG_BRIDGE_TRACE_PATH
|
|
48
|
+
|| join(getPluginData(), 'history', 'bridge-trace.jsonl');
|
|
49
|
+
// R4 data-at-rest: trace rows may carry tool payloads / prompts;
|
|
50
|
+
// clamp dir to owner-only on POSIX (advisory on Windows).
|
|
51
|
+
mkdirSync(dirname(_localTracePath), { recursive: true, mode: 0o700 });
|
|
52
|
+
return _localTracePath;
|
|
53
|
+
} catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function _appendLocalTrace(row) {
|
|
59
|
+
if (!_resolveLocalTracePath()) return;
|
|
60
|
+
try {
|
|
61
|
+
_localTraceBuffer.push(`${JSON.stringify(row)}\n`);
|
|
62
|
+
if (_localTraceBuffer.length >= _LOCAL_TRACE_FLUSH_LINES) {
|
|
63
|
+
_flushLocalTrace();
|
|
64
|
+
} else if (!_localTraceTimer) {
|
|
65
|
+
_localTraceTimer = setTimeout(_flushLocalTrace, _LOCAL_TRACE_FLUSH_MS);
|
|
66
|
+
_localTraceTimer.unref?.();
|
|
67
|
+
}
|
|
68
|
+
} catch (err) {
|
|
69
|
+
warnBridgeOnce('bridge-trace:local-spool', `[bridge-trace] local spool failed (${err?.message})`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function _flushLocalTrace() {
|
|
74
|
+
if (_localTraceTimer) {
|
|
75
|
+
clearTimeout(_localTraceTimer);
|
|
76
|
+
_localTraceTimer = null;
|
|
77
|
+
}
|
|
78
|
+
if (_localTraceBuffer.length === 0) return;
|
|
79
|
+
const path = _resolveLocalTracePath();
|
|
80
|
+
if (!path) return;
|
|
81
|
+
const chunk = _localTraceBuffer.join('');
|
|
82
|
+
_localTraceBuffer = [];
|
|
83
|
+
try {
|
|
84
|
+
_rotateLocalTraceIfNeeded(path);
|
|
85
|
+
// mode only applies on file creation; existing files keep their mode.
|
|
86
|
+
// Windows ignores POSIX bits — ACL governs there.
|
|
87
|
+
appendFileSync(path, chunk, { encoding: 'utf8', mode: 0o600 });
|
|
88
|
+
} catch (err) {
|
|
89
|
+
warnBridgeOnce('bridge-trace:local-spool', `[bridge-trace] local spool failed (${err?.message})`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
process.on('beforeExit', _flushLocalTrace);
|
|
95
|
+
process.on('exit', _flushLocalTrace);
|
|
96
|
+
} catch {
|
|
97
|
+
// Ignore lifecycle hook failures in embedded runtimes.
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function _resolveServiceUrl() {
|
|
101
|
+
if (_serviceUrl) return _serviceUrl;
|
|
102
|
+
try {
|
|
103
|
+
const runtimeRoot = process.env.MIXDOG_RUNTIME_ROOT
|
|
104
|
+
? join(process.env.MIXDOG_RUNTIME_ROOT)
|
|
105
|
+
: join(os.tmpdir(), 'mixdog');
|
|
106
|
+
const activeFile = join(runtimeRoot, 'active-instance.json');
|
|
107
|
+
if (!existsSync(activeFile)) return null;
|
|
108
|
+
const active = JSON.parse(readFileSync(activeFile, 'utf-8'));
|
|
109
|
+
const port = Number(active && active.memory_port);
|
|
110
|
+
if (!Number.isFinite(port) || port <= 0) return null;
|
|
111
|
+
_serviceUrl = `http://127.0.0.1:${port}`;
|
|
112
|
+
return _serviceUrl;
|
|
113
|
+
} catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function _flush() {
|
|
119
|
+
_flushTimer = null;
|
|
120
|
+
if (_buffer.length === 0) return;
|
|
121
|
+
if (_flushInFlight) {
|
|
122
|
+
if (!_flushTimer) _flushTimer = setTimeout(_flush, _FLUSH_INTERVAL_MS);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
_flushInFlight = true;
|
|
126
|
+
try {
|
|
127
|
+
const url = _resolveServiceUrl();
|
|
128
|
+
if (!url) {
|
|
129
|
+
// Service not up yet — keep buffer, retry next timer tick
|
|
130
|
+
if (!_flushTimer) _flushTimer = setTimeout(_flush, _FLUSH_INTERVAL_MS);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const batch = _buffer.splice(0, _FLUSH_BATCH_SIZE);
|
|
134
|
+
try {
|
|
135
|
+
const resp = await fetch(`${url}/admin/trace-record`, {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
headers: { 'Content-Type': 'application/json' },
|
|
138
|
+
body: JSON.stringify({ events: batch }),
|
|
139
|
+
signal: AbortSignal.timeout(5000),
|
|
140
|
+
});
|
|
141
|
+
if (!resp.ok) {
|
|
142
|
+
warnBridgeOnce('bridge-trace:flush-error', `[bridge-trace] /admin/trace-record returned ${resp.status} — dropping batch`);
|
|
143
|
+
}
|
|
144
|
+
} catch (err) {
|
|
145
|
+
_serviceUrl = null;
|
|
146
|
+
warnBridgeOnce('bridge-trace:flush-fetch', `[bridge-trace] flush fetch failed (${err?.message}) — dropping batch`);
|
|
147
|
+
}
|
|
148
|
+
if (_buffer.length >= _FLUSH_BATCH_SIZE) {
|
|
149
|
+
// More pending — schedule another flush immediately
|
|
150
|
+
setImmediate(_flush);
|
|
151
|
+
}
|
|
152
|
+
} finally {
|
|
153
|
+
_flushInFlight = false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function _scheduleFlush(immediate = false) {
|
|
158
|
+
if (immediate) {
|
|
159
|
+
if (_flushTimer) { clearTimeout(_flushTimer); _flushTimer = null; }
|
|
160
|
+
setImmediate(_flush);
|
|
161
|
+
} else if (!_flushTimer) {
|
|
162
|
+
_flushTimer = setTimeout(_flush, _FLUSH_INTERVAL_MS);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function drainBridgeTrace() {
|
|
167
|
+
if (!_resolveServiceUrl()) return;
|
|
168
|
+
if (_flushTimer) { clearTimeout(_flushTimer); _flushTimer = null; }
|
|
169
|
+
for (let i = 0; i < 10 && _buffer.length > 0; i++) {
|
|
170
|
+
await _flush();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function normalizeSessionId(sessionId) {
|
|
175
|
+
return sessionId ? String(sessionId) : 'no-session';
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function appendBridgeTrace(record = {}) {
|
|
179
|
+
// Test isolation — when run-all-tests.mjs sets this env, skip entirely.
|
|
180
|
+
if (process.env.MIXDOG_BRIDGE_TRACE_DISABLE === '1') return;
|
|
181
|
+
try {
|
|
182
|
+
// Coerce ts to epoch ms integer at enqueue time
|
|
183
|
+
let ts = record.ts || Date.now();
|
|
184
|
+
if (typeof ts === 'string') ts = Date.parse(ts);
|
|
185
|
+
ts = Number(ts);
|
|
186
|
+
if (!Number.isFinite(ts)) ts = Date.now();
|
|
187
|
+
|
|
188
|
+
const row = {
|
|
189
|
+
...record,
|
|
190
|
+
ts,
|
|
191
|
+
session_id: record.session_id ?? normalizeSessionId(record.sessionId),
|
|
192
|
+
payload: record.payload ?? {},
|
|
193
|
+
};
|
|
194
|
+
// Drop actor-facing alias to keep schema tidy
|
|
195
|
+
delete row.sessionId;
|
|
196
|
+
|
|
197
|
+
if (_buffer.length >= _BUFFER_MAX) {
|
|
198
|
+
_buffer.shift(); // drop oldest
|
|
199
|
+
warnBridgeOnce('bridge-trace:buffer-full', '[bridge-trace] buffer full (2000) — dropping oldest event');
|
|
200
|
+
}
|
|
201
|
+
_appendLocalTrace(row);
|
|
202
|
+
_buffer.push(row);
|
|
203
|
+
_scheduleFlush(_buffer.length >= _FLUSH_BATCH_SIZE);
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// Never break bridge execution for telemetry
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function estimateProviderPayloadBytes(messages, model, tools) {
|
|
211
|
+
try {
|
|
212
|
+
return Buffer.byteLength(JSON.stringify({ model, messages, tools: tools || [] }), 'utf8');
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function extractCachedTokens(usage) {
|
|
220
|
+
const candidates = [
|
|
221
|
+
usage?.input_tokens_details?.cached_tokens,
|
|
222
|
+
usage?.prompt_tokens_details?.cached_tokens,
|
|
223
|
+
usage?.inputTokensDetails?.cachedTokens,
|
|
224
|
+
usage?.promptTokensDetails?.cachedTokens,
|
|
225
|
+
];
|
|
226
|
+
for (const value of candidates) {
|
|
227
|
+
const n = Number(value);
|
|
228
|
+
if (Number.isFinite(n)) return n;
|
|
229
|
+
}
|
|
230
|
+
return 0;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function warnBridgeOnce(key, message) {
|
|
234
|
+
if (!key || WARNED_KEYS.has(key)) return;
|
|
235
|
+
WARNED_KEYS.add(key);
|
|
236
|
+
try {
|
|
237
|
+
process.stderr.write(`${message}\n`);
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// Ignore logging failures.
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function traceBridgeLoop({ sessionId, iteration, sendMs, messageCount, bodyBytesEst }) {
|
|
245
|
+
if (process.env.MIXDOG_BRIDGE_TRACE_VERBOSE !== '1') return;
|
|
246
|
+
appendBridgeTrace({
|
|
247
|
+
sessionId,
|
|
248
|
+
iteration,
|
|
249
|
+
kind: 'loop',
|
|
250
|
+
send_ms: sendMs,
|
|
251
|
+
message_count: messageCount,
|
|
252
|
+
body_bytes_est: bodyBytesEst,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Lightweight fingerprint of the conversation prefix. Hashes the first 4096
|
|
257
|
+
// characters of JSON.stringify(messages) — enough to detect prefix mutation
|
|
258
|
+
// across iterations (which invalidates the provider prompt cache) without
|
|
259
|
+
// hashing megabytes per turn. Truncated SHA1 keeps the trace row compact.
|
|
260
|
+
function messagePrefixHash(messages) {
|
|
261
|
+
try {
|
|
262
|
+
const json = JSON.stringify(messages || []);
|
|
263
|
+
const slice = json.length > 4096 ? json.slice(0, 4096) : json;
|
|
264
|
+
return createHash('sha1').update(slice).digest('hex').slice(0, 12);
|
|
265
|
+
} catch {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function traceBridgeTrim({
|
|
271
|
+
sessionId,
|
|
272
|
+
iteration,
|
|
273
|
+
prune_count,
|
|
274
|
+
trim_changed,
|
|
275
|
+
input_prefix_hash,
|
|
276
|
+
before_count,
|
|
277
|
+
after_count,
|
|
278
|
+
before_bytes,
|
|
279
|
+
after_bytes,
|
|
280
|
+
}) {
|
|
281
|
+
if (process.env.MIXDOG_BRIDGE_TRACE_VERBOSE !== '1') return;
|
|
282
|
+
appendBridgeTrace({
|
|
283
|
+
sessionId,
|
|
284
|
+
iteration,
|
|
285
|
+
kind: 'trim_meta',
|
|
286
|
+
prune_count: prune_count ?? 0,
|
|
287
|
+
trim_changed: !!trim_changed,
|
|
288
|
+
input_prefix_hash: input_prefix_hash || null,
|
|
289
|
+
before_count: before_count ?? null,
|
|
290
|
+
after_count: after_count ?? null,
|
|
291
|
+
before_bytes: before_bytes ?? null,
|
|
292
|
+
after_bytes: after_bytes ?? null,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const TOOL_ARG_KEYS = {
|
|
297
|
+
read: ['path', 'mode', 'n', 'offset', 'limit', 'full'],
|
|
298
|
+
grep: ['pattern', 'path', 'glob', 'output_mode', 'head_limit', 'offset', 'type', '-i', '-n', '-A', '-B', '-C', 'context', 'multiline'],
|
|
299
|
+
glob: ['pattern', 'path', 'head_limit', 'offset'],
|
|
300
|
+
list: ['path', 'mode', 'depth', 'hidden', 'sort', 'type', 'head_limit', 'offset', 'name', 'min_size', 'max_size', 'modified_after', 'modified_before'],
|
|
301
|
+
code_graph: ['mode', 'file', 'symbol', 'language', 'limit'],
|
|
302
|
+
bash: ['command', 'cwd', 'timeout', 'run_in_background', 'persistent', 'session_id'],
|
|
303
|
+
job_wait: ['job_id', 'timeout_ms', 'poll_ms'],
|
|
304
|
+
edit: ['path', 'replace_all', 'edits'],
|
|
305
|
+
edit_many: ['edits'],
|
|
306
|
+
write: ['path', 'writes'],
|
|
307
|
+
apply_patch: ['base_path', 'dry_run', 'reject_partial'],
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
const REDACT_KEY_RE = /token|secret|password|passwd|credential|authorization|api[_-]?key/i;
|
|
311
|
+
const BODY_KEY_RE = /content|old_string|new_string|patch|rewrite/i;
|
|
312
|
+
// Redact bash `command` values that look like they carry secrets. Covers
|
|
313
|
+
// assignment forms, Authorization headers, --password / -p flags, and
|
|
314
|
+
// secrets embedded in URLs (userinfo + query string).
|
|
315
|
+
const SHELL_SECRET_RE = /(?:(?:^|\s)(?:export\s+\w+=\S+|PASSWORD=|SECRET=|TOKEN=|API_KEY=)|Authorization:\s*Bearer\s+\S+|--(?:password|token|secret|api[-_]?key)(?:\s+|=)\S+|(?:^|\s)-p\s+\S+|:\/\/[^:\/\s@]+:[^@\s]+@|[?&](?:token|api[-_]?key|access[-_]?token|auth|password|secret)=[^&\s#]+)/i;
|
|
316
|
+
|
|
317
|
+
function _redactShellCommand(cmd) {
|
|
318
|
+
if (typeof cmd !== 'string') return cmd;
|
|
319
|
+
let out = cmd;
|
|
320
|
+
// Assignment RHS: PASSWORD=, SECRET=, TOKEN=, API_KEY=/APIKEY=.
|
|
321
|
+
out = out.replace(/((?:PASSWORD|SECRET|TOKEN|API_KEY|APIKEY)\s*=\s*)\S+/gi, '$1[redacted]');
|
|
322
|
+
// Authorization: Bearer <token>.
|
|
323
|
+
out = out.replace(/(Authorization:\s*Bearer\s+)\S+/gi, '$1[redacted]');
|
|
324
|
+
// Long flags: --password <v> / --password=<v> (also --token, --secret, --api-key).
|
|
325
|
+
out = out.replace(/(--(?:password|token|secret|api[-_]?key)(?:\s+|=))\S+/gi, '$1[redacted]');
|
|
326
|
+
// Short -p <v> flag (mysql/psql/curl style).
|
|
327
|
+
out = out.replace(/((?:^|\s)-p(?:\s+|=))\S+/g, '$1[redacted]');
|
|
328
|
+
// URL userinfo: scheme://user:secret@host -> scheme://user:[redacted]@host.
|
|
329
|
+
out = out.replace(/(:\/\/[^:\/\s@]+:)[^@\s]+(@)/g, '$1[redacted]$2');
|
|
330
|
+
// URL query params carrying tokens/keys.
|
|
331
|
+
out = out.replace(/([?&](?:token|api[-_]?key|access[-_]?token|auth|password|secret)=)[^&\s#]+/gi, '$1[redacted]');
|
|
332
|
+
return out;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function compactTraceArgValue(value, key = '', depth = 0) {
|
|
336
|
+
if (REDACT_KEY_RE.test(key)) return '[redacted]';
|
|
337
|
+
if (value === null || value === undefined) return value;
|
|
338
|
+
if (typeof value === 'string') {
|
|
339
|
+
// Redact shell commands that embed secrets before length-truncating.
|
|
340
|
+
if (key === 'command') {
|
|
341
|
+
value = _redactShellCommand(value);
|
|
342
|
+
}
|
|
343
|
+
const limit = BODY_KEY_RE.test(key) ? 60 : 180;
|
|
344
|
+
return value.length > limit ? `${value.slice(0, limit)}...` : value;
|
|
345
|
+
}
|
|
346
|
+
if (typeof value === 'number' || typeof value === 'boolean') return value;
|
|
347
|
+
if (Array.isArray(value)) {
|
|
348
|
+
if (depth >= 2) return `[${value.length} items]`;
|
|
349
|
+
return value.slice(0, 6).map((v) => compactTraceArgValue(v, key, depth + 1));
|
|
350
|
+
}
|
|
351
|
+
if (typeof value === 'object') {
|
|
352
|
+
if (depth >= 2) return '{...}';
|
|
353
|
+
const out = {};
|
|
354
|
+
for (const [k, v] of Object.entries(value).slice(0, 12)) {
|
|
355
|
+
out[k] = compactTraceArgValue(v, k, depth + 1);
|
|
356
|
+
}
|
|
357
|
+
return out;
|
|
358
|
+
}
|
|
359
|
+
return String(value);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function summarizeToolArgs(toolName, args) {
|
|
363
|
+
if (!args || typeof args !== 'object') return null;
|
|
364
|
+
const keys = TOOL_ARG_KEYS[String(toolName || '')] || Object.keys(args).slice(0, 8);
|
|
365
|
+
const out = {};
|
|
366
|
+
for (const key of keys) {
|
|
367
|
+
if (Object.prototype.hasOwnProperty.call(args, key)) out[key] = compactTraceArgValue(args[key], key);
|
|
368
|
+
}
|
|
369
|
+
for (const countKey of ['edits', 'writes']) {
|
|
370
|
+
if (Array.isArray(args[countKey])) out[`${countKey}_count`] = args[countKey].length;
|
|
371
|
+
}
|
|
372
|
+
if (toolName === 'read' && Array.isArray(args.path)) {
|
|
373
|
+
out.path_count = args.path.length;
|
|
374
|
+
}
|
|
375
|
+
return Object.keys(out).length ? out : null;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function traceBridgeTool({ sessionId, iteration, toolName, toolKind, toolMs, toolArgs, role, resultKind, model, resultText }) {
|
|
379
|
+
const nextCallCount = countJsonNextCalls(resultText);
|
|
380
|
+
// Flat shape — fields named exactly as the bridge_calls PG columns so
|
|
381
|
+
// insertBridgeCalls can pick them up by direct property access without
|
|
382
|
+
// a payload-unwrap step. result_kind has no column and rides as plain
|
|
383
|
+
// sibling metadata for downstream consumers.
|
|
384
|
+
appendBridgeTrace({
|
|
385
|
+
sessionId,
|
|
386
|
+
iteration,
|
|
387
|
+
kind: 'tool',
|
|
388
|
+
role: role || null,
|
|
389
|
+
model: model || null,
|
|
390
|
+
tool_name: toolName,
|
|
391
|
+
tool_kind: toolKind,
|
|
392
|
+
tool_ms: toolMs,
|
|
393
|
+
tool_args: summarizeToolArgs(toolName, toolArgs),
|
|
394
|
+
result_kind: resultKind || null,
|
|
395
|
+
result_has_next_call: nextCallCount > 0,
|
|
396
|
+
result_next_call_count: nextCallCount,
|
|
397
|
+
result_bytes_est: typeof resultText === 'string' ? Buffer.byteLength(resultText, 'utf8') : 0,
|
|
398
|
+
result_lines_est: typeof resultText === 'string' && resultText.length > 0 ? resultText.split('\n').length : 0,
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Compression layer trace (result-compression.mjs). One row per tool call
|
|
403
|
+
// where compression actually changed the byte count, so `gain` analytics
|
|
404
|
+
// can sum savings_pct over a window (mirrors RTK's `rtk gain` model
|
|
405
|
+
// without an external binary). No-op rows are dropped at the call site.
|
|
406
|
+
export function traceBridgeCompress({ sessionId, toolName, before, after }) {
|
|
407
|
+
// bytes_before/after/savings_pct moved into payload because the
|
|
408
|
+
// trace_events table only carries known top-level columns (id, ts,
|
|
409
|
+
// session_id, kind, tool_name, payload, ...) — fields outside that
|
|
410
|
+
// set are silently dropped at insert time. payload is jsonb so any
|
|
411
|
+
// shape survives. Aggregation: SELECT (payload->>'bytes_before')::int.
|
|
412
|
+
appendBridgeTrace({
|
|
413
|
+
sessionId,
|
|
414
|
+
kind: 'compress',
|
|
415
|
+
tool_name: toolName,
|
|
416
|
+
payload: {
|
|
417
|
+
bytes_before: before,
|
|
418
|
+
bytes_after: after,
|
|
419
|
+
savings_pct: before > 0 ? Math.round((1 - after / before) * 100) : 0,
|
|
420
|
+
},
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Per-turn batch shape — one row per assistant turn with the number of
|
|
425
|
+
// tool calls observed. Lets a consumer compute Lead-side multi-tool
|
|
426
|
+
// adoption ratio (calls > 1 / total turns) directly from trace rows
|
|
427
|
+
// instead of re-parsing every assistant message body.
|
|
428
|
+
export function traceBridgeBatch({ sessionId, toolCallCount }) {
|
|
429
|
+
appendBridgeTrace({
|
|
430
|
+
sessionId,
|
|
431
|
+
kind: 'batch',
|
|
432
|
+
tool_call_count: toolCallCount,
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function _sanitizeSample(sample) {
|
|
437
|
+
if (sample == null) return sample;
|
|
438
|
+
if (typeof sample === 'string' || typeof sample === 'object') {
|
|
439
|
+
return compactTraceArgValue(sample, '', 0);
|
|
440
|
+
}
|
|
441
|
+
return sample;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function traceStreamStalled({ sessionId, info }) {
|
|
445
|
+
appendBridgeTrace({
|
|
446
|
+
sessionId,
|
|
447
|
+
kind: 'stream_stalled',
|
|
448
|
+
stale_seconds: info.staleSeconds,
|
|
449
|
+
last_tool_call: info.lastToolCall,
|
|
450
|
+
stage: info.stage,
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function traceStreamAborted({ sessionId, info }) {
|
|
455
|
+
appendBridgeTrace({
|
|
456
|
+
sessionId,
|
|
457
|
+
kind: 'stream_aborted',
|
|
458
|
+
stale_seconds: info.staleSeconds,
|
|
459
|
+
last_tool_call: info.lastToolCall,
|
|
460
|
+
stage: info.stage,
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function traceBridgePreset({ sessionId, role, presetName, model, provider, parentSessionId }) {
|
|
465
|
+
// Fires once per dispatch right after the preset has been resolved and
|
|
466
|
+
// its runtime spec (provider/model) assembled. Useful for after-the-fact
|
|
467
|
+
// routing analysis: "which role landed on which preset / provider / model
|
|
468
|
+
// on this request?"
|
|
469
|
+
appendBridgeTrace({
|
|
470
|
+
sessionId,
|
|
471
|
+
kind: 'preset_assign',
|
|
472
|
+
role: role || null,
|
|
473
|
+
preset_name: presetName || null,
|
|
474
|
+
model: model || null,
|
|
475
|
+
provider: provider || null,
|
|
476
|
+
parent_session_id: parentSessionId || null,
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function traceBridgeFetch({ sessionId, headersMs, httpStatus, handshakeRetries, handshakeRetryClassifiers, provider, model, transport }) {
|
|
481
|
+
const payload = {
|
|
482
|
+
headers_ms: headersMs,
|
|
483
|
+
http_status: httpStatus,
|
|
484
|
+
provider: provider || null,
|
|
485
|
+
model: model || null,
|
|
486
|
+
transport: transport || null,
|
|
487
|
+
};
|
|
488
|
+
if (Number.isFinite(Number(handshakeRetries))) {
|
|
489
|
+
payload.handshake_retries = Number(handshakeRetries);
|
|
490
|
+
}
|
|
491
|
+
if (Array.isArray(handshakeRetryClassifiers) && handshakeRetryClassifiers.length > 0) {
|
|
492
|
+
payload.handshake_retry_classifiers = handshakeRetryClassifiers;
|
|
493
|
+
}
|
|
494
|
+
appendBridgeTrace({
|
|
495
|
+
sessionId,
|
|
496
|
+
kind: 'fetch',
|
|
497
|
+
headers_ms: headersMs,
|
|
498
|
+
http_status: httpStatus,
|
|
499
|
+
provider: provider || null,
|
|
500
|
+
model: model || null,
|
|
501
|
+
transport: transport || null,
|
|
502
|
+
handshake_retries: payload.handshake_retries,
|
|
503
|
+
handshake_retry_classifiers: payload.handshake_retry_classifiers,
|
|
504
|
+
payload,
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function traceBridgeSse({ sessionId, sseParseMs, ttftMs, provider, model, transport }) {
|
|
509
|
+
appendBridgeTrace({
|
|
510
|
+
sessionId,
|
|
511
|
+
kind: 'sse',
|
|
512
|
+
sse_parse_ms: sseParseMs,
|
|
513
|
+
ttft_ms: ttftMs,
|
|
514
|
+
provider: provider || null,
|
|
515
|
+
model: model || null,
|
|
516
|
+
transport: transport || null,
|
|
517
|
+
payload: {
|
|
518
|
+
sse_parse_ms: sseParseMs,
|
|
519
|
+
ttft_ms: ttftMs,
|
|
520
|
+
provider: provider || null,
|
|
521
|
+
model: model || null,
|
|
522
|
+
transport: transport || null,
|
|
523
|
+
},
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function traceBridgeUsage({ sessionId, iteration, inputTokens, outputTokens, cachedTokens, cacheWriteTokens, promptTokens, model, modelDisplay, responseId, rawUsage, provider, serviceTier }) {
|
|
528
|
+
const inclusive = isInclusiveProvider(provider);
|
|
529
|
+
const inTok = inputTokens || 0;
|
|
530
|
+
const cacheRead = cachedTokens || 0;
|
|
531
|
+
const cacheWrite = cacheWriteTokens || 0;
|
|
532
|
+
const uncachedInputTokens = inclusive ? Math.max(inTok - cacheRead - cacheWrite, 0) : inTok;
|
|
533
|
+
const promptTotal = typeof promptTokens === 'number'
|
|
534
|
+
? promptTokens
|
|
535
|
+
: (inclusive
|
|
536
|
+
? Math.max(inTok, cacheRead + cacheWrite)
|
|
537
|
+
: inTok + cacheRead + cacheWrite);
|
|
538
|
+
const resolvedServiceTier = serviceTier || rawUsage?.service_tier || rawUsage?.serviceTier || null;
|
|
539
|
+
appendBridgeTrace({
|
|
540
|
+
sessionId,
|
|
541
|
+
iteration,
|
|
542
|
+
kind: 'usage_raw',
|
|
543
|
+
input_tokens: inputTokens,
|
|
544
|
+
output_tokens: outputTokens,
|
|
545
|
+
cached_tokens: cachedTokens,
|
|
546
|
+
cache_write_tokens: cacheWrite,
|
|
547
|
+
uncached_input_tokens: uncachedInputTokens,
|
|
548
|
+
// Unified total-prompt field. Anthropic = input+cache_read+cache_write,
|
|
549
|
+
// OpenAI/Gemini = input_tokens (cached is already a subset).
|
|
550
|
+
prompt_tokens: promptTotal,
|
|
551
|
+
model: model || null,
|
|
552
|
+
model_display: modelDisplay || null,
|
|
553
|
+
response_id: responseId || null,
|
|
554
|
+
service_tier: resolvedServiceTier,
|
|
555
|
+
payload: {
|
|
556
|
+
provider: provider || null,
|
|
557
|
+
prompt_tokens: promptTotal,
|
|
558
|
+
uncached_input_tokens: uncachedInputTokens,
|
|
559
|
+
model_display: modelDisplay || null,
|
|
560
|
+
response_id: responseId || null,
|
|
561
|
+
service_tier: resolvedServiceTier,
|
|
562
|
+
raw_usage: rawUsage || null,
|
|
563
|
+
},
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
export {
|
|
568
|
+
appendBridgeTrace,
|
|
569
|
+
drainBridgeTrace,
|
|
570
|
+
estimateProviderPayloadBytes,
|
|
571
|
+
extractCachedTokens,
|
|
572
|
+
messagePrefixHash,
|
|
573
|
+
traceBridgeFetch,
|
|
574
|
+
traceBridgeLoop,
|
|
575
|
+
traceBridgePreset,
|
|
576
|
+
traceBridgeSse,
|
|
577
|
+
traceBridgeTool,
|
|
578
|
+
traceBridgeTrim,
|
|
579
|
+
traceBridgeUsage,
|
|
580
|
+
traceStreamAborted,
|
|
581
|
+
traceStreamStalled,
|
|
582
|
+
warnBridgeOnce,
|
|
583
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { statSync, readdirSync } from 'fs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Return the maximum mtimeMs across all given paths.
|
|
5
|
+
* Missing / unreadable paths are silently skipped (treated as mtime 0).
|
|
6
|
+
* Pass file paths or directory paths; statSync on a directory returns the
|
|
7
|
+
* mtime of the directory entry itself (updated when children are
|
|
8
|
+
* added/removed), while file mtime covers content changes.
|
|
9
|
+
* Use maxMtimeRecursive for cases where file-content edits within a
|
|
10
|
+
* directory must also invalidate the cache (parent dir mtime is unchanged
|
|
11
|
+
* on Linux/macOS when only a file's content changes).
|
|
12
|
+
*
|
|
13
|
+
* @param {string[]} paths
|
|
14
|
+
* @returns {number}
|
|
15
|
+
*/
|
|
16
|
+
export function maxMtime(paths) {
|
|
17
|
+
let max = 0;
|
|
18
|
+
for (const p of paths) {
|
|
19
|
+
try { const m = statSync(p).mtimeMs; if (m > max) max = m; } catch { /* missing — skip */ }
|
|
20
|
+
}
|
|
21
|
+
return max;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Return the maximum mtimeMs across all given paths, recursing into
|
|
26
|
+
* directories up to `depth` levels. Only .md and .json files inside
|
|
27
|
+
* directories contribute their own mtime (not the parent dir entry).
|
|
28
|
+
* Plain file paths are stat'd directly regardless of extension.
|
|
29
|
+
* Missing / unreadable paths are silently skipped.
|
|
30
|
+
*
|
|
31
|
+
* @param {string[]} paths
|
|
32
|
+
* @param {number} [depth=3]
|
|
33
|
+
* @returns {number}
|
|
34
|
+
*/
|
|
35
|
+
export function maxMtimeRecursive(paths, depth = 3) {
|
|
36
|
+
let max = 0;
|
|
37
|
+
function walk(p, d) {
|
|
38
|
+
let st;
|
|
39
|
+
try { st = statSync(p); } catch { return; }
|
|
40
|
+
if (st.isDirectory()) {
|
|
41
|
+
if (d <= 0) return;
|
|
42
|
+
let entries;
|
|
43
|
+
try { entries = readdirSync(p, { withFileTypes: true }); } catch { return; }
|
|
44
|
+
for (const e of entries) {
|
|
45
|
+
const child = p + '/' + e.name;
|
|
46
|
+
if (e.isDirectory()) {
|
|
47
|
+
walk(child, d - 1);
|
|
48
|
+
} else if (e.isFile() && (e.name.endsWith('.md') || e.name.endsWith('.json'))) {
|
|
49
|
+
try { const m = statSync(child).mtimeMs; if (m > max) max = m; } catch {}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
if (st.mtimeMs > max) max = st.mtimeMs;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
for (const p of paths) walk(p, depth);
|
|
57
|
+
return max;
|
|
58
|
+
}
|