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
|
@@ -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;
|
|
@@ -35,7 +35,54 @@ const NAMED = {
|
|
|
35
35
|
PageUp: { name: "pageup", sequence: "\x1b[5~", raw: "\x1b[5~" },
|
|
36
36
|
PageDown: { name: "pagedown", sequence: "\x1b[6~", raw: "\x1b[6~" },
|
|
37
37
|
};
|
|
38
|
-
|
|
38
|
+
// Case-insensitive view of NAMED. The map above is capitalized, but drivers
|
|
39
|
+
// naturally send lowercase ("enter", "escape", "tab", "space") — those missed
|
|
40
|
+
// the exact-case lookup, so keyForNamed returned null and the keystroke was a
|
|
41
|
+
// SILENT no-op (Enter never submitted, Escape never dismissed a modal). Resolve
|
|
42
|
+
// on the lowercased base so every casing works. Includes a couple of common
|
|
43
|
+
// short aliases drivers reach for.
|
|
44
|
+
const NAMED_LC = {
|
|
45
|
+
...Object.fromEntries(Object.entries(NAMED).map(([k, v]) => [k.toLowerCase(), v])),
|
|
46
|
+
ret: NAMED.Return,
|
|
47
|
+
del: NAMED.Delete,
|
|
48
|
+
spacebar: NAMED.Space,
|
|
49
|
+
pgup: NAMED.PageUp,
|
|
50
|
+
pgdn: NAMED.PageDown,
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Strip modifier prefixes (`C-` ctrl, `M-` meta/alt, `S-` shift) off a harness
|
|
54
|
+
* key string so combos like `C-b` or `C-o` can be driven. Prefixes may stack in
|
|
55
|
+
* any order (`C-S-tab`). The remainder is the base key (named or single char).
|
|
56
|
+
*/
|
|
57
|
+
function parseModifiers(key) {
|
|
58
|
+
const mods = {};
|
|
59
|
+
let base = key;
|
|
60
|
+
// Only consume a prefix when a base remains after it, so a literal "C" or a
|
|
61
|
+
// hyphen key is not mis-parsed.
|
|
62
|
+
for (;;) {
|
|
63
|
+
if (base.length > 2 && base[1] === "-") {
|
|
64
|
+
const p = base[0];
|
|
65
|
+
if (p === "C" || p === "c") {
|
|
66
|
+
mods.ctrl = true;
|
|
67
|
+
base = base.slice(2);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (p === "M" || p === "m") {
|
|
71
|
+
mods.meta = true;
|
|
72
|
+
base = base.slice(2);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (p === "S") {
|
|
76
|
+
mods.shift = true;
|
|
77
|
+
base = base.slice(2);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
return { mods, base };
|
|
84
|
+
}
|
|
85
|
+
function makeKey(partial, mods = {}) {
|
|
39
86
|
// Some app key-handlers conditionally call key.preventDefault()/stopPropagation()
|
|
40
87
|
// (typed `?.()` so they tolerate undefined). When the host's keypress arrives
|
|
41
88
|
// through a terminal, OpenTUI attaches these methods; in agent-mode we
|
|
@@ -48,9 +95,9 @@ function makeKey(partial) {
|
|
|
48
95
|
let _propagationStopped = false;
|
|
49
96
|
const ev = {
|
|
50
97
|
name: partial.name,
|
|
51
|
-
ctrl: false,
|
|
52
|
-
meta: false,
|
|
53
|
-
shift: false,
|
|
98
|
+
ctrl: mods.ctrl ?? false,
|
|
99
|
+
meta: mods.meta ?? false,
|
|
100
|
+
shift: mods.shift ?? false,
|
|
54
101
|
option: false,
|
|
55
102
|
sequence: partial.sequence,
|
|
56
103
|
number: false,
|
|
@@ -72,18 +119,22 @@ function makeKey(partial) {
|
|
|
72
119
|
};
|
|
73
120
|
return ev;
|
|
74
121
|
}
|
|
75
|
-
function keyForChar(ch) {
|
|
76
|
-
return makeKey({ name: ch, sequence: ch, raw: ch });
|
|
122
|
+
function keyForChar(ch, mods = {}) {
|
|
123
|
+
return makeKey({ name: ch, sequence: ch, raw: ch }, mods);
|
|
77
124
|
}
|
|
78
|
-
function keyForNamed(key) {
|
|
79
|
-
const
|
|
125
|
+
export function keyForNamed(key) {
|
|
126
|
+
const { mods, base } = parseModifiers(key);
|
|
127
|
+
// Exact case first (fast path), then case-insensitive so "enter"/"Enter"/
|
|
128
|
+
// "ENTER"/"return" all resolve. Single-letter bases never collide with a
|
|
129
|
+
// NAMED word, so they still fall through to the literal-char path below.
|
|
130
|
+
const m = NAMED[base] ?? NAMED_LC[base.toLowerCase()];
|
|
80
131
|
if (!m) {
|
|
81
132
|
// Unknown named key — fall back to treating it as a literal character if it's 1 char.
|
|
82
|
-
if (
|
|
83
|
-
return keyForChar(
|
|
133
|
+
if (base.length === 1)
|
|
134
|
+
return keyForChar(base, mods);
|
|
84
135
|
return null;
|
|
85
136
|
}
|
|
86
|
-
return makeKey(m);
|
|
137
|
+
return makeKey(m, mods);
|
|
87
138
|
}
|
|
88
139
|
/**
|
|
89
140
|
* Subscribe to agentRuntime.onCommand and inject synthetic key events into
|
|
@@ -95,15 +146,51 @@ function keyForNamed(key) {
|
|
|
95
146
|
* routing in OpenTUI is owned by individual components; a global focus dispatch
|
|
96
147
|
* is out of scope for this bridge.)
|
|
97
148
|
*/
|
|
149
|
+
// Runtimes that already have the input bridge wired — module-level so the guard
|
|
150
|
+
// survives App remounts (a per-component ref would reset and re-register).
|
|
151
|
+
const mountedRuntimes = new WeakSet();
|
|
98
152
|
export function useAgentInputBridge(agentRuntime) {
|
|
99
|
-
const
|
|
153
|
+
const ctx = useAppContext();
|
|
154
|
+
const keyHandler = ctx.keyHandler;
|
|
155
|
+
// Focused renderables (the composer textarea) subscribe to keypresses via
|
|
156
|
+
// renderer._internalKeyInput.onInternal("keypress"), NOT via the public
|
|
157
|
+
// keyHandler (useAppContext().keyHandler === renderer.keyInput). On the real
|
|
158
|
+
// TTY renderer both are the SAME InternalKeyHandler, but under the agent-mode
|
|
159
|
+
// headless renderer they are DISTINCT objects — so emitting only on keyHandler
|
|
160
|
+
// reached app-level useKeyboard shortcuts yet never the textarea, and typed
|
|
161
|
+
// text silently vanished (the tier-2 harness-drive bug). Prefer
|
|
162
|
+
// _internalKeyInput: its emitWithPriority dispatches to BOTH the focused
|
|
163
|
+
// renderable AND global listeners registered on it.
|
|
164
|
+
const internal = ctx.renderer?._internalKeyInput;
|
|
100
165
|
useEffect(() => {
|
|
101
|
-
if (!agentRuntime
|
|
166
|
+
if (!agentRuntime)
|
|
167
|
+
return;
|
|
168
|
+
// onCommand has no unsubscribe (it only pushes to a handler array), so
|
|
169
|
+
// registering twice doubles every keystroke (observed: a typed prompt
|
|
170
|
+
// arrived duplicated). A per-component ref is not enough — the App can
|
|
171
|
+
// remount (e.g. hero → chat transition) giving a fresh ref while the prior
|
|
172
|
+
// handler stays registered on the same long-lived runtime. Track mounted
|
|
173
|
+
// runtimes in a module-level WeakSet so registration is once-per-runtime
|
|
174
|
+
// across remounts.
|
|
175
|
+
if (mountedRuntimes.has(agentRuntime))
|
|
176
|
+
return;
|
|
177
|
+
const target = internal ?? keyHandler;
|
|
178
|
+
if (!target)
|
|
102
179
|
return;
|
|
103
180
|
// Toast-only stub in normal interactive mode provides emitEvent but not
|
|
104
181
|
// onCommand. Guard so the bridge no-ops cleanly instead of crashing the TUI.
|
|
105
182
|
if (typeof agentRuntime.onCommand !== "function")
|
|
106
183
|
return;
|
|
184
|
+
mountedRuntimes.add(agentRuntime);
|
|
185
|
+
// Emit to the renderable channel (the focused textarea), and also to the
|
|
186
|
+
// public keyHandler when it is a distinct object so global shortcuts still
|
|
187
|
+
// fire. The `!== target` guard avoids double-dispatch on the real renderer
|
|
188
|
+
// where the two are identical.
|
|
189
|
+
const emitKey = (k) => {
|
|
190
|
+
target.emit("keypress", k);
|
|
191
|
+
if (keyHandler && keyHandler !== target)
|
|
192
|
+
keyHandler.emit("keypress", k);
|
|
193
|
+
};
|
|
107
194
|
agentRuntime.onCommand((cmd) => {
|
|
108
195
|
if (!cmd || typeof cmd !== "object")
|
|
109
196
|
return;
|
|
@@ -113,14 +200,14 @@ export function useAgentInputBridge(agentRuntime) {
|
|
|
113
200
|
return;
|
|
114
201
|
const k = keyForNamed(c.key);
|
|
115
202
|
if (k)
|
|
116
|
-
|
|
203
|
+
emitKey(k);
|
|
117
204
|
}
|
|
118
205
|
else if (c.op === "type" && typeof c.text === "string") {
|
|
119
206
|
for (const ch of c.text) {
|
|
120
|
-
|
|
207
|
+
emitKey(keyForChar(ch));
|
|
121
208
|
}
|
|
122
209
|
}
|
|
123
210
|
});
|
|
124
|
-
}, [agentRuntime, keyHandler]);
|
|
211
|
+
}, [agentRuntime, internal, keyHandler]);
|
|
125
212
|
}
|
|
126
213
|
//# sourceMappingURL=input-bridge.js.map
|
|
@@ -41,6 +41,14 @@ export interface InstallOpenTUIHarnessOptions {
|
|
|
41
41
|
* the `--agent-fake-clock` CLI flag.
|
|
42
42
|
*/
|
|
43
43
|
fakeClock?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Optional visual-frame capture. When provided, a VisualFrame (the actual
|
|
46
|
+
* rendered cell grid — colors + attributes) is captured and sent right after
|
|
47
|
+
* each SEMANTIC frame change. Piggybacking on semantic changes bounds the
|
|
48
|
+
* per-frame `getSpanLines()` allocation to real UI updates instead of every
|
|
49
|
+
* poll tick. Returns null on dedup / unavailable renderer.
|
|
50
|
+
*/
|
|
51
|
+
captureVisual?: (seq: number, ts: number) => object | null;
|
|
44
52
|
}
|
|
45
53
|
export interface OpenTUIHarnessHandle {
|
|
46
54
|
/**
|
|
@@ -28,6 +28,7 @@ export function installOpenTUIHarness(opts) {
|
|
|
28
28
|
const fps = opts.fps ?? 60;
|
|
29
29
|
const intervalMs = Math.max(1, Math.round(1000 / fps));
|
|
30
30
|
let seq = 0;
|
|
31
|
+
let vseq = 0;
|
|
31
32
|
const fakeClock = opts.fakeClock ?? false;
|
|
32
33
|
const hook = createReconcilerHook({
|
|
33
34
|
registry: opts.registry,
|
|
@@ -43,6 +44,15 @@ export function installOpenTUIHarness(opts) {
|
|
|
43
44
|
try {
|
|
44
45
|
opts.transport.send(`${JSON.stringify(frame)}\n`);
|
|
45
46
|
opts.onFrame?.(frame);
|
|
47
|
+
// Piggyback the visual (rendered cell-grid) frame on semantic changes so
|
|
48
|
+
// getSpanLines() only runs when the UI actually changed, not every tick.
|
|
49
|
+
if (opts.captureVisual) {
|
|
50
|
+
const vframe = opts.captureVisual(vseq, fakeClock ? vseq * 16 : Date.now());
|
|
51
|
+
if (vframe !== null) {
|
|
52
|
+
vseq++;
|
|
53
|
+
opts.transport.send(`${JSON.stringify(vframe)}\n`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
46
56
|
}
|
|
47
57
|
catch {
|
|
48
58
|
// Drop frame on transport error — survivor of next tick will retry.
|
|
@@ -31,22 +31,24 @@ export function Semantic(props) {
|
|
|
31
31
|
const unregister = registry.register({ ...nodeRef.current, parentId });
|
|
32
32
|
return unregister;
|
|
33
33
|
}, [registry, parentId, node.id]);
|
|
34
|
-
// Updates:
|
|
35
|
-
//
|
|
36
|
-
//
|
|
34
|
+
// Updates: patch fields on prop change via registry.update(). nodeKey is the
|
|
35
|
+
// intentional cache-bust dep — it serializes the node fields so this effect
|
|
36
|
+
// re-runs whenever any field changes; Map.set on an existing key preserves
|
|
37
|
+
// insertion order.
|
|
37
38
|
React.useEffect(() => {
|
|
38
39
|
if (!registry)
|
|
39
40
|
return;
|
|
40
41
|
if (!nodeKey)
|
|
41
42
|
return;
|
|
42
43
|
// Skip the very first run — the mount effect above already registered.
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
|
|
44
|
+
// On mount this effect runs after the mount effect, so the entry IS
|
|
45
|
+
// present; update() patches fields in place (Map.set on an existing key
|
|
46
|
+
// preserves insertion order). On subsequent renders with a different
|
|
47
|
+
// nodeKey it patches the changed fields. Using update() (not register())
|
|
48
|
+
// is the cheaper intended path — it merges instead of rebuilding the
|
|
49
|
+
// entry, and it is a no-op if the entry was already unmounted.
|
|
50
|
+
const { id: _id, ...patch } = nodeRef.current;
|
|
51
|
+
registry.update(nodeRef.current.id, patch);
|
|
50
52
|
// No cleanup — the mount effect's cleanup is the single source of
|
|
51
53
|
// truth for unmounting. If we returned a cleanup here, it would race
|
|
52
54
|
// with re-renders and re-delete the entry.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* visual-capture.ts — read OpenTUI's ACTUAL rendered cell grid.
|
|
3
|
+
*
|
|
4
|
+
* The semantic harness (reconciler-hook) reports STRUCTURE (id/role/name/props)
|
|
5
|
+
* but is blind to what a human SEES — colors, bold/italic, alignment, blank
|
|
6
|
+
* rows, mojibake. This module snapshots the ground-truth render buffer instead:
|
|
7
|
+
* OpenTUI's `CliRenderer.currentRenderBuffer` is a cell grid it already paints,
|
|
8
|
+
* and `OptimizedBuffer.getSpanLines()` returns per-cell char + RGBA fg/bg +
|
|
9
|
+
* attribute bits (verified against @opentui/core@0.1.107 buffer.d.ts:43 +
|
|
10
|
+
* lib/RGBA.d.ts). No OCR — the buffer is authoritative and in-process.
|
|
11
|
+
*
|
|
12
|
+
* Consumers get a `VisualFrame` (protocol) they can query per-cell, render to
|
|
13
|
+
* annotated text, or (P2) rasterize to PNG for a vision model.
|
|
14
|
+
*/
|
|
15
|
+
import { type VisualFrame } from "@muonroi/agent-harness-core/protocol";
|
|
16
|
+
interface RgbaLike {
|
|
17
|
+
toInts?: () => [number, number, number, number];
|
|
18
|
+
r?: number;
|
|
19
|
+
g?: number;
|
|
20
|
+
b?: number;
|
|
21
|
+
a?: number;
|
|
22
|
+
}
|
|
23
|
+
interface CapturedSpanLike {
|
|
24
|
+
text: string;
|
|
25
|
+
fg: RgbaLike;
|
|
26
|
+
bg: RgbaLike;
|
|
27
|
+
attributes: number;
|
|
28
|
+
width: number;
|
|
29
|
+
}
|
|
30
|
+
interface CapturedLineLike {
|
|
31
|
+
spans: CapturedSpanLike[];
|
|
32
|
+
}
|
|
33
|
+
interface OptimizedBufferLike {
|
|
34
|
+
width: number;
|
|
35
|
+
height: number;
|
|
36
|
+
getSpanLines: () => CapturedLineLike[];
|
|
37
|
+
}
|
|
38
|
+
export interface RendererLike {
|
|
39
|
+
currentRenderBuffer?: OptimizedBufferLike;
|
|
40
|
+
nextRenderBuffer?: OptimizedBufferLike;
|
|
41
|
+
}
|
|
42
|
+
export interface VisualCaptureHook {
|
|
43
|
+
/** Build a VisualFrame from the renderer's current buffer. Returns null when
|
|
44
|
+
* no renderer is attached, the buffer is unreadable, or content is unchanged
|
|
45
|
+
* (content-hash dedup — same contract as the semantic reconciler hook). */
|
|
46
|
+
capture(seq: number, ts: number): VisualFrame | null;
|
|
47
|
+
/** Reset dedup state so the next capture always emits. */
|
|
48
|
+
resetDedup(): void;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Create a visual-capture hook. `getRenderer` is a late-bound accessor because
|
|
52
|
+
* the OpenTUI renderer is constructed AFTER the agent-mode runtime (which owns
|
|
53
|
+
* this hook) — see src/index.ts attachRenderer wiring.
|
|
54
|
+
*/
|
|
55
|
+
export declare function createVisualCaptureHook(getRenderer: () => RendererLike | undefined): VisualCaptureHook;
|
|
56
|
+
export {};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* visual-capture.ts — read OpenTUI's ACTUAL rendered cell grid.
|
|
3
|
+
*
|
|
4
|
+
* The semantic harness (reconciler-hook) reports STRUCTURE (id/role/name/props)
|
|
5
|
+
* but is blind to what a human SEES — colors, bold/italic, alignment, blank
|
|
6
|
+
* rows, mojibake. This module snapshots the ground-truth render buffer instead:
|
|
7
|
+
* OpenTUI's `CliRenderer.currentRenderBuffer` is a cell grid it already paints,
|
|
8
|
+
* and `OptimizedBuffer.getSpanLines()` returns per-cell char + RGBA fg/bg +
|
|
9
|
+
* attribute bits (verified against @opentui/core@0.1.107 buffer.d.ts:43 +
|
|
10
|
+
* lib/RGBA.d.ts). No OCR — the buffer is authoritative and in-process.
|
|
11
|
+
*
|
|
12
|
+
* Consumers get a `VisualFrame` (protocol) they can query per-cell, render to
|
|
13
|
+
* annotated text, or (P2) rasterize to PNG for a vision model.
|
|
14
|
+
*/
|
|
15
|
+
import { createHash } from "node:crypto";
|
|
16
|
+
import { PROTOCOL_VERSION, } from "@muonroi/agent-harness-core/protocol";
|
|
17
|
+
/** Low byte of OpenTUI's TextAttributes (ATTRIBUTE_BASE_MASK = 255). */
|
|
18
|
+
const ATTR_MASK = 255;
|
|
19
|
+
function clampByte(n) {
|
|
20
|
+
return Math.max(0, Math.min(255, Math.round(n)));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Convert an OpenTUI RGBA to a "#rrggbb" (or "#rrggbbaa" when translucent) hex
|
|
24
|
+
* string. Prefers `toInts()` (0-255 ints); falls back to component getters,
|
|
25
|
+
* scaling 0-1 floats up to 0-255 when the renderer exposes normalized channels.
|
|
26
|
+
*/
|
|
27
|
+
function toHex(c) {
|
|
28
|
+
let r = 0;
|
|
29
|
+
let g = 0;
|
|
30
|
+
let b = 0;
|
|
31
|
+
let a = 255;
|
|
32
|
+
if (c && typeof c.toInts === "function") {
|
|
33
|
+
const ints = c.toInts();
|
|
34
|
+
r = ints[0];
|
|
35
|
+
g = ints[1];
|
|
36
|
+
b = ints[2];
|
|
37
|
+
a = ints[3];
|
|
38
|
+
}
|
|
39
|
+
else if (c) {
|
|
40
|
+
const scale = (v) => (v === undefined ? 0 : v <= 1 ? v * 255 : v);
|
|
41
|
+
r = scale(c.r);
|
|
42
|
+
g = scale(c.g);
|
|
43
|
+
b = scale(c.b);
|
|
44
|
+
a = c.a === undefined ? 255 : c.a <= 1 ? c.a * 255 : c.a;
|
|
45
|
+
}
|
|
46
|
+
const h = (n) => clampByte(n).toString(16).padStart(2, "0");
|
|
47
|
+
return a < 255 ? `#${h(r)}${h(g)}${h(b)}${h(a)}` : `#${h(r)}${h(g)}${h(b)}`;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create a visual-capture hook. `getRenderer` is a late-bound accessor because
|
|
51
|
+
* the OpenTUI renderer is constructed AFTER the agent-mode runtime (which owns
|
|
52
|
+
* this hook) — see src/index.ts attachRenderer wiring.
|
|
53
|
+
*/
|
|
54
|
+
export function createVisualCaptureHook(getRenderer) {
|
|
55
|
+
let lastHash;
|
|
56
|
+
function capture(seq, ts) {
|
|
57
|
+
const renderer = getRenderer();
|
|
58
|
+
const buffer = renderer?.currentRenderBuffer ?? renderer?.nextRenderBuffer;
|
|
59
|
+
if (!buffer || typeof buffer.getSpanLines !== "function")
|
|
60
|
+
return null;
|
|
61
|
+
let captured;
|
|
62
|
+
try {
|
|
63
|
+
captured = buffer.getSpanLines();
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
// getSpanLines allocates + decodes native Zig memory; a mid-resize/destroy
|
|
67
|
+
// race can throw. Skip this frame (the next tick retries). Debug-gated log
|
|
68
|
+
// only — unconditional logging here would spam the render loop.
|
|
69
|
+
if (process.env.MUONROI_DEBUG_VISUAL) {
|
|
70
|
+
console.error(`[visual-capture] getSpanLines failed: ${err?.message}`);
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
const lines = captured.map((ln) => ({
|
|
75
|
+
spans: (ln.spans ?? []).map((s) => ({
|
|
76
|
+
text: s.text,
|
|
77
|
+
fg: toHex(s.fg),
|
|
78
|
+
bg: toHex(s.bg),
|
|
79
|
+
attrs: (s.attributes ?? 0) & ATTR_MASK,
|
|
80
|
+
width: s.width,
|
|
81
|
+
})),
|
|
82
|
+
}));
|
|
83
|
+
const hash = createHash("sha1").update(JSON.stringify(lines)).digest("hex");
|
|
84
|
+
if (lastHash === hash)
|
|
85
|
+
return null;
|
|
86
|
+
lastHash = hash;
|
|
87
|
+
return {
|
|
88
|
+
mode: "visual",
|
|
89
|
+
version: PROTOCOL_VERSION,
|
|
90
|
+
seq,
|
|
91
|
+
ts,
|
|
92
|
+
cols: buffer.width,
|
|
93
|
+
rows: buffer.height,
|
|
94
|
+
cursor: null,
|
|
95
|
+
lines,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function resetDedup() {
|
|
99
|
+
lastHash = undefined;
|
|
100
|
+
}
|
|
101
|
+
return { capture, resetDedup };
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=visual-capture.js.map
|
|
@@ -48,6 +48,44 @@ export interface MockModelFixture {
|
|
|
48
48
|
provider?: string;
|
|
49
49
|
/** Reported model id. Default "mock-model". */
|
|
50
50
|
modelId?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Response for PIL's model-first intent classifier (src/pil/llm-classify.ts).
|
|
53
|
+
* Since the no-regex refactor (2026-07-07) PIL classifies EVERY turn by
|
|
54
|
+
* calling the model with a distinctive system prompt ("Reply with ONE line of
|
|
55
|
+
* EIGHT lowercase words…") and parses a comma-separated line. The generic
|
|
56
|
+
* fixture stream ("Hello back!" / arbitrary chunks) does not parse → the turn
|
|
57
|
+
* degrades to intentKind=UNKNOWN, which skips the gsd gate and breaks routing
|
|
58
|
+
* in E2E specs. The mock detects that classify call by its system prompt and
|
|
59
|
+
* returns THIS line instead of consuming the turn fixture — so every spec gets
|
|
60
|
+
* a sane classification for free. Override per-fixture when a spec needs a
|
|
61
|
+
* specific taskType/intent/depth. Format:
|
|
62
|
+
* <taskType>,<style>,<intent>,<deliverable>,<depth>,<scope>,<lang>,<clarity>
|
|
63
|
+
*/
|
|
64
|
+
classify?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Milliseconds to wait before each streamed chunk. Default 0 (instant).
|
|
67
|
+
*
|
|
68
|
+
* A real provider takes seconds; the mock is instant, which makes anything
|
|
69
|
+
* that only exists WHILE a call is in flight — a progress card, a spinner —
|
|
70
|
+
* impossible to observe from a spec. Set this to hold the in-flight state open
|
|
71
|
+
* long enough to assert on it. Keep it small: it is wall-clock in every spec
|
|
72
|
+
* that sets it.
|
|
73
|
+
*/
|
|
74
|
+
chunkDelayMs?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Opt in to the PIL-classifier intercept described on `classify`. When true,
|
|
77
|
+
* a `doStream` call carrying the classifier's system prompt is answered with
|
|
78
|
+
* `classify` (or DEFAULT_CLASSIFY_LINE) WITHOUT consuming a turn fixture.
|
|
79
|
+
*
|
|
80
|
+
* This is a convenience for the file-based E2E harness (`loadMockModelFromDir`
|
|
81
|
+
* sets it true by default) whose fixtures supply agent turn-rounds and must
|
|
82
|
+
* not spend a round on the classify call. Direct in-memory callers
|
|
83
|
+
* (`createMockModel`/`installMockModel`, e.g. llm-classify.test.ts) leave it
|
|
84
|
+
* OFF so the fixture stream they configure IS delivered to the classifier —
|
|
85
|
+
* otherwise every classification would collapse to DEFAULT_CLASSIFY_LINE.
|
|
86
|
+
* Setting `classify` implies opting in.
|
|
87
|
+
*/
|
|
88
|
+
autoClassify?: boolean;
|
|
51
89
|
}
|
|
52
90
|
export interface MockModelHandle {
|
|
53
91
|
/** The mock model instance — assign to `globalThis.__muonroiMockModel`. */
|
|
@@ -25,6 +25,40 @@
|
|
|
25
25
|
import { APICallError } from "@ai-sdk/provider";
|
|
26
26
|
import { simulateReadableStream } from "ai";
|
|
27
27
|
import { MockLanguageModelV3 } from "ai/test";
|
|
28
|
+
/**
|
|
29
|
+
* System-prompt substring that uniquely identifies PIL's model-first intent
|
|
30
|
+
* classifier call (see SYSTEM_PROMPT in src/pil/llm-classify.ts). Kept in sync
|
|
31
|
+
* with that constant's opening line.
|
|
32
|
+
*/
|
|
33
|
+
const CLASSIFY_SIGNATURE = "Reply with ONE line of EIGHT lowercase words";
|
|
34
|
+
/**
|
|
35
|
+
* Safe default classification: a non-chitchat coding task of standard depth.
|
|
36
|
+
* `intent=task` keeps the toolset + gsd gate active; `standard` depth avoids
|
|
37
|
+
* forcing heavy-only paths. First word MUST be a valid taskType.
|
|
38
|
+
*/
|
|
39
|
+
const DEFAULT_CLASSIFY_LINE = "generate, balanced, task, code, standard, local, english, clear";
|
|
40
|
+
/** Concatenated text of every `system` message in a doStream call's prompt. */
|
|
41
|
+
function systemPromptText(options) {
|
|
42
|
+
const prompt = options.prompt;
|
|
43
|
+
if (!Array.isArray(prompt))
|
|
44
|
+
return "";
|
|
45
|
+
const parts = [];
|
|
46
|
+
for (const msg of prompt) {
|
|
47
|
+
const m = msg;
|
|
48
|
+
if (m.role !== "system")
|
|
49
|
+
continue;
|
|
50
|
+
if (typeof m.content === "string")
|
|
51
|
+
parts.push(m.content);
|
|
52
|
+
else if (Array.isArray(m.content)) {
|
|
53
|
+
for (const c of m.content) {
|
|
54
|
+
const t = c.text;
|
|
55
|
+
if (typeof t === "string")
|
|
56
|
+
parts.push(t);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return parts.join("\n");
|
|
61
|
+
}
|
|
28
62
|
function isNestedArray(v) {
|
|
29
63
|
return Array.isArray(v) && v.length > 0 && Array.isArray(v[0]);
|
|
30
64
|
}
|
|
@@ -44,10 +78,35 @@ export function createMockModel(fx) {
|
|
|
44
78
|
let genIdx = 0;
|
|
45
79
|
const provider = fx.provider ?? "mock";
|
|
46
80
|
const modelId = fx.modelId ?? "mock-model";
|
|
81
|
+
const classifyLine = fx.classify ?? DEFAULT_CLASSIFY_LINE;
|
|
82
|
+
// Intercept the PIL classifier call ONLY when the fixture opts in (E2E
|
|
83
|
+
// harness fixtures do, via loadMockModelFromDir). Direct in-memory callers
|
|
84
|
+
// (llm-classify.test.ts) leave it off so the stream they configure IS
|
|
85
|
+
// delivered to the classifier — intercepting would override their reply with
|
|
86
|
+
// DEFAULT_CLASSIFY_LINE and make every classification collapse to "generate".
|
|
87
|
+
const interceptClassify = fx.autoClassify === true || fx.classify !== undefined;
|
|
88
|
+
const chunkDelayMs = Math.max(0, fx.chunkDelayMs ?? 0);
|
|
47
89
|
const model = new MockLanguageModelV3({
|
|
48
90
|
provider,
|
|
49
91
|
modelId,
|
|
50
|
-
doStream: async () => {
|
|
92
|
+
doStream: async (options) => {
|
|
93
|
+
// PIL model-first classifier call — answer with the parseable eight-word
|
|
94
|
+
// line and DO NOT advance the turn-fixture cursor, so the classify call
|
|
95
|
+
// (which fires on every turn) never steals the round chunks meant for the
|
|
96
|
+
// agent's actual reply. Without this the generic fixture text fails
|
|
97
|
+
// parseResponse → intentKind=UNKNOWN → gsd gate/routing break in E2E.
|
|
98
|
+
if (interceptClassify && systemPromptText(options).includes(CLASSIFY_SIGNATURE)) {
|
|
99
|
+
if (process.env.MUONROI_DEBUG_MOCK_MODEL === "1") {
|
|
100
|
+
process.stderr.write(`[mock-model] doStream classify → "${classifyLine}"\n`);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
stream: simulateReadableStream({
|
|
104
|
+
chunks: textOnlyStream(classifyLine),
|
|
105
|
+
initialDelayInMs: null,
|
|
106
|
+
chunkDelayInMs: null,
|
|
107
|
+
}),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
51
110
|
const chunks = streams[Math.min(callIdx, streams.length - 1)];
|
|
52
111
|
callIdx += 1;
|
|
53
112
|
if (process.env.MUONROI_DEBUG_MOCK_MODEL === "1") {
|
|
@@ -58,8 +117,11 @@ export function createMockModel(fx) {
|
|
|
58
117
|
return {
|
|
59
118
|
stream: simulateReadableStream({
|
|
60
119
|
chunks,
|
|
61
|
-
|
|
62
|
-
|
|
120
|
+
// Only the turn stream honours the delay — the classify intercept above
|
|
121
|
+
// fires on EVERY turn, so pacing it would tax specs that just want a
|
|
122
|
+
// slow answer.
|
|
123
|
+
initialDelayInMs: chunkDelayMs || null,
|
|
124
|
+
chunkDelayInMs: chunkDelayMs || null,
|
|
63
125
|
}),
|
|
64
126
|
};
|
|
65
127
|
},
|
|
@@ -397,6 +459,10 @@ export async function loadMockModelFromDir(dir) {
|
|
|
397
459
|
// to createMockModel, so the AI SDK stream-loop and orchestrator see a
|
|
398
460
|
// consistent Error shape regardless of fixture serialization.
|
|
399
461
|
const normalized = {
|
|
462
|
+
// File-based E2E fixtures supply agent turn-rounds; auto-answer the PIL
|
|
463
|
+
// classifier call so it never consumes a round (a fixture may still set
|
|
464
|
+
// autoClassify:false to opt out, or classify:"…" to force a line).
|
|
465
|
+
autoClassify: true,
|
|
400
466
|
...raw.model,
|
|
401
467
|
stream: isNestedArray(raw.model.stream)
|
|
402
468
|
? raw.model.stream.map(normalizeStreamChunks)
|