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
package/src/tui/engine.mjs
CHANGED
|
@@ -134,480 +134,8 @@ const LEAD_TURN_TIMEOUT_MS = (() => {
|
|
|
134
134
|
// Opt-in diagnostic trace for the hang chain (runTurn start/end, busy-queue
|
|
135
135
|
// enqueue/drain, watchdog trip). Quiet by default so it can never tear through
|
|
136
136
|
// the alternate-screen render; enable with MIXDOG_TUI_DEBUG=1.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if (!TUI_DEBUG) return;
|
|
140
|
-
try { process.stderr.write(`[tui] ${msg}\n`); } catch {}
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
let _idSeq = 0;
|
|
144
|
-
const nextId = () => `it_${++_idSeq}`;
|
|
145
|
-
|
|
146
|
-
export const TRANSCRIPT_LIVE_ITEM_CAP = 512;
|
|
147
|
-
export const TRANSCRIPT_SPILL_CHUNK_ITEMS = 128;
|
|
148
|
-
const TRANSCRIPT_RESTORE_OVERLAP_ITEMS = 64;
|
|
149
|
-
const TRANSCRIPT_SPILL_STALE_MS = 24 * 60 * 60 * 1000;
|
|
150
|
-
const TRANSCRIPT_SPILL_HEARTBEAT_MS = 10_000;
|
|
151
|
-
const TRANSCRIPT_PROCESS_NONCE = randomUUID();
|
|
152
|
-
|
|
153
|
-
export function cleanupStaleTranscriptSpillDirs({
|
|
154
|
-
root = tmpdir(),
|
|
155
|
-
now = Date.now(),
|
|
156
|
-
staleMs = TRANSCRIPT_SPILL_STALE_MS,
|
|
157
|
-
} = {}) {
|
|
158
|
-
try {
|
|
159
|
-
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
160
|
-
if (!entry.isDirectory() || !entry.name.startsWith('mixdog-transcript-')) continue;
|
|
161
|
-
const path = join(root, entry.name);
|
|
162
|
-
try {
|
|
163
|
-
const ownerPid = Number(/^mixdog-transcript-(\d+)-/.exec(entry.name)?.[1]);
|
|
164
|
-
let pidAlive = false;
|
|
165
|
-
if (ownerPid > 0) {
|
|
166
|
-
try { process.kill(ownerPid, 0); pidAlive = true; } catch {}
|
|
167
|
-
}
|
|
168
|
-
if (!pidAlive) {
|
|
169
|
-
rmSync(path, { recursive: true, force: true });
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
// A fresh heartbeat proves the owning process is running. A stale one
|
|
173
|
-
// is ambiguous (suspended owner vs PID reuse), so retain it for the
|
|
174
|
-
// generous staleMs grace period, then reclaim it even if that PID is
|
|
175
|
-
// currently alive. This avoids both short suspension data loss and
|
|
176
|
-
// immortal crash leftovers after PID reuse.
|
|
177
|
-
let heartbeatAge;
|
|
178
|
-
try {
|
|
179
|
-
heartbeatAge = now - statSync(join(path, 'heartbeat')).mtimeMs;
|
|
180
|
-
} catch {
|
|
181
|
-
heartbeatAge = now - statSync(path).mtimeMs;
|
|
182
|
-
}
|
|
183
|
-
if (heartbeatAge <= staleMs) continue;
|
|
184
|
-
rmSync(path, { recursive: true, force: true });
|
|
185
|
-
} catch {}
|
|
186
|
-
}
|
|
187
|
-
} catch {}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Serialized pages deliberately release the old item object graph while
|
|
191
|
-
// keeping every byte restorable. Only `items` is render-live and walkable.
|
|
192
|
-
export function createTranscriptSpillBuffer({
|
|
193
|
-
cap = TRANSCRIPT_LIVE_ITEM_CAP,
|
|
194
|
-
chunkSize = TRANSCRIPT_SPILL_CHUNK_ITEMS,
|
|
195
|
-
// stdout/stderr: worker threads otherwise copy straight into the REAL fds,
|
|
196
|
-
// bypassing the TUI stderr guard and printing over the terminal frame.
|
|
197
|
-
workerFactory = (source) => new Worker(source, { eval: true, stdout: true, stderr: true }),
|
|
198
|
-
onWarning = (message) => tuiDebug(message),
|
|
199
|
-
writeTimeoutMs = 5000,
|
|
200
|
-
} = {}) {
|
|
201
|
-
// Publish this process instance's nonce BEFORE cleanup. If the OS reused our
|
|
202
|
-
// PID after a crash, the old directory's owner nonce now differs from the
|
|
203
|
-
// live registry and cannot be mistaken for this process.
|
|
204
|
-
try {
|
|
205
|
-
writeFileSync(
|
|
206
|
-
join(tmpdir(), `mixdog-transcript-owner-${process.pid}.json`),
|
|
207
|
-
JSON.stringify({ pid: process.pid, nonce: TRANSCRIPT_PROCESS_NONCE }),
|
|
208
|
-
'utf8',
|
|
209
|
-
);
|
|
210
|
-
} catch {}
|
|
211
|
-
cleanupStaleTranscriptSpillDirs();
|
|
212
|
-
const pages = [];
|
|
213
|
-
let cursor = null;
|
|
214
|
-
let spillDir = null;
|
|
215
|
-
let pageSequence = 0;
|
|
216
|
-
let spillWorker = null;
|
|
217
|
-
let workerSpawnCount = 0;
|
|
218
|
-
let activeWrite = null;
|
|
219
|
-
let activeWriteTimer = null;
|
|
220
|
-
let warningEmitted = false;
|
|
221
|
-
let spillDisabled = false;
|
|
222
|
-
const writeQueue = [];
|
|
223
|
-
const heartbeatTimers = new Map();
|
|
224
|
-
const snapshots = new Set();
|
|
225
|
-
const cleanupRecords = (records, directory) => {
|
|
226
|
-
for (const record of records) {
|
|
227
|
-
record.cancelled = true;
|
|
228
|
-
}
|
|
229
|
-
if (directory) {
|
|
230
|
-
const timer = heartbeatTimers.get(directory);
|
|
231
|
-
if (timer) clearInterval(timer);
|
|
232
|
-
heartbeatTimers.delete(directory);
|
|
233
|
-
try { rmSync(directory, { recursive: true, force: true }); } catch {}
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
const ensureSpillDir = () => {
|
|
237
|
-
if (spillDir) return spillDir;
|
|
238
|
-
const root = tmpdir();
|
|
239
|
-
writeFileSync(
|
|
240
|
-
join(root, `mixdog-transcript-owner-${process.pid}.json`),
|
|
241
|
-
JSON.stringify({ pid: process.pid, nonce: TRANSCRIPT_PROCESS_NONCE }),
|
|
242
|
-
'utf8',
|
|
243
|
-
);
|
|
244
|
-
spillDir = mkdtempSync(join(root, `mixdog-transcript-${process.pid}-${TRANSCRIPT_PROCESS_NONCE}-`));
|
|
245
|
-
writeFileSync(
|
|
246
|
-
join(spillDir, 'owner.json'),
|
|
247
|
-
JSON.stringify({ pid: process.pid, nonce: TRANSCRIPT_PROCESS_NONCE }),
|
|
248
|
-
'utf8',
|
|
249
|
-
);
|
|
250
|
-
const heartbeat = join(spillDir, 'heartbeat');
|
|
251
|
-
writeFileSync(heartbeat, String(Date.now()), 'utf8');
|
|
252
|
-
const heartbeatTimer = setInterval(() => {
|
|
253
|
-
try { writeFileSync(heartbeat, String(Date.now()), 'utf8'); } catch {}
|
|
254
|
-
}, TRANSCRIPT_SPILL_HEARTBEAT_MS);
|
|
255
|
-
heartbeatTimer.unref?.();
|
|
256
|
-
heartbeatTimers.set(spillDir, heartbeatTimer);
|
|
257
|
-
return spillDir;
|
|
258
|
-
};
|
|
259
|
-
const workerSource = `
|
|
260
|
-
const { parentPort } = require('node:worker_threads');
|
|
261
|
-
const { renameSync, writeFileSync } = require('node:fs');
|
|
262
|
-
parentPort.on('message', ({ id, targetPath, tempPath, items }) => {
|
|
263
|
-
try {
|
|
264
|
-
writeFileSync(tempPath, JSON.stringify(items), 'utf8');
|
|
265
|
-
renameSync(tempPath, targetPath);
|
|
266
|
-
parentPort.postMessage({ id, ok: true });
|
|
267
|
-
} catch (error) {
|
|
268
|
-
parentPort.postMessage({ id, ok: false, error: String(error && error.message || error) });
|
|
269
|
-
}
|
|
270
|
-
});`;
|
|
271
|
-
const ensureWorker = () => {
|
|
272
|
-
if (spillWorker) return spillWorker;
|
|
273
|
-
try {
|
|
274
|
-
const worker = workerFactory(workerSource);
|
|
275
|
-
spillWorker = worker;
|
|
276
|
-
workerSpawnCount += 1;
|
|
277
|
-
worker.stdout?.on?.('data', (chunk) => { try { process.stderr.write(chunk); } catch { /* best-effort */ } });
|
|
278
|
-
worker.stderr?.on?.('data', (chunk) => { try { process.stderr.write(chunk); } catch { /* best-effort */ } });
|
|
279
|
-
worker.on('message', (result) => {
|
|
280
|
-
if (spillWorker !== worker || result?.id !== activeWrite?.id) return;
|
|
281
|
-
finishWrite(result?.ok === true, result?.error);
|
|
282
|
-
});
|
|
283
|
-
const failWorker = (error) => {
|
|
284
|
-
if (spillWorker !== worker) return;
|
|
285
|
-
if (activeWriteTimer) clearTimeout(activeWriteTimer);
|
|
286
|
-
activeWriteTimer = null;
|
|
287
|
-
const failed = activeWrite;
|
|
288
|
-
activeWrite = null;
|
|
289
|
-
spillWorker = null;
|
|
290
|
-
try { worker.terminate?.(); } catch {}
|
|
291
|
-
if (failed) retryOrPin(failed, error?.message);
|
|
292
|
-
pumpWrites();
|
|
293
|
-
};
|
|
294
|
-
worker.on('error', failWorker);
|
|
295
|
-
worker.on('exit', (code) => {
|
|
296
|
-
failWorker(new Error(`spill worker exited (${code})`));
|
|
297
|
-
});
|
|
298
|
-
worker.unref?.();
|
|
299
|
-
} catch (error) {
|
|
300
|
-
spillWorker = null;
|
|
301
|
-
if (activeWrite) {
|
|
302
|
-
const failed = activeWrite;
|
|
303
|
-
activeWrite = null;
|
|
304
|
-
retryOrPin(failed, error?.message);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return spillWorker;
|
|
308
|
-
};
|
|
309
|
-
const retryOrPin = (record, error) => {
|
|
310
|
-
if (record.cancelled) return;
|
|
311
|
-
record.attempts += 1;
|
|
312
|
-
if (record.attempts <= 2) {
|
|
313
|
-
writeQueue.unshift(record);
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
|
-
record.pinned = true;
|
|
317
|
-
spillDisabled = true;
|
|
318
|
-
for (const queued of writeQueue.splice(0)) {
|
|
319
|
-
if (!queued.cancelled) queued.pinned = true;
|
|
320
|
-
}
|
|
321
|
-
if (!warningEmitted) {
|
|
322
|
-
warningEmitted = true;
|
|
323
|
-
try { onWarning(`transcript spill write failed; history pinned in memory (${error || 'unknown error'})`); } catch {}
|
|
324
|
-
}
|
|
325
|
-
};
|
|
326
|
-
const finishWrite = (ok, error) => {
|
|
327
|
-
if (activeWriteTimer) clearTimeout(activeWriteTimer);
|
|
328
|
-
activeWriteTimer = null;
|
|
329
|
-
const record = activeWrite;
|
|
330
|
-
activeWrite = null;
|
|
331
|
-
if (record && !record.cancelled) {
|
|
332
|
-
if (ok) record.pendingItems = null;
|
|
333
|
-
else retryOrPin(record, error);
|
|
334
|
-
}
|
|
335
|
-
pumpWrites();
|
|
336
|
-
};
|
|
337
|
-
const pumpWrites = () => {
|
|
338
|
-
if (activeWrite) return;
|
|
339
|
-
while (writeQueue.length && writeQueue[0].cancelled) writeQueue.shift();
|
|
340
|
-
if (!writeQueue.length) return;
|
|
341
|
-
activeWrite = writeQueue.shift();
|
|
342
|
-
const worker = ensureWorker();
|
|
343
|
-
if (!worker) {
|
|
344
|
-
if (activeWrite) {
|
|
345
|
-
const failed = activeWrite;
|
|
346
|
-
activeWrite = null;
|
|
347
|
-
retryOrPin(failed, 'worker unavailable');
|
|
348
|
-
}
|
|
349
|
-
queueMicrotask(pumpWrites);
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
// Pages are capped at chunkSize (128 by default), so the structured-clone
|
|
353
|
-
// post cost is bounded. Serialization and filesystem I/O stay in the worker.
|
|
354
|
-
// Every attempt writes a distinct temporary file; atomic rename is the sole
|
|
355
|
-
// commit point. A timed-out old worker can therefore expose only a complete
|
|
356
|
-
// page (the retry payload is identical), never a partial target JSON file.
|
|
357
|
-
const tempPath = `${activeWrite.path}.attempt-${activeWrite.attempts}-${randomUUID()}.tmp`;
|
|
358
|
-
worker.postMessage({
|
|
359
|
-
id: activeWrite.id,
|
|
360
|
-
targetPath: activeWrite.path,
|
|
361
|
-
tempPath,
|
|
362
|
-
items: activeWrite.pendingItems,
|
|
363
|
-
});
|
|
364
|
-
activeWriteTimer = setTimeout(() => {
|
|
365
|
-
if (!activeWrite || spillWorker !== worker) return;
|
|
366
|
-
const failed = activeWrite;
|
|
367
|
-
activeWrite = null;
|
|
368
|
-
activeWriteTimer = null;
|
|
369
|
-
spillWorker = null;
|
|
370
|
-
try { worker.terminate?.(); } catch {}
|
|
371
|
-
retryOrPin(failed, `write timed out after ${writeTimeoutMs}ms`);
|
|
372
|
-
pumpWrites();
|
|
373
|
-
}, Math.max(1, Number(writeTimeoutMs) || 5000));
|
|
374
|
-
activeWriteTimer.unref?.();
|
|
375
|
-
};
|
|
376
|
-
const encode = (items) => {
|
|
377
|
-
const page = join(ensureSpillDir(), `${++pageSequence}.json`);
|
|
378
|
-
const record = {
|
|
379
|
-
id: pageSequence,
|
|
380
|
-
path: page,
|
|
381
|
-
pendingItems: items,
|
|
382
|
-
cancelled: false,
|
|
383
|
-
attempts: 0,
|
|
384
|
-
pinned: false,
|
|
385
|
-
};
|
|
386
|
-
writeQueue.push(record);
|
|
387
|
-
pumpWrites();
|
|
388
|
-
return record;
|
|
389
|
-
};
|
|
390
|
-
const decode = (record) => record.pendingItems || JSON.parse(readFileSync(record.path, 'utf8'));
|
|
391
|
-
return {
|
|
392
|
-
get hasOlder() { return cursor == null ? pages.length > 0 : cursor > 0; },
|
|
393
|
-
get hasNewer() { return cursor != null; },
|
|
394
|
-
reset() {
|
|
395
|
-
const retained = [...snapshots].some((snapshot) => snapshot.spillDir === spillDir);
|
|
396
|
-
const oldPages = pages.splice(0);
|
|
397
|
-
const oldDir = spillDir;
|
|
398
|
-
pages.length = 0;
|
|
399
|
-
cursor = null;
|
|
400
|
-
spillDir = null;
|
|
401
|
-
pageSequence = 0;
|
|
402
|
-
spillDisabled = false;
|
|
403
|
-
warningEmitted = false;
|
|
404
|
-
if (!retained) cleanupRecords(oldPages, oldDir);
|
|
405
|
-
},
|
|
406
|
-
snapshot() {
|
|
407
|
-
const snapshot = {
|
|
408
|
-
pages: pages.slice(),
|
|
409
|
-
cursor,
|
|
410
|
-
spillDir,
|
|
411
|
-
pageSequence,
|
|
412
|
-
spillDisabled,
|
|
413
|
-
warningEmitted,
|
|
414
|
-
};
|
|
415
|
-
snapshots.add(snapshot);
|
|
416
|
-
return snapshot;
|
|
417
|
-
},
|
|
418
|
-
restoreSnapshot(snapshot) {
|
|
419
|
-
if (!snapshot || !snapshots.has(snapshot)) return false;
|
|
420
|
-
if (snapshot.spillDir === spillDir) {
|
|
421
|
-
cursor = snapshot.cursor;
|
|
422
|
-
snapshots.delete(snapshot);
|
|
423
|
-
return true;
|
|
424
|
-
}
|
|
425
|
-
cleanupRecords(pages, spillDir);
|
|
426
|
-
pages.splice(0, pages.length, ...snapshot.pages);
|
|
427
|
-
cursor = snapshot.cursor;
|
|
428
|
-
spillDir = snapshot.spillDir;
|
|
429
|
-
pageSequence = snapshot.pageSequence;
|
|
430
|
-
spillDisabled = snapshot.spillDisabled === true;
|
|
431
|
-
warningEmitted = snapshot.warningEmitted === true;
|
|
432
|
-
snapshots.delete(snapshot);
|
|
433
|
-
return true;
|
|
434
|
-
},
|
|
435
|
-
releaseSnapshot(snapshot) {
|
|
436
|
-
if (!snapshot || !snapshots.delete(snapshot)) return false;
|
|
437
|
-
if (snapshot.spillDir !== spillDir) cleanupRecords(snapshot.pages, snapshot.spillDir);
|
|
438
|
-
return true;
|
|
439
|
-
},
|
|
440
|
-
dispose() {
|
|
441
|
-
cleanupRecords(pages, spillDir);
|
|
442
|
-
for (const snapshot of snapshots) {
|
|
443
|
-
if (snapshot.spillDir !== spillDir) cleanupRecords(snapshot.pages, snapshot.spillDir);
|
|
444
|
-
}
|
|
445
|
-
pages.length = 0;
|
|
446
|
-
snapshots.clear();
|
|
447
|
-
cursor = null;
|
|
448
|
-
spillDir = null;
|
|
449
|
-
for (const timer of heartbeatTimers.values()) clearInterval(timer);
|
|
450
|
-
heartbeatTimers.clear();
|
|
451
|
-
writeQueue.length = 0;
|
|
452
|
-
activeWrite = null;
|
|
453
|
-
if (activeWriteTimer) clearTimeout(activeWriteTimer);
|
|
454
|
-
activeWriteTimer = null;
|
|
455
|
-
try { spillWorker?.terminate(); } catch {}
|
|
456
|
-
spillWorker = null;
|
|
457
|
-
},
|
|
458
|
-
get workerCount() { return workerSpawnCount; },
|
|
459
|
-
get pendingWriteCount() {
|
|
460
|
-
return writeQueue.length + (activeWrite ? 1 : 0);
|
|
461
|
-
},
|
|
462
|
-
get pinnedPageCount() {
|
|
463
|
-
return pages.filter((page) => page.pinned).length;
|
|
464
|
-
},
|
|
465
|
-
get disabled() { return spillDisabled; },
|
|
466
|
-
capLive(items) {
|
|
467
|
-
let live = Array.isArray(items) ? items : [];
|
|
468
|
-
if (spillDisabled) return live;
|
|
469
|
-
while (live.length > cap) {
|
|
470
|
-
pages.push(encode(live.slice(0, chunkSize)));
|
|
471
|
-
live = live.slice(chunkSize);
|
|
472
|
-
}
|
|
473
|
-
return live;
|
|
474
|
-
},
|
|
475
|
-
restoreOlder(liveItems) {
|
|
476
|
-
const nextCursor = cursor == null ? pages.length - 1 : cursor - 1;
|
|
477
|
-
if (nextCursor < 0) return null;
|
|
478
|
-
cursor = nextCursor;
|
|
479
|
-
const restored = decode(pages[cursor]);
|
|
480
|
-
const following = cursor + 1 < pages.length
|
|
481
|
-
? decode(pages[cursor + 1])
|
|
482
|
-
: (Array.isArray(liveItems) ? liveItems : []);
|
|
483
|
-
return [...restored, ...following.slice(0, TRANSCRIPT_RESTORE_OVERLAP_ITEMS)];
|
|
484
|
-
},
|
|
485
|
-
restoreNewer(liveItems) {
|
|
486
|
-
if (cursor == null) return null;
|
|
487
|
-
const nextCursor = cursor + 1;
|
|
488
|
-
if (nextCursor >= pages.length) {
|
|
489
|
-
cursor = null;
|
|
490
|
-
return { items: null, atLive: true };
|
|
491
|
-
}
|
|
492
|
-
cursor = nextCursor;
|
|
493
|
-
const restored = decode(pages[cursor]);
|
|
494
|
-
const following = cursor + 1 < pages.length
|
|
495
|
-
? decode(pages[cursor + 1])
|
|
496
|
-
: (Array.isArray(liveItems) ? liveItems : []);
|
|
497
|
-
return [...restored, ...following.slice(0, TRANSCRIPT_RESTORE_OVERLAP_ITEMS)];
|
|
498
|
-
},
|
|
499
|
-
};
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
export function refillTranscriptViewOverlap(viewItems, previousLiveItems, nextLiveItems) {
|
|
503
|
-
const view = Array.isArray(viewItems) ? viewItems : null;
|
|
504
|
-
if (!view) return null;
|
|
505
|
-
const previousIds = new Set((previousLiveItems || []).map((item) => item?.id).filter((id) => id != null));
|
|
506
|
-
if (!view.some((item) => previousIds.has(item?.id))) return view;
|
|
507
|
-
const historical = view.filter((item) => !previousIds.has(item?.id));
|
|
508
|
-
return [...historical, ...(nextLiveItems || []).slice(0, TRANSCRIPT_RESTORE_OVERLAP_ITEMS)];
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
// Re-export the shared tool-result/notification helpers so importers (and tests)
|
|
512
|
-
// keep resolving them from engine.mjs unchanged.
|
|
513
|
-
export { toolResultText, toolAggregateDetailFallback, toolGroupedDisplayFallback };
|
|
514
|
-
export { parseBackgroundTaskEnvelope };
|
|
515
|
-
// Re-export the pure notification delivery plan (moved to ./engine/notification-plan.mjs)
|
|
516
|
-
// so importers/tests keep resolving resolveTuiRuntimeNotificationDelivery from engine.mjs.
|
|
517
|
-
export { resolveTuiRuntimeNotificationDelivery };
|
|
518
|
-
|
|
519
|
-
export function replaceEngineItemsState({
|
|
520
|
-
state,
|
|
521
|
-
items,
|
|
522
|
-
itemIndexById,
|
|
523
|
-
preserveStreamingTail = false,
|
|
524
|
-
extra = {},
|
|
525
|
-
}) {
|
|
526
|
-
const nextItems = Array.isArray(items) ? items : [];
|
|
527
|
-
itemIndexById.clear();
|
|
528
|
-
for (let i = 0; i < nextItems.length; i++) {
|
|
529
|
-
const id = nextItems[i]?.id;
|
|
530
|
-
if (id != null) itemIndexById.set(id, i);
|
|
531
|
-
}
|
|
532
|
-
return {
|
|
533
|
-
...state,
|
|
534
|
-
...extra,
|
|
535
|
-
items: nextItems,
|
|
536
|
-
structureRevision: (Number(state.structureRevision) || 0) + 1,
|
|
537
|
-
streamingTail: preserveStreamingTail ? state.streamingTail : null,
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
// Shared by the live engine and focused transcript tests so revision/tail
|
|
542
|
-
// regressions exercise the exact mutation implementation used in production.
|
|
543
|
-
export function createEngineItemMutators({
|
|
544
|
-
getState,
|
|
545
|
-
set,
|
|
546
|
-
itemIndexById,
|
|
547
|
-
normalizeItems = (items) => items,
|
|
548
|
-
itemStateExtra = () => ({}),
|
|
549
|
-
}) {
|
|
550
|
-
const patchItem = (id, patch) => {
|
|
551
|
-
const state = getState();
|
|
552
|
-
let index = itemIndexById.get(id);
|
|
553
|
-
if (!Number.isInteger(index) || state.items[index]?.id !== id) {
|
|
554
|
-
index = state.items.findIndex((it) => it.id === id);
|
|
555
|
-
if (index >= 0) itemIndexById.set(id, index);
|
|
556
|
-
}
|
|
557
|
-
if (index < 0) return false;
|
|
558
|
-
const current = state.items[index];
|
|
559
|
-
let changed = false;
|
|
560
|
-
for (const [key, value] of Object.entries(patch || {})) {
|
|
561
|
-
if (!Object.is(current[key], value)) {
|
|
562
|
-
changed = true;
|
|
563
|
-
break;
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
if (!changed) return false;
|
|
567
|
-
const items = state.items.slice();
|
|
568
|
-
items[index] = { ...current, ...patch };
|
|
569
|
-
set({ items, structureRevision: (Number(state.structureRevision) || 0) + 1 });
|
|
570
|
-
return true;
|
|
571
|
-
};
|
|
572
|
-
|
|
573
|
-
const settleStreamingTail = (id, patch = {}, extra = {}) => {
|
|
574
|
-
const state = getState();
|
|
575
|
-
const tail = state.streamingTail?.id === id ? state.streamingTail : null;
|
|
576
|
-
// Bulk transcript replacement/reset owns the new transcript. A stale turn
|
|
577
|
-
// must never append into it after replaceItems deliberately cleared its tail.
|
|
578
|
-
if (!tail) return false;
|
|
579
|
-
let existingIndex = itemIndexById.get(id);
|
|
580
|
-
if (!Number.isInteger(existingIndex) || state.items[existingIndex]?.id !== id) {
|
|
581
|
-
existingIndex = state.items.findIndex((item) => item?.id === id);
|
|
582
|
-
}
|
|
583
|
-
if (existingIndex >= 0) return false;
|
|
584
|
-
const item = {
|
|
585
|
-
...(tail || {}),
|
|
586
|
-
...patch,
|
|
587
|
-
kind: 'assistant',
|
|
588
|
-
id,
|
|
589
|
-
streaming: false,
|
|
590
|
-
};
|
|
591
|
-
const index = state.items.length;
|
|
592
|
-
const items = normalizeItems([...state.items, item]);
|
|
593
|
-
itemIndexById.clear();
|
|
594
|
-
for (let i = 0; i < items.length; i++) {
|
|
595
|
-
const itemId = items[i]?.id;
|
|
596
|
-
if (itemId != null) itemIndexById.set(itemId, i);
|
|
597
|
-
}
|
|
598
|
-
const settledIndex = items.findIndex((entry) => entry?.id === id);
|
|
599
|
-
set({
|
|
600
|
-
items,
|
|
601
|
-
structureRevision: (Number(state.structureRevision) || 0) + 1,
|
|
602
|
-
streamingTail: null,
|
|
603
|
-
...itemStateExtra(),
|
|
604
|
-
...extra,
|
|
605
|
-
});
|
|
606
|
-
return settledIndex >= 0;
|
|
607
|
-
};
|
|
608
|
-
|
|
609
|
-
return { patchItem, settleStreamingTail };
|
|
610
|
-
}
|
|
137
|
+
import { tuiDebug, nextId, cleanupStaleTranscriptSpillDirs, createTranscriptSpillBuffer, refillTranscriptViewOverlap, replaceEngineItemsState, createEngineItemMutators, TRANSCRIPT_LIVE_ITEM_CAP, TRANSCRIPT_SPILL_CHUNK_ITEMS } from './engine/transcript-spill.mjs';
|
|
138
|
+
export { cleanupStaleTranscriptSpillDirs, createTranscriptSpillBuffer, refillTranscriptViewOverlap, replaceEngineItemsState, createEngineItemMutators, TRANSCRIPT_LIVE_ITEM_CAP, TRANSCRIPT_SPILL_CHUNK_ITEMS } from './engine/transcript-spill.mjs';
|
|
611
139
|
|
|
612
140
|
export async function createEngineSession({
|
|
613
141
|
provider: providerName,
|
|
@@ -1167,6 +695,13 @@ export async function createEngineSession({
|
|
|
1167
695
|
lifecycle.runtimePulseTimer = setInterval(() => {
|
|
1168
696
|
if (flags.disposed) return;
|
|
1169
697
|
if (flags.pendingSessionReset) return;
|
|
698
|
+
// Attached viewer with a live pipe: the owner's frames are authoritative
|
|
699
|
+
// for stats/agent/tool state. Recomputing them locally here would stomp
|
|
700
|
+
// the mirror with this process's empty registries every 2s.
|
|
701
|
+
if (bag.liveShareMirroring?.()) {
|
|
702
|
+
set({ ...routeState() });
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
1170
705
|
syncContextStats({ allowEstimated: true });
|
|
1171
706
|
set({
|
|
1172
707
|
...routeState(),
|
|
@@ -1294,6 +829,11 @@ export async function createEngineSession({
|
|
|
1294
829
|
bag.enqueue(text);
|
|
1295
830
|
void bag.drain();
|
|
1296
831
|
},
|
|
832
|
+
onRemoteAbort: () => {
|
|
833
|
+
// Forwarded viewer stop: interrupt OUR active turn (we are the owner).
|
|
834
|
+
if (flags.disposed || state.sessionRemoteAttached) return;
|
|
835
|
+
try { api.abort?.(); } catch { /* abort is best-effort */ }
|
|
836
|
+
},
|
|
1297
837
|
onOwnerClosed: (id) => {
|
|
1298
838
|
// Owner left (clean close or crash): promote via the normal quiet
|
|
1299
839
|
// re-resume once its final save/presence-clear has landed.
|
|
@@ -1321,6 +861,9 @@ export async function createEngineSession({
|
|
|
1321
861
|
// resume() calls this right after installing the restored items so the
|
|
1322
862
|
// owner's full frame lands at the entry boundary instead of seconds later.
|
|
1323
863
|
bag.ensureLiveShare = () => { try { liveShare.ensure(); } catch { /* share tick retries */ } };
|
|
864
|
+
// Pulse guard: while this surface is an attached viewer with a live pipe,
|
|
865
|
+
// owner frames own stats/agent/tool state (see runtimePulseTimer above).
|
|
866
|
+
bag.liveShareMirroring = () => state.sessionRemoteAttached && liveShare.viewerConnected();
|
|
1324
867
|
// Live viewer submits ride the owner's pipe (instant user bubble + shared
|
|
1325
868
|
// streaming); the durable spool path below remains the fallback.
|
|
1326
869
|
if (typeof api.submit === 'function') {
|
|
@@ -1333,6 +876,18 @@ export async function createEngineSession({
|
|
|
1333
876
|
return baseSubmit(prompt, options);
|
|
1334
877
|
};
|
|
1335
878
|
}
|
|
879
|
+
// Viewer stop button: the local engine has no in-flight turn to cancel —
|
|
880
|
+
// forward the interrupt to the owner over the pipe. Falls back to the local
|
|
881
|
+
// abort (no-op safe) when the pipe is down.
|
|
882
|
+
if (typeof api.abort === 'function') {
|
|
883
|
+
const baseAbort = api.abort;
|
|
884
|
+
api.abort = (...args) => {
|
|
885
|
+
if (state.sessionRemoteAttached && liveShare.viewerConnected() && liveShare.sendAbort()) {
|
|
886
|
+
return true;
|
|
887
|
+
}
|
|
888
|
+
return baseAbort(...args);
|
|
889
|
+
};
|
|
890
|
+
}
|
|
1336
891
|
// Attach-time pipe fast-path: session entry (resume) reconciles the live
|
|
1337
892
|
// pipe IMMEDIATELY instead of waiting for the 3s share tick. The attach
|
|
1338
893
|
// render comes from the last disk save WITHOUT the in-flight turn, so that
|
|
@@ -113,7 +113,7 @@ function makeThrottledProgressNotice({ pushNotice, setProgressHint } = {}, inter
|
|
|
113
113
|
* runtime descriptor (resolveVoiceRuntime shape) once `installed` is true;
|
|
114
114
|
* throws on any ensure* failure (manifest fetch, sha256 mismatch, etc.).
|
|
115
115
|
*/
|
|
116
|
-
|
|
116
|
+
async function ensureVoiceRuntimeReady({ dataDir = resolvePluginData(), pushNotice, setProgressHint } = {}) {
|
|
117
117
|
const fetcher = await loadVoiceRuntimeFetcher();
|
|
118
118
|
// System-language default: Korean devices install the Korean fine-tune,
|
|
119
119
|
// everything else the standard multilingual Q8. voice.model overrides.
|
|
@@ -409,7 +409,7 @@ const HIGHLIGHT_CACHE_MAX = 300;
|
|
|
409
409
|
const highlightCache = new Map();
|
|
410
410
|
|
|
411
411
|
/** @internal Test-only introspection for highlight LRU cache. */
|
|
412
|
-
|
|
412
|
+
function _highlightCacheSizeForTests() {
|
|
413
413
|
return highlightCache.size;
|
|
414
414
|
}
|
|
415
415
|
|
|
@@ -34,7 +34,7 @@ export function hasMarkdownSyntax(text) {
|
|
|
34
34
|
return MD_SYNTAX_RE.test(value);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
function lexMarkdown(content, { trimPartialFences = false } = {}) {
|
|
38
38
|
configureMarked();
|
|
39
39
|
const text = String(content ?? '');
|
|
40
40
|
if (!hasMarkdownSyntax(text)) {
|
|
@@ -19,9 +19,9 @@ import wrapAnsi from 'wrap-ansi';
|
|
|
19
19
|
import { formatToken, padAligned } from './format-token.mjs';
|
|
20
20
|
import { displayWidth } from '../display-width.mjs';
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
const SAFETY_MARGIN = 4;
|
|
23
|
+
const MIN_COLUMN_WIDTH = 3;
|
|
24
|
+
const MAX_ROW_LINES = 4;
|
|
25
25
|
const ANSI_BOLD_START = '\x1b[1m';
|
|
26
26
|
const ANSI_BOLD_END = '\x1b[22m';
|
|
27
27
|
|
|
@@ -44,7 +44,7 @@ export function wrapText(text, width, options) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/** Hard-wrap so every line satisfies stringWidth(line) <= width (vertical tables). */
|
|
47
|
-
|
|
47
|
+
function hardWrapLines(text, width) {
|
|
48
48
|
const max = Math.max(1, Math.floor(Number(width) || 1));
|
|
49
49
|
const input = String(text ?? '');
|
|
50
50
|
if (!input) return [''];
|
|
@@ -15,7 +15,7 @@ export function promptHistoryKey(value) {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/** Stable map key for cwd-scoped prompt history buckets. */
|
|
18
|
-
|
|
18
|
+
function promptHistoryCwdKey(rawPath) {
|
|
19
19
|
const text = String(rawPath || '').trim();
|
|
20
20
|
if (!text) return '';
|
|
21
21
|
const abs = resolve(text);
|
|
@@ -153,7 +153,7 @@ async function writeBehindFlush(filePath) {
|
|
|
153
153
|
|
|
154
154
|
// Synchronously flush any coalesced pending writes. Registered on process exit
|
|
155
155
|
// so an in-flight write-behind is never lost when the TUI quits.
|
|
156
|
-
|
|
156
|
+
function flushPromptHistory() {
|
|
157
157
|
for (const timer of pendingTimers.values()) clearTimeout(timer);
|
|
158
158
|
pendingTimers.clear();
|
|
159
159
|
for (const [filePath, pend] of pendingAppends) {
|
|
@@ -170,7 +170,7 @@ process.once('exit', flushPromptHistory);
|
|
|
170
170
|
/**
|
|
171
171
|
* In-memory session list (newest first). Dedupes by promptHistoryKey.
|
|
172
172
|
*/
|
|
173
|
-
|
|
173
|
+
function pushSessionPromptHistory(sessionTexts, value, limit = PROMPT_HISTORY_LIMIT) {
|
|
174
174
|
const text = String(value || '').trim();
|
|
175
175
|
const key = promptHistoryKey(text);
|
|
176
176
|
if (!key) return Array.isArray(sessionTexts) ? sessionTexts : [];
|
|
@@ -39,7 +39,7 @@ function footerLocalNum(value) {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/** Mirrors StatusLine `isResetStatsState` — stats-only identity for footer cache. */
|
|
42
|
-
|
|
42
|
+
function isResetStatsState(stats) {
|
|
43
43
|
const s = stats && typeof stats === 'object' ? stats : {};
|
|
44
44
|
return footerLocalNum(s.currentContextTokens) === 0
|
|
45
45
|
&& footerLocalNum(s.currentEstimatedContextTokens) === 0
|
|
@@ -116,7 +116,7 @@ export function statuslineFooterCacheKey({
|
|
|
116
116
|
* (`Credit $1.23`, `used/limit`). Ink defaults reset to terminal fg; apply
|
|
117
117
|
* themed status text until the next explicit SGR.
|
|
118
118
|
*/
|
|
119
|
-
|
|
119
|
+
function applyDefaultStatusForegroundAfterReset(text, STATUS, reset = RESET) {
|
|
120
120
|
const src = String(text || '');
|
|
121
121
|
if (!STATUS || !reset) return src;
|
|
122
122
|
let out = '';
|
package/src/tui/theme.mjs
CHANGED
|
@@ -53,7 +53,7 @@ export function getThemeSetting() {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/** Coerce any value to a known theme id, falling back to the default. */
|
|
56
|
-
|
|
56
|
+
function resolveThemeId(id) {
|
|
57
57
|
const key = String(id || '').trim();
|
|
58
58
|
if (THEME_ALIASES[key] && THEME_REGISTRY[THEME_ALIASES[key]]) return THEME_ALIASES[key];
|
|
59
59
|
return THEME_REGISTRY[key] ? key : DEFAULT_THEME_ID;
|
|
@@ -23,7 +23,7 @@ export function toolItemResultText(item) {
|
|
|
23
23
|
return chunks.join('\n').trim();
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
function isHookApprovalDenialToolResult(text) {
|
|
27
27
|
const value = String(text ?? '').trim();
|
|
28
28
|
if (!value) return false;
|
|
29
29
|
if (HOOK_DENIAL_RE.test(value)) return true;
|
|
@@ -73,6 +73,6 @@ export function shouldSuppressFullyFailedToolItem(item) {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/** Non-empty result/rawResult text the user can expand and inspect in the transcript. */
|
|
76
|
-
|
|
76
|
+
function hasUsefulFailedToolResultBody(item) {
|
|
77
77
|
return Boolean(toolItemResultText(item));
|
|
78
78
|
}
|