muonroi-cli 1.8.4 → 1.9.0
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/LICENSE +17 -5
- package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
- package/dist/packages/agent-harness-core/src/driver.js +46 -0
- package/dist/packages/agent-harness-core/src/event-filter.js +11 -0
- package/dist/packages/agent-harness-core/src/event-redact.js +7 -0
- package/dist/packages/agent-harness-core/src/event-tee.d.ts +64 -0
- package/dist/packages/agent-harness-core/src/event-tee.js +104 -0
- package/dist/packages/agent-harness-core/src/mcp-server.d.ts +25 -0
- package/dist/packages/agent-harness-core/src/mcp-server.js +169 -21
- package/dist/packages/agent-harness-core/src/predicate.d.ts +1 -1
- package/dist/packages/agent-harness-core/src/protocol.d.ts +90 -4
- package/dist/packages/agent-harness-core/src/protocol.js +15 -0
- package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
- package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
- package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
- package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
- package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
- package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
- package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
- package/dist/packages/agent-harness-opentui/src/install.js +10 -0
- package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
- package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
- package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
- package/dist/src/agent-harness/mock-model.d.ts +38 -0
- package/dist/src/agent-harness/mock-model.js +69 -3
- package/dist/src/agent-harness/test-spawn.js +31 -0
- package/dist/src/chat/chat-keychain.d.ts +7 -12
- package/dist/src/chat/chat-keychain.js +19 -86
- package/dist/src/cli/config/screen-providers.js +1 -1
- package/dist/src/cli/cost-forensics.d.ts +10 -0
- package/dist/src/cli/cost-forensics.js +18 -3
- package/dist/src/cli/keys-bundle.d.ts +1 -1
- package/dist/src/cli/keys-bundle.js +1 -1
- package/dist/src/cli/keys.d.ts +10 -47
- package/dist/src/cli/keys.js +31 -399
- package/dist/src/council/clarifier.d.ts +31 -3
- package/dist/src/council/clarifier.js +220 -32
- package/dist/src/council/context.js +49 -15
- package/dist/src/council/debate-checkpoint.d.ts +129 -0
- package/dist/src/council/debate-checkpoint.js +176 -0
- package/dist/src/council/debate-planner.js +54 -5
- package/dist/src/council/debate-summary.d.ts +25 -0
- package/dist/src/council/debate-summary.js +85 -0
- package/dist/src/council/debate.d.ts +169 -2
- package/dist/src/council/debate.js +1265 -135
- package/dist/src/council/index.d.ts +108 -1
- package/dist/src/council/index.js +670 -197
- package/dist/src/council/leader.d.ts +26 -0
- package/dist/src/council/leader.js +150 -9
- package/dist/src/council/llm.d.ts +94 -0
- package/dist/src/council/llm.js +348 -55
- package/dist/src/council/panel-select.d.ts +30 -0
- package/dist/src/council/panel-select.js +82 -0
- package/dist/src/council/planner.js +40 -0
- package/dist/src/council/preflight.d.ts +17 -0
- package/dist/src/council/preflight.js +50 -2
- package/dist/src/council/prompts.d.ts +39 -4
- package/dist/src/council/prompts.js +256 -69
- package/dist/src/council/stance-recall.d.ts +42 -0
- package/dist/src/council/stance-recall.js +57 -0
- package/dist/src/council/strip-think.d.ts +17 -0
- package/dist/src/council/strip-think.js +33 -0
- package/dist/src/council/types.d.ts +138 -0
- package/dist/src/ee/artifact-cache.d.ts +16 -0
- package/dist/src/ee/artifact-cache.js +32 -0
- package/dist/src/ee/auth.d.ts +20 -0
- package/dist/src/ee/auth.js +54 -2
- package/dist/src/ee/bridge.d.ts +10 -0
- package/dist/src/ee/bridge.js +58 -0
- package/dist/src/ee/client.js +109 -21
- package/dist/src/ee/ee-onboarding.js +6 -26
- package/dist/src/ee/export-transcripts.d.ts +1 -0
- package/dist/src/ee/export-transcripts.js +8 -10
- package/dist/src/ee/extract-session.js +29 -0
- package/dist/src/ee/extract-style.d.ts +58 -0
- package/dist/src/ee/extract-style.js +270 -0
- package/dist/src/ee/recall-ledger.d.ts +9 -0
- package/dist/src/ee/recall-ledger.js +3 -0
- package/dist/src/ee/scope.d.ts +1 -0
- package/dist/src/ee/scope.js +26 -1
- package/dist/src/ee/search.d.ts +7 -0
- package/dist/src/ee/search.js +24 -0
- package/dist/src/ee/transcript-emit.js +2 -0
- package/dist/src/ee/types.d.ts +22 -0
- package/dist/src/ee/who-am-i-brain.d.ts +35 -0
- package/dist/src/ee/who-am-i-brain.js +220 -0
- package/dist/src/ee/who-am-i.d.ts +10 -3
- package/dist/src/ee/who-am-i.js +12 -0
- package/dist/src/ee/workflow-event.d.ts +48 -0
- package/dist/src/ee/workflow-event.js +81 -0
- package/dist/src/flow/compaction/compress.d.ts +3 -3
- package/dist/src/flow/compaction/compress.js +58 -8
- package/dist/src/flow/compaction/extract.d.ts +4 -7
- package/dist/src/flow/compaction/extract.js +50 -10
- package/dist/src/flow/compaction/index.d.ts +14 -1
- package/dist/src/flow/compaction/index.js +96 -3
- package/dist/src/flow/compaction/input-guard.d.ts +24 -0
- package/dist/src/flow/compaction/input-guard.js +43 -0
- package/dist/src/flow/compaction/progress.d.ts +35 -0
- package/dist/src/flow/compaction/progress.js +35 -0
- package/dist/src/flow/fold-planning.d.ts +36 -0
- package/dist/src/flow/fold-planning.js +83 -0
- package/dist/src/flow/hierarchy.d.ts +146 -0
- package/dist/src/flow/hierarchy.js +427 -0
- package/dist/src/flow/index.d.ts +1 -0
- package/dist/src/flow/index.js +2 -0
- package/dist/src/flow/run-artifacts.d.ts +102 -0
- package/dist/src/flow/run-artifacts.js +208 -0
- package/dist/src/generated/version.d.ts +1 -1
- package/dist/src/generated/version.js +1 -1
- package/dist/src/gsd/assessment-schema.d.ts +44 -0
- package/dist/src/gsd/assessment-schema.js +134 -0
- package/dist/src/gsd/capability-registry.d.ts +45 -0
- package/dist/src/gsd/capability-registry.js +337 -0
- package/dist/src/gsd/complexity-assessor.d.ts +39 -0
- package/dist/src/gsd/complexity-assessor.js +152 -0
- package/dist/src/gsd/config-bridge.d.ts +7 -0
- package/dist/src/gsd/config-bridge.js +114 -0
- package/dist/src/gsd/config-loader.d.ts +27 -0
- package/dist/src/gsd/config-loader.js +50 -0
- package/dist/src/gsd/council-context.d.ts +44 -0
- package/dist/src/gsd/council-context.js +114 -0
- package/dist/src/gsd/ee-closure.d.ts +28 -0
- package/dist/src/gsd/ee-closure.js +49 -0
- package/dist/src/gsd/flags.d.ts +66 -0
- package/dist/src/gsd/flags.js +102 -0
- package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
- package/dist/src/gsd/gsd-dispatch.js +131 -0
- package/dist/src/gsd/gsd-runtime.d.ts +22 -0
- package/dist/src/gsd/gsd-runtime.js +37 -0
- package/dist/src/gsd/host-adapter.d.ts +11 -0
- package/dist/src/gsd/host-adapter.js +29 -0
- package/dist/src/gsd/index.d.ts +24 -1
- package/dist/src/gsd/index.js +27 -0
- package/dist/src/gsd/loop-host-contract.d.ts +21 -0
- package/dist/src/gsd/loop-host-contract.js +39 -0
- package/dist/src/gsd/loop-host.d.ts +69 -0
- package/dist/src/gsd/loop-host.js +245 -0
- package/dist/src/gsd/loop-resolver.d.ts +36 -0
- package/dist/src/gsd/loop-resolver.js +79 -0
- package/dist/src/gsd/model-tier.d.ts +13 -0
- package/dist/src/gsd/model-tier.js +45 -0
- package/dist/src/gsd/mutation-gate.d.ts +16 -0
- package/dist/src/gsd/mutation-gate.js +41 -0
- package/dist/src/gsd/native-roadmap.d.ts +89 -0
- package/dist/src/gsd/native-roadmap.js +343 -0
- package/dist/src/gsd/native-state.d.ts +47 -0
- package/dist/src/gsd/native-state.js +220 -0
- package/dist/src/gsd/paths.d.ts +23 -0
- package/dist/src/gsd/paths.js +66 -0
- package/dist/src/gsd/phase-dag.d.ts +12 -0
- package/dist/src/gsd/phase-dag.js +94 -0
- package/dist/src/gsd/phase-sync.d.ts +42 -0
- package/dist/src/gsd/phase-sync.js +321 -0
- package/dist/src/gsd/pil-gate-context.d.ts +13 -0
- package/dist/src/gsd/pil-gate-context.js +64 -0
- package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
- package/dist/src/gsd/pil-gate-critic.js +74 -0
- package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
- package/dist/src/gsd/plan-council-prompts.js +79 -0
- package/dist/src/gsd/plan-council.d.ts +44 -0
- package/dist/src/gsd/plan-council.js +283 -0
- package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
- package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
- package/dist/src/gsd/product-workspace.d.ts +13 -0
- package/dist/src/gsd/product-workspace.js +124 -0
- package/dist/src/gsd/ship-bridge.d.ts +25 -0
- package/dist/src/gsd/ship-bridge.js +65 -0
- package/dist/src/gsd/state-document.d.ts +40 -0
- package/dist/src/gsd/state-document.js +163 -0
- package/dist/src/gsd/verdict-schema.d.ts +39 -0
- package/dist/src/gsd/verdict-schema.js +144 -0
- package/dist/src/gsd/verify-context.d.ts +22 -0
- package/dist/src/gsd/verify-context.js +27 -0
- package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
- package/dist/src/gsd/verify-council-prompts.js +85 -0
- package/dist/src/gsd/verify-council.d.ts +25 -0
- package/dist/src/gsd/verify-council.js +119 -0
- package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
- package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
- package/dist/src/gsd/workflow-engine.d.ts +60 -0
- package/dist/src/gsd/workflow-engine.js +207 -0
- package/dist/src/gsd/workflow-tools.d.ts +13 -0
- package/dist/src/gsd/workflow-tools.js +277 -0
- package/dist/src/headless/council-answers.js +4 -0
- package/dist/src/hooks/index.js +1 -1
- package/dist/src/index.js +172 -270
- package/dist/src/lsp/builtins.js +3 -1
- package/dist/src/lsp/manager.d.ts +5 -1
- package/dist/src/lsp/manager.js +249 -3
- package/dist/src/lsp/npm-cache.d.ts +11 -1
- package/dist/src/lsp/npm-cache.js +17 -1
- package/dist/src/lsp/runtime.d.ts +6 -1
- package/dist/src/lsp/runtime.js +17 -1
- package/dist/src/lsp/types.d.ts +83 -1
- package/dist/src/lsp/types.js +10 -0
- package/dist/src/maintain/pr-builder.js +23 -13
- package/dist/src/mcp/auto-setup.js +57 -32
- package/dist/src/mcp/client-pool.js +44 -16
- package/dist/src/mcp/lsp-tools.d.ts +5 -1
- package/dist/src/mcp/lsp-tools.js +93 -2
- package/dist/src/mcp/mcp-keychain.d.ts +3 -5
- package/dist/src/mcp/mcp-keychain.js +9 -49
- package/dist/src/mcp/research-onboarding.js +8 -7
- package/dist/src/mcp/runtime.js +34 -2
- package/dist/src/mcp/setup-guide-text.d.ts +1 -1
- package/dist/src/mcp/setup-guide-text.js +22 -2
- package/dist/src/mcp/tools-server.d.ts +10 -0
- package/dist/src/mcp/tools-server.js +10 -2
- package/dist/src/models/catalog-client.d.ts +87 -0
- package/dist/src/models/catalog-client.js +105 -38
- package/dist/src/models/catalog.json +528 -265
- package/dist/src/models/registry.d.ts +22 -7
- package/dist/src/models/registry.js +73 -10
- package/dist/src/ops/doctor.js +1 -1
- package/dist/src/orchestrator/ask-user.d.ts +61 -0
- package/dist/src/orchestrator/ask-user.js +65 -0
- package/dist/src/orchestrator/auto-commit.js +1 -1
- package/dist/src/orchestrator/batch-turn-runner.js +2 -2
- package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
- package/dist/src/orchestrator/cache-prefix.js +83 -0
- package/dist/src/orchestrator/compact-request.d.ts +32 -0
- package/dist/src/orchestrator/compact-request.js +41 -0
- package/dist/src/orchestrator/compaction.d.ts +12 -3
- package/dist/src/orchestrator/compaction.js +35 -15
- package/dist/src/orchestrator/council-manager.d.ts +12 -3
- package/dist/src/orchestrator/council-manager.js +74 -32
- package/dist/src/orchestrator/council-request.d.ts +49 -0
- package/dist/src/orchestrator/council-request.js +62 -0
- package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
- package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
- package/dist/src/orchestrator/error-utils.d.ts +29 -0
- package/dist/src/orchestrator/error-utils.js +132 -24
- package/dist/src/orchestrator/grounding-check.js +39 -1
- package/dist/src/orchestrator/interactive-pause.d.ts +26 -0
- package/dist/src/orchestrator/interactive-pause.js +36 -0
- package/dist/src/orchestrator/message-processor.d.ts +4 -0
- package/dist/src/orchestrator/message-processor.js +268 -41
- package/dist/src/orchestrator/orchestrator.d.ts +64 -3
- package/dist/src/orchestrator/orchestrator.js +823 -120
- package/dist/src/orchestrator/preprocessor.js +3 -3
- package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
- package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
- package/dist/src/orchestrator/prompts.js +17 -17
- package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
- package/dist/src/orchestrator/reactive-delegation.js +59 -0
- package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
- package/dist/src/orchestrator/retry-classifier.js +46 -2
- package/dist/src/orchestrator/safety-askcard.d.ts +1 -1
- package/dist/src/orchestrator/safety-askcard.js +5 -2
- package/dist/src/orchestrator/safety-intercept.d.ts +50 -0
- package/dist/src/orchestrator/safety-intercept.js +62 -0
- package/dist/src/orchestrator/scope-reminder.js +1 -1
- package/dist/src/orchestrator/session-experience.d.ts +2 -1
- package/dist/src/orchestrator/session-experience.js +2 -1
- package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
- package/dist/src/orchestrator/should-run-gate.js +18 -0
- package/dist/src/orchestrator/stall-watchdog.d.ts +31 -3
- package/dist/src/orchestrator/stall-watchdog.js +65 -10
- package/dist/src/orchestrator/stream-runner.d.ts +13 -3
- package/dist/src/orchestrator/stream-runner.js +115 -49
- package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
- package/dist/src/orchestrator/sub-agent-cap.js +16 -1
- package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
- package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
- package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
- package/dist/src/orchestrator/subagent-compactor.js +126 -15
- package/dist/src/orchestrator/tool-engine.d.ts +41 -0
- package/dist/src/orchestrator/tool-engine.js +846 -66
- package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
- package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
- package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
- package/dist/src/orchestrator/turn-watchdog.d.ts +44 -0
- package/dist/src/orchestrator/turn-watchdog.js +84 -0
- package/dist/src/pil/agent-operating-contract.d.ts +1 -1
- package/dist/src/pil/agent-operating-contract.js +6 -4
- package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
- package/dist/src/pil/cheap-model-playbook.js +5 -1
- package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
- package/dist/src/pil/cheap-model-workbooks.js +1 -1
- package/dist/src/pil/discovery-types.d.ts +1 -0
- package/dist/src/pil/discovery.d.ts +1 -1
- package/dist/src/pil/discovery.js +18 -13
- package/dist/src/pil/layer1-intent.d.ts +18 -6
- package/dist/src/pil/layer1-intent.js +66 -757
- package/dist/src/pil/layer15-context-scan.js +15 -1
- package/dist/src/pil/layer1_5-complexity-size.d.ts +7 -0
- package/dist/src/pil/layer1_5-complexity-size.js +31 -5
- package/dist/src/pil/layer3-ee-injection.js +23 -8
- package/dist/src/pil/layer4-gsd.js +69 -16
- package/dist/src/pil/layer5-context.js +7 -3
- package/dist/src/pil/layer6-output.d.ts +23 -0
- package/dist/src/pil/layer6-output.js +5 -1
- package/dist/src/pil/llm-classify.d.ts +111 -5
- package/dist/src/pil/llm-classify.js +421 -189
- package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
- package/dist/src/pil/native-capabilities-workbook.js +8 -0
- package/dist/src/pil/pipeline.js +36 -2
- package/dist/src/pil/repo-grounding-probe.d.ts +15 -0
- package/dist/src/pil/repo-grounding-probe.js +136 -0
- package/dist/src/pil/repo-structure-hints.d.ts +7 -0
- package/dist/src/pil/repo-structure-hints.js +45 -0
- package/dist/src/pil/response-tools.js +5 -3
- package/dist/src/pil/schema.d.ts +1 -0
- package/dist/src/pil/schema.js +2 -0
- package/dist/src/pil/types.d.ts +18 -0
- package/dist/src/playbook/directives.d.ts +4 -0
- package/dist/src/playbook/directives.js +17 -5
- package/dist/src/product-loop/artifact-io.js +4 -0
- package/dist/src/product-loop/backlog-builder.d.ts +14 -1
- package/dist/src/product-loop/backlog-builder.js +30 -6
- package/dist/src/product-loop/criteria-seed.d.ts +51 -0
- package/dist/src/product-loop/criteria-seed.js +200 -0
- package/dist/src/product-loop/discovery-context-format.js +3 -1
- package/dist/src/product-loop/discovery-ecosystem.js +4 -1
- package/dist/src/product-loop/discovery-interview.d.ts +9 -0
- package/dist/src/product-loop/discovery-interview.js +60 -12
- package/dist/src/product-loop/discovery-recommender.js +2 -1
- package/dist/src/product-loop/discovery-schema.js +19 -2
- package/dist/src/product-loop/discovery-triage.d.ts +23 -0
- package/dist/src/product-loop/discovery-triage.js +109 -0
- package/dist/src/product-loop/gather.js +150 -2
- package/dist/src/product-loop/ideal-trace.d.ts +7 -0
- package/dist/src/product-loop/ideal-trace.js +64 -0
- package/dist/src/product-loop/index.d.ts +13 -1
- package/dist/src/product-loop/index.js +340 -52
- package/dist/src/product-loop/loop-driver.d.ts +7 -0
- package/dist/src/product-loop/loop-driver.js +330 -106
- package/dist/src/product-loop/phase-plan.d.ts +21 -0
- package/dist/src/product-loop/phase-plan.js +81 -6
- package/dist/src/product-loop/phase-rituals.d.ts +3 -0
- package/dist/src/product-loop/phase-rituals.js +8 -3
- package/dist/src/product-loop/phase-runner.js +39 -12
- package/dist/src/product-loop/plan-adherence-review.d.ts +26 -0
- package/dist/src/product-loop/plan-adherence-review.js +144 -0
- package/dist/src/product-loop/sprint-runner.d.ts +173 -0
- package/dist/src/product-loop/sprint-runner.js +863 -19
- package/dist/src/product-loop/types.d.ts +61 -5
- package/dist/src/providers/adapter.d.ts +1 -1
- package/dist/src/providers/adapter.js +3 -4
- package/dist/src/providers/anthropic.d.ts +9 -8
- package/dist/src/providers/anthropic.js +13 -47
- package/dist/src/providers/auth/browser-flow.d.ts +1 -1
- package/dist/src/providers/auth/browser-flow.js +1 -1
- package/dist/src/providers/auth/grok-oauth.d.ts +1 -0
- package/dist/src/providers/auth/grok-oauth.js +30 -5
- package/dist/src/providers/auth/openai-oauth.d.ts +1 -0
- package/dist/src/providers/auth/openai-oauth.js +15 -1
- package/dist/src/providers/auth/registry.js +0 -34
- package/dist/src/providers/auth/token-store.d.ts +9 -9
- package/dist/src/providers/auth/token-store.js +8 -67
- package/dist/src/providers/auth/types.d.ts +9 -1
- package/dist/src/providers/auth/types.js +1 -1
- package/dist/src/providers/capabilities.d.ts +24 -5
- package/dist/src/providers/capabilities.js +42 -24
- package/dist/src/providers/endpoints.d.ts +2 -2
- package/dist/src/providers/endpoints.js +11 -10
- package/dist/src/providers/env-store.d.ts +17 -0
- package/dist/src/providers/env-store.js +228 -0
- package/dist/src/providers/keychain.d.ts +22 -18
- package/dist/src/providers/keychain.js +127 -140
- package/dist/src/providers/mcp-vision-bridge.js +56 -146
- package/dist/src/providers/openai-compatible.js +8 -1
- package/dist/src/providers/pricing.d.ts +2 -2
- package/dist/src/providers/pricing.js +3 -13
- package/dist/src/providers/runtime.d.ts +43 -3
- package/dist/src/providers/runtime.js +88 -14
- package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
- package/dist/src/providers/strategies/base.strategy.js +24 -1
- package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
- package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
- package/dist/src/providers/strategies/registry.js +4 -4
- package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
- package/dist/src/providers/strategies/thinking-mode.js +288 -1
- package/dist/src/providers/strategies/xai.strategy.js +27 -0
- package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
- package/dist/src/providers/strategies/zai.strategy.js +44 -0
- package/dist/src/providers/types.d.ts +5 -6
- package/dist/src/providers/types.js +2 -2
- package/dist/src/providers/vision-backend.d.ts +47 -0
- package/dist/src/providers/vision-backend.js +258 -0
- package/dist/src/providers/vision-proxy.d.ts +22 -9
- package/dist/src/providers/vision-proxy.js +63 -132
- package/dist/src/providers/warm.d.ts +65 -0
- package/dist/src/providers/warm.js +145 -0
- package/dist/src/providers/wire-debug.js +95 -0
- package/dist/src/router/decide.d.ts +13 -0
- package/dist/src/router/decide.js +138 -36
- package/dist/src/router/peak-hour.d.ts +38 -0
- package/dist/src/router/peak-hour.js +107 -0
- package/dist/src/router/step-router.js +3 -2
- package/dist/src/router/warm.js +4 -5
- package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
- package/dist/src/scaffold/continuation-prompt.js +26 -0
- package/dist/src/scaffold/point-to-existing.d.ts +21 -0
- package/dist/src/scaffold/point-to-existing.js +25 -0
- package/dist/src/self-qa/agentic-loop.js +6 -5
- package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
- package/dist/src/{ui/state → state}/active-run.js +21 -0
- package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
- package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
- package/dist/src/state/turn-trace.d.ts +43 -0
- package/dist/src/state/turn-trace.js +32 -0
- package/dist/src/storage/db.js +2 -1
- package/dist/src/storage/index.d.ts +1 -1
- package/dist/src/storage/index.js +1 -1
- package/dist/src/storage/interaction-log.d.ts +1 -1
- package/dist/src/storage/migrations.js +71 -1
- package/dist/src/storage/sessions.d.ts +28 -10
- package/dist/src/storage/sessions.js +78 -21
- package/dist/src/storage/transcript-view.js +1 -1
- package/dist/src/storage/transcript.d.ts +51 -0
- package/dist/src/storage/transcript.js +340 -15
- package/dist/src/tools/file.d.ts +15 -0
- package/dist/src/tools/file.js +32 -0
- package/dist/src/tools/git-safety.d.ts +19 -0
- package/dist/src/tools/git-safety.js +168 -0
- package/dist/src/tools/native-tools.d.ts +1 -1
- package/dist/src/tools/native-tools.js +81 -1
- package/dist/src/tools/registry.d.ts +20 -0
- package/dist/src/tools/registry.js +576 -23
- package/dist/src/tools/research.d.ts +29 -0
- package/dist/src/tools/research.js +233 -0
- package/dist/src/types/index.d.ts +147 -4
- package/dist/src/ui/app.js +0 -0
- package/dist/src/ui/cards/product-status-card.js +1 -1
- package/dist/src/ui/components/agent-rail-activities.d.ts +26 -0
- package/dist/src/ui/components/agent-rail-activities.js +47 -0
- package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
- package/dist/src/ui/components/bubble-body-guard.js +50 -0
- package/dist/src/ui/components/compact-progress-card.d.ts +24 -0
- package/dist/src/ui/components/compact-progress-card.js +42 -0
- package/dist/src/ui/components/context-rail.d.ts +26 -0
- package/dist/src/ui/components/context-rail.js +33 -0
- package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
- package/dist/src/ui/components/council-conclusion-card.js +420 -0
- package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
- package/dist/src/ui/components/council-debate-pill.js +34 -0
- package/dist/src/ui/components/council-info-card.js +2 -2
- package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
- package/dist/src/ui/components/council-leader-bubble.js +21 -11
- package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
- package/dist/src/ui/components/council-message-bubble.js +16 -15
- package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
- package/dist/src/ui/components/council-phase-timeline.js +66 -17
- package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
- package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
- package/dist/src/ui/components/council-question-card.js +13 -12
- package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
- package/dist/src/ui/components/council-rail-rounds.js +57 -0
- package/dist/src/ui/components/council-round-group.d.ts +38 -0
- package/dist/src/ui/components/council-round-group.js +88 -0
- package/dist/src/ui/components/council-status-list.d.ts +3 -1
- package/dist/src/ui/components/council-status-list.js +36 -24
- package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
- package/dist/src/ui/components/council-synthesis-banner.js +20 -5
- package/dist/src/ui/components/halt-recovery-card.js +9 -5
- package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
- package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
- package/dist/src/ui/components/message-view.d.ts +15 -0
- package/dist/src/ui/components/message-view.js +50 -1
- package/dist/src/ui/components/prompt-box.js +18 -16
- package/dist/src/ui/components/session-tree-card.d.ts +14 -0
- package/dist/src/ui/components/session-tree-card.js +46 -0
- package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
- package/dist/src/ui/components/slash-inline-menu.js +26 -5
- package/dist/src/ui/components/task-list-panel.d.ts +14 -1
- package/dist/src/ui/components/task-list-panel.js +22 -2
- package/dist/src/ui/components/tool-group.d.ts +15 -3
- package/dist/src/ui/components/tool-group.js +69 -11
- package/dist/src/ui/containers/modals-layer.d.ts +4 -2
- package/dist/src/ui/containers/modals-layer.js +2 -2
- package/dist/src/ui/council-harness-event.d.ts +57 -0
- package/dist/src/ui/council-harness-event.js +46 -0
- package/dist/src/ui/heartbeat-debug.d.ts +29 -0
- package/dist/src/ui/heartbeat-debug.js +45 -0
- package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
- package/dist/src/ui/mcp-modal.js +2 -4
- package/dist/src/ui/modals/api-key-modal.js +1 -1
- package/dist/src/ui/modals/connect-modal.js +4 -3
- package/dist/src/ui/modals/model-picker-modal.d.ts +8 -18
- package/dist/src/ui/modals/model-picker-modal.js +8 -10
- package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
- package/dist/src/ui/modals/session-picker-modal.js +3 -5
- package/dist/src/ui/picker-providers.d.ts +1 -1
- package/dist/src/ui/picker-providers.js +1 -1
- package/dist/src/ui/primitives/index.d.ts +1 -0
- package/dist/src/ui/primitives/index.js +2 -0
- package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
- package/dist/src/ui/primitives/semantic-primitives.js +81 -0
- package/dist/src/ui/slash/compact.js +5 -7
- package/dist/src/ui/slash/cost.js +1 -1
- package/dist/src/ui/slash/council.js +19 -1
- package/dist/src/ui/slash/debug.d.ts +3 -31
- package/dist/src/ui/slash/debug.js +9 -20
- package/dist/src/ui/slash/ee.js +81 -0
- package/dist/src/ui/slash/ideal.d.ts +6 -2
- package/dist/src/ui/slash/ideal.js +97 -7
- package/dist/src/ui/slash/menu-items.d.ts +7 -0
- package/dist/src/ui/slash/menu-items.js +23 -20
- package/dist/src/ui/slash/registry.d.ts +2 -0
- package/dist/src/ui/slash/registry.js +4 -0
- package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
- package/dist/src/ui/status-bar/cache-hit.js +9 -0
- package/dist/src/ui/status-bar/index.d.ts +1 -1
- package/dist/src/ui/status-bar/index.js +7 -3
- package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
- package/dist/src/ui/status-bar/usd-meter.js +6 -4
- package/dist/src/ui/theme.d.ts +1 -0
- package/dist/src/ui/theme.js +2 -0
- package/dist/src/ui/types.d.ts +7 -0
- package/dist/src/ui/use-app-logic.js +0 -0
- package/dist/src/ui/utils/agent-activities.d.ts +39 -0
- package/dist/src/ui/utils/agent-activities.js +96 -0
- package/dist/src/ui/utils/format.d.ts +14 -0
- package/dist/src/ui/utils/format.js +23 -3
- package/dist/src/ui/utils/group-tool-entries.d.ts +26 -0
- package/dist/src/ui/utils/group-tool-entries.js +111 -0
- package/dist/src/ui/utils/tool-summary.d.ts +21 -0
- package/dist/src/ui/utils/tool-summary.js +91 -0
- package/dist/src/usage/downgrade.js +2 -2
- package/dist/src/usage/product-ledger.js +2 -2
- package/dist/src/utils/event-loop-monitor.d.ts +85 -0
- package/dist/src/utils/event-loop-monitor.js +107 -0
- package/dist/src/utils/install-manager.js +2 -1
- package/dist/src/utils/llm-deadline.d.ts +14 -0
- package/dist/src/utils/llm-deadline.js +19 -0
- package/dist/src/utils/logger.js +2 -2
- package/dist/src/utils/loop-profiler.d.ts +102 -0
- package/dist/src/utils/loop-profiler.js +202 -0
- package/dist/src/utils/permission-mode.js +5 -3
- package/dist/src/utils/redactor.js +1 -1
- package/dist/src/utils/settings.d.ts +180 -5
- package/dist/src/utils/settings.js +271 -31
- package/dist/src/utils/side-question.d.ts +1 -2
- package/dist/src/utils/side-question.js +2 -2
- package/dist/src/utils/visible-retry.d.ts +11 -0
- package/dist/src/utils/visible-retry.js +10 -1
- package/dist/src/verify/entrypoint.d.ts +1 -1
- package/dist/src/verify/entrypoint.js +52 -17
- package/dist/src/verify/orchestrator.d.ts +1 -1
- package/dist/src/verify/orchestrator.js +20 -3
- package/dist/src/verify/recipes.d.ts +13 -0
- package/dist/src/verify/recipes.js +15 -0
- package/package.json +134 -132
- package/dist/src/cli/bw-vault.d.ts +0 -55
- package/dist/src/cli/bw-vault.js +0 -133
- package/dist/src/mcp/ee-tools.d.ts +0 -46
- package/dist/src/mcp/ee-tools.js +0 -193
- package/dist/src/providers/auth/gcloud.d.ts +0 -28
- package/dist/src/providers/auth/gcloud.js +0 -102
- package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
- package/dist/src/providers/auth/gemini-oauth.js +0 -472
- package/dist/src/providers/gemini.d.ts +0 -11
- package/dist/src/providers/gemini.js +0 -45
- package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
- package/dist/src/providers/siliconflow-sse-repair.js +0 -177
- package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
- package/dist/src/providers/strategies/google.strategy.js +0 -174
- package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
- package/dist/src/ui/containers/chat-feed.d.ts +0 -40
- package/dist/src/ui/containers/chat-feed.js +0 -66
|
@@ -18,6 +18,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
18
18
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
19
19
|
import { z } from "zod";
|
|
20
20
|
import { createDriver } from "./driver.js";
|
|
21
|
+
import { createEventTee, resolveEventLogPath } from "./event-tee.js";
|
|
21
22
|
import { PROTOCOL_VERSION } from "./protocol.js";
|
|
22
23
|
const ARG_ALLOW = /^(--agent-[a-z-]+(=.*)?|--mock-llm(=.+)?|--profile=[a-zA-Z0-9_-]+)$/;
|
|
23
24
|
const ENV_KEY_RE = /^[A-Z_][A-Z0-9_]{0,63}$/;
|
|
@@ -49,6 +50,25 @@ export function sanitizeEnv(env) {
|
|
|
49
50
|
}
|
|
50
51
|
return out;
|
|
51
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Build the child TUI's environment for tui.start.
|
|
55
|
+
*
|
|
56
|
+
* Starts from the driver's own env so PATH/HOME survive, overlays the
|
|
57
|
+
* caller-supplied keys, THEN strips the dangerous ones. The merge-before-strip
|
|
58
|
+
* order keeps the security posture (NODE_OPTIONS/LD_PRELOAD/… still removed)
|
|
59
|
+
* while guaranteeing PATH is present: bun drops the fd 3/4 stdio channels when a
|
|
60
|
+
* child is spawned with a partial env that lacks PATH, which yields a null
|
|
61
|
+
* inWrite and crashes the whole driver on spawn. `base` defaults to process.env
|
|
62
|
+
* and is injectable for tests.
|
|
63
|
+
*/
|
|
64
|
+
export function buildChildEnv(callerEnv = {}, base = process.env) {
|
|
65
|
+
const merged = {};
|
|
66
|
+
for (const [k, v] of Object.entries(base)) {
|
|
67
|
+
if (v !== undefined)
|
|
68
|
+
merged[k] = v;
|
|
69
|
+
}
|
|
70
|
+
return sanitizeEnv({ ...merged, ...callerEnv });
|
|
71
|
+
}
|
|
52
72
|
const REPO_ROOT = process.cwd();
|
|
53
73
|
/**
|
|
54
74
|
* Opt-in extra cwd roots for tui.start, layered ON TOP of the default
|
|
@@ -133,11 +153,30 @@ export function validateMockLlmPath(value) {
|
|
|
133
153
|
const sep = process.platform === "win32" ? "\\" : "/";
|
|
134
154
|
return real === root || real.startsWith(root + sep);
|
|
135
155
|
}
|
|
136
|
-
const FEATURES = [
|
|
156
|
+
const FEATURES = [
|
|
157
|
+
"capabilities",
|
|
158
|
+
"snapshot",
|
|
159
|
+
"press",
|
|
160
|
+
"type",
|
|
161
|
+
"wait_for",
|
|
162
|
+
"query",
|
|
163
|
+
"expect",
|
|
164
|
+
"render_text",
|
|
165
|
+
"render_visual",
|
|
166
|
+
"snapshot_visual",
|
|
167
|
+
"cell",
|
|
168
|
+
"visual_quality",
|
|
169
|
+
"wait_for_event",
|
|
170
|
+
"event_log",
|
|
171
|
+
];
|
|
137
172
|
export function buildCapabilitiesPayload() {
|
|
138
173
|
return {
|
|
139
174
|
protocol: PROTOCOL_VERSION,
|
|
140
175
|
features: FEATURES,
|
|
176
|
+
// A default-on sink nobody can locate is still opt-in. Reporting the
|
|
177
|
+
// resolved path here is what makes it discoverable without the caller
|
|
178
|
+
// reproducing the env/tmpdir/pid rule.
|
|
179
|
+
eventLogPath: resolveEventLogPath(process.env["MUONROI_HARNESS_EVENT_LOG"]),
|
|
141
180
|
};
|
|
142
181
|
}
|
|
143
182
|
export function registerReadTools(server, getDriver) {
|
|
@@ -197,12 +236,54 @@ export function registerReadTools(server, getDriver) {
|
|
|
197
236
|
return noDriver();
|
|
198
237
|
return { content: [{ type: "text", text: String(d.count(selector)) }] };
|
|
199
238
|
});
|
|
200
|
-
server.registerTool("tui.render_text", {
|
|
239
|
+
server.registerTool("tui.render_text", {
|
|
240
|
+
// "debug render" undersold it: this is the primary way to see what is on
|
|
241
|
+
// screen right now — every node, modal and message in the semantic tree.
|
|
242
|
+
description: "See the current screen as a semantic tree (every node, modal, message, and focus state). " +
|
|
243
|
+
"Use tui.render_visual instead for the literal characters a human reads.",
|
|
244
|
+
inputSchema: {},
|
|
245
|
+
}, async () => {
|
|
201
246
|
const d = getDriver();
|
|
202
247
|
if (!d)
|
|
203
248
|
return noDriver();
|
|
204
249
|
return { content: [{ type: "text", text: d.render_text() }] };
|
|
205
250
|
});
|
|
251
|
+
server.registerTool("tui.render_visual", {
|
|
252
|
+
description: "Render the ACTUAL rendered cell grid as plain text — the characters a human reads on screen. Unlike tui.render_text (semantic tree), this reflects the real render. Requires agent-mode with the renderer attached.",
|
|
253
|
+
inputSchema: {},
|
|
254
|
+
}, async () => {
|
|
255
|
+
const d = getDriver();
|
|
256
|
+
if (!d)
|
|
257
|
+
return noDriver();
|
|
258
|
+
return { content: [{ type: "text", text: d.render_visual() }] };
|
|
259
|
+
});
|
|
260
|
+
server.registerTool("tui.snapshot_visual", {
|
|
261
|
+
description: "Return the latest VisualFrame — the real rendered cell grid with per-cell char + fg/bg hex + attribute bits. null until the renderer emits one.",
|
|
262
|
+
inputSchema: {},
|
|
263
|
+
}, async () => {
|
|
264
|
+
const d = getDriver();
|
|
265
|
+
if (!d)
|
|
266
|
+
return noDriver();
|
|
267
|
+
return { content: [{ type: "text", text: JSON.stringify(d.snapshot_visual()) }] };
|
|
268
|
+
});
|
|
269
|
+
server.registerTool("tui.cell", {
|
|
270
|
+
description: "Decode the rendered cell at (row, col): char + fg/bg hex + attribute bits, from the latest VisualFrame. Use to assert the colors/formatting a human actually sees.",
|
|
271
|
+
inputSchema: { row: z.number().int().min(0), col: z.number().int().min(0) },
|
|
272
|
+
}, async ({ row, col }) => {
|
|
273
|
+
const d = getDriver();
|
|
274
|
+
if (!d)
|
|
275
|
+
return noDriver();
|
|
276
|
+
return { content: [{ type: "text", text: JSON.stringify(d.visual_cell(row, col)) }] };
|
|
277
|
+
});
|
|
278
|
+
server.registerTool("tui.visual_quality", {
|
|
279
|
+
description: "Heuristic visual-quality report over the rendered grid: near-empty-row ratio, blank-row runs, whitespace density, mojibake, a 0-100 score and issues[]. Catches 'messy render' the semantic tree cannot see.",
|
|
280
|
+
inputSchema: {},
|
|
281
|
+
}, async () => {
|
|
282
|
+
const d = getDriver();
|
|
283
|
+
if (!d)
|
|
284
|
+
return noDriver();
|
|
285
|
+
return { content: [{ type: "text", text: JSON.stringify(d.visual_quality()) }] };
|
|
286
|
+
});
|
|
206
287
|
}
|
|
207
288
|
export function registerActionTools(server, getDriver) {
|
|
208
289
|
const noDriver = () => ({
|
|
@@ -268,21 +349,53 @@ export function registerAsyncTools(server, getDriver, deps) {
|
|
|
268
349
|
const waitConditionShape = {
|
|
269
350
|
selector: z.string().max(500).optional(),
|
|
270
351
|
idle: z.boolean().optional(),
|
|
352
|
+
event: z.string().max(64).optional(),
|
|
271
353
|
};
|
|
354
|
+
/**
|
|
355
|
+
* Rebuild the driver's WaitArgs from validated MCP input.
|
|
356
|
+
*
|
|
357
|
+
* Built key-by-key rather than passed through, because the driver dispatches
|
|
358
|
+
* on `"selector" in args` BEFORE `"event" in args` — an explicitly-`undefined`
|
|
359
|
+
* `selector` key would still win that check and silently wait on nothing.
|
|
360
|
+
*/
|
|
361
|
+
function toWaitArgs(c) {
|
|
362
|
+
if (typeof c.selector === "string")
|
|
363
|
+
return { selector: c.selector };
|
|
364
|
+
if (typeof c.event === "string")
|
|
365
|
+
return { event: c.event };
|
|
366
|
+
if (c.idle)
|
|
367
|
+
return { idle: true };
|
|
368
|
+
return {};
|
|
369
|
+
}
|
|
272
370
|
server.registerTool("tui.wait_for", {
|
|
273
|
-
description: "
|
|
371
|
+
description: "Block until a selector matches, a LiveEvent of the given kind arrives, or the TUI is idle " +
|
|
372
|
+
"(all= requires every condition). Prefer this over polling: the wait resolves on the driver's " +
|
|
373
|
+
"own event stream, so a modal pause (event='askcard-open') or a sprint halt wakes it immediately.",
|
|
274
374
|
inputSchema: {
|
|
275
375
|
selector: z.string().max(500).optional(),
|
|
276
376
|
idle: z.boolean().optional(),
|
|
377
|
+
// The driver has always supported an `event` condition (buildCheck in
|
|
378
|
+
// driver.ts); only this MCP schema withheld it, so external agents fell
|
|
379
|
+
// back to polling a DB that never records askcard-open at all.
|
|
380
|
+
event: z.string().max(64).optional(),
|
|
277
381
|
all: z.array(z.object(waitConditionShape)).max(10).optional(),
|
|
278
|
-
|
|
382
|
+
// 10 min, matching the longest legitimate single wait (a council debate
|
|
383
|
+
// phase measured 119.5s, and an unattended /ideal sprint runs longer).
|
|
384
|
+
// At 60s a caller had to re-issue the wait repeatedly — polling wearing
|
|
385
|
+
// a wait_for costume.
|
|
386
|
+
timeoutMs: z.number().int().min(0).max(600_000).optional(),
|
|
279
387
|
},
|
|
280
388
|
}, async (input) => {
|
|
281
389
|
const d = getDriver();
|
|
282
390
|
if (!d)
|
|
283
391
|
return noDriver();
|
|
392
|
+
const args = input.all
|
|
393
|
+
? { all: input.all.map(toWaitArgs) }
|
|
394
|
+
: toWaitArgs(input);
|
|
395
|
+
if (typeof input.timeoutMs === "number")
|
|
396
|
+
args.timeoutMs = input.timeoutMs;
|
|
284
397
|
try {
|
|
285
|
-
await d.wait_for(
|
|
398
|
+
await d.wait_for(args);
|
|
286
399
|
return { content: [{ type: "text", text: "ok" }] };
|
|
287
400
|
}
|
|
288
401
|
catch (e) {
|
|
@@ -305,7 +418,17 @@ export function registerAsyncTools(server, getDriver, deps) {
|
|
|
305
418
|
return { content: [{ type: "text", text: String(ok) }] };
|
|
306
419
|
});
|
|
307
420
|
server.registerTool("tui.last_event", {
|
|
308
|
-
|
|
421
|
+
// Keyword-loaded on purpose: deferred-tool search matches this text, and
|
|
422
|
+
// the terse original ("Return the most recent event of the given kind")
|
|
423
|
+
// did not rank for "is the TUI waiting for input or hung" — the exact
|
|
424
|
+
// question it answers. An unfindable tool is an absent one.
|
|
425
|
+
description: "Check what a live run is doing: is it waiting on a human (kind='askcard-open' — the " +
|
|
426
|
+
"modal/prompt/approval question), what stage it reached (kind='sprint-stage'), did it " +
|
|
427
|
+
"fail or hang (kind='sprint-halt' / 'toast'), how the council progressed " +
|
|
428
|
+
"(kind='council-step'). Returns the most recent event of that kind with its FULL payload " +
|
|
429
|
+
"(null if none) — including the complete askcard question text, which tui.query truncates. " +
|
|
430
|
+
"Use this instead of polling a database or log file: modal pauses write no DB row, so a " +
|
|
431
|
+
"poller cannot tell 'waiting for a human' from 'hung'. Pair with tui.wait_for to block.",
|
|
309
432
|
// Full protocol event set (minus the idle sentinel) so an external agent can
|
|
310
433
|
// observe lifecycle events — council/sprint/route/askcard, not just toasts.
|
|
311
434
|
// The Driver accepts any kind; this enum is the MCP-boundary validation.
|
|
@@ -423,7 +546,9 @@ export function createMcpHarnessServer({ spawn }) {
|
|
|
423
546
|
isError: true,
|
|
424
547
|
};
|
|
425
548
|
}
|
|
426
|
-
|
|
549
|
+
// See buildChildEnv: merge process.env (keeps PATH so bun allocates the
|
|
550
|
+
// fd 3/4 transport) with caller keys, then strip dangerous vars.
|
|
551
|
+
const sanitizedEnv = buildChildEnv(input.env ?? {});
|
|
427
552
|
// Build final arg list.
|
|
428
553
|
const finalArgs = [...input.args];
|
|
429
554
|
if (input.mockLlmDir && !finalArgs.some((a) => a.startsWith("--mock-llm"))) {
|
|
@@ -459,22 +584,14 @@ export function createMcpHarnessServer({ spawn }) {
|
|
|
459
584
|
sendKey: (k) => sendLine(JSON.stringify({ op: "press", key: k })),
|
|
460
585
|
sendType: (t) => sendLine(JSON.stringify({ op: "type", text: t })),
|
|
461
586
|
});
|
|
587
|
+
// JSONL event sink for external milestone watchers — on by default, null
|
|
588
|
+
// only when MUONROI_HARNESS_EVENT_LOG explicitly disables it. Ephemeral
|
|
589
|
+
// kinds carry an at-emit visual snapshot so flash events aren't lost
|
|
590
|
+
// before an agent wakes. Path is reported by tui.capabilities.
|
|
591
|
+
const eventTee = createEventTee(() => driver.render_visual(), process.env["MUONROI_HARNESS_EVENT_LOG"]);
|
|
462
592
|
// onLine already delivers complete newline-stripped lines — no extra
|
|
463
593
|
// splitting required.
|
|
464
|
-
const unsub = onLine((
|
|
465
|
-
try {
|
|
466
|
-
const msg = JSON.parse(line);
|
|
467
|
-
if (msg.mode === "live")
|
|
468
|
-
driver._ingest({ kind: "frame", frame: msg });
|
|
469
|
-
else if (msg.t === "idle")
|
|
470
|
-
driver._ingest({ kind: "idle" });
|
|
471
|
-
else if (msg.t === "event")
|
|
472
|
-
driver._ingest({ kind: "event", event: msg });
|
|
473
|
-
}
|
|
474
|
-
catch {
|
|
475
|
-
// ignore malformed lines
|
|
476
|
-
}
|
|
477
|
-
});
|
|
594
|
+
const unsub = onLine(makeLineHandler(driver, eventTee));
|
|
478
595
|
spawnResult.exited.then(() => {
|
|
479
596
|
unsub();
|
|
480
597
|
if (currentPid === proc.pid) {
|
|
@@ -491,6 +608,37 @@ export function createMcpHarnessServer({ spawn }) {
|
|
|
491
608
|
registerAsyncTools(server, () => currentDriver, { onStop });
|
|
492
609
|
return server;
|
|
493
610
|
}
|
|
611
|
+
/**
|
|
612
|
+
* Build the onLine sidechannel handler: parse each JSON line, ingest frames /
|
|
613
|
+
* visuals / idle / events into the driver, and tee events to the optional JSONL
|
|
614
|
+
* sink. Extracted (and exported) so the frame/event/tee wiring is unit-testable
|
|
615
|
+
* without a live TUI or an MCP protocol handshake.
|
|
616
|
+
*
|
|
617
|
+
* @param driver the driver to ingest into (only _ingest is used).
|
|
618
|
+
* @param eventTee optional sink from createEventTee (null → no tee).
|
|
619
|
+
*/
|
|
620
|
+
export function makeLineHandler(driver, eventTee) {
|
|
621
|
+
return (line) => {
|
|
622
|
+
try {
|
|
623
|
+
const msg = JSON.parse(line);
|
|
624
|
+
if (msg.mode === "live")
|
|
625
|
+
driver._ingest({ kind: "frame", frame: msg });
|
|
626
|
+
else if (msg.mode === "visual")
|
|
627
|
+
driver._ingest({ kind: "visual", frame: msg });
|
|
628
|
+
else if (msg.t === "idle")
|
|
629
|
+
driver._ingest({ kind: "idle" });
|
|
630
|
+
else if (msg.t === "event") {
|
|
631
|
+
const event = msg;
|
|
632
|
+
driver._ingest({ kind: "event", event });
|
|
633
|
+
// Tee AFTER ingest so render_visual reflects the frame at this event.
|
|
634
|
+
eventTee?.(event);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
catch {
|
|
638
|
+
// ignore malformed lines
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
}
|
|
494
642
|
/**
|
|
495
643
|
* Run the MCP harness driver over stdio with the OpenTUI spawn implementation
|
|
496
644
|
* injected by the consumer.
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
export declare const PROTOCOL_VERSION: "0.4.0";
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Known accessibility-style roles for semantic blocks. Closed vocabulary —
|
|
4
|
+
* `Role` (below) additionally admits namespaced `x-*` custom roles so new UI
|
|
5
|
+
* surfaces can be introduced without a protocol version bump (additive-only).
|
|
6
|
+
*/
|
|
7
|
+
export type KnownRole = "dialog" | "textbox" | "listbox" | "listitem" | "button" | "checkbox" | "radio" | "radiogroup" | "tab" | "tablist" | "tree" | "treeitem" | "table" | "row" | "cell" | "progressbar" | "spinner" | "log" | "statusbar" | "menu" | "menuitem" | "toast" | "tooltip" | "region" | "editor" | "diff" | "gutter" | "panel";
|
|
8
|
+
/**
|
|
9
|
+
* A semantic role. Either a well-known {@link KnownRole} or a namespaced
|
|
10
|
+
* `x-<custom>` role. The `x-` prefix keeps custom roles greppable and prevents
|
|
11
|
+
* silent collisions with future well-known roles — additive versioning via the
|
|
12
|
+
* `tui.capabilities` handshake rather than a breaking protocol bump.
|
|
13
|
+
*/
|
|
14
|
+
export type Role = KnownRole | `x-${string}`;
|
|
3
15
|
export type UINode = {
|
|
4
16
|
id: string;
|
|
5
17
|
role: Role;
|
|
@@ -23,6 +35,58 @@ export type LiveFrame = {
|
|
|
23
35
|
modals?: string[];
|
|
24
36
|
nodes: UINode[];
|
|
25
37
|
};
|
|
38
|
+
/**
|
|
39
|
+
* Text-attribute bit flags in {@link VisualSpan.attrs}. Mirrors the low byte of
|
|
40
|
+
* OpenTUI's `TextAttributes` (`ATTRIBUTE_BASE_MASK = 255`), so a consumer can
|
|
41
|
+
* decode `attrs & VisualAttr.BOLD` etc. without importing the renderer.
|
|
42
|
+
*/
|
|
43
|
+
export declare const VisualAttr: {
|
|
44
|
+
readonly BOLD: 1;
|
|
45
|
+
readonly DIM: 2;
|
|
46
|
+
readonly ITALIC: 4;
|
|
47
|
+
readonly UNDERLINE: 8;
|
|
48
|
+
readonly BLINK: 16;
|
|
49
|
+
readonly INVERSE: 32;
|
|
50
|
+
readonly HIDDEN: 64;
|
|
51
|
+
readonly STRIKETHROUGH: 128;
|
|
52
|
+
};
|
|
53
|
+
/** One coalesced run of identically-styled cells on a visual line. */
|
|
54
|
+
export type VisualSpan = {
|
|
55
|
+
/** The run's text (wide-char continuation cells omitted; `width` reflects columns). */
|
|
56
|
+
text: string;
|
|
57
|
+
/** Foreground color as "#rrggbb" (or "#rrggbbaa" when alpha < 255). */
|
|
58
|
+
fg: string;
|
|
59
|
+
/** Background color as "#rrggbb" (or "#rrggbbaa"). */
|
|
60
|
+
bg: string;
|
|
61
|
+
/** Text-attribute bitmask — decode with {@link VisualAttr}. */
|
|
62
|
+
attrs: number;
|
|
63
|
+
/** Display columns this run occupies (accounts for wide CJK/emoji). */
|
|
64
|
+
width: number;
|
|
65
|
+
};
|
|
66
|
+
/** One row of the rendered grid, as style-coalesced spans. */
|
|
67
|
+
export type VisualLine = {
|
|
68
|
+
spans: VisualSpan[];
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Ground-truth snapshot of the ACTUAL rendered terminal cell grid — the real
|
|
72
|
+
* characters, colors, and attributes OpenTUI painted, read directly from
|
|
73
|
+
* `CliRenderer.currentRenderBuffer.getSpanLines()`. Unlike {@link LiveFrame}
|
|
74
|
+
* (semantic structure), this is what a human SEES on screen. No OCR — the cell
|
|
75
|
+
* buffer is authoritative. Emitted on the same sidechannel as LiveFrame,
|
|
76
|
+
* deduped by content hash, and (to bound `getSpanLines` allocation) only
|
|
77
|
+
* captured when a semantic frame also changes.
|
|
78
|
+
*/
|
|
79
|
+
export type VisualFrame = {
|
|
80
|
+
mode: "visual";
|
|
81
|
+
version: typeof PROTOCOL_VERSION;
|
|
82
|
+
seq: number;
|
|
83
|
+
ts: number;
|
|
84
|
+
cols: number;
|
|
85
|
+
rows: number;
|
|
86
|
+
/** Cursor [col, row], or null when hidden/unknown. */
|
|
87
|
+
cursor: [number, number] | null;
|
|
88
|
+
lines: VisualLine[];
|
|
89
|
+
};
|
|
26
90
|
export type LiveEvent = {
|
|
27
91
|
t: "event";
|
|
28
92
|
kind: "stream.delta";
|
|
@@ -67,12 +131,34 @@ export type LiveEvent = {
|
|
|
67
131
|
kind: "council-speaker";
|
|
68
132
|
/** The council role label (e.g. "architect", "security", "qa"). */
|
|
69
133
|
role: string;
|
|
70
|
-
/**
|
|
71
|
-
|
|
134
|
+
/**
|
|
135
|
+
* "start" — speaker began; "tick" — 1s progress heartbeat (long phases
|
|
136
|
+
* like research emit these with an advancing `elapsedMs`); "done" —
|
|
137
|
+
* speaker finished. A harness poller distinguishes ALIVE (tick with
|
|
138
|
+
* advancing elapsedMs) from HUNG (elapsedMs frozen) via `tui_last_event`.
|
|
139
|
+
*/
|
|
140
|
+
status: "start" | "tick" | "done";
|
|
72
141
|
/** Round number if available from the status chunk. */
|
|
73
142
|
round?: number;
|
|
74
143
|
/** Correlation ID linking this speaker event to the enclosing council run. */
|
|
75
144
|
correlationId: string;
|
|
145
|
+
/** Milliseconds elapsed in this speaker's turn/phase; advances on ticks. */
|
|
146
|
+
elapsedMs?: number;
|
|
147
|
+
/**
|
|
148
|
+
* Chars (text + reasoning deltas) streamed since this phase began.
|
|
149
|
+
* `elapsedMs` can freeze on a HEALTHY call — its tick generator only
|
|
150
|
+
* advances when the consumer pulls, and a round awaiting its pairs via
|
|
151
|
+
* Promise.all does not pull. This counter is pushed from the token stream
|
|
152
|
+
* itself, so growth here proves liveness regardless of pumping.
|
|
153
|
+
*/
|
|
154
|
+
streamedChars?: number;
|
|
155
|
+
/**
|
|
156
|
+
* Age in ms of the most recent stream delta. Small + growing
|
|
157
|
+
* `streamedChars` = SLOW BUT ALIVE (e.g. a reasoning model emitting
|
|
158
|
+
* reasoning tokens for minutes before any text); growing age + static
|
|
159
|
+
* chars = genuinely STUCK.
|
|
160
|
+
*/
|
|
161
|
+
lastDeltaAgeMs?: number;
|
|
76
162
|
} | {
|
|
77
163
|
t: "event";
|
|
78
164
|
kind: "council-turn-length";
|
|
@@ -226,4 +312,4 @@ export type DesignSpec = {
|
|
|
226
312
|
notes?: string;
|
|
227
313
|
}>;
|
|
228
314
|
};
|
|
229
|
-
export type HarnessMessage = LiveFrame | LiveEvent;
|
|
315
|
+
export type HarnessMessage = LiveFrame | VisualFrame | LiveEvent;
|
|
@@ -1,2 +1,17 @@
|
|
|
1
1
|
export const PROTOCOL_VERSION = "0.4.0";
|
|
2
|
+
/**
|
|
3
|
+
* Text-attribute bit flags in {@link VisualSpan.attrs}. Mirrors the low byte of
|
|
4
|
+
* OpenTUI's `TextAttributes` (`ATTRIBUTE_BASE_MASK = 255`), so a consumer can
|
|
5
|
+
* decode `attrs & VisualAttr.BOLD` etc. without importing the renderer.
|
|
6
|
+
*/
|
|
7
|
+
export const VisualAttr = {
|
|
8
|
+
BOLD: 1,
|
|
9
|
+
DIM: 2,
|
|
10
|
+
ITALIC: 4,
|
|
11
|
+
UNDERLINE: 8,
|
|
12
|
+
BLINK: 16,
|
|
13
|
+
INVERSE: 32,
|
|
14
|
+
HIDDEN: 64,
|
|
15
|
+
STRIKETHROUGH: 128,
|
|
16
|
+
};
|
|
2
17
|
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* visual-quality.ts — programmatic visual-quality heuristics over a VisualFrame.
|
|
3
|
+
*
|
|
4
|
+
* P1 of Harness TUI v2. Given the ground-truth rendered cell grid, compute cheap
|
|
5
|
+
* ground-truth signals a human would call "messy" — WITHOUT a vision model:
|
|
6
|
+
* - blank / near-blank row ratios (the council "↳" + "· Skip" garbage)
|
|
7
|
+
* - long runs of consecutive blank rows (dead space)
|
|
8
|
+
* - whitespace density
|
|
9
|
+
* - mojibake (U+FFFD replacement chars + misdecoded-UTF8 clusters like `💡`)
|
|
10
|
+
*
|
|
11
|
+
* These are the exact defects the semantic tree (LiveFrame) is blind to — the
|
|
12
|
+
* 2217600e1f27 export had 12 near-empty rows + mojibake that no existing
|
|
13
|
+
* self-verify check could see. A composite `score` + `issues[]` lets self-QA
|
|
14
|
+
* fail a render regression automatically.
|
|
15
|
+
*
|
|
16
|
+
* Thresholds are conservative defaults; tune per surface. This is a heuristic,
|
|
17
|
+
* not a proof — a low score flags "look closer", it does not assert a bug.
|
|
18
|
+
*/
|
|
19
|
+
import type { VisualFrame } from "./protocol.js";
|
|
20
|
+
export interface VisualQualityThresholds {
|
|
21
|
+
/** Rows with <= this many non-space chars count as "near-empty". */
|
|
22
|
+
nearEmptyMaxChars: number;
|
|
23
|
+
/** Flag when the near-empty-row ratio exceeds this. */
|
|
24
|
+
nearEmptyRowPct: number;
|
|
25
|
+
/** Flag when consecutive blank rows exceed this run length. */
|
|
26
|
+
maxConsecutiveBlankRows: number;
|
|
27
|
+
/** Flag when any mojibake is detected at/above this count. */
|
|
28
|
+
mojibakeCount: number;
|
|
29
|
+
/** Flag when whitespace density exceeds this fraction. */
|
|
30
|
+
whitespacePct: number;
|
|
31
|
+
}
|
|
32
|
+
export declare const DEFAULT_VISUAL_QUALITY_THRESHOLDS: VisualQualityThresholds;
|
|
33
|
+
export interface VisualQualityReport {
|
|
34
|
+
rows: number;
|
|
35
|
+
cols: number;
|
|
36
|
+
/** Non-space characters across the whole grid. */
|
|
37
|
+
contentChars: number;
|
|
38
|
+
/** Rows that are entirely whitespace. */
|
|
39
|
+
blankRows: number;
|
|
40
|
+
/** Rows with 1..nearEmptyMaxChars non-space chars (skeleton noise). */
|
|
41
|
+
nearEmptyRows: number;
|
|
42
|
+
nearEmptyRowPct: number;
|
|
43
|
+
/** Longest run of consecutive fully-blank rows. */
|
|
44
|
+
maxConsecutiveBlankRows: number;
|
|
45
|
+
whitespacePct: number;
|
|
46
|
+
/** Count of mojibake signals (U+FFFD + misdecoded-UTF8 clusters). */
|
|
47
|
+
mojibakeCount: number;
|
|
48
|
+
/** Sample of offending text fragments (for diagnostics). */
|
|
49
|
+
mojibakeSamples: string[];
|
|
50
|
+
/** 0-100 composite; lower = messier. */
|
|
51
|
+
score: number;
|
|
52
|
+
/** Human-readable problems that tripped a threshold. */
|
|
53
|
+
issues: string[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Compute visual-quality signals for a rendered frame. Pure + deterministic.
|
|
57
|
+
*/
|
|
58
|
+
export declare function computeVisualQuality(frame: VisualFrame, thresholds?: VisualQualityThresholds): VisualQualityReport;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* visual-quality.ts — programmatic visual-quality heuristics over a VisualFrame.
|
|
3
|
+
*
|
|
4
|
+
* P1 of Harness TUI v2. Given the ground-truth rendered cell grid, compute cheap
|
|
5
|
+
* ground-truth signals a human would call "messy" — WITHOUT a vision model:
|
|
6
|
+
* - blank / near-blank row ratios (the council "↳" + "· Skip" garbage)
|
|
7
|
+
* - long runs of consecutive blank rows (dead space)
|
|
8
|
+
* - whitespace density
|
|
9
|
+
* - mojibake (U+FFFD replacement chars + misdecoded-UTF8 clusters like `💡`)
|
|
10
|
+
*
|
|
11
|
+
* These are the exact defects the semantic tree (LiveFrame) is blind to — the
|
|
12
|
+
* 2217600e1f27 export had 12 near-empty rows + mojibake that no existing
|
|
13
|
+
* self-verify check could see. A composite `score` + `issues[]` lets self-QA
|
|
14
|
+
* fail a render regression automatically.
|
|
15
|
+
*
|
|
16
|
+
* Thresholds are conservative defaults; tune per surface. This is a heuristic,
|
|
17
|
+
* not a proof — a low score flags "look closer", it does not assert a bug.
|
|
18
|
+
*/
|
|
19
|
+
export const DEFAULT_VISUAL_QUALITY_THRESHOLDS = {
|
|
20
|
+
nearEmptyMaxChars: 2,
|
|
21
|
+
nearEmptyRowPct: 0.5,
|
|
22
|
+
maxConsecutiveBlankRows: 4,
|
|
23
|
+
mojibakeCount: 1,
|
|
24
|
+
whitespacePct: 0.92,
|
|
25
|
+
};
|
|
26
|
+
// Characters that legitimately never (or almost never) appear in this TUI but
|
|
27
|
+
// are produced when UTF-8 bytes are re-decoded as CP437/latin1. Presence in a
|
|
28
|
+
// 2+ cluster is a strong mojibake signal (e.g. 💡 → "≡ƒÆí", em-dash → "ΓÇô").
|
|
29
|
+
const MOJIBAKE_SIGNAL = new Set([
|
|
30
|
+
..."≡ƒÆÇÃÂ’ÿÖÜúÑŒ¬".split(""),
|
|
31
|
+
"�", // replacement char
|
|
32
|
+
]);
|
|
33
|
+
function rowText(line) {
|
|
34
|
+
return line.spans.map((s) => s.text).join("");
|
|
35
|
+
}
|
|
36
|
+
function countMojibake(text) {
|
|
37
|
+
let count = 0;
|
|
38
|
+
let sample;
|
|
39
|
+
// Definitive: U+FFFD replacement chars.
|
|
40
|
+
for (const ch of text) {
|
|
41
|
+
if (ch === "�")
|
|
42
|
+
count++;
|
|
43
|
+
}
|
|
44
|
+
// Clusters of 2+ consecutive signal chars — mojibake arrives in runs, which
|
|
45
|
+
// keeps ordinary accented text (single é, ü) from tripping the heuristic.
|
|
46
|
+
const chars = [...text];
|
|
47
|
+
let run = 0;
|
|
48
|
+
for (let i = 0; i <= chars.length; i++) {
|
|
49
|
+
const isSignal = i < chars.length && MOJIBAKE_SIGNAL.has(chars[i]) && chars[i] !== "�";
|
|
50
|
+
if (isSignal) {
|
|
51
|
+
run++;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
if (run >= 2) {
|
|
55
|
+
count += run;
|
|
56
|
+
if (!sample)
|
|
57
|
+
sample = chars.slice(Math.max(0, i - run - 4), i + 2).join("");
|
|
58
|
+
}
|
|
59
|
+
run = 0;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return { count, sample };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Compute visual-quality signals for a rendered frame. Pure + deterministic.
|
|
66
|
+
*/
|
|
67
|
+
export function computeVisualQuality(frame, thresholds = DEFAULT_VISUAL_QUALITY_THRESHOLDS) {
|
|
68
|
+
const rows = frame.lines.length;
|
|
69
|
+
const cols = frame.cols;
|
|
70
|
+
let contentChars = 0;
|
|
71
|
+
let totalCells = 0;
|
|
72
|
+
let blankRows = 0;
|
|
73
|
+
let nearEmptyRows = 0;
|
|
74
|
+
let maxConsecutiveBlankRows = 0;
|
|
75
|
+
let curBlankRun = 0;
|
|
76
|
+
let mojibakeCount = 0;
|
|
77
|
+
const mojibakeSamples = [];
|
|
78
|
+
for (const line of frame.lines) {
|
|
79
|
+
const text = rowText(line);
|
|
80
|
+
const nonSpace = [...text].filter((c) => c.trim().length > 0).length;
|
|
81
|
+
contentChars += nonSpace;
|
|
82
|
+
totalCells += Math.max(text.length, cols);
|
|
83
|
+
if (nonSpace === 0) {
|
|
84
|
+
blankRows++;
|
|
85
|
+
curBlankRun++;
|
|
86
|
+
maxConsecutiveBlankRows = Math.max(maxConsecutiveBlankRows, curBlankRun);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
curBlankRun = 0;
|
|
90
|
+
}
|
|
91
|
+
// "Low-content" rows = blank OR only a glyph or two (skeleton noise like the
|
|
92
|
+
// council "↳" / "· Skip" rows, and the blank separators between them). Both
|
|
93
|
+
// are visual garbage, so they count together against the total row budget.
|
|
94
|
+
if (nonSpace <= thresholds.nearEmptyMaxChars)
|
|
95
|
+
nearEmptyRows++;
|
|
96
|
+
const mj = countMojibake(text);
|
|
97
|
+
if (mj.count > 0) {
|
|
98
|
+
mojibakeCount += mj.count;
|
|
99
|
+
if (mj.sample && mojibakeSamples.length < 5)
|
|
100
|
+
mojibakeSamples.push(mj.sample);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Ratio of low-content (blank or near-empty) rows over the whole frame.
|
|
104
|
+
const nearEmptyRowPct = rows > 0 ? nearEmptyRows / rows : 0;
|
|
105
|
+
const whitespacePct = totalCells > 0 ? 1 - contentChars / totalCells : 1;
|
|
106
|
+
const issues = [];
|
|
107
|
+
if (nearEmptyRowPct > thresholds.nearEmptyRowPct) {
|
|
108
|
+
issues.push(`${nearEmptyRows}/${rows} rows are blank or near-empty (<=${thresholds.nearEmptyMaxChars} chars) — skeleton/garbage rows`);
|
|
109
|
+
}
|
|
110
|
+
if (maxConsecutiveBlankRows > thresholds.maxConsecutiveBlankRows) {
|
|
111
|
+
issues.push(`${maxConsecutiveBlankRows} consecutive blank rows — large dead gap`);
|
|
112
|
+
}
|
|
113
|
+
if (mojibakeCount >= thresholds.mojibakeCount) {
|
|
114
|
+
issues.push(`${mojibakeCount} mojibake signal(s) detected (misdecoded UTF-8 / U+FFFD)${mojibakeSamples.length ? ` e.g. ${JSON.stringify(mojibakeSamples[0])}` : ""}`);
|
|
115
|
+
}
|
|
116
|
+
if (whitespacePct > thresholds.whitespacePct && contentChars > 0) {
|
|
117
|
+
issues.push(`${(whitespacePct * 100).toFixed(0)}% of the grid is whitespace — very sparse render`);
|
|
118
|
+
}
|
|
119
|
+
// Composite score: start at 100, subtract weighted penalties.
|
|
120
|
+
let score = 100;
|
|
121
|
+
score -= Math.min(40, Math.round(nearEmptyRowPct * 60));
|
|
122
|
+
score -= Math.min(25, Math.max(0, maxConsecutiveBlankRows - thresholds.maxConsecutiveBlankRows) * 4);
|
|
123
|
+
score -= Math.min(30, mojibakeCount * 6);
|
|
124
|
+
score -= whitespacePct > thresholds.whitespacePct ? 10 : 0;
|
|
125
|
+
score = Math.max(0, Math.min(100, score));
|
|
126
|
+
return {
|
|
127
|
+
rows,
|
|
128
|
+
cols,
|
|
129
|
+
contentChars,
|
|
130
|
+
blankRows,
|
|
131
|
+
nearEmptyRows,
|
|
132
|
+
nearEmptyRowPct,
|
|
133
|
+
maxConsecutiveBlankRows,
|
|
134
|
+
whitespacePct,
|
|
135
|
+
mojibakeCount,
|
|
136
|
+
mojibakeSamples,
|
|
137
|
+
score,
|
|
138
|
+
issues,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=visual-quality.js.map
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import type { LiveEvent } from "@muonroi/agent-harness-core/protocol";
|
|
19
19
|
import type { SemanticRegistry } from "./reconciler-hook.js";
|
|
20
|
+
import { type RendererLike } from "./visual-capture.js";
|
|
20
21
|
export type AgentModeOptions = {
|
|
21
22
|
cols: number;
|
|
22
23
|
rows: number;
|
|
@@ -40,6 +41,11 @@ export type AgentModeRuntime = {
|
|
|
40
41
|
onCommand: (h: (cmd: unknown) => void) => void;
|
|
41
42
|
/** Get the current timestamp (real or fake clock). */
|
|
42
43
|
now: () => number;
|
|
44
|
+
/**
|
|
45
|
+
* Attach the OpenTUI renderer once it exists (constructed AFTER this runtime
|
|
46
|
+
* — see src/index.ts). Enables VisualFrame capture of the real cell grid.
|
|
47
|
+
*/
|
|
48
|
+
attachRenderer: (renderer: RendererLike) => void;
|
|
43
49
|
/** Tear down: close streams, dispose idle detector. */
|
|
44
50
|
dispose: () => void;
|
|
45
51
|
};
|