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
package/dist/src/lsp/manager.js
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
import { readFile } from "fs/promises";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import { pathToFileURL } from "url";
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
4
4
|
import { createRuntimeLspDefinitions } from "./builtins.js";
|
|
5
5
|
import { createLspClientSession } from "./client.js";
|
|
6
6
|
export function createWorkspaceLspManager(cwd, settings, options = {}) {
|
|
7
7
|
const definitions = createRuntimeLspDefinitions(cwd, settings);
|
|
8
8
|
const clients = new Map();
|
|
9
|
+
// Servers we have already reported as not installed. Without this the "no
|
|
10
|
+
// command" path is silent: a Go/Rust/C++/Java file just gets no LSP and the
|
|
11
|
+
// caller sees "unavailable" with no way to learn WHICH server is missing.
|
|
12
|
+
const reportedMissing = new Set();
|
|
9
13
|
const createClient = options.createClient ??
|
|
10
14
|
(async ({ serverId, root, definition, settings: normalizedSettings }) => {
|
|
11
15
|
const launch = await definition.resolveLaunch(root, normalizedSettings);
|
|
12
|
-
if (!launch?.command)
|
|
16
|
+
if (!launch?.command) {
|
|
17
|
+
if (!reportedMissing.has(serverId)) {
|
|
18
|
+
reportedMissing.add(serverId);
|
|
19
|
+
console.error(`[lsp] no language server found for "${serverId}" (${definition.extensions.join(", ")}). ` +
|
|
20
|
+
`Install it and make sure it is on PATH, or set lsp.builtins.${serverId}.command in settings.`);
|
|
21
|
+
}
|
|
13
22
|
return null;
|
|
23
|
+
}
|
|
14
24
|
return createLspClientSession({
|
|
15
25
|
serverId,
|
|
16
26
|
root,
|
|
@@ -96,7 +106,10 @@ export function createWorkspaceLspManager(cwd, settings, options = {}) {
|
|
|
96
106
|
diagnostics: client.getDiagnostics(filePath),
|
|
97
107
|
};
|
|
98
108
|
}
|
|
99
|
-
catch {
|
|
109
|
+
catch (err) {
|
|
110
|
+
// Dropping the client silently here is what let a dead language server
|
|
111
|
+
// look like "no diagnostics" for the whole session.
|
|
112
|
+
console.error(`[lsp:${definition.id}] sync failed for ${filePath}, dropping client: ${err instanceof Error ? err.message : String(err)}`);
|
|
100
113
|
clients.delete(key);
|
|
101
114
|
return null;
|
|
102
115
|
}
|
|
@@ -167,11 +180,238 @@ export function createWorkspaceLspManager(cwd, settings, options = {}) {
|
|
|
167
180
|
await Promise.allSettled(active.map((entry) => entry.client.stop()));
|
|
168
181
|
clients.clear();
|
|
169
182
|
}
|
|
183
|
+
// ── Sprint 1: impact/readiness contract (SLICE1-BUILD-NOTE.md) ─────────────
|
|
184
|
+
const TOKEN_BUDGET_CAP = 500; // hard cap (spec §49-54)
|
|
185
|
+
const REF_TOKEN_COST = 30; // per-reference estimate (spec §53)
|
|
186
|
+
const MAX_REFS = Math.floor(TOKEN_BUDGET_CAP / REF_TOKEN_COST); // 16 — truncation threshold
|
|
187
|
+
/** Error-level = severity ≤ 1 (Error). Warnings/infos ignored (spec §21-25). */
|
|
188
|
+
function errorLevel(diags) {
|
|
189
|
+
return diags.filter((d) => (d.severity ?? 1) <= 1);
|
|
190
|
+
}
|
|
191
|
+
/** tokenBudgetUsed = elapsed estimate + refs×30, clamped ≤500 (spec §49-54). */
|
|
192
|
+
function tokenBudget(elapsedMs, refCount) {
|
|
193
|
+
const elapsedTokens = Math.min(200, Math.round(elapsedMs / 25));
|
|
194
|
+
return Math.min(TOKEN_BUDGET_CAP, elapsedTokens + refCount * REF_TOKEN_COST);
|
|
195
|
+
}
|
|
196
|
+
/** Top-2 distinct error messages joined "; ", ≤120 chars; "none" when clean (spec §42-47). */
|
|
197
|
+
function suggestedGuardFrom(errs) {
|
|
198
|
+
if (errs.length === 0)
|
|
199
|
+
return "none";
|
|
200
|
+
const seen = new Set();
|
|
201
|
+
const messages = [];
|
|
202
|
+
for (const d of errs) {
|
|
203
|
+
const cat = (d.source ?? d.code ?? d.message.split(/[:.]/)[0] ?? "error").toString().trim();
|
|
204
|
+
const key = `${cat}:${d.message.trim()}`;
|
|
205
|
+
if (seen.has(key))
|
|
206
|
+
continue;
|
|
207
|
+
seen.add(key);
|
|
208
|
+
messages.push(d.message.trim());
|
|
209
|
+
if (messages.length === 2)
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
return messages.join("; ").slice(0, 120) || "none";
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* didOpen `filePath` on every client that is about to be asked for its
|
|
216
|
+
* diagnostics, so the server actually analyses it. Returns true when the file
|
|
217
|
+
* cannot be read — nothing to diagnose, and reporting it "clean" would lie.
|
|
218
|
+
*/
|
|
219
|
+
async function openForDiagnostics(filePath, records) {
|
|
220
|
+
let content;
|
|
221
|
+
try {
|
|
222
|
+
content = await readFile(filePath, "utf8");
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
console.error(`[lsp] cannot read ${filePath} for diagnostics: ${err instanceof Error ? err.message : String(err)}`);
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
const extension = path.extname(filePath).toLowerCase();
|
|
229
|
+
await Promise.all(records.map(async ({ key, definition, client }) => {
|
|
230
|
+
const languageId = definition.languageIds[extension] ?? (extension.slice(1) || "plaintext");
|
|
231
|
+
try {
|
|
232
|
+
await client.openOrChangeFile(filePath, languageId, content);
|
|
233
|
+
}
|
|
234
|
+
catch (err) {
|
|
235
|
+
// Drop the client so the next call re-spawns it; the diagnostics wait
|
|
236
|
+
// below will surface this as a failure rather than a clean verdict.
|
|
237
|
+
console.error(`[lsp:${definition.id}] didOpen failed for ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
238
|
+
clients.delete(key);
|
|
239
|
+
}
|
|
240
|
+
}));
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
async function waitForDiagnostics(filePath, timeout) {
|
|
244
|
+
const clampedTimeout = Math.min(Math.max(timeout, 0), 5000);
|
|
245
|
+
const t0 = Date.now();
|
|
246
|
+
const records = await getClientsForFile(filePath);
|
|
247
|
+
if (records.length === 0) {
|
|
248
|
+
return {
|
|
249
|
+
diagnostics: [],
|
|
250
|
+
lspStatus: "unavailable",
|
|
251
|
+
clean: false,
|
|
252
|
+
metadata: { tokenBudgetUsed: tokenBudget(Date.now() - t0, 0) },
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
// A language server only publishes diagnostics for files it has been told
|
|
256
|
+
// about. Without this didOpen, waiting on a file the server has never seen
|
|
257
|
+
// waits out the full timeout, gets nothing, and reports lspStatus "ok" /
|
|
258
|
+
// clean: true — a green verdict on a file that was never analysed at all.
|
|
259
|
+
// (Proven: a file with two tsc type errors reported clean.) Callers that
|
|
260
|
+
// already synced the buffer (syncFile) are unaffected: openOrChangeFile is
|
|
261
|
+
// idempotent, and diagnostics already cached short-circuit the wait below.
|
|
262
|
+
const unreadable = await openForDiagnostics(filePath, records);
|
|
263
|
+
if (unreadable) {
|
|
264
|
+
return {
|
|
265
|
+
diagnostics: [],
|
|
266
|
+
lspStatus: "unavailable",
|
|
267
|
+
clean: false,
|
|
268
|
+
metadata: { tokenBudgetUsed: tokenBudget(Date.now() - t0, 0) },
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
let anyTimedOut = false;
|
|
272
|
+
let anyFailed = false;
|
|
273
|
+
const allDiagnostics = [];
|
|
274
|
+
for (const record of records) {
|
|
275
|
+
try {
|
|
276
|
+
const diags = await withRequestTimeout(record.client.waitForDiagnostics(filePath, clampedTimeout), clampedTimeout);
|
|
277
|
+
allDiagnostics.push(...diags);
|
|
278
|
+
}
|
|
279
|
+
catch (err) {
|
|
280
|
+
if (err instanceof LspRequestTimeoutError) {
|
|
281
|
+
anyTimedOut = true;
|
|
282
|
+
allDiagnostics.push(...record.client.getDiagnostics(filePath));
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
anyFailed = true;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const lspStatus = anyTimedOut
|
|
290
|
+
? "partial"
|
|
291
|
+
: anyFailed && allDiagnostics.length === 0
|
|
292
|
+
? "unavailable"
|
|
293
|
+
: "ok";
|
|
294
|
+
// clean: true only when we actually have data and zero error-level diags (spec §85).
|
|
295
|
+
const clean = lspStatus !== "unavailable" && errorLevel(allDiagnostics).length === 0;
|
|
296
|
+
return {
|
|
297
|
+
diagnostics: allDiagnostics,
|
|
298
|
+
lspStatus,
|
|
299
|
+
clean,
|
|
300
|
+
metadata: { tokenBudgetUsed: tokenBudget(Date.now() - t0, 0) },
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
async function impactOfChange(filePath, _query, timeout) {
|
|
304
|
+
const t0 = Date.now();
|
|
305
|
+
const diag = await waitForDiagnostics(filePath, timeout ?? 1500);
|
|
306
|
+
if (diag.lspStatus === "unavailable") {
|
|
307
|
+
const errs = errorLevel(diag.diagnostics);
|
|
308
|
+
return {
|
|
309
|
+
references: [],
|
|
310
|
+
diagnostics: diag.diagnostics,
|
|
311
|
+
referencesComplete: false,
|
|
312
|
+
safeToRename: false,
|
|
313
|
+
clean: false,
|
|
314
|
+
suggestedGuard: suggestedGuardFrom(errs),
|
|
315
|
+
degraded: "lsp_unavailable",
|
|
316
|
+
lspStatus: "unavailable",
|
|
317
|
+
metadata: { tokenBudgetUsed: tokenBudget(Date.now() - t0, 0) },
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
const records = await getClientsForFile(filePath);
|
|
321
|
+
const rawReferences = [];
|
|
322
|
+
for (const record of records) {
|
|
323
|
+
try {
|
|
324
|
+
const uri = pathToFileURL(path.resolve(filePath)).href;
|
|
325
|
+
const params = {
|
|
326
|
+
textDocument: { uri },
|
|
327
|
+
position: { line: 0, character: 0 },
|
|
328
|
+
context: { includeDeclaration: true },
|
|
329
|
+
};
|
|
330
|
+
const refs = await record.client.sendRequest("textDocument/references", params);
|
|
331
|
+
if (Array.isArray(refs)) {
|
|
332
|
+
for (const ref of refs) {
|
|
333
|
+
const r = ref;
|
|
334
|
+
if (r?.uri && r?.range) {
|
|
335
|
+
rawReferences.push({
|
|
336
|
+
uri: r.uri,
|
|
337
|
+
range: {
|
|
338
|
+
start: { line: r.range.start.line + 1, character: r.range.start.character + 1 },
|
|
339
|
+
end: { line: r.range.end.line + 1, character: r.range.end.character + 1 },
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
// Individual reference query failure: continue with partial results
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
// Truncate so references×30 stays within budget headroom (spec §38, §53).
|
|
351
|
+
const truncated = rawReferences.length > MAX_REFS;
|
|
352
|
+
const references = truncated ? rawReferences.slice(0, MAX_REFS) : rawReferences;
|
|
353
|
+
const referencesComplete = !truncated;
|
|
354
|
+
// Frozen union: the symbol file's waited diagnostics + each unique referenced
|
|
355
|
+
// file's already-published diagnostics (cheap getDiagnostics, no extra waits).
|
|
356
|
+
// clean is computed over this union of error-level diagnostics (spec §19-25).
|
|
357
|
+
const unionDiags = [...diag.diagnostics];
|
|
358
|
+
const seenFiles = new Set([path.resolve(filePath)]);
|
|
359
|
+
for (const ref of references) {
|
|
360
|
+
let refPath;
|
|
361
|
+
try {
|
|
362
|
+
refPath = fileURLToPath(ref.uri);
|
|
363
|
+
}
|
|
364
|
+
catch {
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
if (seenFiles.has(refPath))
|
|
368
|
+
continue;
|
|
369
|
+
seenFiles.add(refPath);
|
|
370
|
+
for (const record of records)
|
|
371
|
+
unionDiags.push(...record.client.getDiagnostics(refPath));
|
|
372
|
+
}
|
|
373
|
+
const unionErrors = errorLevel(unionDiags);
|
|
374
|
+
const clean = unionErrors.length === 0;
|
|
375
|
+
// Precedence: lsp_unavailable (handled above) > diagnostics_timeout > refs_truncated > none.
|
|
376
|
+
const degraded = diag.lspStatus === "partial" ? "diagnostics_timeout" : truncated ? "refs_truncated" : "none";
|
|
377
|
+
// safeToRename only when refs are complete, the union is clean, and nothing degraded (spec §27-31).
|
|
378
|
+
const safeToRename = referencesComplete && clean && degraded === "none" && diag.lspStatus === "ok";
|
|
379
|
+
return {
|
|
380
|
+
references,
|
|
381
|
+
diagnostics: diag.diagnostics,
|
|
382
|
+
referencesComplete,
|
|
383
|
+
safeToRename,
|
|
384
|
+
clean,
|
|
385
|
+
suggestedGuard: suggestedGuardFrom(unionErrors),
|
|
386
|
+
degraded,
|
|
387
|
+
lspStatus: diag.lspStatus,
|
|
388
|
+
metadata: { tokenBudgetUsed: tokenBudget(Date.now() - t0, references.length) },
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
async function lspMutationPreview(_filePath, _change) {
|
|
392
|
+
// Fixed stub schema — no workspaceEdit, no apply path (spec §55-71).
|
|
393
|
+
return { op: "allowlist", dryRunResult: { proposedEdits: [], tokenEstimate: 0 }, schemaVersion: "1.0" };
|
|
394
|
+
}
|
|
395
|
+
async function lspBeforeGrep(filePath, query) {
|
|
396
|
+
const result = await impactOfChange(filePath, query);
|
|
397
|
+
// Policy keys on lspStatus: grep fallback allowed unless the LSP was fully ok (spec §73-77).
|
|
398
|
+
if (result.lspStatus !== "ok") {
|
|
399
|
+
return { kind: "allow", reason: `LSP ${result.lspStatus}; fall back to grep` };
|
|
400
|
+
}
|
|
401
|
+
if (result.safeToRename) {
|
|
402
|
+
return { kind: "allow", reason: "LSP ok and rename is safe" };
|
|
403
|
+
}
|
|
404
|
+
return { kind: "enrich", enrichWith: result };
|
|
405
|
+
}
|
|
170
406
|
return {
|
|
171
407
|
touchFile,
|
|
172
408
|
syncFile,
|
|
173
409
|
query,
|
|
174
410
|
close,
|
|
411
|
+
waitForDiagnostics,
|
|
412
|
+
impactOfChange,
|
|
413
|
+
lspMutationPreview,
|
|
414
|
+
lspBeforeGrep,
|
|
175
415
|
};
|
|
176
416
|
}
|
|
177
417
|
class LspRequestTimeoutError extends Error {
|
|
@@ -211,6 +451,8 @@ function getOperationMethod(operation) {
|
|
|
211
451
|
case "incomingCalls":
|
|
212
452
|
case "outgoingCalls":
|
|
213
453
|
return "textDocument/prepareCallHierarchy";
|
|
454
|
+
case "waitForDiagnostics":
|
|
455
|
+
return "textDocument/diagnostic";
|
|
214
456
|
}
|
|
215
457
|
}
|
|
216
458
|
function createOperationParams(input, absolutePath) {
|
|
@@ -244,6 +486,10 @@ function createOperationParams(input, absolutePath) {
|
|
|
244
486
|
return {
|
|
245
487
|
query: input.query ?? "",
|
|
246
488
|
};
|
|
489
|
+
case "waitForDiagnostics":
|
|
490
|
+
return {
|
|
491
|
+
textDocument: { uri },
|
|
492
|
+
};
|
|
247
493
|
}
|
|
248
494
|
}
|
|
249
495
|
export function summarizeLspDiagnostics(diagnostics) {
|
|
@@ -1,2 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Absolute path to a language-server binary in the cache, installing the package
|
|
3
|
+
* on first use.
|
|
4
|
+
*
|
|
5
|
+
* `preferredBin` is the binary the CALLER needs, which is not always the one
|
|
6
|
+
* named after the package: `pyright` ships both `pyright` (the batch CLI) and
|
|
7
|
+
* `pyright-langserver` (the LSP server). Choosing by package name alone launched
|
|
8
|
+
* the CLI with `--stdio`, which exits 4 with "pyright --help for usage" — so
|
|
9
|
+
* Python LSP never started for anyone relying on auto-install.
|
|
10
|
+
*/
|
|
11
|
+
export declare function lspNpmWhich(pkg: string, preferredBin?: string): Promise<string | null>;
|
|
2
12
|
export declare function lspNpmAdd(pkg: string): Promise<string>;
|
|
@@ -10,13 +10,27 @@ function packageDir(pkg) {
|
|
|
10
10
|
: pkg;
|
|
11
11
|
return path.join(CACHE_ROOT, sanitized);
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Absolute path to a language-server binary in the cache, installing the package
|
|
15
|
+
* on first use.
|
|
16
|
+
*
|
|
17
|
+
* `preferredBin` is the binary the CALLER needs, which is not always the one
|
|
18
|
+
* named after the package: `pyright` ships both `pyright` (the batch CLI) and
|
|
19
|
+
* `pyright-langserver` (the LSP server). Choosing by package name alone launched
|
|
20
|
+
* the CLI with `--stdio`, which exits 4 with "pyright --help for usage" — so
|
|
21
|
+
* Python LSP never started for anyone relying on auto-install.
|
|
22
|
+
*/
|
|
23
|
+
export async function lspNpmWhich(pkg, preferredBin) {
|
|
14
24
|
const dir = packageDir(pkg);
|
|
15
25
|
const binDir = path.join(dir, "node_modules", ".bin");
|
|
16
26
|
const pick = async () => {
|
|
17
27
|
const files = await readdir(binDir).catch(() => []);
|
|
18
28
|
if (files.length === 0)
|
|
19
29
|
return undefined;
|
|
30
|
+
// The caller's choice wins whenever the package actually ships it. Match the
|
|
31
|
+
// extension-less shim: Windows also lists .cmd/.ps1 wrappers for each bin.
|
|
32
|
+
if (preferredBin && files.includes(preferredBin))
|
|
33
|
+
return preferredBin;
|
|
20
34
|
if (files.length === 1)
|
|
21
35
|
return files[0];
|
|
22
36
|
const pkgJsonPath = path.join(dir, "node_modules", pkg, "package.json");
|
|
@@ -29,6 +43,8 @@ export async function lspNpmWhich(pkg) {
|
|
|
29
43
|
const keys = Object.keys(bin);
|
|
30
44
|
if (keys.length === 1)
|
|
31
45
|
return keys[0];
|
|
46
|
+
if (preferredBin && bin[preferredBin])
|
|
47
|
+
return preferredBin;
|
|
32
48
|
return bin[unscoped] ? unscoped : keys[0];
|
|
33
49
|
}
|
|
34
50
|
return files[0];
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { type WorkspaceLspManager } from "./manager.js";
|
|
2
|
+
import type { ImpactOfChangeResult, LspDiagnosticFile, LspQueryInput, LspQueryResult, LspToolResponse, MutationPreviewResult } from "./types.js";
|
|
2
3
|
export declare function queryLsp(cwd: string, input: LspQueryInput): Promise<LspToolResponse>;
|
|
4
|
+
export declare function waitForDiagnosticsLsp(cwd: string, filePath: string, timeout?: number): Promise<LspQueryResult>;
|
|
5
|
+
export declare function impactOfChangeLsp(cwd: string, filePath: string, query?: string): Promise<ImpactOfChangeResult>;
|
|
6
|
+
export declare function lspMutationPreview(cwd: string, filePath: string, change: string): Promise<MutationPreviewResult>;
|
|
3
7
|
export declare function syncFileWithLsp(cwd: string, filePath: string, content: string, save?: boolean, waitForDiagnostics?: boolean, diagnosticsTimeoutMs?: number): Promise<LspDiagnosticFile[]>;
|
|
4
8
|
export declare function isLspToolEnabled(_cwd: string): boolean;
|
|
5
9
|
export declare function summarizeDiagnostics(diagnostics: LspDiagnosticFile[]): string | null;
|
|
6
10
|
export declare function shutdownWorkspaceLspManager(cwd: string): Promise<void>;
|
|
11
|
+
export declare function getOrCreateManager(cwd: string): WorkspaceLspManager;
|
package/dist/src/lsp/runtime.js
CHANGED
|
@@ -10,6 +10,22 @@ export async function queryLsp(cwd, input) {
|
|
|
10
10
|
filePath: path.isAbsolute(input.filePath) ? input.filePath : path.resolve(cwd, input.filePath),
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
|
+
// Default timeout (ms) when a caller omits one. manager.waitForDiagnostics now
|
|
14
|
+
// takes a REQUIRED timeout (Sprint-1 readiness contract, commit 4af6efb1) and no
|
|
15
|
+
// longer defaults internally, so the public wrapper supplies the documented 1500ms.
|
|
16
|
+
const DEFAULT_WAIT_DIAGNOSTICS_MS = 1500;
|
|
17
|
+
export async function waitForDiagnosticsLsp(cwd, filePath, timeout) {
|
|
18
|
+
const manager = getOrCreateManager(cwd);
|
|
19
|
+
return manager.waitForDiagnostics(path.isAbsolute(filePath) ? filePath : path.resolve(cwd, filePath), timeout ?? DEFAULT_WAIT_DIAGNOSTICS_MS);
|
|
20
|
+
}
|
|
21
|
+
export async function impactOfChangeLsp(cwd, filePath, query) {
|
|
22
|
+
const manager = getOrCreateManager(cwd);
|
|
23
|
+
return manager.impactOfChange(path.isAbsolute(filePath) ? filePath : path.resolve(cwd, filePath), query);
|
|
24
|
+
}
|
|
25
|
+
export async function lspMutationPreview(cwd, filePath, change) {
|
|
26
|
+
const manager = getOrCreateManager(cwd);
|
|
27
|
+
return manager.lspMutationPreview(path.isAbsolute(filePath) ? filePath : path.resolve(cwd, filePath), change);
|
|
28
|
+
}
|
|
13
29
|
export async function syncFileWithLsp(cwd, filePath, content, save = true, waitForDiagnostics = true, diagnosticsTimeoutMs) {
|
|
14
30
|
const manager = getOrCreateManager(cwd);
|
|
15
31
|
return manager.syncFile(path.isAbsolute(filePath) ? filePath : path.resolve(cwd, filePath), content, save, waitForDiagnostics, diagnosticsTimeoutMs);
|
|
@@ -29,7 +45,7 @@ export async function shutdownWorkspaceLspManager(cwd) {
|
|
|
29
45
|
managers.delete(key);
|
|
30
46
|
await manager.close();
|
|
31
47
|
}
|
|
32
|
-
function getOrCreateManager(cwd) {
|
|
48
|
+
export function getOrCreateManager(cwd) {
|
|
33
49
|
const key = resolveManagerKey(cwd);
|
|
34
50
|
const existing = managers.get(key);
|
|
35
51
|
if (existing)
|
package/dist/src/lsp/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const LSP_TOOL_OPERATIONS: readonly ["goToDefinition", "findReferences", "hover", "documentSymbol", "workspaceSymbol", "goToImplementation", "prepareCallHierarchy", "incomingCalls", "outgoingCalls"];
|
|
1
|
+
export declare const LSP_TOOL_OPERATIONS: readonly ["goToDefinition", "findReferences", "hover", "documentSymbol", "workspaceSymbol", "goToImplementation", "prepareCallHierarchy", "incomingCalls", "outgoingCalls", "waitForDiagnostics"];
|
|
2
2
|
export type LspToolOperation = (typeof LSP_TOOL_OPERATIONS)[number];
|
|
3
3
|
export type LspBuiltInServerId = "typescript" | "pyright" | "gopls" | "rust-analyzer" | "bash-language-server" | "yaml-language-server" | "clangd" | "jdtls" | "sourcekit-lsp" | "csharp-ls";
|
|
4
4
|
export interface LspPosition {
|
|
@@ -78,6 +78,88 @@ export interface LspQueryInput {
|
|
|
78
78
|
character?: number;
|
|
79
79
|
query?: string;
|
|
80
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* LSP readiness status (SLICE1-BUILD-NOTE.md §79-86, §73-77).
|
|
83
|
+
* - `ok` — diagnostics resolved within the ≤5s budget
|
|
84
|
+
* - `partial` — one or more waits timed out; stale diagnostics were used
|
|
85
|
+
* - `unavailable` — no server could be reached or the query threw
|
|
86
|
+
* The lsp-before-grep policy keys on this: grep fallback is allowed when
|
|
87
|
+
* `lspStatus !== 'ok'`.
|
|
88
|
+
*/
|
|
89
|
+
export type LspStatus = "ok" | "partial" | "unavailable";
|
|
90
|
+
/**
|
|
91
|
+
* Reason a composite result is degraded (SLICE1-BUILD-NOTE.md §33-40).
|
|
92
|
+
* Precedence when several apply: lsp_unavailable > diagnostics_timeout >
|
|
93
|
+
* refs_truncated > none.
|
|
94
|
+
*/
|
|
95
|
+
export type DegradedReason = "none" | "refs_truncated" | "diagnostics_timeout" | "lsp_unavailable";
|
|
96
|
+
/** Per-call token-budget accounting; `tokenBudgetUsed` is hard-capped ≤500. */
|
|
97
|
+
export interface LspResultMetadata {
|
|
98
|
+
/** Elapsed + reference estimate, clamped to ≤500 (SLICE1-BUILD-NOTE.md §49-54). */
|
|
99
|
+
tokenBudgetUsed: number;
|
|
100
|
+
}
|
|
101
|
+
/** `waitForDiagnostics` result (SLICE1-BUILD-NOTE.md §79-86). */
|
|
102
|
+
export interface LspQueryResult {
|
|
103
|
+
diagnostics: LspDiagnostic[];
|
|
104
|
+
lspStatus: LspStatus;
|
|
105
|
+
/** True only when zero error-level (severity ≤ 1) diagnostics exist for the file. */
|
|
106
|
+
clean: boolean;
|
|
107
|
+
metadata: LspResultMetadata;
|
|
108
|
+
}
|
|
109
|
+
/** `impact_of_change` composite result (SLICE1-BUILD-NOTE.md §10, §19-54). */
|
|
110
|
+
export interface ImpactOfChangeResult {
|
|
111
|
+
references: LspLocation[];
|
|
112
|
+
diagnostics: LspDiagnostic[];
|
|
113
|
+
/** False when the reference list was truncated to stay within token budget. */
|
|
114
|
+
referencesComplete: boolean;
|
|
115
|
+
/**
|
|
116
|
+
* True only when `referencesComplete === true` AND the frozen union (symbol
|
|
117
|
+
* file + every referenced file) has zero error-level diagnostics AND the LSP
|
|
118
|
+
* was fully available. `false` is the safe default → agents grep-fallback.
|
|
119
|
+
*/
|
|
120
|
+
safeToRename: boolean;
|
|
121
|
+
/** Zero error-level diagnostics on the union of the symbol file + reference files. */
|
|
122
|
+
clean: boolean;
|
|
123
|
+
/** Top-2 error category messages joined with "; ", ≤120 chars; "none" when clean. */
|
|
124
|
+
suggestedGuard: string;
|
|
125
|
+
degraded: DegradedReason;
|
|
126
|
+
lspStatus: LspStatus;
|
|
127
|
+
metadata: LspResultMetadata;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* `lsp_mutation_preview` stub (SLICE1-BUILD-NOTE.md §55-71). Fixed schema, no
|
|
131
|
+
* `workspaceEdit`, no apply path — real diff computation is Slice 2.
|
|
132
|
+
*/
|
|
133
|
+
export interface MutationPreviewResult {
|
|
134
|
+
readonly op: "allowlist";
|
|
135
|
+
readonly dryRunResult: {
|
|
136
|
+
readonly proposedEdits: [];
|
|
137
|
+
readonly tokenEstimate: number;
|
|
138
|
+
};
|
|
139
|
+
readonly schemaVersion: "1.0";
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Tagged error kind for LSP operation failures.
|
|
143
|
+
* Throw-only canonical failure for slice 1 ── every failure flows
|
|
144
|
+
* through a single syntactic choke point (the projection's try/catch).
|
|
145
|
+
*/
|
|
146
|
+
export type LspErrorKind = "no_server" | "request_timeout" | "request_failed" | "lsp_disabled" | "unknown";
|
|
147
|
+
/** Tagged‑union Error used by manager methods. */
|
|
148
|
+
export declare class LspError extends Error {
|
|
149
|
+
readonly kind: LspErrorKind;
|
|
150
|
+
constructor(kind: LspErrorKind, message: string);
|
|
151
|
+
}
|
|
152
|
+
/** Policy decision the lsp‑before‑grep gate returns. */
|
|
153
|
+
export type PolicyAction = {
|
|
154
|
+
kind: "allow";
|
|
155
|
+
reason: string;
|
|
156
|
+
} | {
|
|
157
|
+
kind: "block";
|
|
158
|
+
reason: string;
|
|
159
|
+
} | {
|
|
160
|
+
kind: "enrich";
|
|
161
|
+
enrichWith: ImpactOfChangeResult;
|
|
162
|
+
};
|
|
81
163
|
export interface LspToolResponse {
|
|
82
164
|
success: boolean;
|
|
83
165
|
output: string;
|
package/dist/src/lsp/types.js
CHANGED
|
@@ -8,5 +8,15 @@ export const LSP_TOOL_OPERATIONS = [
|
|
|
8
8
|
"prepareCallHierarchy",
|
|
9
9
|
"incomingCalls",
|
|
10
10
|
"outgoingCalls",
|
|
11
|
+
"waitForDiagnostics",
|
|
11
12
|
];
|
|
13
|
+
/** Tagged‑union Error used by manager methods. */
|
|
14
|
+
export class LspError extends Error {
|
|
15
|
+
kind;
|
|
16
|
+
constructor(kind, message) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = "LspError";
|
|
19
|
+
this.kind = kind;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
12
22
|
//# sourceMappingURL=types.js.map
|
|
@@ -186,9 +186,13 @@ async function squashSinceMarker(cwd, markerSha, title) {
|
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
// ─── PR body prompt ───────────────────────────────────────────────────────────
|
|
189
|
-
const PR_BODY_SYSTEM = "You are a
|
|
190
|
-
"
|
|
191
|
-
"
|
|
189
|
+
const PR_BODY_SYSTEM = "You are a senior engineer writing the description for your own pull request. " +
|
|
190
|
+
"Write for a busy reviewer: they should understand what this PR does, why it exists, and how to verify it " +
|
|
191
|
+
"within thirty seconds of reading — before they open a single file. " +
|
|
192
|
+
"Write in plain, confident prose. Prefer specific claims ('caps retry backoff at 30s') over vague ones " +
|
|
193
|
+
"('improves retry handling'). Never restate filenames or diffs mechanically — explain intent and effect. " +
|
|
194
|
+
"Do not pad, do not apologize, and do not invent changes that are not evidenced by the task data or diff. " +
|
|
195
|
+
"Output ONLY the finished markdown body — no preamble, no commentary, and no code fence wrapping the whole output.";
|
|
192
196
|
function buildPrBodyPrompt(task, diff, intel, result, filesOutsideRadius) {
|
|
193
197
|
const diffSnippet = diff.length > 8192 ? `${diff.slice(0, 8192)}\n...[diff truncated to 8KB]` : diff;
|
|
194
198
|
const descriptionSummary = task.description.length > 600 ? `${task.description.slice(0, 597)}…` : task.description;
|
|
@@ -199,29 +203,35 @@ function buildPrBodyPrompt(task, diff, intel, result, filesOutsideRadius) {
|
|
|
199
203
|
? `\n## Review Concerns\n${result.reviewConcerns.map((c) => `- ${c}`).join("\n")}`
|
|
200
204
|
: "";
|
|
201
205
|
return [
|
|
202
|
-
"
|
|
203
|
-
"Use the
|
|
206
|
+
"Write the pull request body for the maintenance task below.",
|
|
207
|
+
"Use exactly the section structure described here, in this order. Render real content for every section — no placeholders, no angle brackets in the output.",
|
|
204
208
|
"Output ONLY the rendered markdown body — nothing else.",
|
|
205
209
|
"",
|
|
206
|
-
"##
|
|
210
|
+
"## Structure",
|
|
207
211
|
"---",
|
|
208
212
|
"## Summary",
|
|
209
|
-
"
|
|
213
|
+
"Two to four sentences a reviewer can read in isolation: what problem this PR solves, why it matters now, and the shape of the fix. Ground it in the task description, but rewrite it as prose — do not paste the task text verbatim.",
|
|
210
214
|
"",
|
|
211
215
|
"## What changed",
|
|
212
|
-
"
|
|
216
|
+
"Three to six bullets describing observable behavior changes, ordered most-significant first. Each bullet states an effect ('X now does Y', 'Z no longer happens when W'), not a file operation. Infer these from the diff hunks; mention a file path only when it clarifies scope. If the diff is trivially small, two bullets are fine — do not pad.",
|
|
213
217
|
"",
|
|
214
218
|
"## Test plan",
|
|
215
|
-
"
|
|
219
|
+
"One bullet per acceptance criterion, phrased as a verifiable check the reviewer could repeat. Then list the regression tests that were run. If something was NOT verified, say so plainly rather than omitting it.",
|
|
216
220
|
outsideSection ? "## Files outside declared impact radius" : "",
|
|
217
|
-
outsideSection
|
|
221
|
+
outsideSection
|
|
222
|
+
? "List each file from the task data below, and for each add a short honest note on why it was touched (or 'reason unclear from diff' if you cannot tell). These files deserve extra reviewer scrutiny — do not downplay them."
|
|
223
|
+
: "",
|
|
218
224
|
concernsSection ? "## Review Concerns" : "",
|
|
219
|
-
concernsSection
|
|
225
|
+
concernsSection
|
|
226
|
+
? "List each concern from the task data verbatim, one bullet each. These are non-blocking flags for reviewer awareness — preserve their meaning, do not soften or editorialize."
|
|
227
|
+
: "",
|
|
220
228
|
"## Related",
|
|
221
|
-
"- Impact radius:
|
|
222
|
-
"- Regression tests run:
|
|
229
|
+
"- Impact radius: the first 5 entries from the impact radius in the task data",
|
|
230
|
+
"- Regression tests run: the first 5 entries from the regression tests in the task data",
|
|
223
231
|
"---",
|
|
224
232
|
"",
|
|
233
|
+
"Rules: British understatement over marketing tone. No emoji. No headers beyond those specified. Keep the whole body under ~350 words unless the concerns/outside-radius sections force it longer.",
|
|
234
|
+
"",
|
|
225
235
|
"## Task data",
|
|
226
236
|
`Kind: ${task.kind}`,
|
|
227
237
|
`Title: ${task.title}`,
|