mixdog 0.9.2 → 0.9.4
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/package.json +8 -3
- package/scripts/anthropic-maxtokens-test.mjs +119 -0
- 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/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-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 +215 -29
- package/scripts/build-tui.mjs +13 -1
- package/scripts/explore-bench.mjs +124 -0
- package/scripts/freevar-smoke.mjs +95 -0
- package/scripts/hook-bus-test.mjs +191 -0
- package/scripts/internal-comms-bench.mjs +1 -0
- package/scripts/internal-comms-smoke.mjs +10 -9
- 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/path-suffix-test.mjs +57 -0
- package/scripts/provider-toolcall-test.mjs +7 -3
- package/scripts/recall-bench.mjs +207 -0
- package/scripts/recall-usecase-cases.json +18 -0
- package/scripts/recall-usecase-probe.json +6 -0
- package/scripts/session-bench.mjs +152 -6
- package/scripts/tool-smoke.mjs +30 -67
- package/scripts/tui-render-smoke.mjs +90 -0
- package/scripts/webhook-smoke.mjs +208 -0
- package/src/agents/debugger/AGENT.md +5 -2
- package/src/agents/heavy-worker/AGENT.md +21 -11
- package/src/agents/maintainer/AGENT.md +4 -0
- package/src/agents/reviewer/AGENT.md +3 -2
- package/src/agents/worker/AGENT.md +21 -11
- package/src/lib/rules-builder.cjs +4 -0
- package/src/mixdog-session-runtime.mjs +933 -3731
- package/src/output-styles/default.md +34 -9
- package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
- package/src/output-styles/minimal.md +4 -1
- package/src/output-styles/simple.md +22 -7
- package/src/repl.mjs +5 -5
- package/src/rules/agent/00-common.md +2 -0
- package/src/rules/agent/30-explorer.md +8 -11
- package/src/rules/lead/lead-brief.md +12 -0
- package/src/rules/lead/lead-tool.md +2 -9
- package/src/rules/shared/01-tool.md +11 -5
- 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/context/collect.mjs +51 -0
- package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +63 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
- 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 +97 -1343
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +78 -10
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +1 -13
- 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 +44 -1014
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +18 -4
- package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +86 -11
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +348 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
- package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +19 -12
- 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 +41 -1142
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +732 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +303 -2119
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +140 -995
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +227 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +436 -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/opencode-go-usage.mjs +38 -12
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +7 -8
- 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-debug.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +274 -0
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
- package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +47 -0
- package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +182 -0
- package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
- package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
- package/src/runtime/agent/orchestrator/session/loop.mjs +409 -1304
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +230 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +149 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -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/tool-resolution.mjs +303 -0
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +226 -2114
- 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 +3 -3
- 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 +33 -42
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
- 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 -87
- 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 +78 -304
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +11 -6
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +551 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1080 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +36 -4277
- 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 +1 -23
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +10 -74
- package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
- 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 +12 -292
- package/src/runtime/channels/index.mjs +241 -894
- package/src/runtime/channels/lib/backend-dispatch.mjs +44 -0
- package/src/runtime/channels/lib/boot-profile.mjs +23 -0
- package/src/runtime/channels/lib/crash-log.mjs +106 -0
- package/src/runtime/channels/lib/event-pipeline.mjs +18 -1
- package/src/runtime/channels/lib/event-queue.mjs +63 -4
- package/src/runtime/channels/lib/inbound-routing.mjs +111 -0
- package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
- package/src/runtime/channels/lib/output-forwarder.mjs +9 -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/session-discovery.mjs +56 -4
- package/src/runtime/channels/lib/telegram-format.mjs +19 -22
- 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 +312 -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 +36 -570
- package/src/runtime/channels/lib/whisper-language.mjs +42 -0
- package/src/runtime/channels/tool-defs.mjs +11 -130
- package/src/runtime/memory/index.mjs +258 -2050
- package/src/runtime/memory/lib/core-memory-store.mjs +351 -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/cycle-signatures.mjs +34 -0
- package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
- package/src/runtime/memory/lib/http-wire.mjs +57 -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 +72 -837
- 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-scope-filter.mjs +24 -0
- package/src/runtime/memory/lib/memory-recall-store.mjs +22 -2
- package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
- package/src/runtime/memory/lib/memory.mjs +20 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
- package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
- package/src/runtime/memory/lib/query-handlers.mjs +780 -0
- package/src/runtime/memory/lib/recall-format.mjs +238 -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 +6 -14
- 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/abort-controller.mjs +1 -1
- package/src/runtime/shared/atomic-file.mjs +26 -1
- package/src/runtime/shared/background-tasks.mjs +2 -3
- package/src/runtime/shared/buffered-appender.mjs +149 -0
- package/src/runtime/shared/launcher-control.mjs +2 -2
- package/src/runtime/shared/task-notification-envelope.mjs +98 -0
- 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 +52 -2
- package/src/runtime/shared/update-checker.mjs +7 -4
- package/src/session-runtime/config-helpers.mjs +291 -0
- package/src/session-runtime/config-lifecycle.mjs +232 -0
- package/src/session-runtime/cwd-plugins.mjs +226 -0
- package/src/session-runtime/effort.mjs +128 -0
- package/src/session-runtime/fs-utils.mjs +10 -0
- package/src/session-runtime/mcp-glue.mjs +177 -0
- package/src/session-runtime/model-capabilities.mjs +130 -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 +126 -0
- package/src/session-runtime/plugin-mcp.mjs +114 -0
- 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 +170 -0
- package/src/session-runtime/quick-search-models.mjs +46 -0
- package/src/session-runtime/session-hooks.mjs +93 -0
- package/src/session-runtime/session-text.mjs +100 -0
- package/src/session-runtime/settings-api.mjs +319 -0
- package/src/session-runtime/statusline-route.mjs +35 -0
- package/src/session-runtime/tool-catalog.mjs +720 -0
- package/src/session-runtime/tool-defs.mjs +84 -0
- package/src/session-runtime/warmup-schedulers.mjs +201 -0
- package/src/session-runtime/workflow.mjs +358 -0
- 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 +155 -677
- package/src/standalone/channel-worker.mjs +7 -9
- package/src/standalone/explore-tool.mjs +40 -12
- 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 +110 -746
- package/src/standalone/memory-runtime-proxy.mjs +7 -0
- package/src/standalone/opencode-go-login.mjs +125 -0
- package/src/standalone/provider-admin.mjs +15 -19
- package/src/standalone/usage-dashboard.mjs +3 -1
- package/src/tui/App.jsx +1163 -7571
- package/src/tui/app/app-format.mjs +206 -0
- package/src/tui/app/channel-pickers.mjs +510 -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 +324 -0
- package/src/tui/app/model-options.mjs +330 -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 +490 -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 +671 -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 +510 -0
- package/src/tui/app/use-transcript-window.mjs +589 -0
- package/src/tui/components/ConfirmBar.jsx +1 -1
- package/src/tui/components/Picker.jsx +32 -4
- package/src/tui/components/PromptInput.jsx +259 -80
- package/src/tui/components/SlashCommandPalette.jsx +8 -1
- package/src/tui/components/StatusLine.jsx +63 -12
- package/src/tui/components/TextEntryPanel.jsx +11 -0
- package/src/tui/components/ToolExecution.jsx +56 -588
- 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/components/tool-output-format.mjs +2 -2
- package/src/tui/display-width.mjs +20 -3
- package/src/tui/dist/index.mjs +18034 -17188
- package/src/tui/engine/agent-envelope.mjs +296 -0
- package/src/tui/engine/agent-job-feed.mjs +133 -0
- package/src/tui/engine/boot-profile.mjs +21 -0
- package/src/tui/engine/labels.mjs +67 -0
- package/src/tui/engine/notice-text.mjs +112 -0
- package/src/tui/engine/notification-plan.mjs +76 -0
- package/src/tui/engine/queue-helpers.mjs +161 -0
- package/src/tui/engine/render-timing.mjs +17 -0
- package/src/tui/engine/session-stats.mjs +46 -0
- package/src/tui/engine/tool-approval.mjs +94 -0
- package/src/tui/engine/tool-call-fields.mjs +23 -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/tool-result-text.mjs +126 -0
- package/src/tui/engine.mjs +405 -1385
- package/src/tui/figures.mjs +5 -0
- package/src/tui/index.jsx +105 -0
- package/src/tui/input-editing.mjs +60 -10
- package/src/tui/keyboard-protocol.mjs +2 -2
- package/src/tui/lib/voice-recorder.mjs +35 -19
- package/src/tui/markdown/format-token.mjs +11 -9
- package/src/tui/paste-attachments.mjs +38 -0
- package/src/tui/statusline-ansi-bridge.mjs +11 -3
- package/src/tui/theme.mjs +6 -0
- package/src/tui/themes/base.mjs +2 -2
- package/src/tui/themes/kanagawa.mjs +4 -4
- package/src/tui/themes/teal.mjs +4 -5
- package/src/tui/themes/utils.mjs +1 -1
- 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 -462
- 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 -9
- package/src/workflows/sequential/WORKFLOW.md +16 -11
- package/src/workflows/solo/WORKFLOW.md +5 -1
- package/vendor/ink/build/display-width.js +19 -3
- package/vendor/ink/build/ink.js +103 -6
- 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/open-config-tool.mjs +0 -26
- package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
- 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/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/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
package/src/ui/statusline.mjs
CHANGED
|
@@ -9,47 +9,28 @@
|
|
|
9
9
|
* reused as read-only data sources, but display identity always belongs to the
|
|
10
10
|
* CLI route passed here.
|
|
11
11
|
*/
|
|
12
|
-
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
13
|
-
import { homedir } from 'node:os';
|
|
14
|
-
import { join } from 'node:path';
|
|
15
|
-
import { bold, colorEnabled, rgb } from './ansi.mjs';
|
|
16
|
-
import { displayModelName, shortenModelName } from './model-display.mjs';
|
|
17
|
-
import { createSessionStats } from './session-stats.mjs';
|
|
18
|
-
import { forEachSessionRuntime } from '../runtime/agent/orchestrator/session/manager.mjs';
|
|
19
|
-
import { listHiddenAgentNames } from '../runtime/agent/orchestrator/internal-agents.mjs';
|
|
20
|
-
import { getModelMetadataSync } from '../runtime/agent/orchestrator/providers/model-catalog.mjs';
|
|
21
12
|
import { readCachedOAuthUsageSnapshot } from '../runtime/agent/orchestrator/providers/oauth-usage.mjs';
|
|
22
13
|
import { readCachedOpenCodeGoUsageSnapshot } from '../runtime/agent/orchestrator/providers/opencode-go-usage.mjs';
|
|
23
14
|
import { buildGatewayLimits } from '../runtime/agent/orchestrator/providers/statusline-route-meta.mjs';
|
|
24
15
|
import { compactBoundaryForStatus, formatGatewayLimitSegments, loadGatewayStatus } from '../vendor/statusline/bin/statusline-route.mjs';
|
|
16
|
+
import { createSessionStats } from './session-stats.mjs';
|
|
17
|
+
import {
|
|
18
|
+
FALLBACK_CONTEXT_WINDOW, statusSubtle,
|
|
19
|
+
R, B, D, GRN, YLW, RED,
|
|
20
|
+
terminalColumns, modelContextWindow, formatModelSegment,
|
|
21
|
+
formatContextSegment, colourPct, epochMsToHHMM,
|
|
22
|
+
num, formatElapsed,
|
|
23
|
+
} from './statusline-format.mjs';
|
|
24
|
+
import { shellJobsStatus, memoryCycleStatus } from './statusline-segments.mjs';
|
|
25
|
+
import {
|
|
26
|
+
summarizeWorkerTags, agentStatuslinePayload, classifyAgentWorkers, activeHiddenAgentWorkers,
|
|
27
|
+
} from './statusline-agents.mjs';
|
|
25
28
|
export { createSessionStats, applyUsageDelta } from './session-stats.mjs';
|
|
29
|
+
// Facade re-exports: keep these public symbols resolving from statusline.mjs.
|
|
30
|
+
export { contextPctDisplayLabel } from './statusline-format.mjs';
|
|
26
31
|
|
|
27
|
-
// Token window used to compute a fallback context% from our own session usage.
|
|
28
|
-
// The live gateway (when up) overrides this with the real route's window. This
|
|
29
|
-
// is only the last resort for unknown local models.
|
|
30
|
-
const FALLBACK_CONTEXT_WINDOW = 200000;
|
|
31
|
-
const statusText = rgb(198, 198, 198);
|
|
32
|
-
const statusSubtle = rgb(136, 136, 136);
|
|
33
|
-
const statusAccent = rgb(215, 119, 87);
|
|
34
|
-
const DEFAULT_MIXDOG_HOME = process.env.MIXDOG_HOME || join(homedir(), '.mixdog');
|
|
35
|
-
const DEFAULT_STANDALONE_DATA_DIR = join(DEFAULT_MIXDOG_HOME, 'data');
|
|
36
|
-
|
|
37
|
-
function sgr(code) {
|
|
38
|
-
return colorEnabled() ? `\x1b[${code}m` : '';
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const R = sgr('0');
|
|
42
|
-
const B = sgr('1');
|
|
43
|
-
const D = sgr('38;2;136;136;136');
|
|
44
|
-
const GRN = sgr('38;2;0;170;75');
|
|
45
|
-
const YLW = sgr('38;2;255;193;7');
|
|
46
|
-
const RED = sgr('38;2;220;70;88');
|
|
47
|
-
const CYN = sgr('38;2;136;136;136');
|
|
48
|
-
const GREY = sgr('38;2;136;136;136');
|
|
49
|
-
const SHELL_JOBS_SEGMENT_CACHE_MS = 1000;
|
|
50
32
|
const GATEWAY_QUOTA_STATUS_CACHE_MS = 500;
|
|
51
33
|
const WORKER_SPINNER_FRAMES = Object.freeze(['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']);
|
|
52
|
-
const WORKER_SPINNER_FRAME_MS = 160;
|
|
53
34
|
// L2 segment spinner: reuses the original WORKER_SPINNER_FRAMES dot glyphs (no
|
|
54
35
|
// separate glyph list) but spins them at a faster 120ms step than the worker
|
|
55
36
|
// spinner's 160ms. l2SpinnerFrame() indexes straight into WORKER_SPINNER_FRAMES.
|
|
@@ -61,11 +42,46 @@ const L2_SPINNER_FRAME_MS = 120;
|
|
|
61
42
|
// replaces them. Snapshots from a previous launch stay hidden during boot so the
|
|
62
43
|
// statusline starts empty until the current session captures usage once.
|
|
63
44
|
const STATUSLINE_PROCESS_STARTED_AT_MS = Date.now() - Math.floor((Number(process.uptime?.()) || 0) * 1000);
|
|
64
|
-
const DEFAULT_HIDDEN_STATUSLINE_AGENTS = Object.freeze(['explorer', 'cycle1-agent', 'cycle2-agent', 'cycle3-agent', 'scheduler-task', 'webhook-handler']);
|
|
65
|
-
let _shellJobsSegmentCache = { ownerPid: 0, at: 0, value: { count: 0, elapsedLabel: '' } };
|
|
66
45
|
let _gatewayQuotaStatusCache = { key: '', at: 0, value: null };
|
|
67
46
|
let _fallbackQuotaStatusCache = { key: '', at: 0, value: null };
|
|
68
|
-
|
|
47
|
+
// Holds the last non-empty rendered L1 quota/usage segments per provider+route
|
|
48
|
+
// key, but ONLY for providers that have actually armed the OAuth boot latch
|
|
49
|
+
// (_oauthUsageArmedProviders) — non-OAuth providers (which oauthUsageSegmentReady
|
|
50
|
+
// also returns true for, since they are never gated) must keep their exact
|
|
51
|
+
// prior empty/null behavior, unaffected by this hold. Once armed and at least
|
|
52
|
+
// one non-empty quota segment set has been rendered for a route, a transient
|
|
53
|
+
// resolution failure (cache miss / gateway hiccup) that would otherwise
|
|
54
|
+
// collapse quotaSegments to [] instead re-uses the last held segments, so the
|
|
55
|
+
// L1 segment does not blink out. Replaced only when a newer non-empty result
|
|
56
|
+
// lands for the SAME key. The key includes sessionId + clientHostPid because
|
|
57
|
+
// rendered segments can embed session-scoped routeSpend — without those, a new
|
|
58
|
+
// session sharing provider/model/effort/fast could reuse a stale prior
|
|
59
|
+
// session's spend. Capped at a small LRU size so long-running processes that
|
|
60
|
+
// cycle through many sessions/routes don't grow this map unbounded.
|
|
61
|
+
const _lastNonEmptyQuotaSegmentsByKey = new Map();
|
|
62
|
+
const LAST_NON_EMPTY_QUOTA_SEGMENTS_CACHE_MAX = 8;
|
|
63
|
+
|
|
64
|
+
function quotaSegmentsHoldKey({ provider, model, effort, fast, sessionId, clientHostPid } = {}) {
|
|
65
|
+
return [
|
|
66
|
+
String(provider || '').trim().toLowerCase(),
|
|
67
|
+
String(model || '').trim(),
|
|
68
|
+
String(effort || '').trim(),
|
|
69
|
+
fast === true ? 'fast' : '',
|
|
70
|
+
String(sessionId || ''),
|
|
71
|
+
String(clientHostPid || ''),
|
|
72
|
+
].join('\0');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function rememberNonEmptyQuotaSegments(key, segments) {
|
|
76
|
+
// Delete-then-set to bump this key to most-recently-used position (Map
|
|
77
|
+
// iterates in insertion order), then evict the oldest entry if over cap.
|
|
78
|
+
_lastNonEmptyQuotaSegmentsByKey.delete(key);
|
|
79
|
+
_lastNonEmptyQuotaSegmentsByKey.set(key, segments);
|
|
80
|
+
if (_lastNonEmptyQuotaSegmentsByKey.size > LAST_NON_EMPTY_QUOTA_SEGMENTS_CACHE_MAX) {
|
|
81
|
+
const oldestKey = _lastNonEmptyQuotaSegmentsByKey.keys().next().value;
|
|
82
|
+
_lastNonEmptyQuotaSegmentsByKey.delete(oldestKey);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
69
85
|
// Option A boot gate: the L1 usage/quota segment stays fully empty until THIS
|
|
70
86
|
// process has captured its FIRST confirmed (current-process) OAuth usage
|
|
71
87
|
// snapshot for THAT provider. The latch is monotonic PER PROVIDER — once a
|
|
@@ -85,19 +101,6 @@ function isConfirmedCurrentProcessSnapshot(snapshot) {
|
|
|
85
101
|
return cachedAt > 0 && cachedAt >= STATUSLINE_PROCESS_STARTED_AT_MS;
|
|
86
102
|
}
|
|
87
103
|
|
|
88
|
-
function summarizeWorkerTags(workers, limit = 3) {
|
|
89
|
-
const cleanLabels = [...new Set((Array.isArray(workers) ? workers : [])
|
|
90
|
-
.map((worker) => String(worker?.tag || '').trim())
|
|
91
|
-
.filter(Boolean))];
|
|
92
|
-
if (cleanLabels.length <= limit) return cleanLabels.join(', ');
|
|
93
|
-
return `${cleanLabels.slice(0, limit).join(', ')}, +${cleanLabels.length - limit}`;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function workerSpinnerFrame(now = Date.now()) {
|
|
97
|
-
const index = Math.floor(now / WORKER_SPINNER_FRAME_MS) % WORKER_SPINNER_FRAMES.length;
|
|
98
|
-
return WORKER_SPINNER_FRAMES[index] || WORKER_SPINNER_FRAMES[0];
|
|
99
|
-
}
|
|
100
|
-
|
|
101
104
|
function l2SpinnerFrame(now = Date.now()) {
|
|
102
105
|
const index = Math.floor(now / L2_SPINNER_FRAME_MS) % WORKER_SPINNER_FRAMES.length;
|
|
103
106
|
return WORKER_SPINNER_FRAMES[index] || WORKER_SPINNER_FRAMES[0];
|
|
@@ -114,21 +117,6 @@ function l2SpinnerFrame(now = Date.now()) {
|
|
|
114
117
|
* model / context% / effort / 5H-7D are overridden by the live gateway via
|
|
115
118
|
* loadGatewayStatus() when it's running; these are the standalone fallbacks.
|
|
116
119
|
*/
|
|
117
|
-
function providerInputExcludesCache(provider) {
|
|
118
|
-
return String(provider || '').toLowerCase().includes('anthropic');
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function promptFootprintTokens(provider, stats) {
|
|
122
|
-
const s = stats || createSessionStats();
|
|
123
|
-
const explicit = num(s.promptTokens);
|
|
124
|
-
if (explicit > 0) return explicit;
|
|
125
|
-
const input = num(s.inputTokens);
|
|
126
|
-
if (providerInputExcludesCache(provider)) {
|
|
127
|
-
return input + num(s.cachedTokens) + num(s.cacheWriteTokens);
|
|
128
|
-
}
|
|
129
|
-
return input;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
120
|
function activeContextNumerator(provider, stats) {
|
|
133
121
|
const s = stats || createSessionStats();
|
|
134
122
|
const source = String(s.currentContextSource || '').toLowerCase();
|
|
@@ -144,18 +132,6 @@ function activeContextNumerator(provider, stats) {
|
|
|
144
132
|
return 0;
|
|
145
133
|
}
|
|
146
134
|
|
|
147
|
-
function currentContextTokens(provider, stats) {
|
|
148
|
-
return activeContextNumerator(provider, stats);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function modelContextWindow(provider, model, explicitContextWindow = 0) {
|
|
152
|
-
const explicit = num(explicitContextWindow);
|
|
153
|
-
if (explicit > 0) return explicit;
|
|
154
|
-
const metaWindow = num(getModelMetadataSync(model, provider)?.contextWindow);
|
|
155
|
-
if (metaWindow > 0) return metaWindow;
|
|
156
|
-
return FALLBACK_CONTEXT_WINDOW;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
135
|
function displayContextBoundary({
|
|
160
136
|
contextWindow = 0,
|
|
161
137
|
displayContextWindow = 0,
|
|
@@ -210,88 +186,6 @@ function resolveContextUsedPct({
|
|
|
210
186
|
return 0;
|
|
211
187
|
}
|
|
212
188
|
|
|
213
|
-
function normalizeAgentWorkerForStatusline(worker = {}) {
|
|
214
|
-
const tag = String(worker.tag || worker.agent || worker.name || '').trim();
|
|
215
|
-
if (!tag) return null;
|
|
216
|
-
const statusText = String(worker.stage || worker.status || '').toLowerCase();
|
|
217
|
-
const status = isTerminalBridgeStatus(statusText) ? 'idle' : 'running';
|
|
218
|
-
return {
|
|
219
|
-
tag,
|
|
220
|
-
status,
|
|
221
|
-
startedAtMs: timeMs(worker.startedAt || worker.startTime || worker.createdAt),
|
|
222
|
-
agent: worker.agent || null,
|
|
223
|
-
stage: worker.stage || worker.status || null,
|
|
224
|
-
sessionId: worker.sessionId || null,
|
|
225
|
-
provider: worker.provider || null,
|
|
226
|
-
model: worker.model || null,
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function normalizeAgentJobForStatusline(job = {}) {
|
|
231
|
-
const statusText = String(job.status || job.stage || '').toLowerCase();
|
|
232
|
-
if (!statusText) return null;
|
|
233
|
-
const taskId = String(job.task_id || job.taskId || '').trim();
|
|
234
|
-
const tag = String(job.tag || job.agent || job.type || taskId || '').trim();
|
|
235
|
-
if (!tag && !taskId) return null;
|
|
236
|
-
const startedAtMs = timeMs(job.startedAt);
|
|
237
|
-
const finishedAtMs = timeMs(job.finishedAt);
|
|
238
|
-
if (isTerminalBridgeStatus(statusText) && finishedAtMs > 0) {
|
|
239
|
-
return {
|
|
240
|
-
tag,
|
|
241
|
-
taskId,
|
|
242
|
-
status: 'finished',
|
|
243
|
-
finalStatus: statusText,
|
|
244
|
-
startedAtMs,
|
|
245
|
-
finishedAtMs,
|
|
246
|
-
agent: job.agent || null,
|
|
247
|
-
stage: job.stage || job.workerStatus || job.status || null,
|
|
248
|
-
sessionId: job.sessionId || null,
|
|
249
|
-
provider: job.provider || null,
|
|
250
|
-
model: job.model || null,
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
if (!/running/.test(statusText)) return null;
|
|
254
|
-
return {
|
|
255
|
-
tag,
|
|
256
|
-
taskId,
|
|
257
|
-
status: 'running',
|
|
258
|
-
startedAtMs,
|
|
259
|
-
agent: job.agent || null,
|
|
260
|
-
stage: job.stage || job.workerStatus || job.status || null,
|
|
261
|
-
sessionId: job.sessionId || null,
|
|
262
|
-
provider: job.provider || null,
|
|
263
|
-
model: job.model || null,
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function agentStatuslinePayload(agentWorkers = [], agentJobs = []) {
|
|
268
|
-
const byTag = new Map();
|
|
269
|
-
const finishedJobs = [];
|
|
270
|
-
for (const worker of Array.isArray(agentWorkers) ? agentWorkers : []) {
|
|
271
|
-
const row = normalizeAgentWorkerForStatusline(worker);
|
|
272
|
-
if (row) byTag.set(row.tag, row);
|
|
273
|
-
}
|
|
274
|
-
for (const job of Array.isArray(agentJobs) ? agentJobs : []) {
|
|
275
|
-
const row = normalizeAgentJobForStatusline(job);
|
|
276
|
-
if (!row) continue;
|
|
277
|
-
if (row.status === 'finished') {
|
|
278
|
-
finishedJobs.push(row);
|
|
279
|
-
continue;
|
|
280
|
-
}
|
|
281
|
-
const prev = byTag.get(row.tag);
|
|
282
|
-
byTag.set(row.tag, { ...(prev || {}), ...row, status: 'running' });
|
|
283
|
-
}
|
|
284
|
-
const workers = [...byTag.values()];
|
|
285
|
-
return {
|
|
286
|
-
workers,
|
|
287
|
-
finishedJobs: finishedJobs.sort((a, b) => (b.finishedAtMs || 0) - (a.finishedAtMs || 0)),
|
|
288
|
-
sessions: {
|
|
289
|
-
roles: workers.filter((w) => w.status !== 'idle').map((w) => w.tag),
|
|
290
|
-
workers,
|
|
291
|
-
},
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
|
|
295
189
|
/**
|
|
296
190
|
* Render the L1/L2 statusline footer from CLI state.
|
|
297
191
|
*
|
|
@@ -380,9 +274,23 @@ function renderNativeStatusline({
|
|
|
380
274
|
const quotaStatus = usageReady
|
|
381
275
|
? mergeQuotaStatus(gatewayStatus, fallbackQuotaStatus({ provider, model }))
|
|
382
276
|
: null;
|
|
383
|
-
|
|
277
|
+
let quotaSegments = quotaStatus
|
|
384
278
|
? formatGatewayLimitSegments(quotaStatus, { COLS: cols, D, R, GRN, YLW, RED, colourPct, epochMsToHHMM })
|
|
385
279
|
: [];
|
|
280
|
+
// Only apply the hold to providers that actually armed the OAuth boot latch.
|
|
281
|
+
// oauthUsageSegmentReady() also returns true for non-OAuth providers (they
|
|
282
|
+
// are never gated), so gate the hold itself on _oauthUsageArmedProviders to
|
|
283
|
+
// keep non-OAuth empty/null behavior byte-for-byte unchanged.
|
|
284
|
+
const normalizedHoldProvider = String(provider || '').trim().toLowerCase();
|
|
285
|
+
if (usageReady && _oauthUsageArmedProviders.has(normalizedHoldProvider)) {
|
|
286
|
+
const holdKey = quotaSegmentsHoldKey({ provider, model, effort, fast, sessionId, clientHostPid });
|
|
287
|
+
if (quotaSegments.length) {
|
|
288
|
+
rememberNonEmptyQuotaSegments(holdKey, quotaSegments);
|
|
289
|
+
} else {
|
|
290
|
+
const held = _lastNonEmptyQuotaSegmentsByKey.get(holdKey);
|
|
291
|
+
if (held && held.length) quotaSegments = held;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
386
294
|
for (const seg of quotaSegments) addL1(seg);
|
|
387
295
|
|
|
388
296
|
const agentPayload = agentStatuslinePayload([
|
|
@@ -425,20 +333,21 @@ function renderNativeStatusline({
|
|
|
425
333
|
const label = `Running ${n} Shell${n === 1 ? '' : 's'}`;
|
|
426
334
|
addL2(`${spin} ${B}${label}${R}${elapsedSuffix(shellStatus.elapsedLabel)}`);
|
|
427
335
|
}
|
|
336
|
+
// Memory cycle segment — single unified "Memory" wording for all states:
|
|
337
|
+
// running -> "⠋ Memory · 12s"; backlog warning -> "⠋ Memory · backlog 512"
|
|
338
|
+
// (yellow). Nothing when idle (no L2 pollution).
|
|
339
|
+
const memStatus = memoryCycleStatus();
|
|
340
|
+
if (memStatus?.kind === 'running') {
|
|
341
|
+
const elapsed = formatElapsed(Date.now() - memStatus.startedAt);
|
|
342
|
+
addL2(`${spin} ${B}Memory${R}${elapsedSuffix(elapsed)}`);
|
|
343
|
+
} else if (memStatus?.kind === 'backlog') {
|
|
344
|
+
addL2(`${spin} ${B}Memory${R} ${D}·${R} ${YLW}backlog ${memStatus.pending}${R}`);
|
|
345
|
+
}
|
|
428
346
|
const l1 = l1Parts.join(sep) || 'mixdog';
|
|
429
347
|
const l2 = l2Parts.join(sep);
|
|
430
348
|
return l2 ? `${l1}\n${l2}` : l1;
|
|
431
349
|
}
|
|
432
350
|
|
|
433
|
-
function terminalColumns() {
|
|
434
|
-
const cols = Number(process.stdout?.columns);
|
|
435
|
-
return Number.isFinite(cols) && cols > 0 ? Math.floor(cols) : 120;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
function dataDir() {
|
|
439
|
-
return process.env.MIXDOG_DATA_DIR || DEFAULT_STANDALONE_DATA_DIR;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
351
|
function loadGatewayQuotaStatus({
|
|
443
352
|
provider, model, effort, fast, contextWindow, rawContextWindow, autoCompactTokenLimit = 0,
|
|
444
353
|
sessionId, activeContextTokens, clientHostPid,
|
|
@@ -605,278 +514,6 @@ function mergeQuotaStatus(primary, fallback) {
|
|
|
605
514
|
};
|
|
606
515
|
}
|
|
607
516
|
|
|
608
|
-
function formatModelSegment({ provider, model, effort, fast, cols }) {
|
|
609
|
-
const raw = String(model || '').trim();
|
|
610
|
-
const meta = getModelMetadataSync(raw, provider) || {};
|
|
611
|
-
const displayHint = String(meta.displayName || meta.display || meta.name || '').trim();
|
|
612
|
-
const modelName = shortenModelName(displayModelName(raw, provider, displayHint), cols);
|
|
613
|
-
const bits = [`${B}${modelName}${R}`];
|
|
614
|
-
if (effort) bits.push(`${B}${String(effort).toUpperCase()}${R}`);
|
|
615
|
-
if (fast === true) bits.push(`${B}FAST${R}`);
|
|
616
|
-
return bits.join(` ${D}·${R} `);
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
/** Display label for context % (clamped to 100); raw pct still drives bar/color thresholds. */
|
|
620
|
-
export function contextPctDisplayLabel(ctxPct) {
|
|
621
|
-
const pct = Number(ctxPct);
|
|
622
|
-
if (!Number.isFinite(pct) || pct <= 0) return '0';
|
|
623
|
-
if (pct > 0 && pct < 1) return String(Math.round(pct * 10) / 10);
|
|
624
|
-
return String(Math.floor(Math.min(100, pct)));
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
function formatContextSegment(ctxPct, cols) {
|
|
628
|
-
const raw = Number(ctxPct);
|
|
629
|
-
const pct = Number.isFinite(raw) ? Math.max(0, raw) : 0;
|
|
630
|
-
const barPct = clampPct(pct);
|
|
631
|
-
const fill = pct >= 90 ? RED : pct >= 70 ? YLW : GRN;
|
|
632
|
-
const label = contextPctDisplayLabel(pct);
|
|
633
|
-
// Keep a full-width bar wherever there is room for one. Below 80 cols the bar
|
|
634
|
-
// is dropped (label-only) so the footer never overflows a narrow terminal;
|
|
635
|
-
// at 80+ it stays a fixed 14 cells instead of shrinking to 8, which read as
|
|
636
|
-
// too small/cramped on mid-width terminals.
|
|
637
|
-
const cells = cols >= 80 ? 14 : 0;
|
|
638
|
-
if (!cells) return `${fill}${label}%${R}`;
|
|
639
|
-
const bar = makeBar(barPct, cells);
|
|
640
|
-
const filled = bar.replace(/░/g, '');
|
|
641
|
-
const empty = bar.replace(/▓/g, '');
|
|
642
|
-
return `${fill}${filled}${R}${D}${empty}${R} ${label}%`;
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
function makeBar(pct, cells) {
|
|
646
|
-
let filled = Math.floor((Number(pct) || 0) * cells / 100);
|
|
647
|
-
if (filled < 0) filled = 0;
|
|
648
|
-
if (filled > cells) filled = cells;
|
|
649
|
-
if (pct >= 1 && filled === 0) filled = 1;
|
|
650
|
-
return '▓'.repeat(filled) + '░'.repeat(cells - filled);
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
function colourPct(p) {
|
|
654
|
-
if (p >= 90) return `${RED}${p}%${R}`;
|
|
655
|
-
if (p >= 70) return `${YLW}${p}%${R}`;
|
|
656
|
-
return `${GRN}${p}%${R}`;
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
function epochMsToHHMM(ms) {
|
|
660
|
-
const d = new Date(Number(ms));
|
|
661
|
-
if (!Number.isFinite(d.getTime())) return '';
|
|
662
|
-
return d.toLocaleTimeString('sv-SE', { hour: '2-digit', minute: '2-digit', hour12: false });
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
function classifyAgentWorkers(workers = []) {
|
|
666
|
-
const maintenance = [];
|
|
667
|
-
const runningWorkers = [];
|
|
668
|
-
const seenMaintenance = new Set();
|
|
669
|
-
const seenRunning = new Set();
|
|
670
|
-
for (const w of Array.isArray(workers) ? workers : []) {
|
|
671
|
-
const tag = String(w?.tag || '').trim();
|
|
672
|
-
if (!tag) continue;
|
|
673
|
-
const maint = hiddenWorkerLabel(w);
|
|
674
|
-
if (maint) {
|
|
675
|
-
if (w.status !== 'idle' && !seenMaintenance.has(maint)) {
|
|
676
|
-
seenMaintenance.add(maint);
|
|
677
|
-
maintenance.push(`${GRN}↻${R} ${B}${maint}${R}`);
|
|
678
|
-
}
|
|
679
|
-
continue;
|
|
680
|
-
}
|
|
681
|
-
if (w.status !== 'idle' && !seenRunning.has(tag)) {
|
|
682
|
-
seenRunning.add(tag);
|
|
683
|
-
runningWorkers.push(w);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
return { maintenance, runningWorkers };
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
function hiddenWorkerLabel(worker = {}) {
|
|
690
|
-
const agent = String(worker?.agent || '').trim();
|
|
691
|
-
const tag = String(worker?.tag || '').trim();
|
|
692
|
-
return maintenanceLabel(agent) || (!agent ? maintenanceLabel(tag) : '');
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
function hiddenStatuslineAgents() {
|
|
696
|
-
if (_hiddenStatuslineAgents) return _hiddenStatuslineAgents;
|
|
697
|
-
const agents = new Set(DEFAULT_HIDDEN_STATUSLINE_AGENTS);
|
|
698
|
-
try {
|
|
699
|
-
for (const agent of listHiddenAgentNames()) {
|
|
700
|
-
const clean = String(agent || '').trim();
|
|
701
|
-
if (clean) agents.add(clean);
|
|
702
|
-
}
|
|
703
|
-
} catch {}
|
|
704
|
-
_hiddenStatuslineAgents = agents;
|
|
705
|
-
return agents;
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
function isActiveHiddenStatus(statusText) {
|
|
709
|
-
return /^(connecting|requesting|streaming|tool_running|running)$/i.test(String(statusText || '').trim());
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
function activeHiddenAgentWorkers({ sessionId = '', clientHostPid = 0 } = {}) {
|
|
713
|
-
const agents = hiddenStatuslineAgents();
|
|
714
|
-
const ownerPid = positiveInt(clientHostPid);
|
|
715
|
-
const ownerSessionId = String(sessionId || '').trim();
|
|
716
|
-
const rows = [];
|
|
717
|
-
try {
|
|
718
|
-
for (const [runtimeSessionId, entry] of forEachSessionRuntime() || []) {
|
|
719
|
-
if (!entry || entry.closed === true) continue;
|
|
720
|
-
const session = entry.session || null;
|
|
721
|
-
if (!session || session.closed === true) continue;
|
|
722
|
-
const agent = String(session?.agent || '').trim();
|
|
723
|
-
if (!agent || !agents.has(agent)) continue;
|
|
724
|
-
const id = session?.id || runtimeSessionId || null;
|
|
725
|
-
if (ownerSessionId && id === ownerSessionId) continue;
|
|
726
|
-
const sessionOwnerId = String(session?.ownerSessionId || '').trim();
|
|
727
|
-
if (sessionOwnerId && ownerSessionId && sessionOwnerId !== ownerSessionId) continue;
|
|
728
|
-
const pid = positiveInt(session?.clientHostPid);
|
|
729
|
-
if (ownerPid && pid && pid !== ownerPid) continue;
|
|
730
|
-
const stage = String(entry.stage || session?.stage || session?.status || '').trim().toLowerCase();
|
|
731
|
-
const status = String(session?.status || stage || '').trim().toLowerCase();
|
|
732
|
-
if (!isActiveHiddenStatus(stage || status)) continue;
|
|
733
|
-
rows.push({
|
|
734
|
-
tag: String(session?.agentTag || `${agent}:${id || rows.length}`).trim(),
|
|
735
|
-
agent,
|
|
736
|
-
status: 'running',
|
|
737
|
-
stage: stage || status || 'running',
|
|
738
|
-
sessionId: id,
|
|
739
|
-
provider: session?.provider || null,
|
|
740
|
-
model: session?.model || null,
|
|
741
|
-
});
|
|
742
|
-
}
|
|
743
|
-
} catch {}
|
|
744
|
-
return rows;
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
function isTerminalBridgeStatus(statusText) {
|
|
748
|
-
return /idle|done|complete|success|closed|error|fail|cancel|killed|timeout/.test(String(statusText || '').toLowerCase());
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
function timeMs(value) {
|
|
752
|
-
if (typeof value === 'number' && Number.isFinite(value) && value > 0) return value;
|
|
753
|
-
const n = Date.parse(String(value || ''));
|
|
754
|
-
return Number.isFinite(n) ? n : 0;
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
function maintenanceLabel(tag) {
|
|
758
|
-
switch (tag) {
|
|
759
|
-
case 'cycle1-agent': return 'cycle1';
|
|
760
|
-
case 'cycle2-agent': return 'cycle2';
|
|
761
|
-
case 'cycle3-agent': return 'cycle3';
|
|
762
|
-
case 'scheduler-task': return 'scheduler';
|
|
763
|
-
case 'webhook-handler': return 'webhook';
|
|
764
|
-
case 'explorer': return 'explorer';
|
|
765
|
-
default: return '';
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
function shellJobsStatus({ clientHostPid } = {}) {
|
|
770
|
-
const ownerPid = positiveInt(clientHostPid);
|
|
771
|
-
const empty = { count: 0, elapsedLabel: '' };
|
|
772
|
-
if (!ownerPid) return empty;
|
|
773
|
-
const now = Date.now();
|
|
774
|
-
if (_shellJobsSegmentCache.ownerPid === ownerPid && now - _shellJobsSegmentCache.at < SHELL_JOBS_SEGMENT_CACHE_MS) {
|
|
775
|
-
return _shellJobsSegmentCache.value || empty;
|
|
776
|
-
}
|
|
777
|
-
let value = empty;
|
|
778
|
-
try {
|
|
779
|
-
const dir = join(dataDir(), 'shell-jobs');
|
|
780
|
-
if (!existsSync(dir)) {
|
|
781
|
-
_shellJobsSegmentCache = { ownerPid, at: now, value };
|
|
782
|
-
return value;
|
|
783
|
-
}
|
|
784
|
-
const names = readdirSync(dir);
|
|
785
|
-
const done = new Set(names.filter((n) => n.endsWith('.done')).map((n) => n.slice(0, -5)));
|
|
786
|
-
const ownerByJob = new Map();
|
|
787
|
-
for (const n of names) {
|
|
788
|
-
const i = n.lastIndexOf('.owner-');
|
|
789
|
-
if (i > 0) {
|
|
790
|
-
const pid = positiveInt(n.slice(i + 7));
|
|
791
|
-
if (pid) ownerByJob.set(n.slice(0, i), pid);
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
const ids = names
|
|
795
|
-
.filter((n) => n.endsWith('.json'))
|
|
796
|
-
.map((n) => n.slice(0, -5))
|
|
797
|
-
.filter((id) => !done.has(id) && ownerByJob.get(id) === ownerPid)
|
|
798
|
-
.sort((a, b) => jobStampMs(b) - jobStampMs(a))
|
|
799
|
-
.slice(0, 30);
|
|
800
|
-
let count = 0;
|
|
801
|
-
let oldestMs = Infinity;
|
|
802
|
-
for (const id of ids) {
|
|
803
|
-
const p = join(dir, `${id}.json`);
|
|
804
|
-
let detail;
|
|
805
|
-
try { detail = JSON.parse(readFileSync(p, 'utf-8')); } catch { continue; }
|
|
806
|
-
if (!isShellJobAlive(detail, p, dir, id)) continue;
|
|
807
|
-
count++;
|
|
808
|
-
try {
|
|
809
|
-
const st = statSync(p);
|
|
810
|
-
if (st.mtimeMs < oldestMs) oldestMs = st.mtimeMs;
|
|
811
|
-
} catch {}
|
|
812
|
-
}
|
|
813
|
-
if (!count) {
|
|
814
|
-
_shellJobsSegmentCache = { ownerPid, at: now, value };
|
|
815
|
-
return value;
|
|
816
|
-
}
|
|
817
|
-
const elapsedLabel = Number.isFinite(oldestMs) ? formatElapsed(Date.now() - oldestMs) : '';
|
|
818
|
-
value = { count, elapsedLabel };
|
|
819
|
-
} catch {
|
|
820
|
-
value = empty;
|
|
821
|
-
}
|
|
822
|
-
_shellJobsSegmentCache = { ownerPid, at: now, value };
|
|
823
|
-
return value;
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
function isShellJobAlive(detail, detailPath, dir, id) {
|
|
827
|
-
const pid = positiveInt(detail?.pid);
|
|
828
|
-
if (!pid) return false;
|
|
829
|
-
try {
|
|
830
|
-
const st = statSync(detailPath);
|
|
831
|
-
const timeoutMs = Number(detail?.timeoutMs);
|
|
832
|
-
const enforced = detail?.timeoutEnforced === true || existsSync(join(dir, `${id}.enforced`));
|
|
833
|
-
if (enforced && Number.isFinite(timeoutMs) && timeoutMs > 0 && Date.now() - st.mtimeMs > timeoutMs + 30 * 60_000) {
|
|
834
|
-
return false;
|
|
835
|
-
}
|
|
836
|
-
} catch {
|
|
837
|
-
return false;
|
|
838
|
-
}
|
|
839
|
-
try {
|
|
840
|
-
process.kill(pid, 0);
|
|
841
|
-
return true;
|
|
842
|
-
} catch (e) {
|
|
843
|
-
return e?.code === 'EPERM';
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
function jobStampMs(id) {
|
|
848
|
-
const m = /^job_(\d+)/.exec(String(id || ''));
|
|
849
|
-
return m ? Number(m[1]) : 0;
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
function positiveInt(value) {
|
|
853
|
-
const n = Number(value);
|
|
854
|
-
return Number.isInteger(n) && n > 0 ? n : 0;
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// Byte-identical replica of src/tui/time-format.mjs formatDuration() with
|
|
858
|
-
// DEFAULT options (no mostSignificantOnly / hideTrailingZeros), wrapped to drop
|
|
859
|
-
// sub-1s like formatElapsed there. Output shape: '' (<1s), `Xs`, `Xm Ys`,
|
|
860
|
-
// `Xh Ym Zs`, `Xd Yh Zm`. statusline.mjs is a standalone UI module that should
|
|
861
|
-
// not depend on the React/ink TUI tree, so the algorithm is replicated rather
|
|
862
|
-
// than imported. Used for ALL L2 elapsed (Agents/Explore/Search/Shell).
|
|
863
|
-
function formatElapsed(ms) {
|
|
864
|
-
if (!Number.isFinite(Number(ms))) return '';
|
|
865
|
-
const value = Math.max(0, Number(ms) || 0);
|
|
866
|
-
if (value < 60_000) {
|
|
867
|
-
if (value < 1_000) return '';
|
|
868
|
-
return `${Math.floor(value / 1000)}s`;
|
|
869
|
-
}
|
|
870
|
-
const days = Math.floor(value / 86_400_000);
|
|
871
|
-
const hours = Math.floor((value % 86_400_000) / 3_600_000);
|
|
872
|
-
const minutes = Math.floor((value % 3_600_000) / 60_000);
|
|
873
|
-
const seconds = Math.floor((value % 60_000) / 1000);
|
|
874
|
-
if (days > 0) return `${days}d ${hours}h ${minutes}m`;
|
|
875
|
-
if (hours > 0) return `${hours}h ${minutes}m ${seconds}s`;
|
|
876
|
-
if (minutes > 0) return `${minutes}m ${seconds}s`;
|
|
877
|
-
return `${seconds}s`;
|
|
878
|
-
}
|
|
879
|
-
|
|
880
517
|
/** Minimal one-line footer used when the vendored renderer is unavailable. */
|
|
881
518
|
export function fallbackStatusline({
|
|
882
519
|
provider = '', model = '', effort = '', fast = false, cwd = '', stats, contextWindow = 0,
|
|
@@ -913,25 +550,3 @@ function fallbackLine({
|
|
|
913
550
|
if (!parts.length) return statusSubtle('> mixdog');
|
|
914
551
|
return parts.join(sep);
|
|
915
552
|
}
|
|
916
|
-
|
|
917
|
-
function num(v) {
|
|
918
|
-
const n = Number(v);
|
|
919
|
-
return Number.isFinite(n) ? n : 0;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
function clampPct(v) {
|
|
923
|
-
const n = Number(v);
|
|
924
|
-
if (!Number.isFinite(n)) return 0;
|
|
925
|
-
return Math.max(0, Math.min(100, n));
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
/** Human-friendly token count: 1234 -> 1.2k. */
|
|
929
|
-
function fmt(n) {
|
|
930
|
-
const v = Number(n) || 0;
|
|
931
|
-
if (v < 1000) return String(Math.round(v));
|
|
932
|
-
if (v < 1_000_000) {
|
|
933
|
-
const k = Math.round(v / 1000);
|
|
934
|
-
return k >= 1000 ? '1M' : `${k}k`;
|
|
935
|
-
}
|
|
936
|
-
return (v / 1_000_000).toFixed(1) + 'M';
|
|
937
|
-
}
|
package/src/ui/tool-card.mjs
CHANGED
|
@@ -539,7 +539,14 @@ export function loadGatewayStatus(options = {}) {
|
|
|
539
539
|
: true;
|
|
540
540
|
const metricsOwnCurrentSession = !!(sessionStatus || gatewayCcSessionMatch || gatewayTranscriptMatch || activeTranscriptMatch);
|
|
541
541
|
const metricsMatch = gatewayClientHostMatch && metricsOwnCurrentSession && routeMatchesConfigured;
|
|
542
|
-
|
|
542
|
+
// Strong ownership = this session's own status file or an explicit session/
|
|
543
|
+
// transcript id match from the gateway advert. `activeTranscriptMatch` (the
|
|
544
|
+
// global active-instance transcript merely naming the current session) is NOT
|
|
545
|
+
// strong: right after /new the global record can already point at the new
|
|
546
|
+
// session while its stored gateway metrics (context pct, last usage) still
|
|
547
|
+
// belong to the previous one.
|
|
548
|
+
const strongSessionOwnership = !!(sessionStatus || gatewayCcSessionMatch || gatewayTranscriptMatch);
|
|
549
|
+
const lastUsage = gatewayClientHostMatch && strongSessionOwnership && active.gateway_last_usage && typeof active.gateway_last_usage === 'object'
|
|
543
550
|
? active.gateway_last_usage
|
|
544
551
|
: null;
|
|
545
552
|
const lastCompact = lastUsage?.compact && typeof lastUsage.compact === 'object'
|
|
@@ -593,7 +600,13 @@ export function loadGatewayStatus(options = {}) {
|
|
|
593
600
|
rawContextWindow: configured?.rawContextWindow ?? num(active.gateway_raw_context_window, null),
|
|
594
601
|
effectiveContextWindowPercent: configured?.effectiveContextWindowPercent ?? num(active.gateway_effective_context_window_percent, null),
|
|
595
602
|
autoCompactTokenLimit: statusAutoCompactTokenLimit,
|
|
596
|
-
|
|
603
|
+
// Live recompute (from the caller's own context tokens) may use the weaker
|
|
604
|
+
// metricsMatch gate, but the STORED gateway_context_used_pct fallback needs
|
|
605
|
+
// strong ownership — otherwise a fresh /new session with a not-yet-updated
|
|
606
|
+
// active-instance record would keep showing the old session's context %.
|
|
607
|
+
contextUsedPct: metricsMatch
|
|
608
|
+
? recomputedContextUsedPct ?? (strongSessionOwnership ? num(active.gateway_context_used_pct, null) : null)
|
|
609
|
+
: null,
|
|
597
610
|
lastUsage,
|
|
598
611
|
quotaWindows: activeQuotaWindows.length ? activeQuotaWindows : (configuredStatus?.quotaWindows || []),
|
|
599
612
|
balance: metricsMatch && active.gateway_balance && typeof active.gateway_balance === 'object' ? active.gateway_balance : (configuredStatus?.balance || null),
|