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
|
@@ -3,8 +3,16 @@ import type { Theme } from "../theme.js";
|
|
|
3
3
|
export interface CouncilPhaseTimelineProps {
|
|
4
4
|
phases: CouncilPhaseEvent[];
|
|
5
5
|
theme: Theme;
|
|
6
|
+
/**
|
|
7
|
+
* When false (default), completed phases fold into a single "N steps done"
|
|
8
|
+
* summary line and only the live (active/error) phase is shown — the
|
|
9
|
+
* aggressive-collapse UX. When true (Ctrl+O), the full done-trail is shown.
|
|
10
|
+
* Shares the council transcript's expand state so one toggle controls all
|
|
11
|
+
* council detail.
|
|
12
|
+
*/
|
|
13
|
+
expanded?: boolean;
|
|
6
14
|
}
|
|
7
|
-
export declare function CouncilPhaseTimeline({ phases, theme: t }: CouncilPhaseTimelineProps): import("react").ReactNode;
|
|
15
|
+
export declare function CouncilPhaseTimeline({ phases, theme: t, expanded }: CouncilPhaseTimelineProps): import("react").ReactNode;
|
|
8
16
|
/**
|
|
9
17
|
* Reducer-friendly upsert: returns the next phase array given an incoming event.
|
|
10
18
|
* Matches by phaseId; preserves insertion order for new phases. The first event
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
|
+
import { heartbeatDebug } from "../heartbeat-debug.js";
|
|
3
4
|
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
4
5
|
function Spinner() {
|
|
5
6
|
const [frame, setFrame] = useState(0);
|
|
6
7
|
useEffect(() => {
|
|
7
|
-
const id = setInterval(() =>
|
|
8
|
+
const id = setInterval(() => {
|
|
9
|
+
heartbeatDebug("phase-timeline-spinner", "timer");
|
|
10
|
+
setFrame((n) => (n + 1) % SPINNER_FRAMES.length);
|
|
11
|
+
}, 100);
|
|
8
12
|
return () => clearInterval(id);
|
|
9
13
|
}, []);
|
|
10
14
|
return _jsx(_Fragment, { children: SPINNER_FRAMES[frame] });
|
|
@@ -31,28 +35,73 @@ function formatElapsed(ms) {
|
|
|
31
35
|
function useHeartbeat(tickMs = 1000) {
|
|
32
36
|
const [, force] = useState(0);
|
|
33
37
|
useEffect(() => {
|
|
34
|
-
const id = setInterval(() =>
|
|
38
|
+
const id = setInterval(() => {
|
|
39
|
+
heartbeatDebug("phase-timeline-heartbeat", "timer");
|
|
40
|
+
force((n) => n + 1);
|
|
41
|
+
}, tickMs);
|
|
35
42
|
return () => clearInterval(id);
|
|
36
43
|
}, [tickMs]);
|
|
37
44
|
return Date.now();
|
|
38
45
|
}
|
|
39
|
-
export function CouncilPhaseTimeline({ phases, theme: t }) {
|
|
46
|
+
export function CouncilPhaseTimeline({ phases, theme: t, expanded = false }) {
|
|
40
47
|
const now = useHeartbeat(1000);
|
|
41
|
-
|
|
48
|
+
// Collapse per-round brackets: the "Clarification round N" / "Round N" phases
|
|
49
|
+
// duplicate the live status line ("Generating clarification questions (round
|
|
50
|
+
// N)"), stacking 3-4 near-identical spinner rows at council start. Keep only
|
|
51
|
+
// the coarse lifecycle phases here; round detail already rides on the status
|
|
52
|
+
// line label. Errors are always shown so a failed round stays visible.
|
|
53
|
+
const visible = phases.filter((p) => !((p.kind === "clarification_round" || p.kind === "round") && p.state !== "error"));
|
|
54
|
+
if (visible.length === 0)
|
|
42
55
|
return null;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
// Aggressive collapse (default): show only the live (active/error) phases as
|
|
57
|
+
// full rows; fold every completed phase into one "N steps done" summary line.
|
|
58
|
+
// Ctrl+O (expanded=true) restores the full done-trail. Errors are never
|
|
59
|
+
// folded — a failed phase always stays visible.
|
|
60
|
+
const live = visible.filter((p) => p.state === "active" || p.state === "error");
|
|
61
|
+
const doneCount = visible.length - live.length;
|
|
62
|
+
const rows = expanded ? visible : live;
|
|
63
|
+
// Split off error phases so identical provider failures can be folded into one
|
|
64
|
+
// row instead of N repeated blocks. A flaky proxy (Console Go glm/kimi) makes
|
|
65
|
+
// clarify + spec-infer + eval all fail with the SAME message — rendered raw
|
|
66
|
+
// that spammed the (narrow) context rail. Non-error rows keep their order.
|
|
67
|
+
const nonErrorRows = rows.filter((p) => p.state !== "error");
|
|
68
|
+
const errorRows = rows.filter((p) => p.state === "error");
|
|
69
|
+
const errorGroups = [];
|
|
70
|
+
for (const p of errorRows) {
|
|
71
|
+
const message = p.errorMessage ?? "(failed)";
|
|
72
|
+
const existing = errorGroups.find((g) => g.message === message);
|
|
73
|
+
if (existing)
|
|
74
|
+
existing.phases.push(p);
|
|
75
|
+
else
|
|
76
|
+
errorGroups.push({ message, phases: [p] });
|
|
77
|
+
}
|
|
78
|
+
const renderRow = (p) => {
|
|
79
|
+
const isDone = p.state === "done";
|
|
80
|
+
const marker = isDone ? "✓" : _jsx(Spinner, {});
|
|
81
|
+
const markerColor = isDone ? t.planOptionCheck : t.accent;
|
|
82
|
+
const labelColor = isDone ? t.textMuted : t.text;
|
|
83
|
+
const liveElapsedMs = p.state === "active" && typeof p.startedAt === "number" ? Math.max(0, now - p.startedAt) : p.elapsedMs;
|
|
84
|
+
if (p.state === "active") {
|
|
85
|
+
heartbeatDebug("phase-timeline", "render", {
|
|
86
|
+
label: p.label,
|
|
87
|
+
liveElapsedMs,
|
|
88
|
+
startedAt: p.startedAt,
|
|
89
|
+
now,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const elapsed = formatElapsed(liveElapsedMs);
|
|
93
|
+
const meta = elapsed ? ` (${elapsed})` : isDone ? "" : " …";
|
|
94
|
+
return (_jsxs("box", { flexDirection: "column", children: [_jsxs("box", { children: [_jsx("text", { fg: markerColor, children: marker }), _jsx("text", { fg: labelColor, children: ` ${p.label}` }), meta && _jsx("text", { fg: t.textDim, children: meta })] }), p.detail && (_jsx("box", { paddingLeft: 2, children: _jsx("text", { fg: t.textMuted, children: `└ ${truncate(p.detail, 100)}` }) }))] }, p.phaseId));
|
|
95
|
+
};
|
|
96
|
+
return (_jsxs("box", { flexDirection: "column", paddingLeft: 2, paddingTop: 0, flexShrink: 0, children: [!expanded && doneCount > 0 && (_jsxs("box", { children: [_jsx("text", { fg: t.planOptionCheck, children: "\u2713" }), _jsx("text", { fg: t.textDim, children: ` ${doneCount} step${doneCount === 1 ? "" : "s"} done` }), _jsx("text", { fg: t.textMuted, children: " · Ctrl+O to expand" })] })), nonErrorRows.map(renderRow), errorGroups.map((g) => {
|
|
97
|
+
// One header per unique error; when >1 phase shares it, name the count
|
|
98
|
+
// and list the affected steps compactly instead of repeating the message.
|
|
99
|
+
const first = g.phases[0];
|
|
100
|
+
const label = g.phases.length === 1
|
|
101
|
+
? first.label
|
|
102
|
+
: `${g.phases.length} steps failed: ${g.phases.map((p) => p.label).join(", ")}`;
|
|
103
|
+
return (_jsxs("box", { flexDirection: "column", children: [_jsxs("box", { children: [_jsx("text", { fg: t.diffRemovedFg, children: "\u2717" }), _jsx("text", { fg: t.diffRemovedFg, children: ` ${truncate(label, 100)}` })] }), _jsx("box", { paddingLeft: 2, children: _jsx("text", { fg: t.diffRemovedFg, children: `└ ${truncate(g.message, 100)}` }) })] }, `err-${first.phaseId}`));
|
|
104
|
+
})] }));
|
|
56
105
|
}
|
|
57
106
|
function truncate(s, max) {
|
|
58
107
|
if (s.length <= max)
|
|
@@ -2,20 +2,27 @@ import type { Theme } from "../theme.js";
|
|
|
2
2
|
export type PlaceholderVariant = "participant" | "leader";
|
|
3
3
|
export interface CouncilPlaceholderBubbleProps {
|
|
4
4
|
role: string;
|
|
5
|
+
/** Legacy pair-side hint — ignored in the linear group-chat layout. */
|
|
5
6
|
side: "left" | "right";
|
|
6
7
|
terminalCols: number;
|
|
7
8
|
color: string;
|
|
8
9
|
theme: Theme;
|
|
9
10
|
variant?: PlaceholderVariant;
|
|
11
|
+
/**
|
|
12
|
+
* Optional per-speaker context shown as muted sub-lines while composing, so the
|
|
13
|
+
* main console is not a bare spinner during the 20–60s atomic generateText
|
|
14
|
+
* window. Newline-separated "Name — lens" entries emitted by the engine in the
|
|
15
|
+
* opening/exchange `council_status.detail`. Empty/undefined → label-only.
|
|
16
|
+
*/
|
|
17
|
+
detail?: string;
|
|
10
18
|
}
|
|
11
|
-
export declare function buildPlaceholderLabel(role: string): string;
|
|
19
|
+
export declare function buildPlaceholderLabel(role: string, elapsedSec?: number): string;
|
|
12
20
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* Swapped for the real CouncilMessageBubble
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* - "leader": centered, leader-gray border, 40% width — matches the real leader bubble
|
|
21
|
+
* "Typing…" indicator for a speaker whose turn is in flight — a spinner + a
|
|
22
|
+
* role-colored line (`⠋ Role · composing… · 12s`) in the same linear stream as
|
|
23
|
+
* the real messages, WhatsApp-style. Swapped for the real CouncilMessageBubble
|
|
24
|
+
* when the council_message arrives. The spinner + ticking elapsed distinguish
|
|
25
|
+
* a live provider from a hung one (a static line looked identical at 2s and
|
|
26
|
+
* 2min — live-verified 2026-07-06).
|
|
20
27
|
*/
|
|
21
|
-
export declare function CouncilPlaceholderBubble({ role,
|
|
28
|
+
export declare function CouncilPlaceholderBubble({ role, color, detail, theme: t }: CouncilPlaceholderBubbleProps): import("react").ReactNode;
|
|
@@ -1,37 +1,40 @@
|
|
|
1
|
-
import { jsx as _jsx } from "@opentui/react/jsx-runtime";
|
|
2
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
3
|
const FALLBACK_ROLE = "Speaker";
|
|
4
|
-
const
|
|
5
|
-
export function buildPlaceholderLabel(role) {
|
|
4
|
+
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
5
|
+
export function buildPlaceholderLabel(role, elapsedSec) {
|
|
6
6
|
const trimmed = role.trim();
|
|
7
7
|
const display = trimmed.length > 0 ? trimmed : FALLBACK_ROLE;
|
|
8
|
-
|
|
8
|
+
const elapsed = elapsedSec !== undefined && elapsedSec >= 1 ? ` · ${elapsedSec}s` : "";
|
|
9
|
+
return `${display} · composing…${elapsed}`;
|
|
9
10
|
}
|
|
10
11
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* Swapped for the real CouncilMessageBubble
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* - "leader": centered, leader-gray border, 40% width — matches the real leader bubble
|
|
12
|
+
* "Typing…" indicator for a speaker whose turn is in flight — a spinner + a
|
|
13
|
+
* role-colored line (`⠋ Role · composing… · 12s`) in the same linear stream as
|
|
14
|
+
* the real messages, WhatsApp-style. Swapped for the real CouncilMessageBubble
|
|
15
|
+
* when the council_message arrives. The spinner + ticking elapsed distinguish
|
|
16
|
+
* a live provider from a hung one (a static line looked identical at 2s and
|
|
17
|
+
* 2min — live-verified 2026-07-06).
|
|
18
18
|
*/
|
|
19
|
-
export function CouncilPlaceholderBubble({ role,
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
19
|
+
export function CouncilPlaceholderBubble({ role, color, detail, theme: t }) {
|
|
20
|
+
const [startedAt] = useState(() => Date.now());
|
|
21
|
+
const [frame, setFrame] = useState(0);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
// The 100ms spinner interval doubles as the elapsed re-render tick — no
|
|
24
|
+
// second timer needed. Braille frames match the timeline/pill spinner
|
|
25
|
+
// vocabulary rather than adding a third glyph set.
|
|
26
|
+
const id = setInterval(() => setFrame((n) => n + 1), 100);
|
|
27
|
+
return () => clearInterval(id);
|
|
28
|
+
}, []);
|
|
29
|
+
const elapsedSec = Math.floor((Date.now() - startedAt) / 1000);
|
|
30
|
+
// Split the engine-emitted roster ("Name — lens" per line) into muted preview
|
|
31
|
+
// rows. Trimmed + non-empty only so a trailing newline never renders a blank.
|
|
32
|
+
const detailLines = detail
|
|
33
|
+
? detail
|
|
34
|
+
.split("\n")
|
|
35
|
+
.map((l) => l.trim())
|
|
36
|
+
.filter((l) => l.length > 0)
|
|
37
|
+
: [];
|
|
38
|
+
return (_jsxs("box", { marginBottom: 1, paddingLeft: 2, flexDirection: "column", children: [_jsxs("box", { children: [_jsx("text", { fg: t.accent, children: `${SPINNER_FRAMES[frame % SPINNER_FRAMES.length]} ` }), _jsx("text", { fg: color, children: buildPlaceholderLabel(role, elapsedSec) })] }), detailLines.map((line, i) => (_jsx("text", { fg: t.textMuted, children: ` ↳ ${line}` }, i)))] }));
|
|
36
39
|
}
|
|
37
40
|
//# sourceMappingURL=council-placeholder-bubble.js.map
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
|
|
2
2
|
import { Semantic } from "@muonroi/agent-harness-opentui";
|
|
3
3
|
const PHASE_LABEL = {
|
|
4
|
-
clarify: "
|
|
5
|
-
preflight: "Pre-flight",
|
|
6
|
-
"plan-confirm": "Plan",
|
|
7
|
-
"post-debate": "
|
|
8
|
-
"pil-interview": "Understanding",
|
|
9
|
-
"pil-acceptance": "Confirm
|
|
10
|
-
"tool-loop-cap": "Tool-loop
|
|
11
|
-
"safety-override": "Safety
|
|
4
|
+
clarify: "Quick question",
|
|
5
|
+
preflight: "Pre-flight check",
|
|
6
|
+
"plan-confirm": "Plan review",
|
|
7
|
+
"post-debate": "Debate wrap-up",
|
|
8
|
+
"pil-interview": "Understanding your idea",
|
|
9
|
+
"pil-acceptance": "Confirm the goal",
|
|
10
|
+
"tool-loop-cap": "Tool-loop checkpoint",
|
|
11
|
+
"safety-override": "Safety check",
|
|
12
|
+
"ask-user": "The agent is asking",
|
|
12
13
|
};
|
|
13
14
|
/**
|
|
14
15
|
* AskUserQuestion-style card. Controlled component — parent owns the state
|
|
@@ -32,8 +33,8 @@ export function CouncilQuestionCard({ question, theme: t, state, freetextInputWi
|
|
|
32
33
|
const cursor = selected ? "›" : " ";
|
|
33
34
|
const numberColor = selected ? t.accent : t.textMuted;
|
|
34
35
|
const labelColor = selected ? t.accent : t.text;
|
|
35
|
-
return (_jsx(Semantic, { id: `askcard-option-${opt.value ?? i}`, role: "button", name: opt.label, selected: selected || undefined, children: _jsxs("box", { flexDirection: "column", children: [_jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: numberColor, children: `${cursor} ${i + 1}. ` }), _jsx("text", { fg: labelColor, children: opt.label }), isRecommended && _jsx("text", { fg: t.planOptionCheck, children: " (
|
|
36
|
-
}), freetext !== null && (_jsxs("box", { flexDirection: "column", paddingTop: 1, children: [_jsx("text", { fg: t.textMuted, children: "Type your answer · Enter to
|
|
36
|
+
return (_jsx(Semantic, { id: `askcard-option-${opt.value ?? i}`, role: "button", name: opt.label, selected: selected || undefined, children: _jsxs("box", { flexDirection: "column", children: [_jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: numberColor, children: `${cursor} ${i + 1}. ` }), _jsx("text", { fg: labelColor, children: opt.label }), isRecommended && _jsx("text", { fg: t.planOptionCheck, children: " (recommended)" })] }), opt.description && (_jsx("box", { paddingLeft: 5, children: _jsx("text", { fg: t.textMuted, children: opt.description }) }))] }) }, i));
|
|
37
|
+
}), freetext !== null && (_jsxs("box", { flexDirection: "column", paddingTop: 1, children: [_jsx("text", { fg: t.textMuted, children: "Type your answer · Enter to send · Esc to go back" }), _jsx(Semantic, { id: "askcard-input", role: "textbox", value: freetext, children: _jsx("box", { paddingLeft: 1, paddingRight: 1, width: freetextInputWidth, children: _jsx("text", { fg: t.planInputText, bg: t.planInputBg, children: freetext.length > 0 ? freetext : " " }) }) })] })), _jsx("box", { paddingTop: 1, children: _jsx("text", { fg: t.textDim, children: "↑/↓ to browse · Enter to select · Esc to cancel" }) })] }) }));
|
|
37
38
|
}
|
|
38
39
|
export function clampIndex(i, len) {
|
|
39
40
|
if (len <= 0)
|
|
@@ -50,7 +51,7 @@ function legacyFallback(q) {
|
|
|
50
51
|
.filter((s) => typeof s === "string" && s.trim().length > 0)
|
|
51
52
|
.map((s) => ({ label: s.trim(), value: s.trim(), kind: "choice" }));
|
|
52
53
|
if (choices.length === 0) {
|
|
53
|
-
choices.push({ label: "Answer", value: "", kind: "freetext", description: "
|
|
54
|
+
choices.push({ label: "Answer", value: "", kind: "freetext", description: "Type your answer here" });
|
|
54
55
|
}
|
|
55
56
|
return choices;
|
|
56
57
|
}
|
|
@@ -116,7 +117,7 @@ export function reduceCardKey(question, state, key) {
|
|
|
116
117
|
// Sentinel-ish text: caller may special-case this prefix to pause
|
|
117
118
|
// the council loop. For now we ship a clear default that records a
|
|
118
119
|
// meaningful answer so the run keeps moving.
|
|
119
|
-
text: "
|
|
120
|
+
text: "I'd like to talk this through a bit more before answering.",
|
|
120
121
|
kind: "chat",
|
|
121
122
|
},
|
|
122
123
|
},
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CouncilRoundRecord } from "../../types/index.js";
|
|
2
|
+
import type { Theme } from "../theme.js";
|
|
3
|
+
/**
|
|
4
|
+
* Selectable round list in the context rail (P2 / feature D). The rail keeps its
|
|
5
|
+
* GLOBAL overview; this list lets the user scope the MAIN transcript pane to a
|
|
6
|
+
* single round's debate turns without hiding the overview — reconciling the
|
|
7
|
+
* documented "never re-scope the rail" constraint (context-rail.tsx) with the
|
|
8
|
+
* "click a round → see its debate" request.
|
|
9
|
+
*
|
|
10
|
+
* Selection is driven by keyboard (Ctrl+←/→ when the composer is empty) and by
|
|
11
|
+
* mouse (OpenTUI onMouseDown per row). `null` = global view (all/live rounds).
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Pure selection-cycle used by the keyboard handler. Stepping before the first
|
|
15
|
+
* round returns to the global view (null); stepping past the last clamps.
|
|
16
|
+
*/
|
|
17
|
+
export declare function cycleRoundSelection(roundNumbers: number[], current: number | null, dir: 1 | -1): number | null;
|
|
18
|
+
export interface CouncilRailRoundsProps {
|
|
19
|
+
rounds: CouncilRoundRecord[];
|
|
20
|
+
/** Selected round number, or null for the global (all-rounds) view. */
|
|
21
|
+
selected: number | null;
|
|
22
|
+
onSelect: (round: number | null) => void;
|
|
23
|
+
width: number;
|
|
24
|
+
theme: Theme;
|
|
25
|
+
}
|
|
26
|
+
export declare function CouncilRailRounds({ rounds, selected, onSelect, width, theme }: CouncilRailRoundsProps): import("react").ReactNode;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
|
|
2
|
+
import { Semantic } from "@muonroi/agent-harness-opentui";
|
|
3
|
+
/**
|
|
4
|
+
* Selectable round list in the context rail (P2 / feature D). The rail keeps its
|
|
5
|
+
* GLOBAL overview; this list lets the user scope the MAIN transcript pane to a
|
|
6
|
+
* single round's debate turns without hiding the overview — reconciling the
|
|
7
|
+
* documented "never re-scope the rail" constraint (context-rail.tsx) with the
|
|
8
|
+
* "click a round → see its debate" request.
|
|
9
|
+
*
|
|
10
|
+
* Selection is driven by keyboard (Ctrl+←/→ when the composer is empty) and by
|
|
11
|
+
* mouse (OpenTUI onMouseDown per row). `null` = global view (all/live rounds).
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Pure selection-cycle used by the keyboard handler. Stepping before the first
|
|
15
|
+
* round returns to the global view (null); stepping past the last clamps.
|
|
16
|
+
*/
|
|
17
|
+
export function cycleRoundSelection(roundNumbers, current, dir) {
|
|
18
|
+
if (roundNumbers.length === 0)
|
|
19
|
+
return null;
|
|
20
|
+
if (current === null)
|
|
21
|
+
return dir === 1 ? roundNumbers[0] : null;
|
|
22
|
+
const i = roundNumbers.indexOf(current);
|
|
23
|
+
if (i === -1)
|
|
24
|
+
return dir === 1 ? roundNumbers[0] : null;
|
|
25
|
+
const j = i + dir;
|
|
26
|
+
if (j < 0)
|
|
27
|
+
return null; // step before first → global
|
|
28
|
+
if (j >= roundNumbers.length)
|
|
29
|
+
return roundNumbers[roundNumbers.length - 1]; // clamp at last
|
|
30
|
+
return roundNumbers[j];
|
|
31
|
+
}
|
|
32
|
+
function roundLabel(rec, maxWidth) {
|
|
33
|
+
const base = `Round ${rec.round}`;
|
|
34
|
+
if (!rec.topic)
|
|
35
|
+
return base;
|
|
36
|
+
const budget = Math.max(6, maxWidth - base.length - 3);
|
|
37
|
+
const topic = rec.topic.length > budget ? `${rec.topic.slice(0, budget - 1)}…` : rec.topic;
|
|
38
|
+
return `${base}: ${topic}`;
|
|
39
|
+
}
|
|
40
|
+
export function CouncilRailRounds({ rounds, selected, onSelect, width, theme }) {
|
|
41
|
+
if (rounds.length === 0)
|
|
42
|
+
return null;
|
|
43
|
+
const rows = [
|
|
44
|
+
{ key: "all", label: "All rounds", round: null, running: false },
|
|
45
|
+
...rounds.map((rec) => ({
|
|
46
|
+
key: `round-${rec.round}`,
|
|
47
|
+
label: roundLabel(rec, width),
|
|
48
|
+
round: rec.round,
|
|
49
|
+
running: rec.state === "running",
|
|
50
|
+
})),
|
|
51
|
+
];
|
|
52
|
+
return (_jsx(Semantic, { id: "rail-rounds", role: "listbox", name: "Debate rounds", props: { selected: selected ?? -1, count: rounds.length }, children: _jsxs("box", { flexDirection: "column", flexShrink: 0, marginTop: 1, children: [_jsx("text", { fg: theme.textMuted, attributes: 1, children: "Rounds" }), _jsx("text", { fg: theme.textDim, children: "ctrl+\u2190/\u2192 scope" }), rows.map((row) => {
|
|
53
|
+
const isSel = row.round === selected || (row.round === null && selected === null);
|
|
54
|
+
return (_jsx(Semantic, { id: row.round === null ? "rail-round-all" : `rail-round-${row.round}`, role: "listitem", name: row.label, selected: isSel || undefined, children: _jsxs("box", { flexDirection: "row", onMouseDown: () => onSelect(row.round), children: [_jsx("text", { fg: isSel ? theme.accent : theme.textMuted, children: isSel ? "› " : " " }), _jsx("text", { fg: isSel ? theme.accent : theme.text, attributes: isSel ? 1 : 0, children: row.label }), row.running ? _jsx("text", { fg: theme.accent, children: " ·live" }) : null] }) }, row.key));
|
|
55
|
+
})] }) }));
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=council-rail-rounds.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { CouncilRoundRecord } from "../../types/index.js";
|
|
3
|
+
import type { Theme } from "../theme.js";
|
|
4
|
+
export interface CouncilRoundGroupProps {
|
|
5
|
+
record: CouncilRoundRecord;
|
|
6
|
+
/**
|
|
7
|
+
* Turn nodes for this round. Rendered while the round is running (live stream)
|
|
8
|
+
* OR when the round is selected in the rail (inspect a finished round's debate).
|
|
9
|
+
*/
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
/** True when this round is the one selected in the rail — highlight + expand. */
|
|
12
|
+
selected?: boolean;
|
|
13
|
+
theme: Theme;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* F2 — header that frames a DONE round's persisted directive as its *opening*
|
|
17
|
+
* brief. Without it the directive's "Unmet (n/m)" line reads as current state and
|
|
18
|
+
* contradicts the "✓ Outcome: m/m met" line below on a converged round. When the
|
|
19
|
+
* round met everything, say so ("resolved below") so brief + outcome cohere.
|
|
20
|
+
*/
|
|
21
|
+
export declare function openingBriefHeader(allMet: boolean): string;
|
|
22
|
+
/**
|
|
23
|
+
* One debate round in the round-grouped transcript (P6). The running round auto-
|
|
24
|
+
* opens and streams its turns live; a done round collapses to an expanded-inline
|
|
25
|
+
* summary — input (topic + members), outcome (criteria met/total), and the
|
|
26
|
+
* leader's decision — so a finished round always shows what it achieved instead
|
|
27
|
+
* of a bare "done". When `selected` (P2/D — the round chosen in the rail), a
|
|
28
|
+
* finished round also expands its debate turns and highlights.
|
|
29
|
+
*/
|
|
30
|
+
export declare function CouncilRoundGroup({ record, children, selected, theme }: CouncilRoundGroupProps): ReactNode;
|
|
31
|
+
export interface CouncilRoundsOverviewProps {
|
|
32
|
+
rounds: CouncilRoundRecord[];
|
|
33
|
+
theme: Theme;
|
|
34
|
+
/** Optional session id appended to the overview so it stays visible above the debate transcript. */
|
|
35
|
+
sessionId?: string;
|
|
36
|
+
}
|
|
37
|
+
/** One-line overview above the round groups: totals + emergent count + session id. */
|
|
38
|
+
export declare function CouncilRoundsOverview({ rounds, theme, sessionId }: CouncilRoundsOverviewProps): ReactNode;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
|
|
2
|
+
import { Semantic } from "@muonroi/agent-harness-opentui";
|
|
3
|
+
const DECISION_LABEL = {
|
|
4
|
+
continue: "continue",
|
|
5
|
+
stop: "sufficient — stop",
|
|
6
|
+
extend: "extend (emergent round)",
|
|
7
|
+
aborted: "aborted",
|
|
8
|
+
"circuit-break": "circuit breaker",
|
|
9
|
+
"eval-unavailable": "evaluation unavailable",
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* F2 — header that frames a DONE round's persisted directive as its *opening*
|
|
13
|
+
* brief. Without it the directive's "Unmet (n/m)" line reads as current state and
|
|
14
|
+
* contradicts the "✓ Outcome: m/m met" line below on a converged round. When the
|
|
15
|
+
* round met everything, say so ("resolved below") so brief + outcome cohere.
|
|
16
|
+
*/
|
|
17
|
+
export function openingBriefHeader(allMet) {
|
|
18
|
+
return `Opening brief${allMet ? " — resolved below" : ""}:`;
|
|
19
|
+
}
|
|
20
|
+
/** Color the leader's decision by whether the round landed well. */
|
|
21
|
+
function decisionColor(decision, theme) {
|
|
22
|
+
switch (decision) {
|
|
23
|
+
case "stop":
|
|
24
|
+
return theme.diffAddedFg; // sufficient — a clean landing
|
|
25
|
+
case "aborted":
|
|
26
|
+
case "circuit-break":
|
|
27
|
+
case "eval-unavailable":
|
|
28
|
+
return theme.diffRemovedFg; // ended abnormally
|
|
29
|
+
default:
|
|
30
|
+
return theme.accent; // continue / extend — still in progress
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* One debate round in the round-grouped transcript (P6). The running round auto-
|
|
35
|
+
* opens and streams its turns live; a done round collapses to an expanded-inline
|
|
36
|
+
* summary — input (topic + members), outcome (criteria met/total), and the
|
|
37
|
+
* leader's decision — so a finished round always shows what it achieved instead
|
|
38
|
+
* of a bare "done". When `selected` (P2/D — the round chosen in the rail), a
|
|
39
|
+
* finished round also expands its debate turns and highlights.
|
|
40
|
+
*/
|
|
41
|
+
export function CouncilRoundGroup({ record, children, selected = false, theme }) {
|
|
42
|
+
const running = record.state === "running";
|
|
43
|
+
const headParts = [`Round ${record.round}`];
|
|
44
|
+
if (record.topic)
|
|
45
|
+
headParts.push(record.topic);
|
|
46
|
+
if (record.emergent)
|
|
47
|
+
headParts.push("(emergent)");
|
|
48
|
+
// Outcome verdict: how many acceptance criteria the round met. Colored + marked
|
|
49
|
+
// so a scan of the transcript shows at a glance which rounds landed cleanly.
|
|
50
|
+
const total = record.criteriaTotal ?? -1;
|
|
51
|
+
const met = record.criteriaMet ?? 0;
|
|
52
|
+
const hasCriteria = total > 0;
|
|
53
|
+
const allMet = hasCriteria && met >= total;
|
|
54
|
+
const noneMet = hasCriteria && met === 0;
|
|
55
|
+
const outcomeColor = allMet ? theme.diffAddedFg : noneMet ? theme.diffRemovedFg : theme.mdItalic;
|
|
56
|
+
const outcomeMark = allMet ? "✓" : noneMet ? "✗" : "◐";
|
|
57
|
+
return (_jsx(Semantic, { id: `council-round-${record.round}`, role: "region", name: `Round ${record.round}`, props: {
|
|
58
|
+
state: record.state,
|
|
59
|
+
emergent: record.emergent,
|
|
60
|
+
selected,
|
|
61
|
+
criteriaMet: record.criteriaMet ?? -1,
|
|
62
|
+
criteriaTotal: record.criteriaTotal ?? -1,
|
|
63
|
+
decision: record.leaderDecision ?? "",
|
|
64
|
+
directive: record.directive ?? "",
|
|
65
|
+
}, children: _jsxs("box", { flexDirection: "column", marginBottom: 1, border: ["left"], borderColor: running || selected ? theme.accent : theme.councilLeaderBorder, paddingLeft: 2, children: [_jsx("text", { fg: running || selected ? theme.accent : theme.textMuted, attributes: 1, children: `${running ? "> " : selected ? "› " : "✓ "}${headParts.join(" · ")}` }), record.participants.length > 0 && (_jsx("text", { fg: theme.textMuted, children: `${record.participants.length} members: ${record.participants.join(", ")}` })), running ? (
|
|
66
|
+
// Running round streams its turns live.
|
|
67
|
+
_jsx("box", { flexDirection: "column", marginTop: 1, children: children })) : (
|
|
68
|
+
// Done round: expanded debate turns (when selected in the rail) followed
|
|
69
|
+
// by the outcome verdict + leader decision summary.
|
|
70
|
+
_jsxs("box", { flexDirection: "column", children: [children ? (_jsx("box", { flexDirection: "column", marginTop: 1, marginBottom: 1, children: children })) : null, record.directive && _jsx("text", { fg: theme.textMuted, children: openingBriefHeader(allMet) }), record.directive &&
|
|
71
|
+
record.directive.split("\n").map((line, i) => (_jsx("text", { fg: theme.accent, attributes: i === 0 ? 1 : 0, children: i === 0 ? `▶ ${line}` : ` ${line}` }, `dir-${i}`))), hasCriteria && (_jsx("text", { fg: outcomeColor, attributes: 1, children: `${outcomeMark} Outcome: ${met}/${total} criteria met` })), record.leaderDecision && (_jsx("text", { fg: decisionColor(record.leaderDecision, theme), attributes: 1, children: `Decision: ${DECISION_LABEL[record.leaderDecision]}` })), record.leaderReason && _jsx("text", { fg: theme.textMuted, children: record.leaderReason }), record.nextRoundFocus && _jsx("text", { fg: theme.textMuted, children: `Next focus: ${record.nextRoundFocus}` })] }))] }) }));
|
|
72
|
+
}
|
|
73
|
+
/** One-line overview above the round groups: totals + emergent count + session id. */
|
|
74
|
+
export function CouncilRoundsOverview({ rounds, theme, sessionId }) {
|
|
75
|
+
const total = rounds.length;
|
|
76
|
+
const emergent = rounds.filter((r) => r.emergent).length;
|
|
77
|
+
const members = new Set();
|
|
78
|
+
for (const r of rounds)
|
|
79
|
+
for (const p of r.participants)
|
|
80
|
+
members.add(p);
|
|
81
|
+
const parts = [`Debate: ${total} round${total === 1 ? "" : "s"}`, `${members.size} members`];
|
|
82
|
+
if (emergent > 0)
|
|
83
|
+
parts.push(`${emergent} emergent`);
|
|
84
|
+
if (sessionId)
|
|
85
|
+
parts.push(`session ${sessionId}`);
|
|
86
|
+
return (_jsx(Semantic, { id: "council-rounds-overview", role: "region", props: { total, emergent, members: members.size, sessionId }, children: _jsx("text", { fg: theme.textMuted, attributes: 1, children: parts.join(" · ") }) }));
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=council-round-group.js.map
|
|
@@ -3,8 +3,10 @@ import type { Theme } from "../theme.js";
|
|
|
3
3
|
export interface CouncilStatusListProps {
|
|
4
4
|
statuses: CouncilStatusData[];
|
|
5
5
|
theme: Theme;
|
|
6
|
+
/** Optional session id rendered as a pinned header so the user can correlate a council run with its session. */
|
|
7
|
+
sessionId?: string;
|
|
6
8
|
}
|
|
7
|
-
export declare function CouncilStatusList({ statuses, theme: t }: CouncilStatusListProps): import("react").ReactNode;
|
|
9
|
+
export declare function CouncilStatusList({ statuses, theme: t, sessionId }: CouncilStatusListProps): import("react").ReactNode;
|
|
8
10
|
/**
|
|
9
11
|
* Reducer-friendly upsert: returns the next status array given an incoming
|
|
10
12
|
* status chunk. Done statuses are kept until DONE_HOLD_MS expires (caller
|
|
@@ -2,16 +2,6 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "@opentui/reac
|
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
3
|
const SPINNER_FRAMES = ["⬒", "⬔", "⬓", "⬕"];
|
|
4
4
|
const DONE_HOLD_MS = 1500;
|
|
5
|
-
const PHASE_LABEL = {
|
|
6
|
-
clarify: "clarify",
|
|
7
|
-
plan_debate: "plan",
|
|
8
|
-
research: "research",
|
|
9
|
-
opening: "opening",
|
|
10
|
-
exchange: "exchange",
|
|
11
|
-
evaluate: "evaluate",
|
|
12
|
-
synthesis: "synthesis",
|
|
13
|
-
summary: "summary",
|
|
14
|
-
};
|
|
15
5
|
function Spinner() {
|
|
16
6
|
const [frame, setFrame] = useState(0);
|
|
17
7
|
useEffect(() => {
|
|
@@ -20,6 +10,20 @@ function Spinner() {
|
|
|
20
10
|
}, []);
|
|
21
11
|
return _jsx(_Fragment, { children: SPINNER_FRAMES[frame] });
|
|
22
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Re-render every `tickMs` so active rows show a live-ticking elapsed counter.
|
|
15
|
+
* Without this the row freezes at the last emitter-sent elapsedMs (emitters
|
|
16
|
+
* only send on state transitions) — the same "im lìm" symptom the phase
|
|
17
|
+
* timeline fixed with its own heartbeat (council-phase-timeline.tsx).
|
|
18
|
+
*/
|
|
19
|
+
function useHeartbeat(tickMs = 1000) {
|
|
20
|
+
const [, force] = useState(0);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
const id = setInterval(() => force((n) => n + 1), tickMs);
|
|
23
|
+
return () => clearInterval(id);
|
|
24
|
+
}, [tickMs]);
|
|
25
|
+
return Date.now();
|
|
26
|
+
}
|
|
23
27
|
function formatElapsed(ms) {
|
|
24
28
|
if (!ms || ms < 0)
|
|
25
29
|
return "0s";
|
|
@@ -38,18 +42,22 @@ function formatTokens(s) {
|
|
|
38
42
|
parts.push(`↓ ${s.tokensOut}`);
|
|
39
43
|
return parts.length > 0 ? ` · ${parts.join(" · ")} tokens` : "";
|
|
40
44
|
}
|
|
41
|
-
export function CouncilStatusList({ statuses, theme: t }) {
|
|
42
|
-
|
|
45
|
+
export function CouncilStatusList({ statuses, theme: t, sessionId }) {
|
|
46
|
+
// Hook must run unconditionally — before the empty-list early return.
|
|
47
|
+
const now = useHeartbeat(1000);
|
|
48
|
+
if (statuses.length === 0 && !sessionId)
|
|
43
49
|
return null;
|
|
44
|
-
return (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
return (_jsxs("box", { flexDirection: "column", paddingLeft: 2, paddingTop: 0, flexShrink: 0, children: [sessionId && (_jsx("box", { marginBottom: 1, children: _jsx("text", { fg: t.textDim, children: `session ${sessionId}` }) })), statuses.map((s) => {
|
|
51
|
+
const isError = s.state === "error";
|
|
52
|
+
const isDone = s.state === "done";
|
|
53
|
+
const marker = isError ? "✗" : isDone ? "✓" : _jsx(Spinner, {});
|
|
54
|
+
const markerColor = isError ? t.diffRemovedFg : isDone ? t.planOptionCheck : t.accent;
|
|
55
|
+
const labelColor = isError ? t.diffRemovedFg : t.text;
|
|
56
|
+
const isLive = s.state === "start" || s.state === "tick";
|
|
57
|
+
const liveElapsedMs = isLive && typeof s.startedAt === "number" ? Math.max(0, now - s.startedAt) : s.elapsedMs;
|
|
58
|
+
const meta = `(${formatElapsed(liveElapsedMs)}${formatTokens(s)})`;
|
|
59
|
+
return (_jsxs("box", { flexDirection: "column", children: [_jsxs("box", { children: [_jsx("text", { fg: markerColor, children: marker }), _jsx("text", { fg: labelColor, children: ` ${s.label}` }), _jsx("text", { fg: t.textMuted, children: ` ${meta}` })] }), s.detail && (_jsx("box", { paddingLeft: 2, children: _jsx("text", { fg: t.textMuted, children: `└ ${truncate(s.detail, 140)}` }) })), s.errorMessage && (_jsx("box", { paddingLeft: 2, children: _jsx("text", { fg: t.diffRemovedFg, children: `└ ${truncate(s.errorMessage, 140)}` }) }))] }, s.statusId));
|
|
60
|
+
})] }));
|
|
53
61
|
}
|
|
54
62
|
function truncate(s, max) {
|
|
55
63
|
if (s.length <= max)
|
|
@@ -63,10 +71,14 @@ function truncate(s, max) {
|
|
|
63
71
|
*/
|
|
64
72
|
export function upsertStatus(prev, next) {
|
|
65
73
|
const idx = prev.findIndex((s) => s.statusId === next.statusId);
|
|
66
|
-
if (idx === -1)
|
|
67
|
-
|
|
74
|
+
if (idx === -1) {
|
|
75
|
+
// Stamp a client-side start anchor so the row can live-tick between emitter
|
|
76
|
+
// updates (emitters only send elapsedMs on state transitions).
|
|
77
|
+
const startedAt = next.startedAt ?? Date.now() - (next.elapsedMs ?? 0);
|
|
78
|
+
return [...prev, { ...next, startedAt }];
|
|
79
|
+
}
|
|
68
80
|
const out = prev.slice();
|
|
69
|
-
out[idx] = next;
|
|
81
|
+
out[idx] = { ...next, startedAt: next.startedAt ?? out[idx].startedAt };
|
|
70
82
|
return out;
|
|
71
83
|
}
|
|
72
84
|
/** Remove `done` rows that finished more than DONE_HOLD_MS ago. */
|