muonroi-cli 1.8.3 → 1.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +133 -122
- 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-tee.d.ts +48 -0
- package/dist/packages/agent-harness-core/src/event-tee.js +77 -0
- package/dist/packages/agent-harness-core/src/mcp-server.d.ts +11 -0
- package/dist/packages/agent-harness-core/src/mcp-server.js +87 -15
- package/dist/packages/agent-harness-core/src/protocol.d.ts +66 -2
- 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 +28 -0
- package/dist/src/agent-harness/mock-model.js +63 -1
- package/dist/src/agent-harness/test-spawn.js +31 -0
- 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 +30 -15
- 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 +2 -2
- package/dist/src/cli/keys.js +19 -81
- package/dist/src/council/clarifier.d.ts +28 -2
- package/dist/src/council/clarifier.js +81 -15
- 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 +51 -3
- 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 +1210 -134
- package/dist/src/council/index.d.ts +85 -1
- package/dist/src/council/index.js +634 -196
- package/dist/src/council/leader.d.ts +26 -0
- package/dist/src/council/leader.js +150 -9
- package/dist/src/council/llm.d.ts +32 -0
- package/dist/src/council/llm.js +231 -38
- package/dist/src/council/panel-select.d.ts +30 -0
- package/dist/src/council/panel-select.js +72 -0
- package/dist/src/council/planner.js +23 -0
- package/dist/src/council/preflight.d.ts +7 -0
- package/dist/src/council/preflight.js +14 -2
- package/dist/src/council/prompts.d.ts +30 -3
- package/dist/src/council/prompts.js +254 -84
- 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 +128 -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 +1 -0
- package/dist/src/ee/auth.js +15 -2
- package/dist/src/ee/bridge.d.ts +10 -0
- package/dist/src/ee/bridge.js +58 -0
- package/dist/src/ee/client.js +81 -18
- 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 +45 -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 +13 -1
- package/dist/src/flow/compaction/index.js +70 -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/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 +55 -0
- package/dist/src/gsd/flags.js +83 -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 +251 -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/hooks/index.js +1 -1
- package/dist/src/index.js +44 -11
- 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 +1 -1
- package/dist/src/mcp/ee-tools.js +1 -0
- package/dist/src/mcp/oauth-callback.js +2 -2
- 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 +77 -76
- 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 +8 -8
- 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 +10 -0
- package/dist/src/orchestrator/compaction.js +27 -7
- package/dist/src/orchestrator/council-manager.d.ts +12 -3
- package/dist/src/orchestrator/council-manager.js +65 -24
- 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/message-processor.js +242 -33
- package/dist/src/orchestrator/orchestrator.d.ts +39 -3
- package/dist/src/orchestrator/orchestrator.js +651 -102
- package/dist/src/orchestrator/preprocessor.js +1 -1
- 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 +159 -159
- 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-intercept.d.ts +45 -0
- package/dist/src/orchestrator/safety-intercept.js +55 -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 +24 -3
- package/dist/src/orchestrator/stall-watchdog.js +47 -13
- package/dist/src/orchestrator/stream-runner.js +62 -29
- 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 +26 -0
- package/dist/src/orchestrator/tool-engine.js +669 -56
- 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 +37 -0
- package/dist/src/orchestrator/turn-watchdog.js +55 -0
- package/dist/src/pil/agent-operating-contract.d.ts +1 -1
- package/dist/src/pil/agent-operating-contract.js +1 -1
- 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.js +16 -11
- 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/layer2_5-ponytail.js +8 -8
- 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 +33 -2
- package/dist/src/pil/llm-classify.js +123 -131
- package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
- package/dist/src/pil/native-capabilities-workbook.js +1 -0
- package/dist/src/pil/pipeline.js +34 -2
- 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/backlog-builder.d.ts +14 -1
- package/dist/src/product-loop/backlog-builder.js +30 -6
- 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.js +32 -3
- package/dist/src/product-loop/discovery-schema.js +5 -1
- package/dist/src/product-loop/done-gate.js +3 -3
- 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 +333 -52
- package/dist/src/product-loop/loop-driver.d.ts +7 -0
- package/dist/src/product-loop/loop-driver.js +327 -116
- package/dist/src/product-loop/phase-plan.d.ts +5 -0
- package/dist/src/product-loop/phase-plan.js +39 -2
- package/dist/src/product-loop/phase-runner.js +9 -1
- package/dist/src/product-loop/progress-snapshot.js +4 -4
- package/dist/src/product-loop/sprint-runner.d.ts +111 -0
- package/dist/src/product-loop/sprint-runner.js +559 -16
- package/dist/src/product-loop/types.d.ts +36 -5
- package/dist/src/providers/adapter.d.ts +1 -1
- package/dist/src/providers/adapter.js +3 -4
- 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/openai-oauth.js +1 -1
- package/dist/src/providers/auth/registry.js +0 -34
- package/dist/src/providers/auth/token-store.js +4 -1
- package/dist/src/providers/auth/types.d.ts +1 -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/keychain.d.ts +1 -1
- package/dist/src/providers/keychain.js +7 -9
- package/dist/src/providers/mcp-vision-bridge.js +82 -172
- 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 +27 -2
- package/dist/src/providers/runtime.js +78 -15
- 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 +280 -1
- 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/wire-debug.js +95 -0
- package/dist/src/reporter/index.js +1 -1
- 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/bb-ecosystem-apply.js +47 -47
- package/dist/src/scaffold/bb-quality-gate.js +5 -5
- package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
- package/dist/src/scaffold/continuation-prompt.js +86 -60
- package/dist/src/scaffold/init-new.js +453 -453
- 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 +22 -22
- 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/interaction-log.js +5 -5
- package/dist/src/storage/migrations.js +196 -126
- package/dist/src/storage/session-experience-store.js +4 -4
- package/dist/src/storage/sessions.d.ts +28 -10
- package/dist/src/storage/sessions.js +112 -55
- package/dist/src/storage/transcript-view.js +1 -1
- package/dist/src/storage/transcript.d.ts +51 -0
- package/dist/src/storage/transcript.js +383 -112
- package/dist/src/storage/usage.js +14 -14
- package/dist/src/storage/workspaces.js +12 -12
- package/dist/src/tools/file.d.ts +15 -0
- package/dist/src/tools/file.js +32 -0
- package/dist/src/tools/native-tools.js +5 -0
- package/dist/src/tools/registry.d.ts +3 -0
- package/dist/src/tools/registry.js +460 -22
- package/dist/src/tools/research.d.ts +29 -0
- package/dist/src/tools/research.js +233 -0
- package/dist/src/types/index.d.ts +118 -3
- package/dist/src/ui/app.js +0 -0
- package/dist/src/ui/cards/product-status-card.js +1 -1
- 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/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 +49 -15
- 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 +12 -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/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/containers/modals-layer.d.ts +2 -1
- 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/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-inspect.js +4 -4
- 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/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 +12 -18
- 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/format.d.ts +14 -0
- package/dist/src/ui/utils/format.js +23 -3
- package/dist/src/usage/downgrade.js +2 -2
- package/dist/src/usage/product-ledger.js +2 -2
- package/dist/src/utils/clipboard-image.js +23 -23
- package/dist/src/utils/install-manager.js +14 -11
- package/dist/src/utils/logger.js +2 -2
- package/dist/src/utils/permission-mode.js +5 -3
- package/dist/src/utils/redactor.js +1 -1
- package/dist/src/utils/settings.d.ts +153 -5
- package/dist/src/utils/settings.js +233 -29
- package/dist/src/utils/side-question.js +2 -2
- package/dist/src/utils/skills.js +3 -3
- 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 +1 -1
- package/dist/src/verify/recipes.d.ts +13 -0
- package/dist/src/verify/recipes.js +15 -0
- package/package.json +135 -132
- 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 } 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}$/;
|
|
@@ -133,7 +134,20 @@ export function validateMockLlmPath(value) {
|
|
|
133
134
|
const sep = process.platform === "win32" ? "\\" : "/";
|
|
134
135
|
return real === root || real.startsWith(root + sep);
|
|
135
136
|
}
|
|
136
|
-
const FEATURES = [
|
|
137
|
+
const FEATURES = [
|
|
138
|
+
"capabilities",
|
|
139
|
+
"snapshot",
|
|
140
|
+
"press",
|
|
141
|
+
"type",
|
|
142
|
+
"wait_for",
|
|
143
|
+
"query",
|
|
144
|
+
"expect",
|
|
145
|
+
"render_text",
|
|
146
|
+
"render_visual",
|
|
147
|
+
"snapshot_visual",
|
|
148
|
+
"cell",
|
|
149
|
+
"visual_quality",
|
|
150
|
+
];
|
|
137
151
|
export function buildCapabilitiesPayload() {
|
|
138
152
|
return {
|
|
139
153
|
protocol: PROTOCOL_VERSION,
|
|
@@ -203,6 +217,42 @@ export function registerReadTools(server, getDriver) {
|
|
|
203
217
|
return noDriver();
|
|
204
218
|
return { content: [{ type: "text", text: d.render_text() }] };
|
|
205
219
|
});
|
|
220
|
+
server.registerTool("tui.render_visual", {
|
|
221
|
+
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.",
|
|
222
|
+
inputSchema: {},
|
|
223
|
+
}, async () => {
|
|
224
|
+
const d = getDriver();
|
|
225
|
+
if (!d)
|
|
226
|
+
return noDriver();
|
|
227
|
+
return { content: [{ type: "text", text: d.render_visual() }] };
|
|
228
|
+
});
|
|
229
|
+
server.registerTool("tui.snapshot_visual", {
|
|
230
|
+
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.",
|
|
231
|
+
inputSchema: {},
|
|
232
|
+
}, async () => {
|
|
233
|
+
const d = getDriver();
|
|
234
|
+
if (!d)
|
|
235
|
+
return noDriver();
|
|
236
|
+
return { content: [{ type: "text", text: JSON.stringify(d.snapshot_visual()) }] };
|
|
237
|
+
});
|
|
238
|
+
server.registerTool("tui.cell", {
|
|
239
|
+
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.",
|
|
240
|
+
inputSchema: { row: z.number().int().min(0), col: z.number().int().min(0) },
|
|
241
|
+
}, async ({ row, col }) => {
|
|
242
|
+
const d = getDriver();
|
|
243
|
+
if (!d)
|
|
244
|
+
return noDriver();
|
|
245
|
+
return { content: [{ type: "text", text: JSON.stringify(d.visual_cell(row, col)) }] };
|
|
246
|
+
});
|
|
247
|
+
server.registerTool("tui.visual_quality", {
|
|
248
|
+
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.",
|
|
249
|
+
inputSchema: {},
|
|
250
|
+
}, async () => {
|
|
251
|
+
const d = getDriver();
|
|
252
|
+
if (!d)
|
|
253
|
+
return noDriver();
|
|
254
|
+
return { content: [{ type: "text", text: JSON.stringify(d.visual_quality()) }] };
|
|
255
|
+
});
|
|
206
256
|
}
|
|
207
257
|
export function registerActionTools(server, getDriver) {
|
|
208
258
|
const noDriver = () => ({
|
|
@@ -459,22 +509,13 @@ export function createMcpHarnessServer({ spawn }) {
|
|
|
459
509
|
sendKey: (k) => sendLine(JSON.stringify({ op: "press", key: k })),
|
|
460
510
|
sendType: (t) => sendLine(JSON.stringify({ op: "type", text: t })),
|
|
461
511
|
});
|
|
512
|
+
// Optional JSONL event sink for external milestone watchers (null unless
|
|
513
|
+
// MUONROI_HARNESS_EVENT_LOG is set). Ephemeral kinds carry an at-emit
|
|
514
|
+
// visual snapshot so flash events aren't lost before an agent wakes.
|
|
515
|
+
const eventTee = createEventTee(() => driver.render_visual(), process.env["MUONROI_HARNESS_EVENT_LOG"]);
|
|
462
516
|
// onLine already delivers complete newline-stripped lines — no extra
|
|
463
517
|
// 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
|
-
});
|
|
518
|
+
const unsub = onLine(makeLineHandler(driver, eventTee));
|
|
478
519
|
spawnResult.exited.then(() => {
|
|
479
520
|
unsub();
|
|
480
521
|
if (currentPid === proc.pid) {
|
|
@@ -491,6 +532,37 @@ export function createMcpHarnessServer({ spawn }) {
|
|
|
491
532
|
registerAsyncTools(server, () => currentDriver, { onStop });
|
|
492
533
|
return server;
|
|
493
534
|
}
|
|
535
|
+
/**
|
|
536
|
+
* Build the onLine sidechannel handler: parse each JSON line, ingest frames /
|
|
537
|
+
* visuals / idle / events into the driver, and tee events to the optional JSONL
|
|
538
|
+
* sink. Extracted (and exported) so the frame/event/tee wiring is unit-testable
|
|
539
|
+
* without a live TUI or an MCP protocol handshake.
|
|
540
|
+
*
|
|
541
|
+
* @param driver the driver to ingest into (only _ingest is used).
|
|
542
|
+
* @param eventTee optional sink from createEventTee (null → no tee).
|
|
543
|
+
*/
|
|
544
|
+
export function makeLineHandler(driver, eventTee) {
|
|
545
|
+
return (line) => {
|
|
546
|
+
try {
|
|
547
|
+
const msg = JSON.parse(line);
|
|
548
|
+
if (msg.mode === "live")
|
|
549
|
+
driver._ingest({ kind: "frame", frame: msg });
|
|
550
|
+
else if (msg.mode === "visual")
|
|
551
|
+
driver._ingest({ kind: "visual", frame: msg });
|
|
552
|
+
else if (msg.t === "idle")
|
|
553
|
+
driver._ingest({ kind: "idle" });
|
|
554
|
+
else if (msg.t === "event") {
|
|
555
|
+
const event = msg;
|
|
556
|
+
driver._ingest({ kind: "event", event });
|
|
557
|
+
// Tee AFTER ingest so render_visual reflects the frame at this event.
|
|
558
|
+
eventTee?.(event);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
catch {
|
|
562
|
+
// ignore malformed lines
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
}
|
|
494
566
|
/**
|
|
495
567
|
* Run the MCP harness driver over stdio with the OpenTUI spawn implementation
|
|
496
568
|
* 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";
|
|
@@ -226,4 +290,4 @@ export type DesignSpec = {
|
|
|
226
290
|
notes?: string;
|
|
227
291
|
}>;
|
|
228
292
|
};
|
|
229
|
-
export type HarnessMessage = LiveFrame | LiveEvent;
|
|
293
|
+
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
|
};
|
|
@@ -22,6 +22,7 @@ import { createIdleDetector } from "@muonroi/agent-harness-core/idle";
|
|
|
22
22
|
import { createLineSplitter, createSidechannelWriter } from "@muonroi/agent-harness-core/transports/sidechannel";
|
|
23
23
|
import { installOpenTUIHarness } from "./install.js";
|
|
24
24
|
import { createSemanticRegistry } from "./reconciler-hook.js";
|
|
25
|
+
import { createVisualCaptureHook } from "./visual-capture.js";
|
|
25
26
|
// ---------------------------------------------------------------------------
|
|
26
27
|
// Factory
|
|
27
28
|
// ---------------------------------------------------------------------------
|
|
@@ -90,6 +91,11 @@ export async function startAgentMode(opts) {
|
|
|
90
91
|
const now = () => (opts.fakeClock ? 0 : Date.now());
|
|
91
92
|
// --- Semantic registry ---------------------------------------------------
|
|
92
93
|
const registry = createSemanticRegistry();
|
|
94
|
+
// --- Visual capture (real rendered cell grid) ----------------------------
|
|
95
|
+
// The renderer does not exist yet — it is constructed after this runtime and
|
|
96
|
+
// handed back via attachRenderer(). The hook reads it late-bound.
|
|
97
|
+
let rendererRef;
|
|
98
|
+
const visualHook = createVisualCaptureHook(() => rendererRef);
|
|
93
99
|
// --- Idle detector -------------------------------------------------------
|
|
94
100
|
const idle = createIdleDetector({
|
|
95
101
|
quiescenceMs: opts.idleMs,
|
|
@@ -116,6 +122,9 @@ export async function startAgentMode(opts) {
|
|
|
116
122
|
// becomes deterministic (seq*16). Without this, ts = Date.now() and the
|
|
117
123
|
// determinism spec sees timestamps differ between runs.
|
|
118
124
|
fakeClock: opts.fakeClock,
|
|
125
|
+
// Emit a VisualFrame (real rendered cell grid) alongside each semantic
|
|
126
|
+
// change. No-op until attachRenderer() supplies the renderer.
|
|
127
|
+
captureVisual: (seq, ts) => visualHook.capture(seq, ts),
|
|
119
128
|
});
|
|
120
129
|
// --- Command channel (in stream → handlers) ------------------------------
|
|
121
130
|
const commandHandlers = [];
|
|
@@ -165,6 +174,10 @@ export async function startAgentMode(opts) {
|
|
|
165
174
|
const onCommand = (h) => {
|
|
166
175
|
commandHandlers.push(h);
|
|
167
176
|
};
|
|
177
|
+
const attachRenderer = (renderer) => {
|
|
178
|
+
rendererRef = renderer;
|
|
179
|
+
visualHook.resetDedup(); // force the first visual frame after attach
|
|
180
|
+
};
|
|
168
181
|
const dispose = () => {
|
|
169
182
|
harnessHandle.uninstall(); // stops poll interval; transport.close() ends outStream
|
|
170
183
|
idle.dispose();
|
|
@@ -173,6 +186,6 @@ export async function startAgentMode(opts) {
|
|
|
173
186
|
inStream.destroy();
|
|
174
187
|
}
|
|
175
188
|
};
|
|
176
|
-
return { registry, capture, emitEvent, onCommand, now, dispose };
|
|
189
|
+
return { registry, capture, emitEvent, onCommand, now, attachRenderer, dispose };
|
|
177
190
|
}
|
|
178
191
|
//# sourceMappingURL=agent-mode.js.map
|
|
@@ -13,15 +13,7 @@
|
|
|
13
13
|
* raw byte. We construct ParsedKey directly so we don't depend on terminal
|
|
14
14
|
* escape sequence conventions.
|
|
15
15
|
*/
|
|
16
|
+
import type { KeyEvent } from "@opentui/core";
|
|
16
17
|
import type { AgentModeRuntime } from "./agent-mode.js";
|
|
17
|
-
|
|
18
|
-
* Subscribe to agentRuntime.onCommand and inject synthetic key events into
|
|
19
|
-
* OpenTUI's keyHandler. Safe no-op when agentRuntime is undefined (normal user
|
|
20
|
-
* mode).
|
|
21
|
-
*
|
|
22
|
-
* Special key `__focus__:<id>` is intentionally NOT translated to OpenTUI input
|
|
23
|
-
* here — it is a driver-level signal currently ignored at this layer. (Focus
|
|
24
|
-
* routing in OpenTUI is owned by individual components; a global focus dispatch
|
|
25
|
-
* is out of scope for this bridge.)
|
|
26
|
-
*/
|
|
18
|
+
export declare function keyForNamed(key: string): KeyEvent | null;
|
|
27
19
|
export declare function useAgentInputBridge(agentRuntime: AgentModeRuntime | undefined): void;
|