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
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/ui/utils/tool-summary.ts
|
|
3
|
+
*
|
|
4
|
+
* Phrasing for the tool-group panel. Pure string helpers, no React, so the
|
|
5
|
+
* wording is unit-testable and the component stays presentational.
|
|
6
|
+
*
|
|
7
|
+
* Active: "Reading 2 files…" (header, present participle)
|
|
8
|
+
* Done: "Read 2 files, ran 1 shell command" (past-tense recap)
|
|
9
|
+
*
|
|
10
|
+
* Counting is per CATEGORY, not per tool name: read_file and
|
|
11
|
+
* mcp__filesystem__read_text_file are both "files" to a reader.
|
|
12
|
+
*/
|
|
13
|
+
import { verbForTool } from "./tools.js";
|
|
14
|
+
const CATEGORIES = {
|
|
15
|
+
read: { gerund: "Reading", past: "read", noun: "file", nounPlural: "files" },
|
|
16
|
+
write: { gerund: "Writing", past: "wrote", noun: "file", nounPlural: "files" },
|
|
17
|
+
edit: { gerund: "Editing", past: "edited", noun: "file", nounPlural: "files" },
|
|
18
|
+
bash: { gerund: "Running", past: "ran", noun: "shell command", nounPlural: "shell commands" },
|
|
19
|
+
search: { gerund: "Searching", past: "ran", noun: "search", nounPlural: "searches" },
|
|
20
|
+
agent: { gerund: "Exploring", past: "ran", noun: "sub-agent", nounPlural: "sub-agents" },
|
|
21
|
+
other: { gerund: "Working", past: "ran", noun: "tool", nounPlural: "tools" },
|
|
22
|
+
};
|
|
23
|
+
/** Stable phrase order so the recap doesn't reshuffle as items land. */
|
|
24
|
+
const ORDER = ["read", "write", "edit", "bash", "search", "agent", "other"];
|
|
25
|
+
export function categoryForTool(name) {
|
|
26
|
+
if (name === "write_file" || /^mcp_+filesystem__write_file$/.test(name))
|
|
27
|
+
return "write";
|
|
28
|
+
if (name === "edit_file" || /^mcp_+filesystem__edit_file$/.test(name))
|
|
29
|
+
return "edit";
|
|
30
|
+
if (name === "bash")
|
|
31
|
+
return "bash";
|
|
32
|
+
if (name === "task" || name === "delegate")
|
|
33
|
+
return "agent";
|
|
34
|
+
// Fall back to the existing verb vocabulary so a new tool inherits sane
|
|
35
|
+
// phrasing without being enumerated here twice.
|
|
36
|
+
const verb = verbForTool(name);
|
|
37
|
+
if (verb === "Reading")
|
|
38
|
+
return "read";
|
|
39
|
+
if (verb === "Searching")
|
|
40
|
+
return "search";
|
|
41
|
+
return "other";
|
|
42
|
+
}
|
|
43
|
+
function countByCategory(toolNames) {
|
|
44
|
+
const counts = new Map();
|
|
45
|
+
for (const n of toolNames) {
|
|
46
|
+
const c = categoryForTool(n);
|
|
47
|
+
counts.set(c, (counts.get(c) ?? 0) + 1);
|
|
48
|
+
}
|
|
49
|
+
return counts;
|
|
50
|
+
}
|
|
51
|
+
function phrase(cat, n, past) {
|
|
52
|
+
const noun = n === 1 ? cat.noun : cat.nounPlural;
|
|
53
|
+
return past ? `${cat.past} ${n} ${noun}` : `${cat.gerund} ${n} ${noun}`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Header while the group runs: "Reading 2 files…".
|
|
57
|
+
* With a mixed batch the dominant category wins and the rest are summed into a
|
|
58
|
+
* trailing "+N more" so the header never claims work it isn't doing.
|
|
59
|
+
*/
|
|
60
|
+
export function activeToolGroupHeader(toolNames) {
|
|
61
|
+
if (toolNames.length === 0)
|
|
62
|
+
return "Working…";
|
|
63
|
+
const counts = countByCategory(toolNames);
|
|
64
|
+
let bestKey = "other";
|
|
65
|
+
let best = 0;
|
|
66
|
+
for (const key of ORDER) {
|
|
67
|
+
const c = counts.get(key) ?? 0;
|
|
68
|
+
if (c > best) {
|
|
69
|
+
best = c;
|
|
70
|
+
bestKey = key;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const rest = toolNames.length - best;
|
|
74
|
+
const head = phrase(CATEGORIES[bestKey], best, false);
|
|
75
|
+
return rest > 0 ? `${head} +${rest} more…` : `${head}…`;
|
|
76
|
+
}
|
|
77
|
+
/** Past-tense recap once the group closes: "Read 2 files, ran 1 shell command". */
|
|
78
|
+
export function doneToolGroupSummary(toolNames) {
|
|
79
|
+
if (toolNames.length === 0)
|
|
80
|
+
return "Done";
|
|
81
|
+
const counts = countByCategory(toolNames);
|
|
82
|
+
const parts = [];
|
|
83
|
+
for (const key of ORDER) {
|
|
84
|
+
const n = counts.get(key) ?? 0;
|
|
85
|
+
if (n > 0)
|
|
86
|
+
parts.push(phrase(CATEGORIES[key], n, true));
|
|
87
|
+
}
|
|
88
|
+
const joined = parts.join(", ");
|
|
89
|
+
return joined.charAt(0).toUpperCase() + joined.slice(1);
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=tool-summary.js.map
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Plan 06 (status bar) subscribes to DowngradeEvent for UI updates.
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
10
|
+
import { getRoutedModelByTier } from "../router/peak-hour.js";
|
|
11
11
|
import { getDefaultProvider } from "../utils/settings.js";
|
|
12
12
|
function buildDowngradeChain() {
|
|
13
13
|
const provider = getDefaultProvider() ?? undefined;
|
|
@@ -15,7 +15,7 @@ function buildDowngradeChain() {
|
|
|
15
15
|
const seen = new Set();
|
|
16
16
|
const chain = [];
|
|
17
17
|
for (const tier of tiers) {
|
|
18
|
-
const m =
|
|
18
|
+
const m = getRoutedModelByTier(tier, provider);
|
|
19
19
|
if (m && !seen.has(m.id)) {
|
|
20
20
|
chain.push(m.id);
|
|
21
21
|
seen.add(m.id);
|
|
@@ -24,12 +24,12 @@ async function ensureDirectory(filePath) {
|
|
|
24
24
|
export async function appendProductLedger(productRunId, entry, homeOverride) {
|
|
25
25
|
const filePath = getProductLedgerPath(productRunId, homeOverride);
|
|
26
26
|
await ensureDirectory(filePath);
|
|
27
|
-
// Ensure file exists for lockfile to target
|
|
27
|
+
// Ensure file exists for lockfile to target without truncating it concurrently
|
|
28
28
|
try {
|
|
29
29
|
await fs.access(filePath);
|
|
30
30
|
}
|
|
31
31
|
catch {
|
|
32
|
-
await fs.
|
|
32
|
+
await fs.appendFile(filePath, "");
|
|
33
33
|
}
|
|
34
34
|
const releaseLock = await lockfile.lock(filePath, {
|
|
35
35
|
retries: { retries: 10, minTimeout: 10, maxTimeout: 100 },
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/utils/event-loop-monitor.ts
|
|
3
|
+
*
|
|
4
|
+
* Event-loop block detector.
|
|
5
|
+
*
|
|
6
|
+
* Root cause it addresses (observed live, 2026-07-16, session 90c3ff533826):
|
|
7
|
+
* the TUI froze for 304.5s mid-turn — keystrokes and mouse clicks produced
|
|
8
|
+
* nothing during the freeze, then ALL replayed at once when it ended (the
|
|
9
|
+
* signature of a blocked event loop, not a stalled render). Crucially the
|
|
10
|
+
* 120s provider stall watchdog (tool-engine.ts) did NOT rescue the turn at its
|
|
11
|
+
* deadline: `stall_rescue` landed at 09:05:47, 6.7s AFTER the loop recovered at
|
|
12
|
+
* 09:05:41. A setTimeout cannot fire while the loop is blocked, so every
|
|
13
|
+
* existing guard in this codebase is blind to this failure mode BY
|
|
14
|
+
* CONSTRUCTION — they are all loop-driven. Same pattern measured across 4
|
|
15
|
+
* models / 4 providers (grok-composer 304.5s, deepseek-v4-flash 320.2s,
|
|
16
|
+
* kimi-k2.7-code 329.7s + 314.8s), so it is not a provider quirk.
|
|
17
|
+
*
|
|
18
|
+
* This module is the missing instrument: a timer that measures its OWN lateness.
|
|
19
|
+
* It cannot prevent a block (it is loop-driven too), but the drift it observes
|
|
20
|
+
* on the first tick AFTER the loop frees up measures the block that just
|
|
21
|
+
* happened. Pair it with the CPU profiler in `loop-profiler.ts`, whose V8
|
|
22
|
+
* sampling thread runs INDEPENDENTLY of the JS thread and therefore captures
|
|
23
|
+
* the culprit stack DURING the block.
|
|
24
|
+
*
|
|
25
|
+
* Deliberately dependency-free and cheap: one unref'd interval, no allocation
|
|
26
|
+
* per tick. `detectBlock` is pure so the drift maths is unit-testable without
|
|
27
|
+
* timers.
|
|
28
|
+
*/
|
|
29
|
+
/** A detected event-loop block, reported to `onBlock`. */
|
|
30
|
+
export interface EventLoopBlock {
|
|
31
|
+
/**
|
|
32
|
+
* How long the loop was blocked, in ms. Measured as the monitor tick's own
|
|
33
|
+
* lateness, so it UNDER-reports by up to one tick interval (a block shorter
|
|
34
|
+
* than the tick can hide entirely between two ticks). Treat it as a lower
|
|
35
|
+
* bound.
|
|
36
|
+
*/
|
|
37
|
+
blockedMs: number;
|
|
38
|
+
/** What the process last said it was doing — see {@link setLoopBreadcrumb}. */
|
|
39
|
+
breadcrumb: string | null;
|
|
40
|
+
/** ISO timestamp of the tick that observed the block (i.e. after it ended). */
|
|
41
|
+
detectedAt: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Decide whether an interval tick's lateness constitutes a block.
|
|
45
|
+
*
|
|
46
|
+
* A healthy tick fires ~`tickMs` after the previous one; the loop being busy
|
|
47
|
+
* pushes it later. Lateness beyond `thresholdMs` is reported as a block of that
|
|
48
|
+
* duration. Pure so the drift maths is testable without real timers.
|
|
49
|
+
*
|
|
50
|
+
* @param expectedAt when this tick was due (monotonic ms)
|
|
51
|
+
* @param actualAt when it actually ran (monotonic ms)
|
|
52
|
+
* @param thresholdMs report only blocks at least this long; <= 0 disables
|
|
53
|
+
* @returns block duration in ms, or null when the tick was on time
|
|
54
|
+
*/
|
|
55
|
+
export declare function detectBlock(expectedAt: number, actualAt: number, thresholdMs: number): number | null;
|
|
56
|
+
/**
|
|
57
|
+
* Record what the process is about to do, so a block report can name a suspect
|
|
58
|
+
* instead of just a duration. Call it around anything that could plausibly run
|
|
59
|
+
* long and synchronously (tool execution, a stream step). Cheap — a single
|
|
60
|
+
* assignment; safe to call on a hot path.
|
|
61
|
+
*
|
|
62
|
+
* Pass null to clear. Not a stack: last writer wins, by design — the goal is a
|
|
63
|
+
* hint for the profile, and the profile is the real evidence.
|
|
64
|
+
*/
|
|
65
|
+
export declare function setLoopBreadcrumb(label: string | null): void;
|
|
66
|
+
/** The current breadcrumb, or null. */
|
|
67
|
+
export declare function getLoopBreadcrumb(): string | null;
|
|
68
|
+
/** Options for {@link startEventLoopMonitor}. */
|
|
69
|
+
export interface EventLoopMonitorOpts {
|
|
70
|
+
/** Report blocks at least this long. <= 0 disables the monitor entirely. */
|
|
71
|
+
thresholdMs: number;
|
|
72
|
+
/**
|
|
73
|
+
* How often to check. Bounds both the detection granularity and the amount a
|
|
74
|
+
* block can be under-reported by. 500ms costs ~2 wakeups/sec.
|
|
75
|
+
*/
|
|
76
|
+
tickMs?: number;
|
|
77
|
+
/** Called once per detected block. Must not throw (it is guarded anyway). */
|
|
78
|
+
onBlock: (block: EventLoopBlock) => void;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Start watching for event-loop blocks. Returns a stop function (idempotent).
|
|
82
|
+
*
|
|
83
|
+
* The interval is unref'd so it never keeps the process alive on its own.
|
|
84
|
+
*/
|
|
85
|
+
export declare function startEventLoopMonitor(opts: EventLoopMonitorOpts): () => void;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/utils/event-loop-monitor.ts
|
|
3
|
+
*
|
|
4
|
+
* Event-loop block detector.
|
|
5
|
+
*
|
|
6
|
+
* Root cause it addresses (observed live, 2026-07-16, session 90c3ff533826):
|
|
7
|
+
* the TUI froze for 304.5s mid-turn — keystrokes and mouse clicks produced
|
|
8
|
+
* nothing during the freeze, then ALL replayed at once when it ended (the
|
|
9
|
+
* signature of a blocked event loop, not a stalled render). Crucially the
|
|
10
|
+
* 120s provider stall watchdog (tool-engine.ts) did NOT rescue the turn at its
|
|
11
|
+
* deadline: `stall_rescue` landed at 09:05:47, 6.7s AFTER the loop recovered at
|
|
12
|
+
* 09:05:41. A setTimeout cannot fire while the loop is blocked, so every
|
|
13
|
+
* existing guard in this codebase is blind to this failure mode BY
|
|
14
|
+
* CONSTRUCTION — they are all loop-driven. Same pattern measured across 4
|
|
15
|
+
* models / 4 providers (grok-composer 304.5s, deepseek-v4-flash 320.2s,
|
|
16
|
+
* kimi-k2.7-code 329.7s + 314.8s), so it is not a provider quirk.
|
|
17
|
+
*
|
|
18
|
+
* This module is the missing instrument: a timer that measures its OWN lateness.
|
|
19
|
+
* It cannot prevent a block (it is loop-driven too), but the drift it observes
|
|
20
|
+
* on the first tick AFTER the loop frees up measures the block that just
|
|
21
|
+
* happened. Pair it with the CPU profiler in `loop-profiler.ts`, whose V8
|
|
22
|
+
* sampling thread runs INDEPENDENTLY of the JS thread and therefore captures
|
|
23
|
+
* the culprit stack DURING the block.
|
|
24
|
+
*
|
|
25
|
+
* Deliberately dependency-free and cheap: one unref'd interval, no allocation
|
|
26
|
+
* per tick. `detectBlock` is pure so the drift maths is unit-testable without
|
|
27
|
+
* timers.
|
|
28
|
+
*/
|
|
29
|
+
import { logger } from "./logger.js";
|
|
30
|
+
/**
|
|
31
|
+
* Decide whether an interval tick's lateness constitutes a block.
|
|
32
|
+
*
|
|
33
|
+
* A healthy tick fires ~`tickMs` after the previous one; the loop being busy
|
|
34
|
+
* pushes it later. Lateness beyond `thresholdMs` is reported as a block of that
|
|
35
|
+
* duration. Pure so the drift maths is testable without real timers.
|
|
36
|
+
*
|
|
37
|
+
* @param expectedAt when this tick was due (monotonic ms)
|
|
38
|
+
* @param actualAt when it actually ran (monotonic ms)
|
|
39
|
+
* @param thresholdMs report only blocks at least this long; <= 0 disables
|
|
40
|
+
* @returns block duration in ms, or null when the tick was on time
|
|
41
|
+
*/
|
|
42
|
+
export function detectBlock(expectedAt, actualAt, thresholdMs) {
|
|
43
|
+
if (!(thresholdMs > 0))
|
|
44
|
+
return null;
|
|
45
|
+
const lateBy = actualAt - expectedAt;
|
|
46
|
+
if (!Number.isFinite(lateBy) || lateBy < thresholdMs)
|
|
47
|
+
return null;
|
|
48
|
+
return Math.round(lateBy);
|
|
49
|
+
}
|
|
50
|
+
let _breadcrumb = null;
|
|
51
|
+
/**
|
|
52
|
+
* Record what the process is about to do, so a block report can name a suspect
|
|
53
|
+
* instead of just a duration. Call it around anything that could plausibly run
|
|
54
|
+
* long and synchronously (tool execution, a stream step). Cheap — a single
|
|
55
|
+
* assignment; safe to call on a hot path.
|
|
56
|
+
*
|
|
57
|
+
* Pass null to clear. Not a stack: last writer wins, by design — the goal is a
|
|
58
|
+
* hint for the profile, and the profile is the real evidence.
|
|
59
|
+
*/
|
|
60
|
+
export function setLoopBreadcrumb(label) {
|
|
61
|
+
_breadcrumb = label;
|
|
62
|
+
}
|
|
63
|
+
/** The current breadcrumb, or null. */
|
|
64
|
+
export function getLoopBreadcrumb() {
|
|
65
|
+
return _breadcrumb;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Start watching for event-loop blocks. Returns a stop function (idempotent).
|
|
69
|
+
*
|
|
70
|
+
* The interval is unref'd so it never keeps the process alive on its own.
|
|
71
|
+
*/
|
|
72
|
+
export function startEventLoopMonitor(opts) {
|
|
73
|
+
const { thresholdMs, onBlock } = opts;
|
|
74
|
+
const tickMs = opts.tickMs && opts.tickMs > 0 ? opts.tickMs : 500;
|
|
75
|
+
if (!(thresholdMs > 0))
|
|
76
|
+
return () => { };
|
|
77
|
+
let expectedAt = performance.now() + tickMs;
|
|
78
|
+
const timer = setInterval(() => {
|
|
79
|
+
const actualAt = performance.now();
|
|
80
|
+
const blockedMs = detectBlock(expectedAt, actualAt, thresholdMs);
|
|
81
|
+
expectedAt = actualAt + tickMs;
|
|
82
|
+
if (blockedMs === null)
|
|
83
|
+
return;
|
|
84
|
+
try {
|
|
85
|
+
onBlock({
|
|
86
|
+
blockedMs,
|
|
87
|
+
breadcrumb: getLoopBreadcrumb(),
|
|
88
|
+
detectedAt: new Date().toISOString(),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
logger.error("cli", `[event-loop-monitor] onBlock handler threw: ${err?.message}`, {
|
|
93
|
+
error: err,
|
|
94
|
+
blockedMs,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}, tickMs);
|
|
98
|
+
timer.unref?.();
|
|
99
|
+
let stopped = false;
|
|
100
|
+
return () => {
|
|
101
|
+
if (stopped)
|
|
102
|
+
return;
|
|
103
|
+
stopped = true;
|
|
104
|
+
clearInterval(timer);
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=event-loop-monitor.js.map
|
|
@@ -194,7 +194,8 @@ export function detectInstallMethod(homeDir = os.homedir()) {
|
|
|
194
194
|
}
|
|
195
195
|
// Not under node_modules and not launched by node/bun → standalone binary.
|
|
196
196
|
const exeBase = ((process.execPath || "").replace(/\\/g, "/").split("/").pop() ?? "").toLowerCase();
|
|
197
|
-
|
|
197
|
+
const isNodeOrBunRunner = /^(node|bun)(\.exe|-[\d.]+)?$/i.test(exeBase);
|
|
198
|
+
if (!modPath.includes("/node_modules/") && !isNodeOrBunRunner) {
|
|
198
199
|
return "compiled";
|
|
199
200
|
}
|
|
200
201
|
// Linked/source build run from a git checkout (e.g. `bun link`, a symlinked
|
|
@@ -50,3 +50,17 @@ export declare function withDeadlineRace<T>(fn: () => Promise<T>, deadlineMs: nu
|
|
|
50
50
|
* The short grace lets the normal fetch-level abort win first when it's quick.
|
|
51
51
|
*/
|
|
52
52
|
abortSignal?: AbortSignal, abortGraceMs?: number): Promise<T>;
|
|
53
|
+
/**
|
|
54
|
+
* Wall-clock backstop (ms) for an isolated sub-agent task (`runIsolatedTask`).
|
|
55
|
+
*
|
|
56
|
+
* The council `generate()` chokepoint and the sprint impl/verify stages already
|
|
57
|
+
* have deadlines, but the *other* `runIsolatedTask` await points — plan-adherence
|
|
58
|
+
* review + fix, council research, grounding-verify — were bare `await`s. A
|
|
59
|
+
* provider that hangs on the JS side after the sub-agent's stream finishes wedges
|
|
60
|
+
* the whole pipeline with no error (observed live: run mrhc43f0fb9b impl, and the
|
|
61
|
+
* scoping stall). Wrap those calls in `withDeadlineRace(fn, getIsolatedTaskDeadlineMs(), ...)`
|
|
62
|
+
* so a hang surfaces as a rejection the caller already handles. Generous by
|
|
63
|
+
* default so a legitimately long tool-using sub-agent is not cut short; override
|
|
64
|
+
* with MUONROI_IDEAL_ISOLATED_TASK_MS. Clamped to [60s, 30min].
|
|
65
|
+
*/
|
|
66
|
+
export declare function getIsolatedTaskDeadlineMs(): number;
|
|
@@ -106,4 +106,23 @@ abortSignal, abortGraceMs = 1500) {
|
|
|
106
106
|
abortSignal.removeEventListener("abort", abortListener);
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Wall-clock backstop (ms) for an isolated sub-agent task (`runIsolatedTask`).
|
|
111
|
+
*
|
|
112
|
+
* The council `generate()` chokepoint and the sprint impl/verify stages already
|
|
113
|
+
* have deadlines, but the *other* `runIsolatedTask` await points — plan-adherence
|
|
114
|
+
* review + fix, council research, grounding-verify — were bare `await`s. A
|
|
115
|
+
* provider that hangs on the JS side after the sub-agent's stream finishes wedges
|
|
116
|
+
* the whole pipeline with no error (observed live: run mrhc43f0fb9b impl, and the
|
|
117
|
+
* scoping stall). Wrap those calls in `withDeadlineRace(fn, getIsolatedTaskDeadlineMs(), ...)`
|
|
118
|
+
* so a hang surfaces as a rejection the caller already handles. Generous by
|
|
119
|
+
* default so a legitimately long tool-using sub-agent is not cut short; override
|
|
120
|
+
* with MUONROI_IDEAL_ISOLATED_TASK_MS. Clamped to [60s, 30min].
|
|
121
|
+
*/
|
|
122
|
+
export function getIsolatedTaskDeadlineMs() {
|
|
123
|
+
const raw = Number.parseInt(process.env.MUONROI_IDEAL_ISOLATED_TASK_MS ?? "", 10);
|
|
124
|
+
if (Number.isFinite(raw) && raw >= 60_000 && raw <= 1_800_000)
|
|
125
|
+
return raw;
|
|
126
|
+
return 900_000; // 15 min backstop
|
|
127
|
+
}
|
|
109
128
|
//# sourceMappingURL=llm-deadline.js.map
|
package/dist/src/utils/logger.js
CHANGED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/utils/loop-profiler.ts
|
|
3
|
+
*
|
|
4
|
+
* Rolling V8 CPU profiler — the instrument that names the culprit when the
|
|
5
|
+
* event loop blocks (see `event-loop-monitor.ts` for the incident this exists
|
|
6
|
+
* for).
|
|
7
|
+
*
|
|
8
|
+
* Why a CPU profile and not a stack dump: while the JS thread is blocked, NO
|
|
9
|
+
* JS can run — you cannot ask the process what it is doing, because asking is
|
|
10
|
+
* itself JS. V8's sampling profiler runs on its OWN thread and samples the JS
|
|
11
|
+
* thread regardless of whether that thread is stuck, so the profile taken
|
|
12
|
+
* across a block contains the blocking frames. Verified under Bun 1.3.13: a
|
|
13
|
+
* deliberate 400ms synchronous block yielded 54 samples.
|
|
14
|
+
*
|
|
15
|
+
* Rolling segments keep the retained profile small without losing the block:
|
|
16
|
+
* rotation is loop-driven, so it CANNOT run during a block — whichever segment
|
|
17
|
+
* is in flight when the loop freezes stays in flight for the whole freeze, and
|
|
18
|
+
* is still open when the monitor detects the block right after. So `capture()`
|
|
19
|
+
* always writes a profile containing the entire block, however long it ran.
|
|
20
|
+
*
|
|
21
|
+
* Off by default (`MUONROI_LOOP_PROFILE=1` to arm) — continuous profiling has a
|
|
22
|
+
* real, if small, cost and this is a diagnostic, not a feature.
|
|
23
|
+
*/
|
|
24
|
+
/** Minimal shape of the V8 CPU profile we consume (`Profiler.stop` result). */
|
|
25
|
+
interface CpuProfileNode {
|
|
26
|
+
id: number;
|
|
27
|
+
callFrame: {
|
|
28
|
+
functionName?: string;
|
|
29
|
+
url?: string;
|
|
30
|
+
lineNumber?: number;
|
|
31
|
+
};
|
|
32
|
+
children?: number[];
|
|
33
|
+
}
|
|
34
|
+
interface CpuProfile {
|
|
35
|
+
nodes: CpuProfileNode[];
|
|
36
|
+
samples?: number[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Reduce a CPU profile to the single hottest stack, leaf-first.
|
|
40
|
+
*
|
|
41
|
+
* Why not just the top frame: samples land on the LEAF, which for a blocking
|
|
42
|
+
* loop is whatever primitive it calls (`Date.now`, a regex step, a syscall) —
|
|
43
|
+
* true but useless. Verified on a synthetic 3s block: the leaf was `now` with
|
|
44
|
+
* 188 samples while the actual culprit `theGuiltyFunction` had 4. The CALLERS
|
|
45
|
+
* are the answer, so we walk up from the hottest leaf and return the chain.
|
|
46
|
+
*
|
|
47
|
+
* This is what makes the profile readable from debug.log alone, without
|
|
48
|
+
* requiring anyone to open Chrome DevTools.
|
|
49
|
+
*
|
|
50
|
+
* Pure — unit-testable with a hand-built profile.
|
|
51
|
+
*
|
|
52
|
+
* @param maxFrames how many frames of the chain to return, leaf-first
|
|
53
|
+
* @returns frames like `theGuiltyFunction (file.ts:12)`, or [] if unusable
|
|
54
|
+
*/
|
|
55
|
+
export declare function summarizeHotStack(profile: CpuProfile, maxFrames?: number): string[];
|
|
56
|
+
/** What a successful {@link LoopProfiler.capture} produced. */
|
|
57
|
+
export interface CaptureResult {
|
|
58
|
+
/** Path of the written `.cpuprofile` (open in Chrome DevTools for detail). */
|
|
59
|
+
file: string;
|
|
60
|
+
/** Hottest stack, leaf-first — readable without DevTools. See {@link summarizeHotStack}. */
|
|
61
|
+
hotStack: string[];
|
|
62
|
+
}
|
|
63
|
+
/** A rolling CPU profiler. All methods are best-effort and never throw. */
|
|
64
|
+
export interface LoopProfiler {
|
|
65
|
+
/**
|
|
66
|
+
* Discard the current segment and start a fresh one. Call periodically from
|
|
67
|
+
* the event loop to bound profile size — it is a no-op during a block, which
|
|
68
|
+
* is exactly what preserves the evidence.
|
|
69
|
+
*/
|
|
70
|
+
rotate(): void;
|
|
71
|
+
/**
|
|
72
|
+
* Stop the current segment, write it to disk, and start a fresh one.
|
|
73
|
+
*
|
|
74
|
+
* Async because the inspector delivers `Profiler.stop` on a later tick
|
|
75
|
+
* (measured under Bun 1.3.13 — the callback does NOT run synchronously). The
|
|
76
|
+
* loop is already free by the time this is called, so awaiting is safe.
|
|
77
|
+
*
|
|
78
|
+
* @returns the profile path plus the hottest stack, or null on failure.
|
|
79
|
+
*/
|
|
80
|
+
capture(reason: string): Promise<CaptureResult | null>;
|
|
81
|
+
/** Stop profiling and disconnect. Idempotent. */
|
|
82
|
+
dispose(): void;
|
|
83
|
+
}
|
|
84
|
+
/** Options for {@link createLoopProfiler}. */
|
|
85
|
+
export interface LoopProfilerOpts {
|
|
86
|
+
/**
|
|
87
|
+
* V8 sampling interval in microseconds. 10_000 (10ms) is ~100 samples/sec —
|
|
88
|
+
* plenty to identify a multi-second blocking frame, at a fraction of the cost
|
|
89
|
+
* of the 1ms default.
|
|
90
|
+
*/
|
|
91
|
+
samplingIntervalUs?: number;
|
|
92
|
+
/** Directory for `.cpuprofile` files. Defaults to `~/.muonroi-cli/profiles`. */
|
|
93
|
+
dir?: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Create and arm a rolling CPU profiler.
|
|
97
|
+
*
|
|
98
|
+
* Returns null when the inspector is unavailable (some runtimes/builds) — the
|
|
99
|
+
* caller keeps the block detector, just without stacks. Never throws.
|
|
100
|
+
*/
|
|
101
|
+
export declare function createLoopProfiler(opts?: LoopProfilerOpts): Promise<LoopProfiler | null>;
|
|
102
|
+
export {};
|