mixdog 0.9.63 → 0.9.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/package.json +9 -2
- package/scripts/code-graph-description-contract.mjs +3 -3
- package/scripts/verify-release-assets.mjs +2 -2
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +11 -14
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -6
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -2
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +1 -0
- package/src/runtime/agent/orchestrator/config.mjs +19 -124
- package/src/runtime/agent/orchestrator/context/collect.mjs +6 -6
- package/src/runtime/agent/orchestrator/dispatch-persist.mjs +2 -2
- package/src/runtime/agent/orchestrator/internal-agents.mjs +2 -2
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +1 -1
- package/src/runtime/agent/orchestrator/mcp/client.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +333 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -277
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +6 -6
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +196 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +460 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +14 -593
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +5 -280
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +357 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-headers.mjs +216 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +2 -188
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/provider-catalog-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/registry.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/compact/budget.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/compact/file-reattach.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +17 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +18 -26
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/delivered-completions.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +49 -0
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +49 -0
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +260 -0
- package/src/runtime/agent/orchestrator/session/store/serialize.mjs +72 -0
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +163 -0
- package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/store.mjs +9 -561
- package/src/runtime/agent/orchestrator/session/tool-envelope.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +2 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +11 -11
- package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +2 -154
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/cwd-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/fs-reachability.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/path-locks.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +2 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-open.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-spawn.mjs +519 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +5 -449
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +212 -0
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +1 -7
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +9 -36
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +15 -3
- package/src/runtime/agent/orchestrator/tools/code-graph/search-references.mjs +429 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +2 -395
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-state.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/mutation-planner.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/next-call-utils.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +7 -7
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +72 -9
- package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/result-compression.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +2 -444
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +505 -0
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +1 -1
- package/src/runtime/channels/lib/backend-dispatch.mjs +20 -5
- package/src/runtime/channels/lib/scheduler.mjs +1 -1
- package/src/runtime/channels/lib/telegram-format.mjs +1 -1
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +4 -4
- package/src/runtime/channels/tool-defs.mjs +2 -3
- package/src/runtime/memory/index.mjs +1 -5
- package/src/runtime/memory/lib/core-memory-candidates.mjs +357 -0
- package/src/runtime/memory/lib/core-memory-store.mjs +7 -357
- package/src/runtime/memory/lib/cycle-signatures.mjs +1 -1
- package/src/runtime/memory/lib/embedding-model-config.mjs +1 -1
- package/src/runtime/memory/lib/embedding-provider.mjs +1 -5
- package/src/runtime/memory/lib/embedding-worker.mjs +1 -5
- package/src/runtime/memory/lib/ko-morph.mjs +2 -2
- package/src/runtime/memory/lib/memory-config-flags.mjs +2 -5
- package/src/runtime/memory/lib/memory-cycle-requests.mjs +3 -7
- package/src/runtime/memory/lib/memory-cycle1.mjs +4 -8
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-shared.mjs +2 -5
- package/src/runtime/memory/lib/memory-cycle3.mjs +1 -5
- package/src/runtime/memory/lib/memory-embed.mjs +2 -6
- package/src/runtime/memory/lib/memory-log.mjs +8 -0
- package/src/runtime/memory/lib/memory-ops-policy.mjs +4 -8
- package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +1 -1
- package/src/runtime/memory/lib/memory-recall-store.mjs +2 -193
- package/src/runtime/memory/lib/memory-score.mjs +1 -1
- package/src/runtime/memory/lib/memory-text-utils.mjs +2 -2
- package/src/runtime/memory/lib/memory.mjs +2 -6
- package/src/runtime/memory/lib/pg/adapter.mjs +2 -6
- package/src/runtime/memory/lib/pg/process.mjs +1 -5
- package/src/runtime/memory/lib/pg/supervisor.mjs +1 -5
- package/src/runtime/memory/lib/recall-format.mjs +2 -2
- package/src/runtime/memory/lib/recall-scoring.mjs +195 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -5
- package/src/runtime/memory/lib/trace-store.mjs +2 -6
- package/src/runtime/search/lib/http-fetch.mjs +6 -6
- package/src/runtime/search/lib/web-tools.mjs +2 -2
- package/src/runtime/shared/buffered-appender.mjs +1 -1
- package/src/runtime/shared/child-guardian.mjs +1 -1
- package/src/runtime/shared/child-spawn-gate.mjs +1 -1
- package/src/runtime/shared/config.mjs +4 -4
- package/src/runtime/shared/launcher-control.mjs +9 -10
- package/src/runtime/shared/llm/index.mjs +5 -20
- package/src/runtime/shared/markdown-frontmatter.mjs +1 -1
- package/src/runtime/shared/memory-snapshot.mjs +4 -4
- package/src/runtime/shared/pristine-execution.mjs +1 -1
- package/src/runtime/shared/process-lifecycle.mjs +0 -1
- package/src/runtime/shared/process-shutdown.mjs +1 -1
- package/src/runtime/shared/resource-admission.mjs +2 -2
- package/src/runtime/shared/schedule-session-run.mjs +1 -1
- package/src/runtime/shared/schedules-db.mjs +1 -1
- package/src/runtime/shared/service-discovery.mjs +2 -2
- package/src/runtime/shared/staged-update.mjs +6 -6
- package/src/runtime/shared/tool-execution-contract.mjs +1 -1
- package/src/runtime/shared/tool-primitives.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +2 -2
- package/src/runtime/shared/turn-snapshot.mjs +184 -0
- package/src/runtime/shared/update-checker.mjs +1 -1
- package/src/runtime/shared/user-cwd.mjs +3 -3
- package/src/runtime/shared/user-data-guard.mjs +4 -4
- package/src/runtime/shared/workspace-router.mjs +5 -5
- package/src/session-runtime/config-helpers.mjs +2 -3
- package/src/session-runtime/config-lifecycle.mjs +1 -1
- package/src/session-runtime/hitch-profile.mjs +1 -1
- package/src/session-runtime/lifecycle-api.mjs +6 -4
- package/src/session-runtime/model-recency.mjs +5 -5
- package/src/session-runtime/plugin-mcp.mjs +1 -1
- package/src/session-runtime/provider-request-snapshot.mjs +338 -0
- package/src/session-runtime/runtime-core.mjs +4 -0
- package/src/session-runtime/session-text.mjs +4 -4
- package/src/session-runtime/session-turn-api.mjs +7 -0
- package/src/session-runtime/tool-catalog-schema.mjs +197 -0
- package/src/session-runtime/tool-catalog.mjs +6 -483
- package/src/session-runtime/tool-defs.mjs +1 -1
- package/src/standalone/agent-task-status.mjs +1 -1
- package/src/standalone/agent-tool/helpers.mjs +2 -2
- package/src/standalone/channel-admin.mjs +4 -4
- package/src/standalone/explore-tool.mjs +3 -3
- package/src/standalone/hook-bus/config.mjs +1 -1
- package/src/standalone/hook-bus/constants.mjs +1 -1
- package/src/standalone/hook-bus/rules.mjs +1 -1
- package/src/standalone/projects.mjs +1 -1
- package/src/standalone/provider-admin.mjs +2 -2
- package/src/tui/App.jsx +1 -1
- package/src/tui/app/app-format.mjs +2 -2
- package/src/tui/app/clipboard.mjs +3 -3
- package/src/tui/app/input-parsers.mjs +1 -1
- package/src/tui/app/text-layout.mjs +1 -1
- package/src/tui/app/transcript-row-estimate.mjs +360 -0
- package/src/tui/app/transcript-window.mjs +5 -347
- package/src/tui/app/use-mouse-input.mjs +1 -1
- package/src/tui/app/use-prompt-handlers.mjs +1 -1
- package/src/tui/components/tool-execution/surface-detail.mjs +9 -9
- package/src/tui/components/tool-execution/text-format.mjs +2 -2
- package/src/tui/components/tool-output-format.mjs +7 -7
- package/src/tui/display-width.mjs +4 -4
- package/src/tui/dist/index.mjs +187 -99
- package/src/tui/engine/agent-envelope.mjs +5 -5
- package/src/tui/engine/live-share.mjs +100 -0
- package/src/tui/engine/notification-plan.mjs +1 -1
- package/src/tui/engine/queue-helpers.mjs +3 -3
- package/src/tui/engine/render-timing.mjs +4 -5
- package/src/tui/engine/session-api-ext.mjs +6 -3
- package/src/tui/engine/tool-result-status.mjs +5 -5
- package/src/tui/engine/tool-result-text.mjs +1 -1
- package/src/tui/engine/transcript-spill.mjs +585 -0
- package/src/tui/engine/tui-steering-persist.mjs +1 -1
- package/src/tui/engine.mjs +29 -474
- package/src/tui/lib/voice-setup.mjs +1 -1
- package/src/tui/markdown/format-token.mjs +1 -1
- package/src/tui/markdown/render-ansi.mjs +1 -1
- package/src/tui/markdown/table-layout.mjs +4 -4
- package/src/tui/paste-attachments.mjs +1 -1
- package/src/tui/prompt-history-store.mjs +3 -3
- package/src/tui/statusline-ansi-bridge.mjs +2 -2
- package/src/tui/theme.mjs +1 -1
- package/src/tui/transcript-tool-failures.mjs +2 -2
- package/src/ui/ansi.mjs +0 -9
- package/src/ui/statusline-format.mjs +2 -4
- package/scripts/_bench-cwc.json +0 -20
- package/scripts/_jitter-fuzz.jsx +0 -42
- package/scripts/_jitter-fuzz2.jsx +0 -30
- package/scripts/_jitter-probe.jsx +0 -35
- package/scripts/_jp2.jsx +0 -16
- package/scripts/_smoke_wd.mjs +0 -7
- package/scripts/abort-recovery-test.mjs +0 -175
- package/scripts/agent-dispatch-abort-compose-test.mjs +0 -31
- package/scripts/agent-live-arg-guard-smoke.mjs +0 -20
- package/scripts/agent-live-path-suffix-smoke.mjs +0 -34
- package/scripts/agent-live-toolcall-args-smoke.mjs +0 -45
- package/scripts/agent-loop-policy-test.mjs +0 -37
- package/scripts/agent-model-liveness-test.mjs +0 -763
- package/scripts/agent-parallel-smoke.mjs +0 -435
- package/scripts/agent-route-batch-test.mjs +0 -40
- package/scripts/agent-tag-reuse-smoke.mjs +0 -441
- package/scripts/agent-terminal-reap-test.mjs +0 -252
- package/scripts/agent-trace-io-test.mjs +0 -133
- package/scripts/ansi-color-capability-test.mjs +0 -90
- package/scripts/anthropic-admission-retry-integration-test.mjs +0 -119
- package/scripts/anthropic-maxtokens-test.mjs +0 -119
- package/scripts/anthropic-oauth-refresh-race-test.mjs +0 -397
- package/scripts/anthropic-transport-policy-test.mjs +0 -726
- package/scripts/apply-patch-edit-smoke.mjs +0 -71
- package/scripts/arg-guard-test.mjs +0 -93
- package/scripts/async-notify-settlement-test.mjs +0 -99
- package/scripts/atomic-lock-tryonce-test.mjs +0 -125
- package/scripts/background-task-meta-smoke.mjs +0 -38
- package/scripts/bench-run.mjs +0 -508
- package/scripts/boot-smoke.mjs +0 -137
- package/scripts/build-runtime-windows.ps1 +0 -242
- package/scripts/channel-daemon-smoke.mjs +0 -1103
- package/scripts/code-graph-aggregate-cwd-test.mjs +0 -158
- package/scripts/code-graph-disk-hit-test.mjs +0 -290
- package/scripts/code-graph-dispatch-test.mjs +0 -96
- package/scripts/code-graph-root-federation-test.mjs +0 -273
- package/scripts/compact-active-turn-test.mjs +0 -68
- package/scripts/compact-file-reattach-test.mjs +0 -88
- package/scripts/compact-pressure-test.mjs +0 -788
- package/scripts/compact-prior-context-flatten-test.mjs +0 -252
- package/scripts/compact-recall-digest-test.mjs +0 -57
- package/scripts/compact-smoke.mjs +0 -1017
- package/scripts/compact-trigger-migration-smoke.mjs +0 -261
- package/scripts/compacted-placeholder-scrub-test.mjs +0 -63
- package/scripts/context-mcp-metering-test.mjs +0 -1406
- package/scripts/debounced-skills-async-save-test.mjs +0 -57
- package/scripts/deferred-tool-loading-test.mjs +0 -250
- package/scripts/desktop-session-bridge-test.mjs +0 -1013
- package/scripts/dispatch-persist-recovery-test.mjs +0 -141
- package/scripts/embedding-worker-exit-test.mjs +0 -76
- package/scripts/execution-completion-dedup-test.mjs +0 -205
- package/scripts/execution-pending-resume-kick-test.mjs +0 -151
- package/scripts/execution-resume-esc-integration-test.mjs +0 -176
- package/scripts/explore-bench-tmp.mjs +0 -36
- package/scripts/explore-bench.mjs +0 -248
- package/scripts/explore-prompt-policy-test.mjs +0 -256
- package/scripts/explore-timeout-cancel-test.mjs +0 -345
- package/scripts/find-fuzzy-hidden-test.mjs +0 -267
- package/scripts/forwarder-rebind-tail-test.mjs +0 -67
- package/scripts/freevar-smoke.mjs +0 -98
- package/scripts/gemini-provider-test.mjs +0 -1448
- package/scripts/generate-oc-icons.mjs +0 -11
- package/scripts/grok-oauth-refresh-race-test.mjs +0 -273
- package/scripts/headless-pristine-execution-test.mjs +0 -614
- package/scripts/hook-bus-test.mjs +0 -552
- package/scripts/ingest-pure-conversation-smoke.mjs +0 -175
- package/scripts/internal-comms-bench-test.mjs +0 -226
- package/scripts/internal-comms-bench.mjs +0 -853
- package/scripts/internal-comms-smoke.mjs +0 -277
- package/scripts/internal-tools-normalization-test.mjs +0 -62
- package/scripts/interrupted-turn-history-test.mjs +0 -399
- package/scripts/lead-workflow-smoke.mjs +0 -592
- package/scripts/lifecycle-api-test.mjs +0 -137
- package/scripts/live-share-test.mjs +0 -148
- package/scripts/live-worker-smoke.mjs +0 -333
- package/scripts/log-writer-guard-smoke.mjs +0 -131
- package/scripts/maintenance-default-routes-test.mjs +0 -164
- package/scripts/max-output-recovery-persist-test.mjs +0 -81
- package/scripts/max-output-recovery-test.mjs +0 -368
- package/scripts/mcp-client-normalization-test.mjs +0 -45
- package/scripts/mcp-grace-deferred-test.mjs +0 -225
- package/scripts/memory-core-input-test.mjs +0 -167
- package/scripts/memory-cycle-routing-test.mjs +0 -111
- package/scripts/memory-meta-concurrency-test.mjs +0 -20
- package/scripts/memory-pg-recovery-test.mjs +0 -59
- package/scripts/memory-rule-contract-test.mjs +0 -93
- package/scripts/model-list-sanitize-test.mjs +0 -37
- package/scripts/mouse-tracking-restore-smoke.mjs +0 -107
- package/scripts/native-edit-wire-test.mjs +0 -152
- package/scripts/notify-completion-mirror-test.mjs +0 -73
- package/scripts/openai-oauth-refresh-race-test.mjs +0 -120
- package/scripts/openai-oauth-ws-1006-retry-test.mjs +0 -954
- package/scripts/openai-ws-early-settle-test.mjs +0 -216
- package/scripts/output-style-bench.mjs +0 -292
- package/scripts/output-style-smoke.mjs +0 -145
- package/scripts/parent-abort-link-test.mjs +0 -90
- package/scripts/patch-binary-cache-test.mjs +0 -181
- package/scripts/path-suffix-test.mjs +0 -57
- package/scripts/pending-completion-drop-test.mjs +0 -239
- package/scripts/pending-messages-lock-nonblocking-test.mjs +0 -62
- package/scripts/pretool-ask-runtime-test.mjs +0 -54
- package/scripts/process-lifecycle-test.mjs +0 -461
- package/scripts/prompt-immediate-render-test.mjs +0 -89
- package/scripts/prompt-input-parity-test.mjs +0 -145
- package/scripts/provider-admission-scheduler-test.mjs +0 -681
- package/scripts/provider-contract-test.mjs +0 -632
- package/scripts/provider-stream-stall-test.mjs +0 -276
- package/scripts/provider-toolcall-test.mjs +0 -3063
- package/scripts/reactive-compact-persist-smoke.mjs +0 -203
- package/scripts/recall-bench.mjs +0 -359
- package/scripts/resource-admission-test.mjs +0 -792
- package/scripts/result-classification-test.mjs +0 -75
- package/scripts/rg-runner-test.mjs +0 -240
- package/scripts/routing-corpus-test.mjs +0 -349
- package/scripts/sanitize-tool-pairs-test.mjs +0 -260
- package/scripts/session-bench-cache-break-test.mjs +0 -102
- package/scripts/session-bench.mjs +0 -1708
- package/scripts/session-context-bench.mjs +0 -344
- package/scripts/session-heartbeat-lifecycle-test.mjs +0 -68
- package/scripts/session-ingest-compaction-smoke.mjs +0 -279
- package/scripts/session-ingest-smoke.mjs +0 -177
- package/scripts/session-orphan-sweep-test.mjs +0 -109
- package/scripts/set-effort-config-test.mjs +0 -41
- package/scripts/shell-failure-diagnostics-test.mjs +0 -280
- package/scripts/shell-hardening-test.mjs +0 -209
- package/scripts/shell-jobs-windows-hide-test.mjs +0 -164
- package/scripts/ship-mode-test.mjs +0 -98
- package/scripts/smoke-loop-failure-summary-test.mjs +0 -38
- package/scripts/smoke-loop-failure-summary.mjs +0 -16
- package/scripts/smoke-loop-report.mjs +0 -221
- package/scripts/smoke-loop.mjs +0 -202
- package/scripts/smoke-runtime-negative.ps1 +0 -106
- package/scripts/statusline-quota-hysteresis-test.mjs +0 -62
- package/scripts/steering-drain-buckets-test.mjs +0 -467
- package/scripts/steering-fold-provenance-test.mjs +0 -71
- package/scripts/streaming-tail-window-test.mjs +0 -175
- package/scripts/submit-commandbusy-race-test.mjs +0 -257
- package/scripts/task-bench.mjs +0 -205
- package/scripts/terminal-bench-isolation-guards-test.mjs +0 -102
- package/scripts/termio-input-smoke.mjs +0 -199
- package/scripts/tool-result-hook-test.mjs +0 -48
- package/scripts/tool-smoke.mjs +0 -2453
- package/scripts/tool-tui-presentation-test.mjs +0 -286
- package/scripts/toolcall-args-test.mjs +0 -239
- package/scripts/tui-ambiguous-width-test.mjs +0 -113
- package/scripts/tui-background-failure-smoke.mjs +0 -73
- package/scripts/tui-perf-run.ps1 +0 -26
- package/scripts/tui-render-smoke.mjs +0 -90
- package/scripts/tui-runtime-load-bench-entry.jsx +0 -608
- package/scripts/tui-runtime-load-bench.mjs +0 -50
- package/scripts/tui-store-frame-batch-test.mjs +0 -99
- package/scripts/tui-transcript-jitter-harness-entry.jsx +0 -383
- package/scripts/tui-transcript-perf-test.mjs +0 -934
- package/scripts/usage-metrics-epoch-smoke.mjs +0 -114
- package/scripts/verify-release-assets-test.mjs +0 -281
- package/scripts/web-fetch-routing-test.mjs +0 -158
- package/scripts/webhook-smoke.mjs +0 -201
- package/scripts/windows-hide-spawn-options-test.mjs +0 -19
- package/scripts/worker-notify-rejection-test.mjs +0 -51
- package/scripts/write-backpressure-test.mjs +0 -147
|
@@ -294,7 +294,7 @@ export function updateConfig(updater) {
|
|
|
294
294
|
return saved
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
-
|
|
297
|
+
function writeSection(section, data) {
|
|
298
298
|
withConfigLock(() => {
|
|
299
299
|
const all = readAllForRmW()
|
|
300
300
|
all[section] = stripGeneratedMarker(data)
|
|
@@ -383,7 +383,7 @@ export function updateConfigAsync(updater) {
|
|
|
383
383
|
})
|
|
384
384
|
}
|
|
385
385
|
|
|
386
|
-
|
|
386
|
+
function writeSectionAsync(section, data) {
|
|
387
387
|
return trackConfigWrite(() => withConfigLockAsync(async () => {
|
|
388
388
|
const all = readAllForRmW()
|
|
389
389
|
all[section] = stripGeneratedMarker(data)
|
|
@@ -427,7 +427,7 @@ function readCapabilities() {
|
|
|
427
427
|
// Convenience alias requested by B2 call-site plumbing. Returns the
|
|
428
428
|
// same object shape as readCapabilities(); callers that only need a
|
|
429
429
|
// boolean can read `.homeAccess` directly.
|
|
430
|
-
|
|
430
|
+
function getCapabilities() {
|
|
431
431
|
return readCapabilities()
|
|
432
432
|
}
|
|
433
433
|
|
|
@@ -443,7 +443,7 @@ export const SECRET_ACCOUNTS = Object.freeze({
|
|
|
443
443
|
opencodeGoAuthCookie: 'agent.opencode-go.authCookie',
|
|
444
444
|
})
|
|
445
445
|
|
|
446
|
-
|
|
446
|
+
function isDiscordSnowflake(value) {
|
|
447
447
|
return /^\d{17,20}$/.test(String(value || '').trim())
|
|
448
448
|
}
|
|
449
449
|
|
|
@@ -47,12 +47,11 @@ const RECORD_SEP = '\x1e';
|
|
|
47
47
|
|
|
48
48
|
// Names the env vars the launcher must set on the child so this module's
|
|
49
49
|
// managedLaunchId() resolves inside the MCP server.
|
|
50
|
-
export const LAUNCHER_ENV = Object.freeze({ ENV_LAUNCH_ID, ENV_MANAGED });
|
|
51
50
|
|
|
52
51
|
// Mirror of channels/lib/runtime-paths.mjs RUNTIME_ROOT resolution so the
|
|
53
52
|
// launcher and the MCP server agree on the queue location without importing
|
|
54
53
|
// the channels layer into setup/.
|
|
55
|
-
|
|
54
|
+
function launcherRuntimeRoot() {
|
|
56
55
|
return process.env.MIXDOG_RUNTIME_ROOT
|
|
57
56
|
? resolve(process.env.MIXDOG_RUNTIME_ROOT)
|
|
58
57
|
: join(tmpdir(), 'mixdog');
|
|
@@ -62,7 +61,7 @@ function sanitize(value) {
|
|
|
62
61
|
return String(value).replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
63
62
|
}
|
|
64
63
|
|
|
65
|
-
|
|
64
|
+
function launcherQueueDir(launchId) {
|
|
66
65
|
return join(launcherRuntimeRoot(), `launch-cmds-${sanitize(launchId)}`);
|
|
67
66
|
}
|
|
68
67
|
|
|
@@ -118,7 +117,7 @@ function nativeLaunchPrebuiltPath() {
|
|
|
118
117
|
}
|
|
119
118
|
|
|
120
119
|
let _nativeBinCache; // undefined = unresolved, string|null = resolved
|
|
121
|
-
|
|
120
|
+
function nativeLaunchBin() {
|
|
122
121
|
if (_nativeBinCache !== undefined) return _nativeBinCache;
|
|
123
122
|
// Opt-out for tests / forced-JS parity checks.
|
|
124
123
|
if (/^(0|false|no|off|js)$/i.test(String(process.env.MIXDOG_LAUNCH_NATIVE || ''))) {
|
|
@@ -141,7 +140,7 @@ export function nativeLaunchBin() {
|
|
|
141
140
|
// Returns true when the native mixdog-launch binary's `bridge` subcommand is
|
|
142
141
|
// available for this platform (exit 0). The launcher uses this to gate the
|
|
143
142
|
// managed-launch interactive path — no JS stdin pipe bridge fallback.
|
|
144
|
-
|
|
143
|
+
function nativeBridgeAvailable() {
|
|
145
144
|
const bin = nativeLaunchBin();
|
|
146
145
|
if (!bin) return false;
|
|
147
146
|
const r = spawnSync(bin, ['bridge', '--probe'], {
|
|
@@ -151,7 +150,7 @@ export function nativeBridgeAvailable() {
|
|
|
151
150
|
return r.status === 0;
|
|
152
151
|
}
|
|
153
152
|
|
|
154
|
-
|
|
153
|
+
function newLaunchId() {
|
|
155
154
|
return `${process.pid}-${randomUUID().slice(0, 8)}`;
|
|
156
155
|
}
|
|
157
156
|
|
|
@@ -159,7 +158,7 @@ export function newLaunchId() {
|
|
|
159
158
|
// `mixdog`-launched session that engaged the control bridge, else null. The
|
|
160
159
|
// launcher only sets MIXDOG_LAUNCH_ID once the bridge is live, so presence is
|
|
161
160
|
// sufficient — there is no half-managed state to disambiguate.
|
|
162
|
-
|
|
161
|
+
function managedLaunchId() {
|
|
163
162
|
const id = process.env[ENV_LAUNCH_ID];
|
|
164
163
|
return id && String(id).length > 0 ? String(id) : null;
|
|
165
164
|
}
|
|
@@ -170,7 +169,7 @@ let enqueueSequence = 0;
|
|
|
170
169
|
// launcher to deliver. Prefers the canonical Rust backend; the JS writer (temp
|
|
171
170
|
// name + rename so the watcher never sees a partial file) is the fallback.
|
|
172
171
|
// Returns the published path.
|
|
173
|
-
|
|
172
|
+
function enqueueLauncherCommand(launchId, command) {
|
|
174
173
|
const dir = launcherQueueDir(launchId);
|
|
175
174
|
mkdirSync(dir, { recursive: true });
|
|
176
175
|
const bin = nativeLaunchBin();
|
|
@@ -196,7 +195,7 @@ export function enqueueLauncherCommand(launchId, command) {
|
|
|
196
195
|
// Launcher side: drain queued commands oldest-first (lexical sort on the
|
|
197
196
|
// timestamp-prefixed name), deleting each as it is read. Prefers the canonical
|
|
198
197
|
// Rust backend; the JS reader is the fallback.
|
|
199
|
-
|
|
198
|
+
function drainLauncherCommands(launchId) {
|
|
200
199
|
const dir = launcherQueueDir(launchId);
|
|
201
200
|
const bin = nativeLaunchBin();
|
|
202
201
|
if (bin) {
|
|
@@ -236,7 +235,7 @@ export function drainLauncherCommands(launchId) {
|
|
|
236
235
|
// platforms (and miss atomic-rename publishes on some) that a short poll is the
|
|
237
236
|
// robust choice for this low-rate control path. Returns a stop() that also
|
|
238
237
|
// removes the queue directory.
|
|
239
|
-
|
|
238
|
+
function watchLauncherCommands(launchId, onCommand, { intervalMs = 150 } = {}) {
|
|
240
239
|
mkdirSync(launcherQueueDir(launchId), { recursive: true });
|
|
241
240
|
let stopped = false;
|
|
242
241
|
const timer = setInterval(() => {
|
|
@@ -26,37 +26,22 @@ function loadAgentConfig() {
|
|
|
26
26
|
/**
|
|
27
27
|
* Resolve the maintenance model ROUTE for a given task from agent-config.
|
|
28
28
|
*
|
|
29
|
-
* Maintenance slots
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* canonical DEFAULT_MAINTENANCE route. Returns null only when nothing resolves.
|
|
29
|
+
* Maintenance slots store a direct `{provider, model, effort?, fast?}` route
|
|
30
|
+
* (parity with `agents.<role>`). This returns that route object, falling back
|
|
31
|
+
* to the canonical DEFAULT_MAINTENANCE route. Returns null only when nothing
|
|
32
|
+
* resolves.
|
|
34
33
|
*
|
|
35
34
|
* The returned value is passed straight through as `opts.preset` to
|
|
36
|
-
* makeAgentDispatch
|
|
37
|
-
* accept either a route object or a legacy name string.
|
|
35
|
+
* makeAgentDispatch (resolveMaintenanceRoute()/maintenanceRouteToPreset()).
|
|
38
36
|
*/
|
|
39
37
|
export function resolveMaintenancePreset(task, agentConfig) {
|
|
40
38
|
const cfg = agentConfig || loadAgentConfig()
|
|
41
39
|
const maint = cfg?.maintenance || {}
|
|
42
|
-
const presets = cfg?.presets || []
|
|
43
40
|
const slot = maint[task]
|
|
44
|
-
// Preferred: slot already holds a direct route object.
|
|
45
41
|
if (slot && typeof slot === 'object' && !Array.isArray(slot)
|
|
46
42
|
&& slot.provider && slot.model) {
|
|
47
43
|
return { ...slot }
|
|
48
44
|
}
|
|
49
|
-
// Legacy: slot holds a preset-NAME string — resolve it to a route.
|
|
50
|
-
const name = String(slot || '').trim()
|
|
51
|
-
if (name) {
|
|
52
|
-
const preset = presets.find(p => p && (p.id === name || p.name === name))
|
|
53
|
-
if (preset && preset.provider && preset.model) {
|
|
54
|
-
const route = { provider: preset.provider, model: preset.model }
|
|
55
|
-
if (preset.effort) route.effort = preset.effort
|
|
56
|
-
if (preset.fast === true) route.fast = true
|
|
57
|
-
return route
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
45
|
// Canonical default route (DEFAULT_MAINTENANCE is now route-shaped).
|
|
61
46
|
const def = DEFAULT_MAINTENANCE[task]
|
|
62
47
|
if (def && def.provider && def.model) return { ...def }
|
|
@@ -14,7 +14,7 @@ import { withFileLock } from './atomic-file.mjs';
|
|
|
14
14
|
import { resolvePluginData } from './plugin-paths.mjs';
|
|
15
15
|
|
|
16
16
|
const execFileAsync = promisify(execFile);
|
|
17
|
-
|
|
17
|
+
const MEMORY_PRESSURE_SNAPSHOT_MAX_BYTES = 64 * 1024;
|
|
18
18
|
const SNAPSHOT_NAME = 'memory-pressure.jsonl';
|
|
19
19
|
const SNAPSHOT_INTERVAL_MS = 10 * 60 * 1000;
|
|
20
20
|
const SNAPSHOT_INTERVAL_JITTER_MS = 60 * 1000;
|
|
@@ -196,7 +196,7 @@ function baseSnapshot(reason) {
|
|
|
196
196
|
* Collect a full attribution snapshot. Process enumeration failures are
|
|
197
197
|
* intentionally omitted from the record, rather than surfacing to callers.
|
|
198
198
|
*/
|
|
199
|
-
|
|
199
|
+
async function captureMemoryPressureSnapshot(reason = 'memory-pressure') {
|
|
200
200
|
if (!enabled()) return false;
|
|
201
201
|
const entry = baseSnapshot(reason);
|
|
202
202
|
const processes = await topProcesses();
|
|
@@ -229,7 +229,7 @@ export function requestMemoryPressureSnapshot(reason) {
|
|
|
229
229
|
}
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
-
|
|
232
|
+
function armMemoryPressureSampling() {
|
|
233
233
|
if (!enabled() || periodicTimer) return false;
|
|
234
234
|
periodicTimer = setInterval(() => {
|
|
235
235
|
void capturePeriodicMemorySnapshot().catch(() => {});
|
|
@@ -238,7 +238,7 @@ export function armMemoryPressureSampling() {
|
|
|
238
238
|
return true;
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
-
|
|
241
|
+
function memoryPressureSnapshotPath() {
|
|
242
242
|
return snapshotPaths().snapshot;
|
|
243
243
|
}
|
|
244
244
|
|
|
@@ -22,7 +22,6 @@ import { resolvePluginData } from './plugin-paths.mjs';
|
|
|
22
22
|
|
|
23
23
|
const execFileAsync = promisify(execFile);
|
|
24
24
|
export const LIFECYCLE_LEDGER_MAX_BYTES = 64 * 1024;
|
|
25
|
-
export const LIFECYCLE_LEDGER_KEEP_FILES = 2;
|
|
26
25
|
const LEDGER_NAME = 'process-lifecycle.jsonl';
|
|
27
26
|
const MARKER_DIR_NAME = 'process-lifecycle.active';
|
|
28
27
|
const LEGACY_MARKER_NAME = 'process-lifecycle.active.json';
|
|
@@ -50,7 +50,7 @@ function abortError(signal) {
|
|
|
50
50
|
: new Error(String(signal?.reason || 'resource admission canceled'));
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
class ResourcePressureError extends Error {
|
|
54
54
|
constructor(message, details = {}) {
|
|
55
55
|
super(`resource pressure: ${message}`);
|
|
56
56
|
this.name = 'ResourcePressureError';
|
|
@@ -59,7 +59,7 @@ export class ResourcePressureError extends Error {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
class ResourceAdmissionQueueFullError extends ResourcePressureError {
|
|
63
63
|
constructor(maxQueue) {
|
|
64
64
|
super(`high-load admission queue full (maximum ${maxQueue}); retry after running work completes`, {
|
|
65
65
|
maxQueue,
|
|
@@ -12,7 +12,7 @@ import { askSession } from '../agent/orchestrator/session/manager/ask-session.mj
|
|
|
12
12
|
import { parseScheduleModelRef } from './schedule-model-ref.mjs';
|
|
13
13
|
|
|
14
14
|
/** Resolve schedule.model into a {provider,model,effort?,fast?} route. */
|
|
15
|
-
|
|
15
|
+
function scheduleRouteFromModelRef(modelRef, config = null) {
|
|
16
16
|
const ref = parseScheduleModelRef(modelRef);
|
|
17
17
|
if (ref && typeof ref === 'object') return ref;
|
|
18
18
|
const cfg = config || loadConfig({ secrets: false });
|
|
@@ -220,7 +220,7 @@ export async function setSkippedUntil(name, ts, { dataDir } = {}) {
|
|
|
220
220
|
* next_fire_at at/before `now`, and not currently deferred or skipped past
|
|
221
221
|
* `now`.
|
|
222
222
|
*/
|
|
223
|
-
|
|
223
|
+
async function listDue(now = new Date(), { dataDir } = {}) {
|
|
224
224
|
const db = await getDb(dataDir);
|
|
225
225
|
const { rows } = await db.query(
|
|
226
226
|
`SELECT ${COLS} FROM scheduler.schedules
|
|
@@ -15,7 +15,7 @@ import { tmpdir } from 'node:os'
|
|
|
15
15
|
import { join, resolve } from 'node:path'
|
|
16
16
|
import { writeJsonAtomicSync } from './atomic-file.mjs'
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
function discoveryRoot() {
|
|
19
19
|
const root = process.env.MIXDOG_RUNTIME_ROOT
|
|
20
20
|
? resolve(process.env.MIXDOG_RUNTIME_ROOT)
|
|
21
21
|
: join(tmpdir(), 'mixdog')
|
|
@@ -152,7 +152,7 @@ export function writeServiceAdvert(service, fields = {}) {
|
|
|
152
152
|
// advertises a port, the file is removed (clean shutdown). Read-modify-write is
|
|
153
153
|
// race-free enough for a genuine single owner (only the service's supervisor
|
|
154
154
|
// writes its own file).
|
|
155
|
-
|
|
155
|
+
function patchServiceAdvert(service, fields = {}) {
|
|
156
156
|
const cur = readServiceAdvert(service) ?? {}
|
|
157
157
|
const merged = { ...cur }
|
|
158
158
|
for (const [k, v] of Object.entries(fields)) {
|
|
@@ -116,7 +116,7 @@ export function unregisterLiveSession() {
|
|
|
116
116
|
try { unlinkSync(selfPidFile()); } catch { /* already gone */ }
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
function otherLiveSessionExists() {
|
|
120
120
|
let entries;
|
|
121
121
|
try { entries = readdirSync(liveSessionsDir()); } catch { return false; }
|
|
122
122
|
let alive = false;
|
|
@@ -278,7 +278,7 @@ export function spawnStagedInstall(version) {
|
|
|
278
278
|
* bestStagedVersion(currentVersion) — highest completed staged version strictly
|
|
279
279
|
* newer than current, with a valid self-contained package dir; else null.
|
|
280
280
|
*/
|
|
281
|
-
|
|
281
|
+
function bestStagedVersion(currentVersion) {
|
|
282
282
|
const cur = String(currentVersion || localPackageVersion());
|
|
283
283
|
let best = null;
|
|
284
284
|
let entries;
|
|
@@ -303,7 +303,7 @@ export function bestStagedVersion(currentVersion) {
|
|
|
303
303
|
* success; on failure of the second rename the backup is rolled back into
|
|
304
304
|
* place. Returns true only when the new version is live. Never throws.
|
|
305
305
|
*/
|
|
306
|
-
|
|
306
|
+
function swapStagedIntoGlobal({ globalPkgRoot, pkgDir, expectedVersion, _rename } = {}) {
|
|
307
307
|
if (!globalPkgRoot || !pkgDir) return false;
|
|
308
308
|
// `_rename` is a test seam; production always uses renameWithRetrySync.
|
|
309
309
|
const rename = typeof _rename === 'function' ? _rename : renameWithRetrySync;
|
|
@@ -366,7 +366,7 @@ function globalPopulated(root) {
|
|
|
366
366
|
* cleanupStaging(currentVersion) — remove superseded/stale staging dirs and any
|
|
367
367
|
* leftover swap backups. Best-effort; never throws.
|
|
368
368
|
*/
|
|
369
|
-
|
|
369
|
+
function cleanupStaging(currentVersion) {
|
|
370
370
|
const cur = String(currentVersion || localPackageVersion());
|
|
371
371
|
try {
|
|
372
372
|
for (const name of readdirSync(stagingRootDir())) {
|
|
@@ -458,7 +458,7 @@ export function performPendingSwap() {
|
|
|
458
458
|
// present + size-stable package; otherwise print a one-line notice and
|
|
459
459
|
// process.exit(1). Exported so the swap-safety proof can exercise the exact
|
|
460
460
|
// production decision.
|
|
461
|
-
|
|
461
|
+
function ensureGlobalStableOrExit(root, timeoutMs = 3000) {
|
|
462
462
|
if (ensureGlobalStable(root, timeoutMs) && globalPopulated(root)) return true;
|
|
463
463
|
process.stderr.write('mixdog: update in progress — retry in a moment.\n');
|
|
464
464
|
process.exit(1);
|
|
@@ -479,7 +479,7 @@ function currentGlobalVersion() {
|
|
|
479
479
|
// Block until the swap lock file disappears (owner finished) or the deadline
|
|
480
480
|
// passes. A dead/abandoned owner is reaped and treated as cleared. Returns true
|
|
481
481
|
// if the lock is gone, false if it timed out with a live owner still holding.
|
|
482
|
-
|
|
482
|
+
function waitForSwapLockClear(lock, timeoutMs) {
|
|
483
483
|
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
484
484
|
while (Date.now() < deadline) {
|
|
485
485
|
if (!existsSync(lock)) return true;
|
|
@@ -135,7 +135,7 @@ export function toolCompletionInstruction({ surface = 'tool', id, status, detail
|
|
|
135
135
|
return `The async ${label} ${id || ''} has finished${statusText} - review this result in your next step.`;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
function toolCompletionMeta({
|
|
139
139
|
surface = 'tool',
|
|
140
140
|
id,
|
|
141
141
|
status,
|
|
@@ -37,7 +37,7 @@ export function isMcpToolName(name) {
|
|
|
37
37
|
// (mcp__plugin_mixdog_mixdog__<tool>). Those must render as their stripped
|
|
38
38
|
// builtin names, not as external "MCP" calls. Define the server id once here
|
|
39
39
|
// and reuse everywhere a display path branches on MCP-ness.
|
|
40
|
-
|
|
40
|
+
const SELF_MCP_SERVER = 'plugin_mixdog_mixdog';
|
|
41
41
|
|
|
42
42
|
export function isSelfMcpToolName(name) {
|
|
43
43
|
const mcp = parseMcpToolName(name);
|
|
@@ -317,7 +317,7 @@ export function formatToolSurface(name, args, opts = {}) {
|
|
|
317
317
|
|
|
318
318
|
// ── Aggregate tool-card classification & formatting ──────────────
|
|
319
319
|
|
|
320
|
-
|
|
320
|
+
const CATEGORY_ORDER = [
|
|
321
321
|
'Read', 'Search', 'Load', 'MCP', 'Skill', 'Web Research', 'Memory', 'Explore',
|
|
322
322
|
'Patch', 'Shell', 'Agent', 'Task', 'Schedule', 'Channel', 'Setup', 'Other',
|
|
323
323
|
];
|
|
@@ -400,7 +400,7 @@ const CATEGORY_COPY = new Map([
|
|
|
400
400
|
]);
|
|
401
401
|
|
|
402
402
|
/** Active gerund for a category (e.g. "Reading" for "Read"). */
|
|
403
|
-
|
|
403
|
+
function activeCategoryLabel(category) {
|
|
404
404
|
return CATEGORY_COPY.get(category)?.active || category;
|
|
405
405
|
}
|
|
406
406
|
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// Turn-scoped worktree snapshots over a SHADOW git repository.
|
|
2
|
+
//
|
|
3
|
+
// A per-worktree bare repo lives under <data>/turn-snapshots/<hash>; `git
|
|
4
|
+
// --git-dir <shadow> --work-tree <project>` add/write-tree captures the whole
|
|
5
|
+
// worktree as a tree object WITHOUT touching the project's own git state (or
|
|
6
|
+
// requiring the project to be a git repo at all). Diffing the turn-start tree
|
|
7
|
+
// against the current tree therefore reports EVERYTHING a turn changed —
|
|
8
|
+
// lead edits, subagent edits, background shell jobs, even external editors —
|
|
9
|
+
// which transcript-parsed patches structurally cannot see.
|
|
10
|
+
//
|
|
11
|
+
// Costs: the first track() of a project hashes the worktree once (mitigated
|
|
12
|
+
// by reusing the project's own .git objects via alternates); every later
|
|
13
|
+
// track() is an index stat-scan. All entry points are best-effort and never
|
|
14
|
+
// throw into the turn path. MIXDOG_TURN_SNAPSHOT=0 disables the feature.
|
|
15
|
+
import { execFile } from 'child_process';
|
|
16
|
+
import { createHash } from 'crypto';
|
|
17
|
+
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
18
|
+
import { join, resolve } from 'path';
|
|
19
|
+
import { resolvePluginData } from './plugin-paths.mjs';
|
|
20
|
+
|
|
21
|
+
const DISABLED = /^(0|false|off)$/i.test(String(process.env.MIXDOG_TURN_SNAPSHOT || ''));
|
|
22
|
+
const GIT_TIMEOUT_MS = 120_000;
|
|
23
|
+
const BEGIN_WAIT_CAP_MS = 1_500;
|
|
24
|
+
const MAX_PATCH_BYTES = 2_000_000;
|
|
25
|
+
const BASE_CACHE_MAX = 32;
|
|
26
|
+
const FAILURE_BACKOFF_MS = 5 * 60_000;
|
|
27
|
+
|
|
28
|
+
const _queues = new Map(); // gitdir → tail promise (serialize per repo)
|
|
29
|
+
const _baseBySession = new Map(); // sessionId → { worktree, tree, at }
|
|
30
|
+
const _failedUntil = new Map(); // gitdir → timestamp
|
|
31
|
+
|
|
32
|
+
function _worktreeKey(worktree) {
|
|
33
|
+
const raw = String(worktree || '').trim();
|
|
34
|
+
if (!raw) return '';
|
|
35
|
+
const full = resolve(raw);
|
|
36
|
+
return process.platform === 'win32' ? full.toLowerCase() : full;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function _gitDirFor(worktreeKey) {
|
|
40
|
+
const hash = createHash('sha1').update(worktreeKey).digest('hex').slice(0, 20);
|
|
41
|
+
return join(resolvePluginData(), 'turn-snapshots', hash);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function _git(args, { cwd } = {}) {
|
|
45
|
+
return new Promise((resolveExec) => {
|
|
46
|
+
execFile('git', args, {
|
|
47
|
+
cwd: cwd || undefined,
|
|
48
|
+
windowsHide: true,
|
|
49
|
+
timeout: GIT_TIMEOUT_MS,
|
|
50
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
51
|
+
}, (error, stdout, stderr) => {
|
|
52
|
+
resolveExec({ code: error ? (error.code ?? 1) : 0, stdout: String(stdout || ''), stderr: String(stderr || '') });
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Serialize all git operations per shadow repo: concurrent index writes would
|
|
58
|
+
// corrupt each other, and turn-start/track/diff can overlap freely otherwise.
|
|
59
|
+
function _enqueue(gitdir, task) {
|
|
60
|
+
const tail = (_queues.get(gitdir) || Promise.resolve()).then(task, task);
|
|
61
|
+
_queues.set(gitdir, tail.catch(() => {}));
|
|
62
|
+
return tail;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function _ensureRepo(worktree, gitdir) {
|
|
66
|
+
if (existsSync(join(gitdir, 'HEAD'))) return true;
|
|
67
|
+
mkdirSync(gitdir, { recursive: true });
|
|
68
|
+
const init = await _git(['init', '--bare', '--quiet', gitdir]);
|
|
69
|
+
if (init.code !== 0) return false;
|
|
70
|
+
// The shadow repo indexes the project via --work-tree; never let it descend
|
|
71
|
+
// into the project's real .git, and keep bytes stable/gc quiet.
|
|
72
|
+
await _git(['--git-dir', gitdir, 'config', 'core.bare', 'false']);
|
|
73
|
+
await _git(['--git-dir', gitdir, 'config', 'core.autocrlf', 'false']);
|
|
74
|
+
await _git(['--git-dir', gitdir, 'config', 'gc.auto', '0']);
|
|
75
|
+
try {
|
|
76
|
+
mkdirSync(join(gitdir, 'info'), { recursive: true });
|
|
77
|
+
writeFileSync(join(gitdir, 'info', 'exclude'), '.git/\n');
|
|
78
|
+
// First-snapshot cost: reuse the project's own git objects so unchanged
|
|
79
|
+
// blobs need no re-hash/store (the opencode chromium lesson).
|
|
80
|
+
const projectObjects = join(worktree, '.git', 'objects');
|
|
81
|
+
if (existsSync(projectObjects)) {
|
|
82
|
+
mkdirSync(join(gitdir, 'objects', 'info'), { recursive: true });
|
|
83
|
+
writeFileSync(join(gitdir, 'objects', 'info', 'alternates'), `${projectObjects}\n`);
|
|
84
|
+
}
|
|
85
|
+
} catch { /* exclusions/alternates are optimizations, not requirements */ }
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Capture the current worktree as a tree object; null on any failure.
|
|
90
|
+
async function _trackTree(worktree) {
|
|
91
|
+
const key = _worktreeKey(worktree);
|
|
92
|
+
if (!key || !existsSync(key)) return null;
|
|
93
|
+
const gitdir = _gitDirFor(key);
|
|
94
|
+
const failedUntil = _failedUntil.get(gitdir) || 0;
|
|
95
|
+
if (Date.now() < failedUntil) return null;
|
|
96
|
+
return _enqueue(gitdir, async () => {
|
|
97
|
+
if (!(await _ensureRepo(key, gitdir))) {
|
|
98
|
+
_failedUntil.set(gitdir, Date.now() + FAILURE_BACKOFF_MS);
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
const base = ['--git-dir', gitdir, '--work-tree', key];
|
|
102
|
+
const add = await _git([...base, 'add', '-A', '--', '.'], { cwd: key });
|
|
103
|
+
if (add.code !== 0) {
|
|
104
|
+
_failedUntil.set(gitdir, Date.now() + FAILURE_BACKOFF_MS);
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
const tree = await _git([...base, 'write-tree'], { cwd: key });
|
|
108
|
+
if (tree.code !== 0) return null;
|
|
109
|
+
const hash = tree.stdout.trim();
|
|
110
|
+
return /^[0-9a-f]{40,64}$/.test(hash) ? hash : null;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Fire-and-forget shadow-repo warmup so a project's first turn never pays
|
|
115
|
+
* the initial full snapshot inline. */
|
|
116
|
+
export function prewarmTurnSnapshot(worktree) {
|
|
117
|
+
if (DISABLED || !worktree) return;
|
|
118
|
+
void _trackTree(worktree).catch(() => {});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Capture the turn base tree for a session. Waits at most BEGIN_WAIT_CAP_MS
|
|
122
|
+
* so a cold first snapshot cannot stall the turn; a slower capture still
|
|
123
|
+
* lands through the shared promise and applies to this turn retroactively. */
|
|
124
|
+
export async function beginTurnSnapshot(worktree, sessionId) {
|
|
125
|
+
if (DISABLED || !worktree || !sessionId) return;
|
|
126
|
+
const key = _worktreeKey(worktree);
|
|
127
|
+
const capture = _trackTree(worktree).then((tree) => {
|
|
128
|
+
if (!tree) return;
|
|
129
|
+
_baseBySession.delete(sessionId);
|
|
130
|
+
_baseBySession.set(sessionId, { worktree: key, tree, at: Date.now() });
|
|
131
|
+
while (_baseBySession.size > BASE_CACHE_MAX) {
|
|
132
|
+
const oldest = _baseBySession.keys().next().value;
|
|
133
|
+
if (oldest === undefined) break;
|
|
134
|
+
_baseBySession.delete(oldest);
|
|
135
|
+
}
|
|
136
|
+
}).catch(() => {});
|
|
137
|
+
await Promise.race([capture, new Promise((r) => { const t = setTimeout(r, BEGIN_WAIT_CAP_MS); t.unref?.(); })]);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Diff the session's turn-start tree against the CURRENT worktree state.
|
|
141
|
+
* Returns { supported, files:[{name, additions, deletions}], patch }. */
|
|
142
|
+
export async function getTurnReviewDiff(worktree, sessionId) {
|
|
143
|
+
if (DISABLED) return { supported: false, files: [], patch: '' };
|
|
144
|
+
const key = _worktreeKey(worktree);
|
|
145
|
+
const base = sessionId ? _baseBySession.get(sessionId) : null;
|
|
146
|
+
if (!key) return { supported: false, files: [], patch: '' };
|
|
147
|
+
if (!base || base.worktree !== key) {
|
|
148
|
+
return { supported: true, files: [], patch: '', reason: 'no-base' };
|
|
149
|
+
}
|
|
150
|
+
const head = await _trackTree(worktree);
|
|
151
|
+
if (!head) return { supported: false, files: [], patch: '' };
|
|
152
|
+
if (head === base.tree) return { supported: true, files: [], patch: '', baseTree: base.tree, headTree: head };
|
|
153
|
+
const gitdir = _gitDirFor(key);
|
|
154
|
+
const argsBase = ['--git-dir', gitdir];
|
|
155
|
+
const [numstat, patch] = await Promise.all([
|
|
156
|
+
_git([...argsBase, 'diff-tree', '-r', '--numstat', '-z', base.tree, head]),
|
|
157
|
+
_git([...argsBase, 'diff-tree', '-r', '-p', '--no-color', base.tree, head]),
|
|
158
|
+
]);
|
|
159
|
+
if (numstat.code !== 0) return { supported: false, files: [], patch: '' };
|
|
160
|
+
const files = [];
|
|
161
|
+
const fields = numstat.stdout.split('\0').filter(Boolean);
|
|
162
|
+
for (const row of fields) {
|
|
163
|
+
const match = row.match(/^(\d+|-)\t(\d+|-)\t([\s\S]+)$/);
|
|
164
|
+
if (!match) continue;
|
|
165
|
+
files.push({
|
|
166
|
+
name: match[3],
|
|
167
|
+
additions: match[1] === '-' ? 0 : Number(match[1]),
|
|
168
|
+
deletions: match[2] === '-' ? 0 : Number(match[2]),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
let patchText = patch.code === 0 ? patch.stdout : '';
|
|
172
|
+
if (patchText.length > MAX_PATCH_BYTES) {
|
|
173
|
+
patchText = patchText.slice(0, MAX_PATCH_BYTES);
|
|
174
|
+
const cut = patchText.lastIndexOf('\ndiff --git ');
|
|
175
|
+
if (cut > 0) patchText = patchText.slice(0, cut + 1);
|
|
176
|
+
}
|
|
177
|
+
return { supported: true, files, patch: patchText, baseTree: base.tree, headTree: head };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function _resetTurnSnapshotForTest() {
|
|
181
|
+
_queues.clear();
|
|
182
|
+
_baseBySession.clear();
|
|
183
|
+
_failedUntil.clear();
|
|
184
|
+
}
|
|
@@ -252,7 +252,7 @@ export function npmCliJsPath() {
|
|
|
252
252
|
* npm-cli.js cannot be located. Resolves once the child exits; never throws —
|
|
253
253
|
* failures come back as {ok:false, error}.
|
|
254
254
|
*/
|
|
255
|
-
|
|
255
|
+
function runGlobalUpdate() {
|
|
256
256
|
return new Promise((resolvePromise) => {
|
|
257
257
|
let child;
|
|
258
258
|
try {
|
|
@@ -44,7 +44,7 @@ function _dataFile(name) {
|
|
|
44
44
|
// back to the home dir: a missing session signal then surfaces as ENOENT
|
|
45
45
|
// (absolute paths required) rather than a silent stale read. Invariant check
|
|
46
46
|
// (exact path equality with the known root), not a path-substring heuristic.
|
|
47
|
-
|
|
47
|
+
function _safeProcessCwd() {
|
|
48
48
|
const cwd = process.cwd()
|
|
49
49
|
try { if (resolve(cwd) === resolve(mixdogRoot())) return homedir() } catch { /* fall through to cwd */ }
|
|
50
50
|
return cwd
|
|
@@ -143,7 +143,7 @@ export function captureOriginalUserCwd() {
|
|
|
143
143
|
* Used by the cwd-tool auto-init path to avoid self-reference when
|
|
144
144
|
* deciding whether to seed MIXDOG_SESSION_CWD from disk.
|
|
145
145
|
*/
|
|
146
|
-
|
|
146
|
+
function rawUserCwd() {
|
|
147
147
|
try {
|
|
148
148
|
const txt = readFileSync(_dataFile('user-cwd.txt'), 'utf8').trim()
|
|
149
149
|
return _normalizePlatformCwd(txt) || startRootCwd() || _safeProcessCwd()
|
|
@@ -208,7 +208,7 @@ export function readLastSessionCwd(keyPid) {
|
|
|
208
208
|
* Run fn inside an async context where pwd() returns cwd.
|
|
209
209
|
* All descendant async calls within fn see cwd as their working directory.
|
|
210
210
|
*/
|
|
211
|
-
|
|
211
|
+
function runWithCwdOverride(cwd, fn) {
|
|
212
212
|
return _cwdOverride.run(cwd, fn)
|
|
213
213
|
}
|
|
214
214
|
|
|
@@ -23,7 +23,7 @@ function mixdogConfigBaseDir() {
|
|
|
23
23
|
return process.env.MIXDOG_CONFIG_DIR || join(homedir(), '.mixdog');
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
function getBackupRoot() {
|
|
27
27
|
return process.env.MIXDOG_USER_DATA_BACKUP_ROOT
|
|
28
28
|
|| join(mixdogConfigBaseDir(), 'backups', 'user-data');
|
|
29
29
|
}
|
|
@@ -64,7 +64,7 @@ export function hasUserDataInitMarker(dataDir) {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/** Skip single-section wipe remnants (e.g. `{ search: … }` only). */
|
|
67
|
-
|
|
67
|
+
function isStructurallyCompleteMixdogConfigBackup(parsed) {
|
|
68
68
|
if (!isPlainObject(parsed)) return false;
|
|
69
69
|
if (Object.keys(parsed).length <= 1) return false;
|
|
70
70
|
if (!parsed.agent && !parsed.channels) return false;
|
|
@@ -224,7 +224,7 @@ export async function backupUserDataAsync(dataDir, reason = 'snapshot') {
|
|
|
224
224
|
return { dir: copied.length > 0 ? backupDir : null, copied };
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
|
|
227
|
+
function shouldSeedMissingUserData(dataDir, rel) {
|
|
228
228
|
if (!dataDir) return true;
|
|
229
229
|
if (existsSync(join(dataDir, rel))) {
|
|
230
230
|
markUserDataInitialized(dataDir);
|
|
@@ -275,7 +275,7 @@ function normCase(p) {
|
|
|
275
275
|
* @param {string} [ownedSubdir] the single owned subdir name (default '.deps')
|
|
276
276
|
* @returns {string} the resolved owned path (only on allow)
|
|
277
277
|
*/
|
|
278
|
-
|
|
278
|
+
function assertSafeOwnedDir(targetDir, dataDir, op = 'destructive op', ownedSubdir = OWNED_SUBDIR) {
|
|
279
279
|
if (!targetDir) throw new Error(`[data-guard] ${op} refused: empty target dir`);
|
|
280
280
|
if (!dataDir) throw new Error(`[data-guard] ${op} refused: empty data dir`);
|
|
281
281
|
|