mixdog 0.9.3 → 0.9.5
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 +112 -38
- package/package.json +10 -3
- package/scripts/bench/lead-review-tasks-r3.json +20 -0
- package/scripts/bench/lead-review-tasks.json +20 -0
- package/scripts/bench/r4-mixed-tasks.json +20 -0
- package/scripts/bench/r5-orchestrated-task.json +7 -0
- package/scripts/bench/review-tasks.json +20 -0
- package/scripts/bench/round-codex.json +114 -0
- package/scripts/bench/round-mixdog-lead-r3.json +269 -0
- package/scripts/bench/round-mixdog-lead.json +269 -0
- package/scripts/bench/round-mixdog.json +126 -0
- package/scripts/bench/round-r10-bigsample.json +679 -0
- package/scripts/bench/round-r11-codexalign.json +257 -0
- package/scripts/bench/round-r13-clientmeta.json +464 -0
- package/scripts/bench/round-r14-betafeatures.json +466 -0
- package/scripts/bench/round-r15-fulldefault.json +462 -0
- package/scripts/bench/round-r16-sessionid.json +466 -0
- package/scripts/bench/round-r17-wirebytes.json +456 -0
- package/scripts/bench/round-r18-prewarm.json +468 -0
- package/scripts/bench/round-r19-clean.json +472 -0
- package/scripts/bench/round-r20-prewarm-clean.json +475 -0
- package/scripts/bench/round-r21-delta-retry.json +473 -0
- package/scripts/bench/round-r22-full-probe.json +693 -0
- package/scripts/bench/round-r23-itemprobe.json +701 -0
- package/scripts/bench/round-r24-shapefix.json +677 -0
- package/scripts/bench/round-r25-serial.json +464 -0
- package/scripts/bench/round-r26-parallel3.json +671 -0
- package/scripts/bench/round-r27-parallel10.json +894 -0
- package/scripts/bench/round-r28-parallel10-stagger.json +882 -0
- package/scripts/bench/round-r29-parallel10-stagger166.json +886 -0
- package/scripts/bench/round-r30-instid.json +253 -0
- package/scripts/bench/round-r31-upgradeprobe.json +256 -0
- package/scripts/bench/round-r32-vs-codex-lead.json +254 -0
- package/scripts/bench/round-r33-vs-codex-codex.json +115 -0
- package/scripts/bench/round-r34-orchestrated.json +120 -0
- package/scripts/bench/round-r35-orchestrated-codex.json +61 -0
- package/scripts/bench/round-r36-orchestrated-capped.json +128 -0
- package/scripts/bench/round-r4-codex.json +114 -0
- package/scripts/bench/round-r4-mixed.json +225 -0
- package/scripts/bench/round-r5-gpt-lead.json +259 -0
- package/scripts/bench/round-r6-codex.json +114 -0
- package/scripts/bench/round-r6-solo.json +257 -0
- package/scripts/bench/round-r7-full.json +254 -0
- package/scripts/bench/round-r8-fulldefault.json +255 -0
- package/scripts/bench-run.mjs +251 -32
- package/scripts/freevar-smoke.mjs +95 -0
- package/scripts/internal-comms-bench.mjs +3 -4
- package/scripts/internal-comms-smoke.mjs +10 -9
- package/scripts/model-catalog-audit.mjs +209 -0
- package/scripts/model-list-sanitize-test.mjs +37 -0
- package/scripts/mouse-probe.mjs +45 -0
- package/scripts/output-style-bench.mjs +13 -6
- package/scripts/output-style-smoke.mjs +4 -4
- package/scripts/provider-toolcall-test.mjs +7 -3
- package/scripts/recall-bench.mjs +76 -13
- package/scripts/recall-quality-cases.json +12 -0
- package/scripts/recall-usecase-cases.json +18 -0
- package/scripts/session-bench.mjs +152 -6
- package/scripts/tool-smoke.mjs +25 -65
- package/scripts/tui-render-smoke.mjs +90 -0
- package/scripts/webhook-smoke.mjs +208 -0
- package/src/agents/debugger/AGENT.md +4 -1
- package/src/agents/heavy-worker/AGENT.md +9 -8
- package/src/agents/maintainer/AGENT.md +4 -0
- package/src/agents/reviewer/AGENT.md +2 -1
- package/src/agents/scheduler-task/AGENT.md +2 -3
- package/src/agents/webhook-handler/AGENT.md +2 -3
- package/src/agents/worker/AGENT.md +10 -7
- package/src/app.mjs +12 -1
- package/src/headless-role.mjs +7 -1
- package/src/lib/rules-builder.cjs +4 -0
- package/src/mixdog-session-runtime.mjs +647 -2056
- package/src/output-styles/default.md +30 -9
- package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
- package/src/output-styles/minimal.md +8 -6
- package/src/output-styles/simple.md +21 -7
- package/src/rules/agent/00-common.md +6 -3
- package/src/rules/agent/30-explorer.md +16 -5
- package/src/rules/lead/01-general.md +5 -5
- package/src/rules/lead/lead-brief.md +15 -0
- package/src/rules/lead/lead-tool.md +6 -15
- package/src/rules/shared/01-tool.md +17 -21
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +8 -3
- package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
- package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
- package/src/runtime/agent/orchestrator/config.mjs +69 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +62 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +81 -1281
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +32 -3
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +43 -1013
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +17 -3
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +105 -11
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +356 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +40 -1143
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +740 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +349 -2131
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +143 -1002
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +229 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +465 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/provider-catalog-cache.mjs +80 -0
- package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
- package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
- package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
- package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
- package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +14 -2
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -3
- package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +275 -0
- package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
- package/src/runtime/agent/orchestrator/session/loop.mjs +278 -402
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +7 -4
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +166 -1087
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
- package/src/runtime/agent/orchestrator/stall-policy.mjs +20 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +35 -44
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -92
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +28 -265
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +0 -6
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +57 -3
- package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +10 -122
- package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
- package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
- package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
- package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
- package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +0 -21
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +9 -72
- package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
- package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
- package/src/runtime/channels/backends/discord-access.mjs +32 -0
- package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
- package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
- package/src/runtime/channels/backends/discord.mjs +27 -318
- package/src/runtime/channels/backends/telegram.mjs +8 -12
- package/src/runtime/channels/index.mjs +247 -701
- package/src/runtime/channels/lib/backend-dispatch.mjs +46 -0
- package/src/runtime/channels/lib/config.mjs +37 -149
- package/src/runtime/channels/lib/event-pipeline.mjs +22 -5
- package/src/runtime/channels/lib/event-queue.mjs +78 -13
- package/src/runtime/channels/lib/inbound-routing.mjs +74 -0
- package/src/runtime/channels/lib/interaction-workflows.mjs +5 -113
- package/src/runtime/channels/lib/output-forwarder.mjs +1 -1
- package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
- package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
- package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
- package/src/runtime/channels/lib/scheduler.mjs +27 -113
- package/src/runtime/channels/lib/session-discovery.mjs +56 -4
- package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
- package/src/runtime/channels/lib/tool-format.mjs +1 -1
- package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
- package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
- package/src/runtime/channels/lib/webhook/deliveries.mjs +313 -0
- package/src/runtime/channels/lib/webhook/log.mjs +42 -0
- package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
- package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
- package/src/runtime/channels/lib/webhook.mjs +43 -616
- package/src/runtime/channels/tool-defs.mjs +11 -130
- package/src/runtime/memory/index.mjs +210 -1948
- package/src/runtime/memory/lib/core-memory-store.mjs +5 -1
- package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
- package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
- package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
- package/src/runtime/memory/lib/ko-morph.mjs +195 -0
- package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
- package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
- package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
- package/src/runtime/memory/lib/memory-cycle2.mjs +24 -842
- package/src/runtime/memory/lib/memory-embed.mjs +149 -0
- package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
- package/src/runtime/memory/lib/memory-recall-store.mjs +69 -12
- package/src/runtime/memory/lib/memory-text-utils.mjs +46 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
- package/src/runtime/memory/lib/query-handlers.mjs +802 -0
- package/src/runtime/memory/lib/recall-format.mjs +55 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
- package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
- package/src/runtime/memory/tool-defs.mjs +5 -13
- package/src/runtime/search/lib/http-fetch.mjs +274 -0
- package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
- package/src/runtime/search/lib/web-tools.mjs +24 -602
- package/src/runtime/shared/atomic-file.mjs +26 -1
- package/src/runtime/shared/config.mjs +14 -4
- package/src/runtime/shared/launcher-control.mjs +2 -2
- package/src/runtime/shared/markdown-frontmatter.mjs +19 -0
- package/src/runtime/shared/schedules-store.mjs +13 -3
- package/src/runtime/shared/tool-execution-contract.mjs +2 -2
- package/src/runtime/shared/tool-primitives.mjs +308 -0
- package/src/runtime/shared/tool-result-summary.mjs +515 -0
- package/src/runtime/shared/tool-surface.mjs +80 -898
- package/src/runtime/shared/transcript-writer.mjs +23 -0
- package/src/runtime/shared/update-checker.mjs +7 -4
- package/src/session-runtime/config-helpers.mjs +119 -2
- package/src/session-runtime/config-lifecycle.mjs +232 -0
- package/src/session-runtime/cwd-plugins.mjs +226 -0
- package/src/session-runtime/mcp-glue.mjs +177 -0
- package/src/session-runtime/model-recency.mjs +111 -0
- package/src/session-runtime/native-search.mjs +247 -0
- package/src/session-runtime/output-styles.mjs +11 -9
- package/src/session-runtime/prewarm.mjs +142 -0
- package/src/session-runtime/provider-models.mjs +278 -0
- package/src/session-runtime/provider-usage.mjs +120 -0
- package/src/session-runtime/quick-model-rows.mjs +205 -0
- package/src/session-runtime/quick-search-models.mjs +47 -0
- package/src/session-runtime/session-hooks.mjs +93 -0
- package/src/session-runtime/settings-api.mjs +352 -0
- package/src/session-runtime/tool-catalog.mjs +29 -29
- package/src/session-runtime/tool-defs.mjs +84 -0
- package/src/session-runtime/warmup-schedulers.mjs +201 -0
- package/src/session-runtime/workflow.mjs +1 -1
- package/src/standalone/agent-tool/helpers.mjs +237 -0
- package/src/standalone/agent-tool/notify.mjs +107 -0
- package/src/standalone/agent-tool/provider-init.mjs +143 -0
- package/src/standalone/agent-tool/render.mjs +152 -0
- package/src/standalone/agent-tool/tool-def.mjs +55 -0
- package/src/standalone/agent-tool.mjs +138 -669
- package/src/standalone/channel-admin.mjs +102 -90
- package/src/standalone/channel-worker.mjs +4 -7
- package/src/standalone/explore-tool.mjs +64 -14
- package/src/standalone/hook-bus/config.mjs +207 -0
- package/src/standalone/hook-bus/constants.mjs +90 -0
- package/src/standalone/hook-bus/handlers.mjs +481 -0
- package/src/standalone/hook-bus/payload.mjs +31 -0
- package/src/standalone/hook-bus/rules.mjs +77 -0
- package/src/standalone/hook-bus.mjs +77 -870
- package/src/standalone/memory-runtime-proxy.mjs +7 -0
- package/src/standalone/opencode-go-login.mjs +5 -1
- package/src/standalone/provider-admin.mjs +1 -16
- package/src/standalone/usage-dashboard.mjs +3 -1
- package/src/tui/App.jsx +1059 -8110
- package/src/tui/app/app-format.mjs +213 -0
- package/src/tui/app/channel-pickers.mjs +508 -0
- package/src/tui/app/clipboard.mjs +67 -0
- package/src/tui/app/core-memory-picker.mjs +210 -0
- package/src/tui/app/extension-pickers.mjs +506 -0
- package/src/tui/app/input-parsers.mjs +193 -0
- package/src/tui/app/maintenance-pickers.mjs +356 -0
- package/src/tui/app/model-options.mjs +334 -0
- package/src/tui/app/model-picker.mjs +365 -0
- package/src/tui/app/onboarding-steps.mjs +400 -0
- package/src/tui/app/project-picker.mjs +247 -0
- package/src/tui/app/provider-setup-picker.mjs +580 -0
- package/src/tui/app/resume-picker.mjs +55 -0
- package/src/tui/app/route-pickers.mjs +419 -0
- package/src/tui/app/settings-picker.mjs +489 -0
- package/src/tui/app/slash-commands.mjs +101 -0
- package/src/tui/app/slash-dispatch.mjs +427 -0
- package/src/tui/app/text-layout.mjs +46 -0
- package/src/tui/app/theme-effort-pickers.mjs +154 -0
- package/src/tui/app/transcript-window.mjs +677 -0
- package/src/tui/app/use-mouse-input.mjs +460 -0
- package/src/tui/app/use-prompt-handlers.mjs +310 -0
- package/src/tui/app/use-transcript-scroll.mjs +512 -0
- package/src/tui/app/use-transcript-window.mjs +607 -0
- package/src/tui/components/ConfirmBar.jsx +10 -7
- package/src/tui/components/Picker.jsx +64 -15
- package/src/tui/components/PromptInput.jsx +33 -102
- package/src/tui/components/SlashCommandPalette.jsx +8 -1
- package/src/tui/components/StatusLine.jsx +69 -15
- package/src/tui/components/TextEntryPanel.jsx +11 -0
- package/src/tui/components/ToolExecution.jsx +52 -594
- package/src/tui/components/TranscriptItem.jsx +105 -0
- package/src/tui/components/UsagePanel.jsx +18 -4
- package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
- package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
- package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
- package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
- package/src/tui/components/tool-execution/text-format.mjs +161 -0
- package/src/tui/display-width.mjs +20 -3
- package/src/tui/dist/index.mjs +13553 -12384
- package/src/tui/engine/agent-job-feed.mjs +133 -0
- package/src/tui/engine/notification-plan.mjs +76 -0
- package/src/tui/engine/render-timing.mjs +17 -0
- package/src/tui/engine/tool-approval.mjs +94 -0
- package/src/tui/engine/tool-card-results.mjs +234 -0
- package/src/tui/engine/tool-result-status.mjs +135 -0
- package/src/tui/engine.mjs +170 -574
- package/src/tui/figures.mjs +5 -0
- package/src/tui/index.jsx +65 -1
- package/src/tui/input-editing.mjs +2 -2
- package/src/tui/markdown/format-token.mjs +4 -1
- package/src/tui/statusline-ansi-bridge.mjs +11 -3
- package/src/tui/theme.mjs +6 -0
- package/src/ui/statusline-agents.mjs +213 -0
- package/src/ui/statusline-format.mjs +146 -0
- package/src/ui/statusline-segments.mjs +148 -0
- package/src/ui/statusline.mjs +77 -501
- package/src/ui/tool-card.mjs +0 -1
- package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
- package/src/workflows/default/WORKFLOW.md +16 -18
- package/src/workflows/sequential/WORKFLOW.md +16 -18
- package/vendor/ink/build/display-width.js +19 -3
- package/vendor/ink/build/ink.js +112 -7
- package/vendor/ink/build/log-update.js +17 -3
- package/vendor/ink/build/wrap-text.js +125 -0
- package/scripts/_test-folder-dialog.mjs +0 -30
- package/scripts/fix-brief-fn.mjs +0 -35
- package/scripts/fix-format-tool-surface.mjs +0 -24
- package/scripts/fix-tool-exec-visible.mjs +0 -42
- package/scripts/patch-agent-brief.mjs +0 -48
- package/scripts/patch-app.mjs +0 -21
- package/scripts/patch-app2.mjs +0 -18
- package/scripts/patch-dist-brief.mjs +0 -96
- package/scripts/patch-tool-exec.mjs +0 -70
- package/src/examples/schedules/SCHEDULE.example.md +0 -32
- package/src/examples/webhooks/WEBHOOK.example.md +0 -40
- package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
- package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.test.mjs +0 -162
- package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
- package/src/runtime/channels/lib/holidays.mjs +0 -138
- package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
- package/src/runtime/shared/task-notification-envelope.test.mjs +0 -107
- package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
- package/src/standalone/agent-task-status.test.mjs +0 -76
- package/src/tui/components/tool-output-format.test.mjs +0 -399
- package/src/tui/display-width.test.mjs +0 -35
- package/src/tui/engine-runtime-notification.test.mjs +0 -115
- package/src/tui/engine-tool-result-text.test.mjs +0 -75
- package/src/tui/input-editing.selection.test.mjs +0 -75
- package/src/tui/markdown/format-token.test.mjs +0 -354
- package/src/tui/markdown/render-ansi.test.mjs +0 -108
- package/src/tui/markdown/stream-fence.test.mjs +0 -26
- package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
- package/src/tui/paste-fix.test.mjs +0 -119
- package/src/tui/prompt-history-store.test.mjs +0 -52
- package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
- package/src/tui/transcript-tool-failures.test.mjs +0 -111
- package/src/ui/markdown.test.mjs +0 -70
- package/src/ui/statusline-context-label.test.mjs +0 -15
- package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
- package/src/vendor/statusline/bin/statusline-route.test.mjs +0 -80
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
// Native mixdog-patch engine transport: persistent stdio server, env-driven
|
|
2
|
+
// mode gating, binary resolution, prewarm/idle lifecycle, and the char-indexed
|
|
3
|
+
// EDIT client. Split out of patch.mjs; behavior is identical.
|
|
4
|
+
//
|
|
5
|
+
// Backend: NATIVE-ONLY. Every supported apply/edit case is dispatched to the
|
|
6
|
+
// mixdog-patch Rust engine via the persistent stdio server. There is NO JS
|
|
7
|
+
// apply fallback: unsupported / unsafe input returns a clean Error string.
|
|
8
|
+
|
|
9
|
+
import { existsSync } from 'node:fs';
|
|
10
|
+
import { spawn } from 'node:child_process';
|
|
11
|
+
import { createInterface } from 'node:readline';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
import { resolve as pathResolve, dirname as pathDirname, join as pathJoin } from 'node:path';
|
|
14
|
+
import { performance } from 'node:perf_hooks';
|
|
15
|
+
import { startChildGuardian } from '../../../../shared/child-guardian.mjs';
|
|
16
|
+
import { getPluginData } from '../../config.mjs';
|
|
17
|
+
import { ensurePatchBinary, findCachedPatchBinary } from '../patch-binary-fetcher.mjs';
|
|
18
|
+
|
|
19
|
+
const PLUGIN_ROOT = process.env.MIXDOG_ROOT
|
|
20
|
+
|| pathResolve(pathDirname(fileURLToPath(import.meta.url)), '../../../../..');
|
|
21
|
+
const NATIVE_PATCH_DEFAULT_BIN = pathJoin(
|
|
22
|
+
PLUGIN_ROOT,
|
|
23
|
+
'native/mixdog-patch/target/release',
|
|
24
|
+
process.platform === 'win32' ? 'mixdog-patch.exe' : 'mixdog-patch',
|
|
25
|
+
);
|
|
26
|
+
let _nativePatchServer = null;
|
|
27
|
+
let _nativePatchPrewarmTimer = null;
|
|
28
|
+
let _nativeEditServer = null;
|
|
29
|
+
|
|
30
|
+
function markNativePatchRuntimeTouched() {
|
|
31
|
+
try { globalThis.__mixdogNativePatchRuntimeTouched = true; } catch {}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function nativePatchMode() {
|
|
35
|
+
return String(process.env.MIXDOG_PATCH_NATIVE || 'auto').toLowerCase();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function nativePatchEnabled() {
|
|
39
|
+
return !/^(0|false|no|off|js|legacy)$/i.test(nativePatchMode());
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function nativePatchTraceEnabled() {
|
|
43
|
+
return /^(1|true|yes)$/i.test(process.env.MIXDOG_PATCH_NATIVE_TRACE || '');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function ioTraceEnabled() {
|
|
47
|
+
return /^(1|true|yes|on)$/i.test(String(process.env.MIXDOG_IO_TRACE || ''));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function ioTrace(event, fields = {}) {
|
|
51
|
+
if (!ioTraceEnabled()) return;
|
|
52
|
+
try {
|
|
53
|
+
process.stderr.write(`[io-trace] ${JSON.stringify({ event, ts: Date.now(), ...fields })}\n`);
|
|
54
|
+
} catch {}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function patchTraceEnabled() {
|
|
58
|
+
return ioTraceEnabled()
|
|
59
|
+
|| nativePatchTraceEnabled()
|
|
60
|
+
|| /^(1|true|yes|on)$/i.test(String(process.env.MIXDOG_PATCH_TRACE || ''));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function nativePatchPrewarmEnabled() {
|
|
64
|
+
if (!nativePatchEnabled()) return false;
|
|
65
|
+
if (process.env.MIXDOG_PATCH_NATIVE_BIN && !existsSync(nativePatchBinPath())) return false;
|
|
66
|
+
return !/^(0|false|no)$/i.test(process.env.MIXDOG_PATCH_NATIVE_PREWARM || '');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function nativePatchPersistent() {
|
|
70
|
+
return /^(1|true|yes|server|persistent)$/i.test(nativePatchMode());
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function nativePatchBinPath() {
|
|
74
|
+
if (process.env.MIXDOG_PATCH_NATIVE_BIN) return process.env.MIXDOG_PATCH_NATIVE_BIN;
|
|
75
|
+
// Local cargo build first, then a fetched/cached prebuilt; absence is
|
|
76
|
+
// a hard error at dispatch (no JS fallback in native-only mode).
|
|
77
|
+
if (existsSync(NATIVE_PATCH_DEFAULT_BIN)) return NATIVE_PATCH_DEFAULT_BIN;
|
|
78
|
+
return findCachedPatchBinary(getPluginData()) || NATIVE_PATCH_DEFAULT_BIN;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function ensureNativePatchBinaryAvailable() {
|
|
82
|
+
if (!nativePatchEnabled()) {
|
|
83
|
+
throw new Error('apply_patch: native engine disabled via MIXDOG_PATCH_NATIVE; set it to "auto" or "1" to apply patches.');
|
|
84
|
+
}
|
|
85
|
+
const current = nativePatchBinPath();
|
|
86
|
+
if (existsSync(current)) return current;
|
|
87
|
+
if (process.env.MIXDOG_PATCH_NATIVE_BIN) {
|
|
88
|
+
throw new Error(`apply_patch: native patch binary not found at MIXDOG_PATCH_NATIVE_BIN=${current}.`);
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const fetched = await ensurePatchBinary(getPluginData());
|
|
92
|
+
if (fetched && existsSync(fetched)) return fetched;
|
|
93
|
+
} catch (err) {
|
|
94
|
+
throw new Error(`apply_patch: native patch binary unavailable — ${err?.message || String(err)}`);
|
|
95
|
+
}
|
|
96
|
+
const resolved = nativePatchBinPath();
|
|
97
|
+
if (existsSync(resolved)) return resolved;
|
|
98
|
+
throw new Error(`apply_patch: native patch binary not found at ${resolved}.`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Decode the hex-encoded failures payload that accompanies OK_PARTIAL:
|
|
102
|
+
// the Rust side emits utf-8 bytes (`<path>\t<reason>` records joined by
|
|
103
|
+
// `\n`) hex-encoded so they can ride the tab-separated response line
|
|
104
|
+
// without escaping. An empty / unparseable payload becomes an empty list
|
|
105
|
+
// so a missing field never crashes the caller.
|
|
106
|
+
function decodeNativeFailures(hexPayload) {
|
|
107
|
+
if (typeof hexPayload !== 'string' || hexPayload.length === 0) return [];
|
|
108
|
+
if (!/^[0-9a-fA-F]+$/.test(hexPayload) || hexPayload.length % 2 !== 0) return [];
|
|
109
|
+
let text = '';
|
|
110
|
+
try { text = Buffer.from(hexPayload, 'hex').toString('utf-8'); }
|
|
111
|
+
catch { return []; }
|
|
112
|
+
const out = [];
|
|
113
|
+
for (const raw of text.split('\n')) {
|
|
114
|
+
if (!raw) continue;
|
|
115
|
+
const tab = raw.indexOf('\t');
|
|
116
|
+
if (tab === -1) out.push({ path: '', reason: raw });
|
|
117
|
+
else out.push({ path: raw.slice(0, tab), reason: raw.slice(tab + 1) });
|
|
118
|
+
}
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
class NativePatchServer {
|
|
123
|
+
constructor(binPath) {
|
|
124
|
+
this.binPath = binPath;
|
|
125
|
+
// windowsHide: mixdog-patch.exe is a console binary; without this each spawn
|
|
126
|
+
// flashes an empty console window on Windows. Especially visible now that the
|
|
127
|
+
// idle watchdog exits the server and it respawns on the next request.
|
|
128
|
+
this.child = spawn(binPath, ['--server'], { stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true });
|
|
129
|
+
startChildGuardian({ childPid: this.child.pid, label: 'native-patch-server', orphanGraceMs: 5000, forceGraceMs: 2000 });
|
|
130
|
+
this.stderr = '';
|
|
131
|
+
this.lines = [];
|
|
132
|
+
this.waiters = [];
|
|
133
|
+
this.exited = false;
|
|
134
|
+
this.child.stderr.setEncoding('utf8');
|
|
135
|
+
this.child.stderr.on('data', (chunk) => { this.stderr += chunk; });
|
|
136
|
+
this.rl = createInterface({ input: this.child.stdout });
|
|
137
|
+
this.rl.on('line', (line) => {
|
|
138
|
+
const waiter = this.waiters.shift();
|
|
139
|
+
if (waiter) waiter.resolve(line);
|
|
140
|
+
else this.lines.push(line);
|
|
141
|
+
});
|
|
142
|
+
this.child.on('exit', (code, signal) => {
|
|
143
|
+
this.exited = true;
|
|
144
|
+
const err = new Error(`native patch server exited code=${code} signal=${signal} stderr=${this.stderr}`);
|
|
145
|
+
for (const waiter of this.waiters.splice(0)) waiter.reject(err);
|
|
146
|
+
try { this.rl.close(); } catch {}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
abort(signal) {
|
|
151
|
+
const err = new Error(signal?.reason?.message || signal?.reason || 'native patch aborted');
|
|
152
|
+
err.name = 'AbortError';
|
|
153
|
+
if (_nativePatchServer === this) _nativePatchServer = null;
|
|
154
|
+
for (const waiter of this.waiters.splice(0)) waiter.reject(err);
|
|
155
|
+
try { this.child.kill('SIGTERM'); } catch {}
|
|
156
|
+
return err;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
nextLine() {
|
|
160
|
+
if (this.lines.length > 0) return Promise.resolve(this.lines.shift());
|
|
161
|
+
if (this.exited) return Promise.reject(new Error(`native patch server already exited: ${this.stderr}`));
|
|
162
|
+
return new Promise((resolve, reject) => this.waiters.push({ resolve, reject }));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
ref() {
|
|
166
|
+
try { this.child.ref(); } catch {}
|
|
167
|
+
try { this.child.stdin.ref?.(); } catch {}
|
|
168
|
+
try { this.child.stdout.ref?.(); } catch {}
|
|
169
|
+
try { this.child.stderr.ref?.(); } catch {}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
unref() {
|
|
173
|
+
try { this.child.unref(); } catch {}
|
|
174
|
+
try { this.child.stdin.unref?.(); } catch {}
|
|
175
|
+
try { this.child.stdout.unref?.(); } catch {}
|
|
176
|
+
try { this.child.stderr.unref?.(); } catch {}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async ping() {
|
|
180
|
+
this.ref();
|
|
181
|
+
const linePromise = this.nextLine();
|
|
182
|
+
this.child.stdin.write('PING\n');
|
|
183
|
+
const line = await linePromise;
|
|
184
|
+
if (line !== 'OK\tPONG') {
|
|
185
|
+
throw new Error(`native patch server ping failed: ${line || 'no native response'}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async apply(basePath, patchText, { fuzz = 2, rejectPartial = true, dryRun = false, signal = null } = {}) {
|
|
190
|
+
this.ref();
|
|
191
|
+
if (signal?.aborted) {
|
|
192
|
+
const err = new Error(signal.reason?.message || signal.reason || 'native patch aborted');
|
|
193
|
+
err.name = 'AbortError';
|
|
194
|
+
throw err;
|
|
195
|
+
}
|
|
196
|
+
const started = performance.now();
|
|
197
|
+
const baseBuf = Buffer.from(basePath, 'utf8');
|
|
198
|
+
const patchBuf = Buffer.from(patchText, 'utf8');
|
|
199
|
+
const linePromise = this.nextLine();
|
|
200
|
+
if (signal) linePromise.catch(() => {});
|
|
201
|
+
let abortListener = null;
|
|
202
|
+
const abortPromise = signal ? new Promise((_, reject) => {
|
|
203
|
+
abortListener = () => {
|
|
204
|
+
reject(this.abort(signal));
|
|
205
|
+
};
|
|
206
|
+
signal.addEventListener('abort', abortListener, { once: true });
|
|
207
|
+
}) : null;
|
|
208
|
+
// 7-token APPLY protocol: APPLY <base_len> <patch_len> <timing> <dry_run> <fuzz> <reject_partial>
|
|
209
|
+
// - timing=1 keeps the server emitting per-phase ms fields
|
|
210
|
+
// - dry_run=1 validates without writing; useful for tests and explicit callers
|
|
211
|
+
// - fuzz=0 means strict context match; fuzz=2 absorbs minor outer-context drift and context trailing spaces/tabs
|
|
212
|
+
// - reject_partial=0 unlocks file-level isolation (OK_PARTIAL response)
|
|
213
|
+
const fuzzTok = Number.isFinite(fuzz) && fuzz >= 0 ? Math.floor(fuzz) : 2;
|
|
214
|
+
const rpTok = rejectPartial ? 1 : 0;
|
|
215
|
+
const dryTok = dryRun ? 1 : 0;
|
|
216
|
+
this.child.stdin.write(`APPLY ${baseBuf.length} ${patchBuf.length} 1 ${dryTok} ${fuzzTok} ${rpTok}\n`);
|
|
217
|
+
this.child.stdin.write(baseBuf);
|
|
218
|
+
this.child.stdin.write(patchBuf);
|
|
219
|
+
let line;
|
|
220
|
+
try {
|
|
221
|
+
line = abortPromise ? await Promise.race([linePromise, abortPromise]) : await linePromise;
|
|
222
|
+
} finally {
|
|
223
|
+
if (abortListener) {
|
|
224
|
+
try { signal.removeEventListener('abort', abortListener); } catch {}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (!line) throw new Error('no native response');
|
|
228
|
+
if (line.startsWith('ERR\t')) throw new Error(line.slice(4));
|
|
229
|
+
const okFull = line.startsWith('OK\t');
|
|
230
|
+
const okPartial = line.startsWith('OK_PARTIAL\t');
|
|
231
|
+
if (!okFull && !okPartial) throw new Error(line);
|
|
232
|
+
const fields = line.split('\t');
|
|
233
|
+
// fields[0] = "OK" | "OK_PARTIAL".
|
|
234
|
+
// OK layout: <files> <readMs> <applyMs> <writeMs> <totalMs> <hashMs> <contentHashes>
|
|
235
|
+
// OK_PARTIAL layout: <files> <failed> <readMs> <applyMs> <writeMs> <totalMs> <hashMs> <contentHashes> <hexFailures>
|
|
236
|
+
// The OK_PARTIAL line carries an extra <failed> count between <files>
|
|
237
|
+
// and the timing block, plus a trailing <hexFailures> column — keep
|
|
238
|
+
// the two decodes separate so SKIP failure counts stay accurate.
|
|
239
|
+
let files; let readMs; let applyMs; let writeMs; let totalMs; let hashMs;
|
|
240
|
+
let contentHashesRaw; let hexFailures;
|
|
241
|
+
if (okPartial) {
|
|
242
|
+
files = fields[1];
|
|
243
|
+
// fields[2] = <failed> count; the JS layer already derives a failure
|
|
244
|
+
// count from decodeNativeFailures(hexFailures), so skip the raw cell.
|
|
245
|
+
readMs = fields[3];
|
|
246
|
+
applyMs = fields[4];
|
|
247
|
+
writeMs = fields[5];
|
|
248
|
+
totalMs = fields[6];
|
|
249
|
+
hashMs = fields[7];
|
|
250
|
+
contentHashesRaw = fields[8];
|
|
251
|
+
hexFailures = fields[9];
|
|
252
|
+
} else {
|
|
253
|
+
files = fields[1];
|
|
254
|
+
readMs = fields[2];
|
|
255
|
+
applyMs = fields[3];
|
|
256
|
+
writeMs = fields[4];
|
|
257
|
+
totalMs = fields[5];
|
|
258
|
+
hashMs = fields[6];
|
|
259
|
+
contentHashesRaw = fields[7];
|
|
260
|
+
}
|
|
261
|
+
const contentHashes = String(contentHashesRaw || '')
|
|
262
|
+
.split(',')
|
|
263
|
+
.filter((value) => value.length > 0)
|
|
264
|
+
.map((value) => (/^[a-f0-9]{64}$/i.test(value) ? value.toLowerCase() : null));
|
|
265
|
+
const failures = okPartial ? decodeNativeFailures(hexFailures) : [];
|
|
266
|
+
return {
|
|
267
|
+
partial: okPartial,
|
|
268
|
+
files: Number(files) || 0,
|
|
269
|
+
readMs: Number(readMs) || 0,
|
|
270
|
+
applyMs: Number(applyMs) || 0,
|
|
271
|
+
writeMs: Number(writeMs) || 0,
|
|
272
|
+
hashMs: Number(hashMs) || 0,
|
|
273
|
+
totalMs: Number(totalMs) || 0,
|
|
274
|
+
contentHashes,
|
|
275
|
+
contentHash: contentHashes.length === 1 ? contentHashes[0] : null,
|
|
276
|
+
failures,
|
|
277
|
+
roundtripMs: performance.now() - started,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// EDIT protocol client: invariant-safe char-indexed edit. Mirrors apply()'s
|
|
282
|
+
// abort/await-line handling. EDIT <path_len> <old_len> <new_len> <replace_all>
|
|
283
|
+
// <dry_run> then path+old+new bytes; response is the 8-field OK line with the
|
|
284
|
+
// matched tier.
|
|
285
|
+
async edit(fullPath, oldBuf, newBuf, { replaceAll = false, dryRun = false, signal = null } = {}) {
|
|
286
|
+
this.ref();
|
|
287
|
+
if (signal?.aborted) {
|
|
288
|
+
const err = new Error(signal.reason?.message || signal.reason || 'native edit aborted');
|
|
289
|
+
err.name = 'AbortError';
|
|
290
|
+
throw err;
|
|
291
|
+
}
|
|
292
|
+
const started = performance.now();
|
|
293
|
+
const pathBuf = Buffer.from(fullPath, 'utf8');
|
|
294
|
+
const linePromise = this.nextLine();
|
|
295
|
+
if (signal) linePromise.catch(() => {});
|
|
296
|
+
let abortListener = null;
|
|
297
|
+
const abortPromise = signal ? new Promise((_, reject) => {
|
|
298
|
+
abortListener = () => { reject(this.abort(signal)); };
|
|
299
|
+
signal.addEventListener('abort', abortListener, { once: true });
|
|
300
|
+
}) : null;
|
|
301
|
+
this.child.stdin.write(
|
|
302
|
+
`EDIT ${pathBuf.length} ${oldBuf.length} ${newBuf.length} ${replaceAll ? 1 : 0} ${dryRun ? 1 : 0}\n`,
|
|
303
|
+
);
|
|
304
|
+
this.child.stdin.write(pathBuf);
|
|
305
|
+
this.child.stdin.write(oldBuf);
|
|
306
|
+
this.child.stdin.write(newBuf);
|
|
307
|
+
let line;
|
|
308
|
+
try {
|
|
309
|
+
line = abortPromise ? await Promise.race([linePromise, abortPromise]) : await linePromise;
|
|
310
|
+
} finally {
|
|
311
|
+
if (abortListener) {
|
|
312
|
+
try { signal.removeEventListener('abort', abortListener); } catch {}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (!line) throw new Error('no native response');
|
|
316
|
+
if (line.startsWith('ERR\t')) throw new Error(line.slice(4));
|
|
317
|
+
if (!line.startsWith('OK\t')) throw new Error(line);
|
|
318
|
+
const f = line.split('\t');
|
|
319
|
+
// OK \t replacements \t readMs \t applyMs \t writeMs \t totalMs \t tier \t hash
|
|
320
|
+
return {
|
|
321
|
+
replacements: Number(f[1]) || 0,
|
|
322
|
+
readMs: Number(f[2]) || 0,
|
|
323
|
+
applyMs: Number(f[3]) || 0,
|
|
324
|
+
writeMs: Number(f[4]) || 0,
|
|
325
|
+
totalMs: Number(f[5]) || 0,
|
|
326
|
+
tier: f[6] || 'exact',
|
|
327
|
+
contentHash: /^[a-f0-9]{64}$/i.test(f[7] || '') ? f[7].toLowerCase() : null,
|
|
328
|
+
roundtripMs: performance.now() - started,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
async close(options = {}) {
|
|
333
|
+
if (this.exited) return;
|
|
334
|
+
const waitForExit = options?.waitForExit !== false;
|
|
335
|
+
if (!waitForExit) {
|
|
336
|
+
try { this.child.stdin.end('QUIT\n'); } catch {}
|
|
337
|
+
this.unref();
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
this.ref();
|
|
341
|
+
try { this.child.stdin.end('QUIT\n'); } catch {}
|
|
342
|
+
await new Promise((resolve) => this.child.once('exit', resolve));
|
|
343
|
+
try { this.rl.close(); } catch {}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export function getNativePatchServer() {
|
|
348
|
+
markNativePatchRuntimeTouched();
|
|
349
|
+
const binPath = nativePatchBinPath();
|
|
350
|
+
if (!existsSync(binPath)) {
|
|
351
|
+
throw new Error(`native patch binary not found: ${binPath}`);
|
|
352
|
+
}
|
|
353
|
+
if (!_nativePatchServer || _nativePatchServer.exited || _nativePatchServer.binPath !== binPath) {
|
|
354
|
+
_nativePatchServer = new NativePatchServer(binPath);
|
|
355
|
+
}
|
|
356
|
+
return _nativePatchServer;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function getNativeEditServer() {
|
|
360
|
+
markNativePatchRuntimeTouched();
|
|
361
|
+
// Honor MIXDOG_EDIT_NATIVE_BIN (the same override the edit gating checks) so
|
|
362
|
+
// the gated binary and the spawned server binary cannot diverge.
|
|
363
|
+
const binPath = process.env.MIXDOG_EDIT_NATIVE_BIN || nativePatchBinPath();
|
|
364
|
+
if (!existsSync(binPath)) {
|
|
365
|
+
throw new Error(`native patch binary not found: ${binPath}`);
|
|
366
|
+
}
|
|
367
|
+
if (!_nativeEditServer || _nativeEditServer.exited || _nativeEditServer.binPath !== binPath) {
|
|
368
|
+
_nativeEditServer = new NativePatchServer(binPath);
|
|
369
|
+
}
|
|
370
|
+
return _nativeEditServer;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Invariant-safe char-indexed edit over the persistent server (B2). Shares the
|
|
374
|
+
// NativePatchServer transport but runs on a DEDICATED instance so edit and
|
|
375
|
+
// patch requests never interleave their stdin framing on one stdout stream.
|
|
376
|
+
export async function runServerEdit({ fullPath, oldBuf, newBuf, replaceAll = false, dryRun = false, signal = null }) {
|
|
377
|
+
const server = getNativeEditServer();
|
|
378
|
+
return server.edit(fullPath, oldBuf, newBuf, { replaceAll, dryRun, signal });
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
export function scheduleNativePatchPrewarm() {
|
|
382
|
+
if (!nativePatchPrewarmEnabled() || _nativePatchPrewarmTimer || _nativePatchServer) return;
|
|
383
|
+
_nativePatchPrewarmTimer = setImmediate(() => {
|
|
384
|
+
void (async () => {
|
|
385
|
+
_nativePatchPrewarmTimer = null;
|
|
386
|
+
const started = performance.now();
|
|
387
|
+
try {
|
|
388
|
+
// Ensure the native binary is present (local build or fetched
|
|
389
|
+
// prebuilt) before starting the server. Best-effort: failures
|
|
390
|
+
// surface as a hard error at dispatch (no JS fallback in the
|
|
391
|
+
// native-only path).
|
|
392
|
+
if (!existsSync(nativePatchBinPath())) {
|
|
393
|
+
try { await ensurePatchBinary(getPluginData()); } catch { /* surfaces at dispatch */ }
|
|
394
|
+
}
|
|
395
|
+
await getNativePatchServer().ping();
|
|
396
|
+
if (!nativePatchPersistent() && (_nativePatchServer?.waiters?.length || 0) === 0) {
|
|
397
|
+
_nativePatchServer?.unref();
|
|
398
|
+
}
|
|
399
|
+
if (nativePatchTraceEnabled()) {
|
|
400
|
+
process.stderr.write(`[patch-native-trace] prewarm_ms=${(performance.now() - started).toFixed(3)}\n`);
|
|
401
|
+
}
|
|
402
|
+
} catch (err) {
|
|
403
|
+
if (nativePatchTraceEnabled()) {
|
|
404
|
+
process.stderr.write(`[patch-native-trace] prewarm_failed=${err?.message || String(err)}\n`);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
})();
|
|
408
|
+
});
|
|
409
|
+
if (_nativePatchPrewarmTimer?.unref) _nativePatchPrewarmTimer.unref();
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
export function scheduleNativePatchIdleClose() {
|
|
413
|
+
if (nativePatchPersistent() || !_nativePatchServer) return;
|
|
414
|
+
if (process.versions?.bun) {
|
|
415
|
+
const server = _nativePatchServer;
|
|
416
|
+
_nativePatchServer = null;
|
|
417
|
+
void server?.close().catch(() => {});
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
_nativePatchServer.unref();
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
export async function closeNativePatchServerForTests(options = {}) {
|
|
424
|
+
if (_nativePatchPrewarmTimer) {
|
|
425
|
+
try { clearImmediate(_nativePatchPrewarmTimer); } catch {}
|
|
426
|
+
_nativePatchPrewarmTimer = null;
|
|
427
|
+
}
|
|
428
|
+
const server = _nativePatchServer;
|
|
429
|
+
_nativePatchServer = null;
|
|
430
|
+
const editServer = _nativeEditServer;
|
|
431
|
+
_nativeEditServer = null;
|
|
432
|
+
await server?.close(options);
|
|
433
|
+
await editServer?.close(options);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
try { globalThis.__mixdogCloseNativePatchServers = closeNativePatchServerForTests; } catch {}
|