@jokerized/getresearchdone 0.4.1
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/.claude-plugin/plugin.json +103 -0
- package/README.md +211 -0
- package/agents/grd-baseline-assessor.md +684 -0
- package/agents/grd-code-reviewer.md +300 -0
- package/agents/grd-codebase-mapper.md +355 -0
- package/agents/grd-critique-agent.md +119 -0
- package/agents/grd-debugger.md +519 -0
- package/agents/grd-deep-diver.md +737 -0
- package/agents/grd-eval-planner.md +913 -0
- package/agents/grd-eval-reporter.md +717 -0
- package/agents/grd-executor.md +683 -0
- package/agents/grd-feasibility-analyst.md +624 -0
- package/agents/grd-integration-checker.md +367 -0
- package/agents/grd-knowledge-miner.md +81 -0
- package/agents/grd-migrator.md +88 -0
- package/agents/grd-phase-researcher.md +697 -0
- package/agents/grd-plan-checker.md +443 -0
- package/agents/grd-planner.md +1532 -0
- package/agents/grd-product-owner.md +562 -0
- package/agents/grd-project-researcher.md +513 -0
- package/agents/grd-research-synthesizer.md +273 -0
- package/agents/grd-roadmapper.md +798 -0
- package/agents/grd-surveyor.md +566 -0
- package/agents/grd-verifier.md +893 -0
- package/bin/gd.js +4 -0
- package/bin/gd.ts +227 -0
- package/bin/grd-manifest.js +4 -0
- package/bin/grd-manifest.ts +286 -0
- package/bin/grd-mcp-server.js +4 -0
- package/bin/grd-mcp-server.ts +124 -0
- package/bin/grd-tools.js +4 -0
- package/bin/grd-tools.ts +2471 -0
- package/bin/postinstall.js +4 -0
- package/bin/postinstall.ts +80 -0
- package/commands/add-phase.md +123 -0
- package/commands/add-todo.md +87 -0
- package/commands/assess-baseline.md +289 -0
- package/commands/autopilot.md +100 -0
- package/commands/autoplan.md +55 -0
- package/commands/check-todos.md +87 -0
- package/commands/compare-methods.md +262 -0
- package/commands/complete-milestone.md +225 -0
- package/commands/debug.md +372 -0
- package/commands/deep-dive.md +288 -0
- package/commands/discover.md +281 -0
- package/commands/discuss-phase.md +188 -0
- package/commands/discuss.md +55 -0
- package/commands/eval-report.md +310 -0
- package/commands/evolve.md +79 -0
- package/commands/execute-phase.md +1017 -0
- package/commands/feasibility.md +292 -0
- package/commands/help.md +407 -0
- package/commands/init.md +1508 -0
- package/commands/insert-phase.md +113 -0
- package/commands/iterate.md +327 -0
- package/commands/list-phase-assumptions.md +217 -0
- package/commands/long-term-roadmap.md +202 -0
- package/commands/map-codebase.md +111 -0
- package/commands/migrate.md +159 -0
- package/commands/new-milestone.md +169 -0
- package/commands/pause-work.md +83 -0
- package/commands/plan-milestone-gaps.md +373 -0
- package/commands/plan-phase.md +655 -0
- package/commands/principles.md +328 -0
- package/commands/product-plan.md +319 -0
- package/commands/progress.md +481 -0
- package/commands/quick.md +167 -0
- package/commands/reapply-patches.md +154 -0
- package/commands/remove-phase.md +97 -0
- package/commands/requirement.md +96 -0
- package/commands/resume-project.md +113 -0
- package/commands/settings.md +1144 -0
- package/commands/survey.md +242 -0
- package/commands/sync.md +246 -0
- package/commands/tracker-setup.md +322 -0
- package/commands/update.md +202 -0
- package/commands/verify-phase.md +335 -0
- package/commands/verify-work.md +701 -0
- package/commands/wireup.md +29 -0
- package/dist/bin/gd.d.ts +3 -0
- package/dist/bin/gd.d.ts.map +1 -0
- package/dist/bin/gd.js +178 -0
- package/dist/bin/gd.js.map +1 -0
- package/dist/bin/grd-manifest.d.ts +3 -0
- package/dist/bin/grd-manifest.d.ts.map +1 -0
- package/dist/bin/grd-manifest.js +202 -0
- package/dist/bin/grd-manifest.js.map +1 -0
- package/dist/bin/grd-mcp-server.d.ts +3 -0
- package/dist/bin/grd-mcp-server.d.ts.map +1 -0
- package/dist/bin/grd-mcp-server.js +71 -0
- package/dist/bin/grd-mcp-server.js.map +1 -0
- package/dist/bin/grd-tools.d.ts +3 -0
- package/dist/bin/grd-tools.d.ts.map +1 -0
- package/dist/bin/grd-tools.js +1680 -0
- package/dist/bin/grd-tools.js.map +1 -0
- package/dist/bin/postinstall.d.ts +3 -0
- package/dist/bin/postinstall.d.ts.map +1 -0
- package/dist/bin/postinstall.js +61 -0
- package/dist/bin/postinstall.js.map +1 -0
- package/dist/lib/autopilot-milestone.d.ts +2 -0
- package/dist/lib/autopilot-milestone.d.ts.map +1 -0
- package/dist/lib/autopilot-milestone.js +94 -0
- package/dist/lib/autopilot-milestone.js.map +1 -0
- package/dist/lib/autopilot-pipeline.d.ts +2 -0
- package/dist/lib/autopilot-pipeline.d.ts.map +1 -0
- package/dist/lib/autopilot-pipeline.js +830 -0
- package/dist/lib/autopilot-pipeline.js.map +1 -0
- package/dist/lib/autopilot-waves.d.ts +2 -0
- package/dist/lib/autopilot-waves.d.ts.map +1 -0
- package/dist/lib/autopilot-waves.js +266 -0
- package/dist/lib/autopilot-waves.js.map +1 -0
- package/dist/lib/autopilot.d.ts +2 -0
- package/dist/lib/autopilot.d.ts.map +1 -0
- package/dist/lib/autopilot.js +1314 -0
- package/dist/lib/autopilot.js.map +1 -0
- package/dist/lib/autoplan.d.ts +2 -0
- package/dist/lib/autoplan.d.ts.map +1 -0
- package/dist/lib/autoplan.js +198 -0
- package/dist/lib/autoplan.js.map +1 -0
- package/dist/lib/autoresearch.d.ts +2 -0
- package/dist/lib/autoresearch.d.ts.map +1 -0
- package/dist/lib/autoresearch.js +626 -0
- package/dist/lib/autoresearch.js.map +1 -0
- package/dist/lib/backend.d.ts +2 -0
- package/dist/lib/backend.d.ts.map +1 -0
- package/dist/lib/backend.js +1036 -0
- package/dist/lib/backend.js.map +1 -0
- package/dist/lib/benchmark.d.ts +99 -0
- package/dist/lib/benchmark.d.ts.map +1 -0
- package/dist/lib/benchmark.js +278 -0
- package/dist/lib/benchmark.js.map +1 -0
- package/dist/lib/citations.d.ts +2 -0
- package/dist/lib/citations.d.ts.map +1 -0
- package/dist/lib/citations.js +642 -0
- package/dist/lib/citations.js.map +1 -0
- package/dist/lib/cleanup.d.ts +2 -0
- package/dist/lib/cleanup.d.ts.map +1 -0
- package/dist/lib/cleanup.js +1222 -0
- package/dist/lib/cleanup.js.map +1 -0
- package/dist/lib/cli/adapters.d.ts +10 -0
- package/dist/lib/cli/adapters.d.ts.map +1 -0
- package/dist/lib/cli/adapters.js +27 -0
- package/dist/lib/cli/adapters.js.map +1 -0
- package/dist/lib/cli/agent.d.ts +17 -0
- package/dist/lib/cli/agent.d.ts.map +1 -0
- package/dist/lib/cli/agent.js +53 -0
- package/dist/lib/cli/agent.js.map +1 -0
- package/dist/lib/cli/index.d.ts +21 -0
- package/dist/lib/cli/index.d.ts.map +1 -0
- package/dist/lib/cli/index.js +264 -0
- package/dist/lib/cli/index.js.map +1 -0
- package/dist/lib/cli/output.d.ts +20 -0
- package/dist/lib/cli/output.d.ts.map +1 -0
- package/dist/lib/cli/output.js +22 -0
- package/dist/lib/cli/output.js.map +1 -0
- package/dist/lib/cli/scan-dispatch.d.ts +9 -0
- package/dist/lib/cli/scan-dispatch.d.ts.map +1 -0
- package/dist/lib/cli/scan-dispatch.js +107 -0
- package/dist/lib/cli/scan-dispatch.js.map +1 -0
- package/dist/lib/cli/tools.d.ts +16 -0
- package/dist/lib/cli/tools.d.ts.map +1 -0
- package/dist/lib/cli/tools.js +168 -0
- package/dist/lib/cli/tools.js.map +1 -0
- package/dist/lib/commands/_dashboard-parsers.d.ts +2 -0
- package/dist/lib/commands/_dashboard-parsers.d.ts.map +1 -0
- package/dist/lib/commands/_dashboard-parsers.js +192 -0
- package/dist/lib/commands/_dashboard-parsers.js.map +1 -0
- package/dist/lib/commands/analysis.d.ts +2 -0
- package/dist/lib/commands/analysis.d.ts.map +1 -0
- package/dist/lib/commands/analysis.js +1418 -0
- package/dist/lib/commands/analysis.js.map +1 -0
- package/dist/lib/commands/assumptions.d.ts +2 -0
- package/dist/lib/commands/assumptions.d.ts.map +1 -0
- package/dist/lib/commands/assumptions.js +166 -0
- package/dist/lib/commands/assumptions.js.map +1 -0
- package/dist/lib/commands/blame.d.ts +2 -0
- package/dist/lib/commands/blame.d.ts.map +1 -0
- package/dist/lib/commands/blame.js +133 -0
- package/dist/lib/commands/blame.js.map +1 -0
- package/dist/lib/commands/budget.d.ts +2 -0
- package/dist/lib/commands/budget.d.ts.map +1 -0
- package/dist/lib/commands/budget.js +100 -0
- package/dist/lib/commands/budget.js.map +1 -0
- package/dist/lib/commands/check-plans.d.ts +2 -0
- package/dist/lib/commands/check-plans.d.ts.map +1 -0
- package/dist/lib/commands/check-plans.js +190 -0
- package/dist/lib/commands/check-plans.js.map +1 -0
- package/dist/lib/commands/config.d.ts +2 -0
- package/dist/lib/commands/config.d.ts.map +1 -0
- package/dist/lib/commands/config.js +188 -0
- package/dist/lib/commands/config.js.map +1 -0
- package/dist/lib/commands/dashboard.d.ts +2 -0
- package/dist/lib/commands/dashboard.d.ts.map +1 -0
- package/dist/lib/commands/dashboard.js +466 -0
- package/dist/lib/commands/dashboard.js.map +1 -0
- package/dist/lib/commands/estimate.d.ts +2 -0
- package/dist/lib/commands/estimate.d.ts.map +1 -0
- package/dist/lib/commands/estimate.js +148 -0
- package/dist/lib/commands/estimate.js.map +1 -0
- package/dist/lib/commands/eval-diff.d.ts +2 -0
- package/dist/lib/commands/eval-diff.d.ts.map +1 -0
- package/dist/lib/commands/eval-diff.js +213 -0
- package/dist/lib/commands/eval-diff.js.map +1 -0
- package/dist/lib/commands/freshness.d.ts +2 -0
- package/dist/lib/commands/freshness.d.ts.map +1 -0
- package/dist/lib/commands/freshness.js +163 -0
- package/dist/lib/commands/freshness.js.map +1 -0
- package/dist/lib/commands/health.d.ts +2 -0
- package/dist/lib/commands/health.d.ts.map +1 -0
- package/dist/lib/commands/health.js +435 -0
- package/dist/lib/commands/health.js.map +1 -0
- package/dist/lib/commands/index.d.ts +2 -0
- package/dist/lib/commands/index.d.ts.map +1 -0
- package/dist/lib/commands/index.js +128 -0
- package/dist/lib/commands/index.js.map +1 -0
- package/dist/lib/commands/install.d.ts +56 -0
- package/dist/lib/commands/install.d.ts.map +1 -0
- package/dist/lib/commands/install.js +214 -0
- package/dist/lib/commands/install.js.map +1 -0
- package/dist/lib/commands/knowhow-aggregator.d.ts +2 -0
- package/dist/lib/commands/knowhow-aggregator.d.ts.map +1 -0
- package/dist/lib/commands/knowhow-aggregator.js +279 -0
- package/dist/lib/commands/knowhow-aggregator.js.map +1 -0
- package/dist/lib/commands/knowledge-search.d.ts +2 -0
- package/dist/lib/commands/knowledge-search.d.ts.map +1 -0
- package/dist/lib/commands/knowledge-search.js +113 -0
- package/dist/lib/commands/knowledge-search.js.map +1 -0
- package/dist/lib/commands/long-term-roadmap.d.ts +2 -0
- package/dist/lib/commands/long-term-roadmap.d.ts.map +1 -0
- package/dist/lib/commands/long-term-roadmap.js +272 -0
- package/dist/lib/commands/long-term-roadmap.js.map +1 -0
- package/dist/lib/commands/patterns.d.ts +91 -0
- package/dist/lib/commands/patterns.d.ts.map +1 -0
- package/dist/lib/commands/patterns.js +391 -0
- package/dist/lib/commands/patterns.js.map +1 -0
- package/dist/lib/commands/phase-info.d.ts +2 -0
- package/dist/lib/commands/phase-info.d.ts.map +1 -0
- package/dist/lib/commands/phase-info.js +509 -0
- package/dist/lib/commands/phase-info.js.map +1 -0
- package/dist/lib/commands/plan-lint.d.ts +56 -0
- package/dist/lib/commands/plan-lint.d.ts.map +1 -0
- package/dist/lib/commands/plan-lint.js +481 -0
- package/dist/lib/commands/plan-lint.js.map +1 -0
- package/dist/lib/commands/plan-phase.d.ts +53 -0
- package/dist/lib/commands/plan-phase.d.ts.map +1 -0
- package/dist/lib/commands/plan-phase.js +288 -0
- package/dist/lib/commands/plan-phase.js.map +1 -0
- package/dist/lib/commands/progress.d.ts +2 -0
- package/dist/lib/commands/progress.d.ts.map +1 -0
- package/dist/lib/commands/progress.js +266 -0
- package/dist/lib/commands/progress.js.map +1 -0
- package/dist/lib/commands/quality.d.ts +2 -0
- package/dist/lib/commands/quality.d.ts.map +1 -0
- package/dist/lib/commands/quality.js +80 -0
- package/dist/lib/commands/quality.js.map +1 -0
- package/dist/lib/commands/rollback.d.ts +2 -0
- package/dist/lib/commands/rollback.d.ts.map +1 -0
- package/dist/lib/commands/rollback.js +145 -0
- package/dist/lib/commands/rollback.js.map +1 -0
- package/dist/lib/commands/scan.d.ts +25 -0
- package/dist/lib/commands/scan.d.ts.map +1 -0
- package/dist/lib/commands/scan.js +28 -0
- package/dist/lib/commands/scan.js.map +1 -0
- package/dist/lib/commands/search.d.ts +2 -0
- package/dist/lib/commands/search.d.ts.map +1 -0
- package/dist/lib/commands/search.js +212 -0
- package/dist/lib/commands/search.js.map +1 -0
- package/dist/lib/commands/select-candidate.d.ts +128 -0
- package/dist/lib/commands/select-candidate.d.ts.map +1 -0
- package/dist/lib/commands/select-candidate.js +518 -0
- package/dist/lib/commands/select-candidate.js.map +1 -0
- package/dist/lib/commands/singularity.d.ts +2 -0
- package/dist/lib/commands/singularity.d.ts.map +1 -0
- package/dist/lib/commands/singularity.js +185 -0
- package/dist/lib/commands/singularity.js.map +1 -0
- package/dist/lib/commands/slug-timestamp.d.ts +2 -0
- package/dist/lib/commands/slug-timestamp.d.ts.map +1 -0
- package/dist/lib/commands/slug-timestamp.js +54 -0
- package/dist/lib/commands/slug-timestamp.js.map +1 -0
- package/dist/lib/commands/tail.d.ts +2 -0
- package/dist/lib/commands/tail.d.ts.map +1 -0
- package/dist/lib/commands/tail.js +100 -0
- package/dist/lib/commands/tail.js.map +1 -0
- package/dist/lib/commands/todo.d.ts +2 -0
- package/dist/lib/commands/todo.d.ts.map +1 -0
- package/dist/lib/commands/todo.js +200 -0
- package/dist/lib/commands/todo.js.map +1 -0
- package/dist/lib/commands/watch.d.ts +2 -0
- package/dist/lib/commands/watch.d.ts.map +1 -0
- package/dist/lib/commands/watch.js +72 -0
- package/dist/lib/commands/watch.js.map +1 -0
- package/dist/lib/complexity.d.ts +55 -0
- package/dist/lib/complexity.d.ts.map +1 -0
- package/dist/lib/complexity.js +80 -0
- package/dist/lib/complexity.js.map +1 -0
- package/dist/lib/context/agents.d.ts +2 -0
- package/dist/lib/context/agents.d.ts.map +1 -0
- package/dist/lib/context/agents.js +344 -0
- package/dist/lib/context/agents.js.map +1 -0
- package/dist/lib/context/base.d.ts +2 -0
- package/dist/lib/context/base.d.ts.map +1 -0
- package/dist/lib/context/base.js +81 -0
- package/dist/lib/context/base.js.map +1 -0
- package/dist/lib/context/execute.d.ts +2 -0
- package/dist/lib/context/execute.d.ts.map +1 -0
- package/dist/lib/context/execute.js +753 -0
- package/dist/lib/context/execute.js.map +1 -0
- package/dist/lib/context/index.d.ts +2 -0
- package/dist/lib/context/index.d.ts.map +1 -0
- package/dist/lib/context/index.js +88 -0
- package/dist/lib/context/index.js.map +1 -0
- package/dist/lib/context/progress.d.ts +2 -0
- package/dist/lib/context/progress.d.ts.map +1 -0
- package/dist/lib/context/progress.js +178 -0
- package/dist/lib/context/progress.js.map +1 -0
- package/dist/lib/context/project.d.ts +2 -0
- package/dist/lib/context/project.d.ts.map +1 -0
- package/dist/lib/context/project.js +413 -0
- package/dist/lib/context/project.js.map +1 -0
- package/dist/lib/context/research.d.ts +2 -0
- package/dist/lib/context/research.d.ts.map +1 -0
- package/dist/lib/context/research.js +466 -0
- package/dist/lib/context/research.js.map +1 -0
- package/dist/lib/dead-ends.d.ts +28 -0
- package/dist/lib/dead-ends.d.ts.map +1 -0
- package/dist/lib/dead-ends.js +451 -0
- package/dist/lib/dead-ends.js.map +1 -0
- package/dist/lib/deps.d.ts +2 -0
- package/dist/lib/deps.d.ts.map +1 -0
- package/dist/lib/deps.js +630 -0
- package/dist/lib/deps.js.map +1 -0
- package/dist/lib/discussion.d.ts +2 -0
- package/dist/lib/discussion.d.ts.map +1 -0
- package/dist/lib/discussion.js +1041 -0
- package/dist/lib/discussion.js.map +1 -0
- package/dist/lib/drift.d.ts +36 -0
- package/dist/lib/drift.d.ts.map +1 -0
- package/dist/lib/drift.js +481 -0
- package/dist/lib/drift.js.map +1 -0
- package/dist/lib/evolve/_dimensions-features.d.ts +2 -0
- package/dist/lib/evolve/_dimensions-features.d.ts.map +1 -0
- package/dist/lib/evolve/_dimensions-features.js +369 -0
- package/dist/lib/evolve/_dimensions-features.js.map +1 -0
- package/dist/lib/evolve/_dimensions.d.ts +2 -0
- package/dist/lib/evolve/_dimensions.d.ts.map +1 -0
- package/dist/lib/evolve/_dimensions.js +358 -0
- package/dist/lib/evolve/_dimensions.js.map +1 -0
- package/dist/lib/evolve/_product-ideation.d.ts +2 -0
- package/dist/lib/evolve/_product-ideation.d.ts.map +1 -0
- package/dist/lib/evolve/_product-ideation.js +281 -0
- package/dist/lib/evolve/_product-ideation.js.map +1 -0
- package/dist/lib/evolve/_prompts.d.ts +2 -0
- package/dist/lib/evolve/_prompts.d.ts.map +1 -0
- package/dist/lib/evolve/_prompts.js +153 -0
- package/dist/lib/evolve/_prompts.js.map +1 -0
- package/dist/lib/evolve/cli.d.ts +2 -0
- package/dist/lib/evolve/cli.d.ts.map +1 -0
- package/dist/lib/evolve/cli.js +224 -0
- package/dist/lib/evolve/cli.js.map +1 -0
- package/dist/lib/evolve/discovery.d.ts +2 -0
- package/dist/lib/evolve/discovery.d.ts.map +1 -0
- package/dist/lib/evolve/discovery.js +391 -0
- package/dist/lib/evolve/discovery.js.map +1 -0
- package/dist/lib/evolve/index.d.ts +2 -0
- package/dist/lib/evolve/index.d.ts.map +1 -0
- package/dist/lib/evolve/index.js +88 -0
- package/dist/lib/evolve/index.js.map +1 -0
- package/dist/lib/evolve/orchestrator.d.ts +2 -0
- package/dist/lib/evolve/orchestrator.d.ts.map +1 -0
- package/dist/lib/evolve/orchestrator.js +851 -0
- package/dist/lib/evolve/orchestrator.js.map +1 -0
- package/dist/lib/evolve/scoring.d.ts +2 -0
- package/dist/lib/evolve/scoring.d.ts.map +1 -0
- package/dist/lib/evolve/scoring.js +118 -0
- package/dist/lib/evolve/scoring.js.map +1 -0
- package/dist/lib/evolve/state.d.ts +2 -0
- package/dist/lib/evolve/state.d.ts.map +1 -0
- package/dist/lib/evolve/state.js +264 -0
- package/dist/lib/evolve/state.js.map +1 -0
- package/dist/lib/evolve/types.d.ts +249 -0
- package/dist/lib/evolve/types.d.ts.map +1 -0
- package/dist/lib/evolve/types.js +3 -0
- package/dist/lib/evolve/types.js.map +1 -0
- package/dist/lib/frontmatter.d.ts +2 -0
- package/dist/lib/frontmatter.d.ts.map +1 -0
- package/dist/lib/frontmatter.js +513 -0
- package/dist/lib/frontmatter.js.map +1 -0
- package/dist/lib/gates.d.ts +2 -0
- package/dist/lib/gates.d.ts.map +1 -0
- package/dist/lib/gates.js +578 -0
- package/dist/lib/gates.js.map +1 -0
- package/dist/lib/genome.d.ts +10 -0
- package/dist/lib/genome.d.ts.map +1 -0
- package/dist/lib/genome.js +368 -0
- package/dist/lib/genome.js.map +1 -0
- package/dist/lib/got.d.ts +2 -0
- package/dist/lib/got.d.ts.map +1 -0
- package/dist/lib/got.js +280 -0
- package/dist/lib/got.js.map +1 -0
- package/dist/lib/invariants.d.ts +2 -0
- package/dist/lib/invariants.d.ts.map +1 -0
- package/dist/lib/invariants.js +298 -0
- package/dist/lib/invariants.js.map +1 -0
- package/dist/lib/knowledge.d.ts +2 -0
- package/dist/lib/knowledge.d.ts.map +1 -0
- package/dist/lib/knowledge.js +658 -0
- package/dist/lib/knowledge.js.map +1 -0
- package/dist/lib/long-term-roadmap.d.ts +2 -0
- package/dist/lib/long-term-roadmap.d.ts.map +1 -0
- package/dist/lib/long-term-roadmap.js +602 -0
- package/dist/lib/long-term-roadmap.js.map +1 -0
- package/dist/lib/markdown-split.d.ts +2 -0
- package/dist/lib/markdown-split.d.ts.map +1 -0
- package/dist/lib/markdown-split.js +199 -0
- package/dist/lib/markdown-split.js.map +1 -0
- package/dist/lib/mcp-server.d.ts +2 -0
- package/dist/lib/mcp-server.d.ts.map +1 -0
- package/dist/lib/mcp-server.js +2424 -0
- package/dist/lib/mcp-server.js.map +1 -0
- package/dist/lib/metrics.d.ts +16 -0
- package/dist/lib/metrics.d.ts.map +1 -0
- package/dist/lib/metrics.js +48 -0
- package/dist/lib/metrics.js.map +1 -0
- package/dist/lib/overstory.d.ts +2 -0
- package/dist/lib/overstory.d.ts.map +1 -0
- package/dist/lib/overstory.js +211 -0
- package/dist/lib/overstory.js.map +1 -0
- package/dist/lib/parallel.d.ts +2 -0
- package/dist/lib/parallel.d.ts.map +1 -0
- package/dist/lib/parallel.js +349 -0
- package/dist/lib/parallel.js.map +1 -0
- package/dist/lib/paths.d.ts +2 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/paths.js +254 -0
- package/dist/lib/paths.js.map +1 -0
- package/dist/lib/phase-complete-llm.d.ts +22 -0
- package/dist/lib/phase-complete-llm.d.ts.map +1 -0
- package/dist/lib/phase-complete-llm.js +331 -0
- package/dist/lib/phase-complete-llm.js.map +1 -0
- package/dist/lib/phase-complete.d.ts +46 -0
- package/dist/lib/phase-complete.d.ts.map +1 -0
- package/dist/lib/phase-complete.js +278 -0
- package/dist/lib/phase-complete.js.map +1 -0
- package/dist/lib/phase-io.d.ts +2 -0
- package/dist/lib/phase-io.d.ts.map +1 -0
- package/dist/lib/phase-io.js +126 -0
- package/dist/lib/phase-io.js.map +1 -0
- package/dist/lib/phase.d.ts +2 -0
- package/dist/lib/phase.d.ts.map +1 -0
- package/dist/lib/phase.js +1344 -0
- package/dist/lib/phase.js.map +1 -0
- package/dist/lib/plan-tournament.d.ts +63 -0
- package/dist/lib/plan-tournament.d.ts.map +1 -0
- package/dist/lib/plan-tournament.js +353 -0
- package/dist/lib/plan-tournament.js.map +1 -0
- package/dist/lib/refinement.d.ts +74 -0
- package/dist/lib/refinement.d.ts.map +1 -0
- package/dist/lib/refinement.js +283 -0
- package/dist/lib/refinement.js.map +1 -0
- package/dist/lib/requirements.d.ts +2 -0
- package/dist/lib/requirements.d.ts.map +1 -0
- package/dist/lib/requirements.js +355 -0
- package/dist/lib/requirements.js.map +1 -0
- package/dist/lib/research-bundle.d.ts +2 -0
- package/dist/lib/research-bundle.d.ts.map +1 -0
- package/dist/lib/research-bundle.js +246 -0
- package/dist/lib/research-bundle.js.map +1 -0
- package/dist/lib/roadmap.d.ts +2 -0
- package/dist/lib/roadmap.d.ts.map +1 -0
- package/dist/lib/roadmap.js +541 -0
- package/dist/lib/roadmap.js.map +1 -0
- package/dist/lib/sample.d.ts +16 -0
- package/dist/lib/sample.d.ts.map +1 -0
- package/dist/lib/sample.js +20 -0
- package/dist/lib/sample.js.map +1 -0
- package/dist/lib/scaffold.d.ts +2 -0
- package/dist/lib/scaffold.d.ts.map +1 -0
- package/dist/lib/scaffold.js +355 -0
- package/dist/lib/scaffold.js.map +1 -0
- package/dist/lib/scan/_utils.d.ts +11 -0
- package/dist/lib/scan/_utils.d.ts.map +1 -0
- package/dist/lib/scan/_utils.js +36 -0
- package/dist/lib/scan/_utils.js.map +1 -0
- package/dist/lib/scan/base64.d.ts +15 -0
- package/dist/lib/scan/base64.d.ts.map +1 -0
- package/dist/lib/scan/base64.js +66 -0
- package/dist/lib/scan/base64.js.map +1 -0
- package/dist/lib/scan/ignorefile.d.ts +30 -0
- package/dist/lib/scan/ignorefile.d.ts.map +1 -0
- package/dist/lib/scan/ignorefile.js +101 -0
- package/dist/lib/scan/ignorefile.js.map +1 -0
- package/dist/lib/scan/injection.d.ts +14 -0
- package/dist/lib/scan/injection.d.ts.map +1 -0
- package/dist/lib/scan/injection.js +39 -0
- package/dist/lib/scan/injection.js.map +1 -0
- package/dist/lib/scan/patterns.d.ts +17 -0
- package/dist/lib/scan/patterns.d.ts.map +1 -0
- package/dist/lib/scan/patterns.js +123 -0
- package/dist/lib/scan/patterns.js.map +1 -0
- package/dist/lib/scan/strip-markdown.d.ts +7 -0
- package/dist/lib/scan/strip-markdown.d.ts.map +1 -0
- package/dist/lib/scan/strip-markdown.js +38 -0
- package/dist/lib/scan/strip-markdown.js.map +1 -0
- package/dist/lib/scan/types.d.ts +23 -0
- package/dist/lib/scan/types.d.ts.map +1 -0
- package/dist/lib/scan/types.js +3 -0
- package/dist/lib/scan/types.js.map +1 -0
- package/dist/lib/scheduler-wait.d.ts +2 -0
- package/dist/lib/scheduler-wait.d.ts.map +1 -0
- package/dist/lib/scheduler-wait.js +59 -0
- package/dist/lib/scheduler-wait.js.map +1 -0
- package/dist/lib/scheduler.d.ts +254 -0
- package/dist/lib/scheduler.d.ts.map +1 -0
- package/dist/lib/scheduler.js +1147 -0
- package/dist/lib/scheduler.js.map +1 -0
- package/dist/lib/state.d.ts +2 -0
- package/dist/lib/state.d.ts.map +1 -0
- package/dist/lib/state.js +744 -0
- package/dist/lib/state.js.map +1 -0
- package/dist/lib/think.d.ts +18 -0
- package/dist/lib/think.d.ts.map +1 -0
- package/dist/lib/think.js +317 -0
- package/dist/lib/think.js.map +1 -0
- package/dist/lib/tracker.d.ts +2 -0
- package/dist/lib/tracker.d.ts.map +1 -0
- package/dist/lib/tracker.js +1121 -0
- package/dist/lib/tracker.js.map +1 -0
- package/dist/lib/types.d.ts +1514 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +4 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +1363 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/verify.d.ts +2 -0
- package/dist/lib/verify.d.ts.map +1 -0
- package/dist/lib/verify.js +1153 -0
- package/dist/lib/verify.js.map +1 -0
- package/dist/lib/wireup/autofix.d.ts +2 -0
- package/dist/lib/wireup/autofix.d.ts.map +1 -0
- package/dist/lib/wireup/autofix.js +188 -0
- package/dist/lib/wireup/autofix.js.map +1 -0
- package/dist/lib/wireup/cli.d.ts +2 -0
- package/dist/lib/wireup/cli.d.ts.map +1 -0
- package/dist/lib/wireup/cli.js +194 -0
- package/dist/lib/wireup/cli.js.map +1 -0
- package/dist/lib/wireup/detection.d.ts +47 -0
- package/dist/lib/wireup/detection.d.ts.map +1 -0
- package/dist/lib/wireup/detection.js +410 -0
- package/dist/lib/wireup/detection.js.map +1 -0
- package/dist/lib/wireup/discovery.d.ts +2 -0
- package/dist/lib/wireup/discovery.d.ts.map +1 -0
- package/dist/lib/wireup/discovery.js +934 -0
- package/dist/lib/wireup/discovery.js.map +1 -0
- package/dist/lib/wireup/execution.d.ts +2 -0
- package/dist/lib/wireup/execution.d.ts.map +1 -0
- package/dist/lib/wireup/execution.js +573 -0
- package/dist/lib/wireup/execution.js.map +1 -0
- package/dist/lib/wireup/index.d.ts +2 -0
- package/dist/lib/wireup/index.d.ts.map +1 -0
- package/dist/lib/wireup/index.js +85 -0
- package/dist/lib/wireup/index.js.map +1 -0
- package/dist/lib/wireup/orchestrator.d.ts +2 -0
- package/dist/lib/wireup/orchestrator.d.ts.map +1 -0
- package/dist/lib/wireup/orchestrator.js +366 -0
- package/dist/lib/wireup/orchestrator.js.map +1 -0
- package/dist/lib/wireup/report.d.ts +47 -0
- package/dist/lib/wireup/report.d.ts.map +1 -0
- package/dist/lib/wireup/report.js +201 -0
- package/dist/lib/wireup/report.js.map +1 -0
- package/dist/lib/wireup/scenarios.d.ts +2 -0
- package/dist/lib/wireup/scenarios.d.ts.map +1 -0
- package/dist/lib/wireup/scenarios.js +516 -0
- package/dist/lib/wireup/scenarios.js.map +1 -0
- package/dist/lib/wireup/state.d.ts +2 -0
- package/dist/lib/wireup/state.d.ts.map +1 -0
- package/dist/lib/wireup/state.js +102 -0
- package/dist/lib/wireup/state.js.map +1 -0
- package/dist/lib/wireup/types.d.ts +376 -0
- package/dist/lib/wireup/types.d.ts.map +1 -0
- package/dist/lib/wireup/types.js +3 -0
- package/dist/lib/wireup/types.js.map +1 -0
- package/dist/lib/worktree.d.ts +2 -0
- package/dist/lib/worktree.d.ts.map +1 -0
- package/dist/lib/worktree.js +999 -0
- package/dist/lib/worktree.js.map +1 -0
- package/lib/autopilot-milestone.ts +136 -0
- package/lib/autopilot-pipeline.ts +1179 -0
- package/lib/autopilot-waves.ts +361 -0
- package/lib/autopilot.ts +1874 -0
- package/lib/autoplan.ts +280 -0
- package/lib/autoresearch.js +4 -0
- package/lib/autoresearch.ts +886 -0
- package/lib/backend.ts +1252 -0
- package/lib/benchmark.ts +341 -0
- package/lib/citations.ts +760 -0
- package/lib/cleanup.ts +1588 -0
- package/lib/cli/adapters.ts +41 -0
- package/lib/cli/agent.ts +83 -0
- package/lib/cli/index.ts +273 -0
- package/lib/cli/output.ts +33 -0
- package/lib/cli/scan-dispatch.ts +130 -0
- package/lib/cli/tools.ts +198 -0
- package/lib/commands/_dashboard-parsers.ts +275 -0
- package/lib/commands/analysis.ts +1851 -0
- package/lib/commands/assumptions.ts +232 -0
- package/lib/commands/blame.ts +174 -0
- package/lib/commands/budget.ts +148 -0
- package/lib/commands/check-plans.ts +233 -0
- package/lib/commands/config.ts +287 -0
- package/lib/commands/dashboard.ts +680 -0
- package/lib/commands/estimate.ts +204 -0
- package/lib/commands/eval-diff.ts +252 -0
- package/lib/commands/freshness.ts +213 -0
- package/lib/commands/health.ts +607 -0
- package/lib/commands/index.ts +266 -0
- package/lib/commands/install.ts +307 -0
- package/lib/commands/knowhow-aggregator.ts +345 -0
- package/lib/commands/knowledge-search.ts +153 -0
- package/lib/commands/long-term-roadmap.ts +390 -0
- package/lib/commands/patterns.ts +465 -0
- package/lib/commands/phase-info.ts +698 -0
- package/lib/commands/plan-lint.ts +546 -0
- package/lib/commands/plan-phase.ts +375 -0
- package/lib/commands/progress.ts +319 -0
- package/lib/commands/quality.ts +138 -0
- package/lib/commands/rollback.ts +195 -0
- package/lib/commands/scan.ts +72 -0
- package/lib/commands/search.ts +300 -0
- package/lib/commands/select-candidate.ts +687 -0
- package/lib/commands/singularity.ts +222 -0
- package/lib/commands/slug-timestamp.ts +74 -0
- package/lib/commands/tail.ts +129 -0
- package/lib/commands/todo.ts +273 -0
- package/lib/commands/watch.ts +80 -0
- package/lib/complexity.ts +117 -0
- package/lib/context/agents.ts +505 -0
- package/lib/context/base.ts +123 -0
- package/lib/context/execute.ts +977 -0
- package/lib/context/index.ts +110 -0
- package/lib/context/progress.ts +278 -0
- package/lib/context/project.ts +531 -0
- package/lib/context/research.ts +646 -0
- package/lib/dead-ends.ts +506 -0
- package/lib/deps.ts +773 -0
- package/lib/discussion.ts +1275 -0
- package/lib/drift.ts +519 -0
- package/lib/evolve/_dimensions-features.ts +525 -0
- package/lib/evolve/_dimensions.ts +511 -0
- package/lib/evolve/_product-ideation.ts +405 -0
- package/lib/evolve/_prompts.ts +178 -0
- package/lib/evolve/cli.ts +330 -0
- package/lib/evolve/discovery.ts +571 -0
- package/lib/evolve/index.ts +105 -0
- package/lib/evolve/orchestrator.ts +1139 -0
- package/lib/evolve/scoring.ts +167 -0
- package/lib/evolve/state.ts +330 -0
- package/lib/evolve/types.ts +290 -0
- package/lib/frontmatter.ts +615 -0
- package/lib/gates.ts +695 -0
- package/lib/genome.ts +402 -0
- package/lib/got.js +4 -0
- package/lib/got.ts +361 -0
- package/lib/invariants.ts +378 -0
- package/lib/knowledge.ts +768 -0
- package/lib/long-term-roadmap.ts +806 -0
- package/lib/markdown-split.ts +273 -0
- package/lib/mcp-server.ts +3292 -0
- package/lib/metrics.ts +49 -0
- package/lib/overstory.ts +270 -0
- package/lib/parallel.ts +570 -0
- package/lib/paths.ts +293 -0
- package/lib/phase-complete-llm.ts +376 -0
- package/lib/phase-complete.ts +366 -0
- package/lib/phase-io.ts +101 -0
- package/lib/phase.ts +1981 -0
- package/lib/plan-tournament.ts +426 -0
- package/lib/refinement.ts +349 -0
- package/lib/requirements.ts +469 -0
- package/lib/research-bundle.ts +300 -0
- package/lib/roadmap.ts +775 -0
- package/lib/scaffold.ts +480 -0
- package/lib/scan/_utils.ts +37 -0
- package/lib/scan/base64.ts +90 -0
- package/lib/scan/ignorefile.ts +109 -0
- package/lib/scan/injection.ts +67 -0
- package/lib/scan/patterns.ts +139 -0
- package/lib/scan/strip-markdown.ts +39 -0
- package/lib/scan/types.ts +28 -0
- package/lib/scheduler-wait.ts +58 -0
- package/lib/scheduler.ts +1370 -0
- package/lib/state.ts +1000 -0
- package/lib/think.ts +365 -0
- package/lib/tracker.ts +1591 -0
- package/lib/types.ts +1663 -0
- package/lib/utils.ts +1479 -0
- package/lib/verify.ts +1434 -0
- package/lib/wireup/autofix.ts +241 -0
- package/lib/wireup/cli.ts +278 -0
- package/lib/wireup/detection.ts +542 -0
- package/lib/wireup/discovery.ts +1063 -0
- package/lib/wireup/execution.ts +686 -0
- package/lib/wireup/index.ts +117 -0
- package/lib/wireup/orchestrator.ts +519 -0
- package/lib/wireup/report.ts +286 -0
- package/lib/wireup/scenarios.ts +616 -0
- package/lib/wireup/state.ts +139 -0
- package/lib/wireup/types.ts +436 -0
- package/lib/worktree.ts +1309 -0
- package/package.json +67 -0
|
@@ -0,0 +1,1041 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const { execFileSync } = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { detectAvailableBackends, buildBackendEnv } = require('./backend');
|
|
7
|
+
const { discussionsDir } = require('./paths');
|
|
8
|
+
const { safeReadFile } = require('./utils');
|
|
9
|
+
// --- Constants ---------------------------------------------------------------
|
|
10
|
+
/**
|
|
11
|
+
* Sonnet-tier model ceiling for primary-backend discussion subagent spawns.
|
|
12
|
+
* Mirrors the pattern from lib/wireup/state.ts and lib/evolve/state.ts.
|
|
13
|
+
* REQ-149: discussion subagents must not exceed sonnet tier.
|
|
14
|
+
*/
|
|
15
|
+
const DISCUSSION_SONNET_MODEL = 'sonnet';
|
|
16
|
+
/**
|
|
17
|
+
* Default dispatch timeout: 5 minutes.
|
|
18
|
+
*/
|
|
19
|
+
const DEFAULT_DISPATCH_TIMEOUT_MS = 5 * 60 * 1000;
|
|
20
|
+
/**
|
|
21
|
+
* Valid severity levels for review findings. Shared across all review functions.
|
|
22
|
+
*/
|
|
23
|
+
const SEVERITY_VALUES = ['blocker', 'warning', 'suggestion'];
|
|
24
|
+
function coerceSeverity(raw) {
|
|
25
|
+
const normalized = typeof raw === 'string' ? raw.toLowerCase() : '';
|
|
26
|
+
return SEVERITY_VALUES.includes(normalized) ? normalized : 'warning';
|
|
27
|
+
}
|
|
28
|
+
function reviewFallbackMessage(response) {
|
|
29
|
+
return response.stderr
|
|
30
|
+
? `Reviewer dispatch failed: ${response.stderr.slice(0, 200)}`
|
|
31
|
+
: `Reviewer returned unparseable response: ${response.response_text.slice(0, 200)}`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolve the reviewer backend from config. Returns null if not configured,
|
|
35
|
+
* not available, or same as primary backend (when requireDifferentFromPrimary is true).
|
|
36
|
+
*/
|
|
37
|
+
function resolveReviewer(config, cwd, opts) {
|
|
38
|
+
if (!config.backend_roles?.reviewer)
|
|
39
|
+
return null;
|
|
40
|
+
const reviewerBackend = config.backend_roles.reviewer;
|
|
41
|
+
if ((opts?.requireDifferentFromPrimary ?? true) && config.backend && reviewerBackend === config.backend) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
const availability = detectAvailableBackends(cwd);
|
|
45
|
+
if (!availability[reviewerBackend]?.available)
|
|
46
|
+
return null;
|
|
47
|
+
return { backend: reviewerBackend, availability };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* CLI binary name and argument builder for each dispatchable backend.
|
|
51
|
+
* Only the four backends with known CLI invocation conventions are included.
|
|
52
|
+
*/
|
|
53
|
+
const BACKEND_CLI_MAP = {
|
|
54
|
+
claude: {
|
|
55
|
+
bin: 'claude',
|
|
56
|
+
buildArgs: (prompt, model) => [
|
|
57
|
+
'--print',
|
|
58
|
+
'-p',
|
|
59
|
+
prompt,
|
|
60
|
+
...(model ? ['--model', model] : []),
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
codex: {
|
|
64
|
+
bin: 'codex',
|
|
65
|
+
buildArgs: (prompt, _model) => ['exec', prompt],
|
|
66
|
+
},
|
|
67
|
+
gemini: {
|
|
68
|
+
bin: 'gemini',
|
|
69
|
+
buildArgs: (prompt, model) => [
|
|
70
|
+
'-p',
|
|
71
|
+
prompt,
|
|
72
|
+
'--approval-mode',
|
|
73
|
+
'yolo',
|
|
74
|
+
...(model ? ['-m', model] : []),
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
opencode: {
|
|
78
|
+
bin: 'opencode',
|
|
79
|
+
buildArgs: (prompt, model) => [
|
|
80
|
+
'run',
|
|
81
|
+
...(model ? ['-m', model] : []),
|
|
82
|
+
prompt,
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
// --- Functions ---------------------------------------------------------------
|
|
87
|
+
/**
|
|
88
|
+
* Dispatch a prompt to a backend CLI subprocess and return a typed response.
|
|
89
|
+
*
|
|
90
|
+
* Validates the backend is dispatchable and currently available on PATH before
|
|
91
|
+
* spawning. Times out after `options.timeout_ms` (default 5 minutes) and
|
|
92
|
+
* returns a structured error response instead of throwing.
|
|
93
|
+
*
|
|
94
|
+
* @param backendId - Which backend CLI to invoke (must be in BACKEND_CLI_MAP)
|
|
95
|
+
* @param prompt - The full prompt string to send to the backend
|
|
96
|
+
* @param options - Optional dispatch configuration (timeout, cwd, model override)
|
|
97
|
+
* @returns A BackendResponse with response_text populated on success, or
|
|
98
|
+
* stderr populated with an error description on failure
|
|
99
|
+
*/
|
|
100
|
+
function dispatchToBackend(backendId, prompt, options) {
|
|
101
|
+
const cliEntry = BACKEND_CLI_MAP[backendId];
|
|
102
|
+
if (!cliEntry) {
|
|
103
|
+
return {
|
|
104
|
+
backend: backendId,
|
|
105
|
+
response_text: '',
|
|
106
|
+
duration_ms: 0,
|
|
107
|
+
stderr: `Backend "${backendId}" is not dispatchable`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const cwd = options?.cwd ?? process.cwd();
|
|
111
|
+
const availability = options?._availability ?? detectAvailableBackends(cwd);
|
|
112
|
+
if (!availability[backendId]?.available) {
|
|
113
|
+
return {
|
|
114
|
+
backend: backendId,
|
|
115
|
+
response_text: '',
|
|
116
|
+
duration_ms: 0,
|
|
117
|
+
stderr: `Backend "${backendId}" is not available on PATH`,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const timeout = options?.timeout_ms ?? DEFAULT_DISPATCH_TIMEOUT_MS;
|
|
121
|
+
const args = cliEntry.buildArgs(prompt, options?.model);
|
|
122
|
+
const start = Date.now();
|
|
123
|
+
try {
|
|
124
|
+
const stdout = execFileSync(cliEntry.bin, args, {
|
|
125
|
+
timeout,
|
|
126
|
+
encoding: 'utf-8',
|
|
127
|
+
cwd,
|
|
128
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
129
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
130
|
+
env: buildBackendEnv(backendId),
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
backend: backendId,
|
|
134
|
+
response_text: stdout.trim(),
|
|
135
|
+
duration_ms: Date.now() - start,
|
|
136
|
+
stderr: '',
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
const duration_ms = Date.now() - start;
|
|
141
|
+
const error = err;
|
|
142
|
+
if (error.killed || error.signal === 'SIGTERM') {
|
|
143
|
+
// Distinguish maxBuffer exceeded (fast kill) from timeout (near-timeout kill)
|
|
144
|
+
const isTimeout = duration_ms >= timeout * 0.9;
|
|
145
|
+
return {
|
|
146
|
+
backend: backendId,
|
|
147
|
+
response_text: '',
|
|
148
|
+
duration_ms,
|
|
149
|
+
stderr: isTimeout
|
|
150
|
+
? `Dispatch timed out after ${timeout}ms`
|
|
151
|
+
: `Dispatch killed (maxBuffer exceeded or signal) after ${duration_ms}ms`,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
backend: backendId,
|
|
156
|
+
response_text: '',
|
|
157
|
+
duration_ms,
|
|
158
|
+
stderr: error.stderr || error.message || 'Unknown dispatch error',
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Build the synthesis prompt from the original topic and round 1 entries.
|
|
164
|
+
*
|
|
165
|
+
* Internal helper — not exported.
|
|
166
|
+
*
|
|
167
|
+
* @param topic - The original discussion topic/question
|
|
168
|
+
* @param roundEntries - Entries from round 1 (mix of BackendResponse and skipped)
|
|
169
|
+
* @returns A formatted prompt string for the synthesizer backend
|
|
170
|
+
*/
|
|
171
|
+
function buildSynthesisPrompt(topic, roundEntries) {
|
|
172
|
+
const responseSections = roundEntries
|
|
173
|
+
.map((entry) => {
|
|
174
|
+
if ('skipped' in entry) {
|
|
175
|
+
return `### ${entry.backend} Response\n[SKIPPED]`;
|
|
176
|
+
}
|
|
177
|
+
return `### ${entry.backend} Response\n${entry.response_text}`;
|
|
178
|
+
})
|
|
179
|
+
.join('\n\n');
|
|
180
|
+
return [
|
|
181
|
+
'You are synthesizing responses from multiple AI backends on the following topic:',
|
|
182
|
+
'',
|
|
183
|
+
'## Topic',
|
|
184
|
+
topic,
|
|
185
|
+
'',
|
|
186
|
+
'## Responses',
|
|
187
|
+
'',
|
|
188
|
+
responseSections,
|
|
189
|
+
'',
|
|
190
|
+
'## Instructions',
|
|
191
|
+
'Synthesize the above responses. Identify areas of consensus, disagreement, and unique insights. Provide a unified recommendation.',
|
|
192
|
+
].join('\n');
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Build the markdown content for a discussion history file.
|
|
196
|
+
*
|
|
197
|
+
* Internal helper — not exported.
|
|
198
|
+
*
|
|
199
|
+
* @param result - The completed DiscussionResult
|
|
200
|
+
* @param phase - Phase identifier used in the header
|
|
201
|
+
* @param type - Discussion type label used in the header
|
|
202
|
+
* @returns Formatted markdown string for writing to disk
|
|
203
|
+
*/
|
|
204
|
+
function buildDiscussionMarkdown(result, phase, type) {
|
|
205
|
+
const lines = [];
|
|
206
|
+
lines.push(`# Discussion: ${result.topic}`, '');
|
|
207
|
+
lines.push(`**Phase:** ${phase} **Type:** ${type} **Participants:** ${result.participants.join(', ')}`);
|
|
208
|
+
lines.push(`**Synthesizer:** ${result.synthesis.backend} **Rounds:** ${result.rounds.length} **Duration:** ${result.duration_ms}ms`);
|
|
209
|
+
lines.push(`**Timestamp:** ${new Date().toISOString()}`, '');
|
|
210
|
+
for (let i = 0; i < result.rounds.length; i++) {
|
|
211
|
+
lines.push(`## Round ${i + 1}`, '');
|
|
212
|
+
for (const entry of result.rounds[i]) {
|
|
213
|
+
if ('skipped' in entry) {
|
|
214
|
+
lines.push(`### ${entry.backend} Response`, `[SKIPPED: ${entry.reason}]`, '---', '');
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
lines.push(`### ${entry.backend} Response`, entry.response_text, '---', '');
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (i === 0) {
|
|
221
|
+
lines.push(`## Synthesis (${result.synthesis.backend})`, '', result.synthesis.response_text, '');
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
lines.push('## Outcome', '', result.synthesis.response_text, '');
|
|
225
|
+
return lines.join('\n');
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Dispatch a prompt to all participants and collect results.
|
|
229
|
+
* Skips unavailable participants with a `{ skipped: true }` entry.
|
|
230
|
+
*/
|
|
231
|
+
function dispatchRound(participants, prompt, availability, dispatchOpts) {
|
|
232
|
+
return participants.map((participant) => {
|
|
233
|
+
if (!availability[participant]?.available) {
|
|
234
|
+
return { backend: participant, skipped: true, reason: `Backend "${participant}" is not available` };
|
|
235
|
+
}
|
|
236
|
+
return dispatchToBackend(participant, prompt, dispatchOpts);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Run a multi-backend discussion and return a structured result.
|
|
241
|
+
*
|
|
242
|
+
* Dispatches the topic to all participants (see module-level NOTE on
|
|
243
|
+
* concurrency), synthesizes responses, optionally runs additional
|
|
244
|
+
* rounds, writes a markdown history file, and returns a typed DiscussionResult.
|
|
245
|
+
*
|
|
246
|
+
* Unavailable participants produce `{ skipped: true, reason }` entries;
|
|
247
|
+
* the discussion continues with the remaining available participants.
|
|
248
|
+
*
|
|
249
|
+
* @param topic - The question or topic posed to all participants
|
|
250
|
+
* @param participants - Backend IDs to include in the discussion
|
|
251
|
+
* @param options - Optional configuration (rounds, synthesizer, timeout, paths, labels)
|
|
252
|
+
* @returns A DiscussionResult with all rounds, synthesis, and the path to the written file
|
|
253
|
+
*/
|
|
254
|
+
function runDiscussion(topic, participants, options) {
|
|
255
|
+
const { rounds = 2, synthesizer = 'claude', timeout_per_round_seconds = 180, cwd = process.cwd(), phase = 'unknown', type = 'discussion', milestone = null, } = options ?? {};
|
|
256
|
+
const clampedRounds = Math.min(Math.max(rounds, 1), 3);
|
|
257
|
+
const start = Date.now();
|
|
258
|
+
const availability = detectAvailableBackends(cwd);
|
|
259
|
+
// Sanitize phase/type to prevent path traversal
|
|
260
|
+
const safePhase = phase.replace(/[/\\]/g, '_');
|
|
261
|
+
const safeType = type.replace(/[/\\]/g, '_');
|
|
262
|
+
const filename = `discussion-${safePhase}-${safeType}-${Date.now()}.md`;
|
|
263
|
+
const dir = discussionsDir(cwd, milestone);
|
|
264
|
+
const timeoutMs = timeout_per_round_seconds * 1000;
|
|
265
|
+
const dispatchOpts = { timeout_ms: timeoutMs, cwd, _availability: availability };
|
|
266
|
+
// Round 1: dispatch to all participants sequentially
|
|
267
|
+
const round1Results = dispatchRound(participants, topic, availability, dispatchOpts);
|
|
268
|
+
const allRounds = [round1Results];
|
|
269
|
+
// Synthesize after round 1, then re-synthesize after each additional round
|
|
270
|
+
let synthPrompt = buildSynthesisPrompt(topic, round1Results);
|
|
271
|
+
let synthesis = dispatchToBackend(synthesizer, synthPrompt, dispatchOpts);
|
|
272
|
+
for (let roundNum = 2; roundNum <= clampedRounds; roundNum++) {
|
|
273
|
+
const roundPrompt = [
|
|
274
|
+
'You are participating in a multi-round discussion on the following topic:',
|
|
275
|
+
'',
|
|
276
|
+
'## Topic',
|
|
277
|
+
topic,
|
|
278
|
+
'',
|
|
279
|
+
'## Synthesis from Previous Round',
|
|
280
|
+
synthesis.response_text,
|
|
281
|
+
'',
|
|
282
|
+
'## Instructions',
|
|
283
|
+
'Please respond to the synthesis above. Do you agree, disagree, or have additional insights to add?',
|
|
284
|
+
].join('\n');
|
|
285
|
+
const roundResults = dispatchRound(participants, roundPrompt, availability, dispatchOpts);
|
|
286
|
+
allRounds.push(roundResults);
|
|
287
|
+
// Re-synthesize incorporating the new round's responses
|
|
288
|
+
synthPrompt = buildSynthesisPrompt(topic, roundResults);
|
|
289
|
+
synthesis = dispatchToBackend(synthesizer, synthPrompt, dispatchOpts);
|
|
290
|
+
}
|
|
291
|
+
// --- Build result ---
|
|
292
|
+
const duration_ms = Date.now() - start;
|
|
293
|
+
const filePath = path.join(dir, filename);
|
|
294
|
+
const result = {
|
|
295
|
+
topic,
|
|
296
|
+
participants,
|
|
297
|
+
rounds: allRounds,
|
|
298
|
+
synthesis,
|
|
299
|
+
duration_ms,
|
|
300
|
+
discussion_file: filePath,
|
|
301
|
+
};
|
|
302
|
+
// --- Write history file (BEFORE return) ---
|
|
303
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
304
|
+
fs.writeFileSync(filePath, buildDiscussionMarkdown(result, phase, type), 'utf-8');
|
|
305
|
+
return result;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* List all discussion filenames in the discussions directory for a milestone.
|
|
309
|
+
*
|
|
310
|
+
* @param cwd - Working directory (project root)
|
|
311
|
+
* @param milestone - Optional milestone version string; defaults to current milestone
|
|
312
|
+
* @returns Array of filenames in the discussions directory, or empty array if not found
|
|
313
|
+
*/
|
|
314
|
+
function listDiscussions(cwd, milestone) {
|
|
315
|
+
const dir = discussionsDir(cwd, milestone);
|
|
316
|
+
try {
|
|
317
|
+
return fs.readdirSync(dir);
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
return [];
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Read the content of a specific discussion file.
|
|
325
|
+
*
|
|
326
|
+
* @param filename - Filename of the discussion (not full path)
|
|
327
|
+
* @param cwd - Working directory (project root)
|
|
328
|
+
* @param milestone - Optional milestone version string; defaults to current milestone
|
|
329
|
+
* @returns UTF-8 content of the discussion file, or null if not found
|
|
330
|
+
*/
|
|
331
|
+
function readDiscussion(filename, cwd, milestone) {
|
|
332
|
+
const dir = discussionsDir(cwd, milestone);
|
|
333
|
+
const filePath = path.join(dir, filename);
|
|
334
|
+
if (!filePath.startsWith(dir + path.sep) && filePath !== dir) {
|
|
335
|
+
throw new Error('Invalid filename: path would escape discussions directory');
|
|
336
|
+
}
|
|
337
|
+
return safeReadFile(filePath);
|
|
338
|
+
}
|
|
339
|
+
// --- Workflow Integration Functions ------------------------------------------
|
|
340
|
+
/**
|
|
341
|
+
* Extract JSON from a raw backend response string.
|
|
342
|
+
*
|
|
343
|
+
* Handles markdown code fences (```json ... ``` or ``` ... ```) and plain JSON.
|
|
344
|
+
* Returns null on parse failure.
|
|
345
|
+
*
|
|
346
|
+
* Internal helper — not exported.
|
|
347
|
+
*/
|
|
348
|
+
function parseJSONFromResponse(raw) {
|
|
349
|
+
// Try to extract JSON from markdown code fences first
|
|
350
|
+
const fenceMatch = raw.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
351
|
+
const candidate = fenceMatch ? fenceMatch[1].trim() : raw.trim();
|
|
352
|
+
try {
|
|
353
|
+
const parsed = JSON.parse(candidate);
|
|
354
|
+
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
|
355
|
+
return parsed;
|
|
356
|
+
}
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
catch {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Check if the brainstormer backend is configured and available for a
|
|
365
|
+
* discussion gate (before_planning or before_execution).
|
|
366
|
+
*
|
|
367
|
+
* Returns the brainstormer BackendId on success, or null to skip.
|
|
368
|
+
*/
|
|
369
|
+
function resolveBrainstormer(config, gate, cwd) {
|
|
370
|
+
if (config.discussion?.enabled === false)
|
|
371
|
+
return null;
|
|
372
|
+
// before_planning defaults to true; before_execution must be explicitly true
|
|
373
|
+
if (gate === 'before_planning' && config.discussion?.before_planning === false)
|
|
374
|
+
return null;
|
|
375
|
+
if (gate === 'before_execution' && config.discussion?.before_execution !== true)
|
|
376
|
+
return null;
|
|
377
|
+
if (!config.backend_roles?.brainstormer)
|
|
378
|
+
return null;
|
|
379
|
+
const brainstormerBackend = config.backend_roles.brainstormer;
|
|
380
|
+
const availability = detectAvailableBackends(cwd);
|
|
381
|
+
if (!availability[brainstormerBackend]?.available)
|
|
382
|
+
return null;
|
|
383
|
+
return brainstormerBackend;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Run a pre-planning discussion with the configured brainstormer backend.
|
|
387
|
+
*
|
|
388
|
+
* Checks config flags before dispatching. Returns null (silently skips)
|
|
389
|
+
* when discussion is disabled, before_planning is false, or the brainstormer
|
|
390
|
+
* backend is not configured or unavailable.
|
|
391
|
+
*
|
|
392
|
+
* REQ-138
|
|
393
|
+
*/
|
|
394
|
+
function runPrePlanningDiscussion(options) {
|
|
395
|
+
const { phaseGoal, requirements, cwd, phase, milestone, config } = options;
|
|
396
|
+
const brainstormer = resolveBrainstormer(config, 'before_planning', cwd);
|
|
397
|
+
if (!brainstormer)
|
|
398
|
+
return null;
|
|
399
|
+
const reqLines = requirements.map((r) => `- ${r}`).join('\n');
|
|
400
|
+
const topic = `Pre-planning discussion for phase goal: ${phaseGoal}\n\nRequirements:\n${reqLines}`;
|
|
401
|
+
return runDiscussion(topic, [brainstormer], {
|
|
402
|
+
rounds: 1,
|
|
403
|
+
phase,
|
|
404
|
+
type: 'pre-planning',
|
|
405
|
+
cwd,
|
|
406
|
+
milestone,
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Run a pre-execution discussion with the configured brainstormer backend.
|
|
411
|
+
*
|
|
412
|
+
* Checks config flags before dispatching. Returns null when discussion is
|
|
413
|
+
* disabled, before_execution is not explicitly enabled, or the brainstormer
|
|
414
|
+
* backend is not configured or unavailable.
|
|
415
|
+
*
|
|
416
|
+
* REQ-139
|
|
417
|
+
*/
|
|
418
|
+
function runPreExecutionDiscussion(options) {
|
|
419
|
+
const { planSummary, cwd, phase, milestone, config } = options;
|
|
420
|
+
const brainstormer = resolveBrainstormer(config, 'before_execution', cwd);
|
|
421
|
+
if (!brainstormer)
|
|
422
|
+
return null;
|
|
423
|
+
const topic = `Pre-execution discussion: surface implementation concerns for the following plan:\n\n${planSummary}`;
|
|
424
|
+
return runDiscussion(topic, [brainstormer], {
|
|
425
|
+
rounds: 1,
|
|
426
|
+
phase,
|
|
427
|
+
type: 'pre-execution',
|
|
428
|
+
cwd,
|
|
429
|
+
milestone,
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Dispatch a plan text to the reviewer backend and parse the structured response.
|
|
434
|
+
*
|
|
435
|
+
* Checks that a reviewer is configured and that it differs from the primary
|
|
436
|
+
* backend. Returns null when reviewer is unavailable. Handles malformed JSON
|
|
437
|
+
* responses gracefully.
|
|
438
|
+
*
|
|
439
|
+
* REQ-140
|
|
440
|
+
*
|
|
441
|
+
* @param options - Plan text, working directory, and GRD config
|
|
442
|
+
* @returns A PlanReviewResult on success, null if skipped/unavailable
|
|
443
|
+
*/
|
|
444
|
+
function reviewPlanViaBackend(options) {
|
|
445
|
+
const { planText, cwd, config } = options;
|
|
446
|
+
const resolved = resolveReviewer(config, cwd);
|
|
447
|
+
if (!resolved)
|
|
448
|
+
return null;
|
|
449
|
+
const { backend: reviewerBackend, availability } = resolved;
|
|
450
|
+
const prompt = [
|
|
451
|
+
'Review the following plan and provide structured feedback.',
|
|
452
|
+
'',
|
|
453
|
+
'## Plan',
|
|
454
|
+
planText,
|
|
455
|
+
'',
|
|
456
|
+
'Respond with JSON only (no markdown prose outside the JSON block):',
|
|
457
|
+
'```json',
|
|
458
|
+
'{ "approved": boolean, "concerns": [{"description": string, "severity": "blocker"|"warning"|"suggestion"}], "suggestions": [string] }',
|
|
459
|
+
'```',
|
|
460
|
+
].join('\n');
|
|
461
|
+
const start = Date.now();
|
|
462
|
+
const response = dispatchToBackend(reviewerBackend, prompt, { cwd, _availability: availability });
|
|
463
|
+
const duration_ms = Date.now() - start;
|
|
464
|
+
const parsed = parseJSONFromResponse(response.response_text);
|
|
465
|
+
if (!parsed) {
|
|
466
|
+
const concerns = [
|
|
467
|
+
{ description: reviewFallbackMessage(response), severity: 'warning' },
|
|
468
|
+
];
|
|
469
|
+
return {
|
|
470
|
+
approved: false,
|
|
471
|
+
concerns,
|
|
472
|
+
suggestions: [response.response_text],
|
|
473
|
+
reviewer_backend: reviewerBackend,
|
|
474
|
+
duration_ms,
|
|
475
|
+
raw_response: response.response_text,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
const approved = typeof parsed['approved'] === 'boolean' ? parsed['approved'] : false;
|
|
479
|
+
const rawConcerns = Array.isArray(parsed['concerns']) ? parsed['concerns'] : [];
|
|
480
|
+
const concerns = rawConcerns
|
|
481
|
+
.filter((c) => typeof c === 'object' && c !== null)
|
|
482
|
+
.map((c) => ({
|
|
483
|
+
description: typeof c['description'] === 'string' ? c['description'] : String(c['description'] ?? ''),
|
|
484
|
+
severity: coerceSeverity(c['severity']),
|
|
485
|
+
}));
|
|
486
|
+
const rawSuggestions = Array.isArray(parsed['suggestions']) ? parsed['suggestions'] : [];
|
|
487
|
+
const suggestions = rawSuggestions.map((s) => String(s));
|
|
488
|
+
return {
|
|
489
|
+
approved,
|
|
490
|
+
concerns,
|
|
491
|
+
suggestions,
|
|
492
|
+
reviewer_backend: reviewerBackend,
|
|
493
|
+
duration_ms,
|
|
494
|
+
raw_response: response.response_text,
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Dispatch a code diff to the reviewer backend and parse the structured response.
|
|
499
|
+
*
|
|
500
|
+
* Same reviewer availability checks as reviewPlanViaBackend.
|
|
501
|
+
* Handles malformed JSON responses gracefully.
|
|
502
|
+
*
|
|
503
|
+
* REQ-141
|
|
504
|
+
*
|
|
505
|
+
* @param options - Code diff text, working directory, and GRD config
|
|
506
|
+
* @returns A CodeReviewResult on success, null if skipped/unavailable
|
|
507
|
+
*/
|
|
508
|
+
function reviewCodeViaBackend(options) {
|
|
509
|
+
const { diff, cwd, config } = options;
|
|
510
|
+
const resolved = resolveReviewer(config, cwd);
|
|
511
|
+
if (!resolved)
|
|
512
|
+
return null;
|
|
513
|
+
const { backend: reviewerBackend, availability } = resolved;
|
|
514
|
+
const prompt = [
|
|
515
|
+
'Review this code diff and provide structured feedback.',
|
|
516
|
+
'',
|
|
517
|
+
'## Diff',
|
|
518
|
+
diff,
|
|
519
|
+
'',
|
|
520
|
+
'Respond with JSON only (no markdown prose outside the JSON block):',
|
|
521
|
+
'```json',
|
|
522
|
+
'{ "approved": boolean, "issues": [{"severity": "blocker"|"warning"|"suggestion", "file": string, "line_range": string, "description": string}], "summary": string }',
|
|
523
|
+
'```',
|
|
524
|
+
].join('\n');
|
|
525
|
+
const start = Date.now();
|
|
526
|
+
const response = dispatchToBackend(reviewerBackend, prompt, { cwd, _availability: availability });
|
|
527
|
+
const duration_ms = Date.now() - start;
|
|
528
|
+
const parsed = parseJSONFromResponse(response.response_text);
|
|
529
|
+
if (!parsed) {
|
|
530
|
+
const issues = [
|
|
531
|
+
{ severity: 'warning', file: '', line_range: '', description: reviewFallbackMessage(response) },
|
|
532
|
+
];
|
|
533
|
+
return {
|
|
534
|
+
approved: false,
|
|
535
|
+
issues,
|
|
536
|
+
summary: response.response_text,
|
|
537
|
+
reviewer_backend: reviewerBackend,
|
|
538
|
+
duration_ms,
|
|
539
|
+
raw_response: response.response_text,
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
const approved = typeof parsed['approved'] === 'boolean' ? parsed['approved'] : false;
|
|
543
|
+
const rawIssues = Array.isArray(parsed['issues']) ? parsed['issues'] : [];
|
|
544
|
+
const issues = rawIssues
|
|
545
|
+
.filter((i) => typeof i === 'object' && i !== null)
|
|
546
|
+
.map((i) => ({
|
|
547
|
+
severity: coerceSeverity(i['severity']),
|
|
548
|
+
file: typeof i['file'] === 'string' ? i['file'] : '',
|
|
549
|
+
line_range: typeof i['line_range'] === 'string' ? i['line_range'] : '',
|
|
550
|
+
description: typeof i['description'] === 'string' ? i['description'] : String(i['description'] ?? ''),
|
|
551
|
+
}));
|
|
552
|
+
const summary = typeof parsed['summary'] === 'string' ? parsed['summary'] : '';
|
|
553
|
+
return {
|
|
554
|
+
approved,
|
|
555
|
+
issues,
|
|
556
|
+
summary,
|
|
557
|
+
reviewer_backend: reviewerBackend,
|
|
558
|
+
duration_ms,
|
|
559
|
+
raw_response: response.response_text,
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Dispatch a PR diff to the reviewer backend and parse structured review comments.
|
|
564
|
+
*
|
|
565
|
+
* Checks code_review_enabled and reviewer role configuration.
|
|
566
|
+
* Handles malformed JSON responses gracefully.
|
|
567
|
+
*
|
|
568
|
+
* REQ-142
|
|
569
|
+
*
|
|
570
|
+
* @param options - PR diff text, PR number, working directory, and GRD config
|
|
571
|
+
* @returns A PRReviewResult on success, null if skipped/unavailable
|
|
572
|
+
*/
|
|
573
|
+
function reviewPRViaBackend(options) {
|
|
574
|
+
const { diff, prNumber, cwd, config } = options;
|
|
575
|
+
if (!config.code_review_enabled)
|
|
576
|
+
return null;
|
|
577
|
+
// PR review allows reviewer === primary backend (no requireDifferentFromPrimary)
|
|
578
|
+
const resolved = resolveReviewer(config, cwd, { requireDifferentFromPrimary: false });
|
|
579
|
+
if (!resolved)
|
|
580
|
+
return null;
|
|
581
|
+
const { backend: reviewerBackend, availability } = resolved;
|
|
582
|
+
const prompt = [
|
|
583
|
+
`Review this PR #${prNumber} diff and provide structured review comments.`,
|
|
584
|
+
'',
|
|
585
|
+
'## Diff',
|
|
586
|
+
diff,
|
|
587
|
+
'',
|
|
588
|
+
'Respond with JSON only (no markdown prose outside the JSON block):',
|
|
589
|
+
'```json',
|
|
590
|
+
'{ "comments": [{"file": string, "line": number, "body": string, "severity": "blocker"|"warning"|"suggestion"}], "summary": string }',
|
|
591
|
+
'```',
|
|
592
|
+
].join('\n');
|
|
593
|
+
const start = Date.now();
|
|
594
|
+
const response = dispatchToBackend(reviewerBackend, prompt, { cwd, _availability: availability });
|
|
595
|
+
const duration_ms = Date.now() - start;
|
|
596
|
+
const parsed = parseJSONFromResponse(response.response_text);
|
|
597
|
+
if (!parsed) {
|
|
598
|
+
const comments = [
|
|
599
|
+
{
|
|
600
|
+
file: '',
|
|
601
|
+
line: 0,
|
|
602
|
+
body: `Reviewer returned unparseable response: ${response.response_text.slice(0, 200)}`,
|
|
603
|
+
severity: 'warning',
|
|
604
|
+
},
|
|
605
|
+
];
|
|
606
|
+
return {
|
|
607
|
+
comments,
|
|
608
|
+
summary: response.response_text,
|
|
609
|
+
reviewer_backend: reviewerBackend,
|
|
610
|
+
duration_ms,
|
|
611
|
+
raw_response: response.response_text,
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
const rawComments = Array.isArray(parsed['comments']) ? parsed['comments'] : [];
|
|
615
|
+
const comments = rawComments
|
|
616
|
+
.filter((c) => typeof c === 'object' && c !== null)
|
|
617
|
+
.map((c) => ({
|
|
618
|
+
file: typeof c['file'] === 'string' ? c['file'] : '',
|
|
619
|
+
line: typeof c['line'] === 'number' ? c['line'] : 0,
|
|
620
|
+
body: typeof c['body'] === 'string' ? c['body'] : '',
|
|
621
|
+
severity: coerceSeverity(c['severity']),
|
|
622
|
+
}));
|
|
623
|
+
const summary = typeof parsed['summary'] === 'string' ? parsed['summary'] : '';
|
|
624
|
+
return {
|
|
625
|
+
comments,
|
|
626
|
+
summary,
|
|
627
|
+
reviewer_backend: reviewerBackend,
|
|
628
|
+
duration_ms,
|
|
629
|
+
raw_response: response.response_text,
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
// --- Elicitation Detection ---------------------------------------------------
|
|
633
|
+
/**
|
|
634
|
+
* Clarification phrases that strongly indicate a backend is asking for input.
|
|
635
|
+
* Matched case-insensitively.
|
|
636
|
+
*/
|
|
637
|
+
const CLARIFICATION_PHRASES = [
|
|
638
|
+
'please clarify',
|
|
639
|
+
'which approach',
|
|
640
|
+
'could you specify',
|
|
641
|
+
'would you prefer',
|
|
642
|
+
'do you want',
|
|
643
|
+
];
|
|
644
|
+
/**
|
|
645
|
+
* Detect elicitation patterns in backend output text.
|
|
646
|
+
*
|
|
647
|
+
* Parses the output line-by-line to find questions, numbered option lists,
|
|
648
|
+
* or clarification phrases that indicate the backend is waiting for user input.
|
|
649
|
+
* False-positive filters exclude questions inside code blocks, comments,
|
|
650
|
+
* string literals, and markdown headers.
|
|
651
|
+
*
|
|
652
|
+
* Detection patterns (in priority order):
|
|
653
|
+
* 1. direct_question: Line ends with '?' (not in code/comment context)
|
|
654
|
+
* 2. numbered_options: 2+ consecutive lines matching /^\s*\d+[.)]\s+/
|
|
655
|
+
* 3. clarification_phrase: Line contains known clarification keywords
|
|
656
|
+
* 4. option_prompt: Line contains "Choose one", "Select an option", "Pick one"
|
|
657
|
+
*
|
|
658
|
+
* @param output - Full text output from a backend subprocess (may be multi-line)
|
|
659
|
+
* @returns An ElicitationDetection on match, or null if no elicitation detected
|
|
660
|
+
*/
|
|
661
|
+
function detectElicitation(output) {
|
|
662
|
+
if (!output)
|
|
663
|
+
return null;
|
|
664
|
+
const lines = output.split('\n');
|
|
665
|
+
let inCodeBlock = false;
|
|
666
|
+
// Option-prompt phrases (case-insensitive)
|
|
667
|
+
const OPTION_PROMPTS = [
|
|
668
|
+
'choose one',
|
|
669
|
+
'select an option',
|
|
670
|
+
'pick one',
|
|
671
|
+
];
|
|
672
|
+
// Numbered option pattern: lines like "1. Foo", "2) Bar"
|
|
673
|
+
const NUMBERED_OPTION_RE = /^\s*\d+[.)]\s+/;
|
|
674
|
+
/**
|
|
675
|
+
* Returns true if a '?' on this line appears to be inside a string literal.
|
|
676
|
+
* Simple heuristic: count quote characters before the last '?'. If the
|
|
677
|
+
* number of quotes before the '?' is odd, the '?' is likely inside a string.
|
|
678
|
+
*/
|
|
679
|
+
function questionInString(line) {
|
|
680
|
+
const qIdx = line.lastIndexOf('?');
|
|
681
|
+
if (qIdx === -1)
|
|
682
|
+
return false;
|
|
683
|
+
const before = line.slice(0, qIdx);
|
|
684
|
+
// Count unescaped single quotes and double quotes separately
|
|
685
|
+
const singleQuotes = (before.match(/(?<!\\)'/g) ?? []).length;
|
|
686
|
+
const doubleQuotes = (before.match(/(?<!\\)"/g) ?? []).length;
|
|
687
|
+
// If either count is odd, the '?' is inside a string
|
|
688
|
+
return singleQuotes % 2 !== 0 || doubleQuotes % 2 !== 0;
|
|
689
|
+
}
|
|
690
|
+
const SKIPPED_PREFIXES = ['//', '/*', '*', '#', 'at ', 'Error:', 'Warning:'];
|
|
691
|
+
function isSkippedContext(trimmed) {
|
|
692
|
+
return SKIPPED_PREFIXES.some((p) => trimmed.startsWith(p));
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Returns true if a line looks like a short rhetorical question
|
|
696
|
+
* (single word followed by '?') that appears to be a sentence connector
|
|
697
|
+
* rather than a standalone question to the user.
|
|
698
|
+
* Pattern: one word ending with '?', not preceded by typical elicitation context.
|
|
699
|
+
*/
|
|
700
|
+
function isRhetoricalQuestion(trimmed) {
|
|
701
|
+
// "Why?" or "Why? Because..." — single word before '?'
|
|
702
|
+
return /^\w+\?/.test(trimmed) && trimmed.split(/\s+/).length <= 2;
|
|
703
|
+
}
|
|
704
|
+
// Pass 1: look for numbered option blocks (need 2+ consecutive matches)
|
|
705
|
+
// We need to find these first to handle mixed patterns correctly.
|
|
706
|
+
let consecutiveNumbered = 0;
|
|
707
|
+
let numberedStart = -1;
|
|
708
|
+
let numberedEnd = -1;
|
|
709
|
+
{
|
|
710
|
+
let blockDepth = 0;
|
|
711
|
+
for (let i = 0; i < lines.length; i++) {
|
|
712
|
+
const trimmed = lines[i].trim();
|
|
713
|
+
if (trimmed.startsWith('```')) {
|
|
714
|
+
blockDepth = blockDepth === 0 ? 1 : 0;
|
|
715
|
+
}
|
|
716
|
+
if (blockDepth > 0) {
|
|
717
|
+
consecutiveNumbered = 0;
|
|
718
|
+
continue;
|
|
719
|
+
}
|
|
720
|
+
if (NUMBERED_OPTION_RE.test(lines[i])) {
|
|
721
|
+
if (consecutiveNumbered === 0)
|
|
722
|
+
numberedStart = i;
|
|
723
|
+
consecutiveNumbered++;
|
|
724
|
+
numberedEnd = i;
|
|
725
|
+
}
|
|
726
|
+
else {
|
|
727
|
+
if (consecutiveNumbered >= 2)
|
|
728
|
+
break; // found block
|
|
729
|
+
consecutiveNumbered = 0;
|
|
730
|
+
numberedStart = -1;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
if (consecutiveNumbered >= 2 && numberedStart !== -1) {
|
|
735
|
+
const questionLines = lines.slice(numberedStart, numberedEnd + 1);
|
|
736
|
+
return {
|
|
737
|
+
question: questionLines.join('\n'),
|
|
738
|
+
patterns: ['numbered_options'],
|
|
739
|
+
confidence: 'high',
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
// Pass 2: scan line-by-line for other patterns
|
|
743
|
+
for (const line of lines) {
|
|
744
|
+
const trimmed = line.trim();
|
|
745
|
+
// Track code block fences
|
|
746
|
+
if (trimmed.startsWith('```')) {
|
|
747
|
+
inCodeBlock = !inCodeBlock;
|
|
748
|
+
continue;
|
|
749
|
+
}
|
|
750
|
+
if (inCodeBlock)
|
|
751
|
+
continue;
|
|
752
|
+
// Skip commented/header/trace lines
|
|
753
|
+
if (isSkippedContext(trimmed))
|
|
754
|
+
continue;
|
|
755
|
+
// Skip empty lines
|
|
756
|
+
if (trimmed.length === 0)
|
|
757
|
+
continue;
|
|
758
|
+
const lower = trimmed.toLowerCase();
|
|
759
|
+
// Pattern: clarification_phrase
|
|
760
|
+
for (const phrase of CLARIFICATION_PHRASES) {
|
|
761
|
+
if (lower.includes(phrase)) {
|
|
762
|
+
return {
|
|
763
|
+
question: trimmed,
|
|
764
|
+
patterns: ['clarification_phrase'],
|
|
765
|
+
confidence: 'high',
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
// Pattern: direct_question — line ends with '?'
|
|
770
|
+
if (trimmed.endsWith('?')) {
|
|
771
|
+
if (questionInString(trimmed))
|
|
772
|
+
continue;
|
|
773
|
+
if (isRhetoricalQuestion(trimmed))
|
|
774
|
+
continue;
|
|
775
|
+
return {
|
|
776
|
+
question: trimmed,
|
|
777
|
+
patterns: ['direct_question'],
|
|
778
|
+
confidence: 'high',
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
// Pattern: option_prompt
|
|
782
|
+
for (const phrase of OPTION_PROMPTS) {
|
|
783
|
+
if (lower.includes(phrase)) {
|
|
784
|
+
return {
|
|
785
|
+
question: trimmed,
|
|
786
|
+
patterns: ['option_prompt'],
|
|
787
|
+
confidence: 'medium',
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return null;
|
|
793
|
+
}
|
|
794
|
+
// --- Elicitation Context Builder and Resolver --------------------------------
|
|
795
|
+
/**
|
|
796
|
+
* Section budgets in characters for buildElicitationContext.
|
|
797
|
+
* Total: ~32000 chars (~8K tokens).
|
|
798
|
+
*/
|
|
799
|
+
const ELICITATION_BUDGET = {
|
|
800
|
+
question: 1000,
|
|
801
|
+
phaseGoal: 1000,
|
|
802
|
+
planSummary: 2000,
|
|
803
|
+
recentChanges: 2000,
|
|
804
|
+
projectState: 1000,
|
|
805
|
+
};
|
|
806
|
+
/**
|
|
807
|
+
* Truncate a string to maxChars, appending a truncation notice if needed.
|
|
808
|
+
*/
|
|
809
|
+
function truncate(s, maxChars) {
|
|
810
|
+
if (s.length <= maxChars)
|
|
811
|
+
return s;
|
|
812
|
+
return s.slice(0, maxChars) + '\n[... truncated ...]';
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
815
|
+
* Search milestones/MILESTONE/phases/PHASE*\/*-PLAN.md for an objective tag.
|
|
816
|
+
* Returns the trimmed objective text or '' if not found.
|
|
817
|
+
*/
|
|
818
|
+
function findPlanObjective(milestonesDir, phase, milestone) {
|
|
819
|
+
try {
|
|
820
|
+
const milestones = milestone ? [milestone] : fs.readdirSync(milestonesDir);
|
|
821
|
+
for (const ms of milestones) {
|
|
822
|
+
const phasesPath = path.join(milestonesDir, ms, 'phases');
|
|
823
|
+
let phaseEntries;
|
|
824
|
+
try {
|
|
825
|
+
phaseEntries = fs.readdirSync(phasesPath);
|
|
826
|
+
}
|
|
827
|
+
catch {
|
|
828
|
+
continue;
|
|
829
|
+
}
|
|
830
|
+
for (const entry of phaseEntries) {
|
|
831
|
+
if (!entry.startsWith(phase))
|
|
832
|
+
continue;
|
|
833
|
+
let planFiles;
|
|
834
|
+
try {
|
|
835
|
+
planFiles = fs.readdirSync(path.join(phasesPath, entry));
|
|
836
|
+
}
|
|
837
|
+
catch {
|
|
838
|
+
continue;
|
|
839
|
+
}
|
|
840
|
+
const planFile = planFiles.find((f) => f.endsWith('-PLAN.md'));
|
|
841
|
+
if (!planFile)
|
|
842
|
+
continue;
|
|
843
|
+
const content = fs.readFileSync(path.join(phasesPath, entry, planFile), 'utf-8');
|
|
844
|
+
const objMatch = content.match(/<objective>([\s\S]*?)<\/objective>/);
|
|
845
|
+
return objMatch ? objMatch[1].trim() : '';
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
catch { /* milestonesDir not readable */ }
|
|
850
|
+
return '';
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Build a context string for elicitation resolution.
|
|
854
|
+
*
|
|
855
|
+
* Assembles up to 5 sections:
|
|
856
|
+
* - ## Question: the detected elicitation text
|
|
857
|
+
* - ## Phase Goal: extracted from ROADMAP.md for the given phase
|
|
858
|
+
* - ## Plan Summary: extracted from the active PLAN.md objective element
|
|
859
|
+
* - ## Recent Changes: git diff --stat HEAD~3..HEAD
|
|
860
|
+
* - ## Project State: current position from STATE.md
|
|
861
|
+
*
|
|
862
|
+
* All file reads are wrapped in try/catch — missing files silently omit the section.
|
|
863
|
+
* Total output is kept under 32000 chars (~8K tokens).
|
|
864
|
+
*
|
|
865
|
+
* @param question - The elicitation question text to answer
|
|
866
|
+
* @param options - Configuration: cwd (project root), optional phase identifier
|
|
867
|
+
* @returns A context string with clearly labeled sections
|
|
868
|
+
*/
|
|
869
|
+
function buildElicitationContext(question, options) {
|
|
870
|
+
const { cwd, phase, milestone } = options;
|
|
871
|
+
const planningDir = path.join(cwd, '.planning');
|
|
872
|
+
const sections = [];
|
|
873
|
+
// ## Question
|
|
874
|
+
sections.push('## Question\n' + truncate(question, ELICITATION_BUDGET.question));
|
|
875
|
+
// ## Phase Goal — read from ROADMAP.md
|
|
876
|
+
try {
|
|
877
|
+
const roadmapPath = path.join(planningDir, 'ROADMAP.md');
|
|
878
|
+
const roadmapContent = fs.readFileSync(roadmapPath, 'utf-8');
|
|
879
|
+
let goalText = '';
|
|
880
|
+
if (phase) {
|
|
881
|
+
// Find the phase section and extract the goal line
|
|
882
|
+
const lines = roadmapContent.split('\n');
|
|
883
|
+
let inPhaseSection = false;
|
|
884
|
+
const phaseRe = new RegExp(`Phase\\s+${phase.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`, 'i');
|
|
885
|
+
for (const line of lines) {
|
|
886
|
+
// Match headings containing the phase number
|
|
887
|
+
if (line.match(phaseRe)) {
|
|
888
|
+
inPhaseSection = true;
|
|
889
|
+
continue;
|
|
890
|
+
}
|
|
891
|
+
if (inPhaseSection) {
|
|
892
|
+
// Stop at next heading of same or higher level
|
|
893
|
+
if (line.match(/^#{1,3}\s/))
|
|
894
|
+
break;
|
|
895
|
+
const trimmed = line.trim();
|
|
896
|
+
if (trimmed.length > 0) {
|
|
897
|
+
goalText += (goalText ? '\n' : '') + trimmed;
|
|
898
|
+
if (goalText.length >= ELICITATION_BUDGET.phaseGoal)
|
|
899
|
+
break;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
if (!goalText && roadmapContent.length > 0) {
|
|
905
|
+
// Fallback: first non-empty paragraph from ROADMAP
|
|
906
|
+
const paras = roadmapContent.split(/\n{2,}/);
|
|
907
|
+
for (const para of paras) {
|
|
908
|
+
const trimmed = para.trim();
|
|
909
|
+
if (trimmed.length > 10) {
|
|
910
|
+
goalText = trimmed;
|
|
911
|
+
break;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
if (goalText) {
|
|
916
|
+
sections.push('## Phase Goal\n' + truncate(goalText, ELICITATION_BUDGET.phaseGoal));
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
catch {
|
|
920
|
+
// Missing ROADMAP.md — omit section
|
|
921
|
+
}
|
|
922
|
+
// Section: Plan Summary — read active PLAN.md objective
|
|
923
|
+
if (phase) {
|
|
924
|
+
const planText = findPlanObjective(path.join(planningDir, 'milestones'), String(phase), milestone);
|
|
925
|
+
if (planText) {
|
|
926
|
+
sections.push('## Plan Summary\n' + truncate(planText, ELICITATION_BUDGET.planSummary));
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
// ## Recent Changes — git diff --stat HEAD~3..HEAD
|
|
930
|
+
try {
|
|
931
|
+
const _gitCfg = (() => {
|
|
932
|
+
try {
|
|
933
|
+
return JSON.parse(safeReadFile(path.join(cwd, '.planning', 'config.json')) ?? '{}');
|
|
934
|
+
}
|
|
935
|
+
catch {
|
|
936
|
+
return {};
|
|
937
|
+
}
|
|
938
|
+
})();
|
|
939
|
+
const _gitTimeouts = _gitCfg.timeouts;
|
|
940
|
+
const gitTimeout = typeof _gitTimeouts?.discussion_git_ms === 'number' ? _gitTimeouts.discussion_git_ms : 10000;
|
|
941
|
+
const diffStat = execFileSync('git', ['diff', '--stat', 'HEAD~3..HEAD'], {
|
|
942
|
+
timeout: gitTimeout,
|
|
943
|
+
encoding: 'utf-8',
|
|
944
|
+
cwd,
|
|
945
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
946
|
+
maxBuffer: 1024 * 1024,
|
|
947
|
+
});
|
|
948
|
+
if (diffStat && diffStat.trim()) {
|
|
949
|
+
sections.push('## Recent Changes\n' + truncate(diffStat.trim(), ELICITATION_BUDGET.recentChanges));
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
catch {
|
|
953
|
+
// Git not available or no history — omit section
|
|
954
|
+
}
|
|
955
|
+
// ## Project State — read STATE.md current position section
|
|
956
|
+
try {
|
|
957
|
+
const statePath = path.join(planningDir, 'STATE.md');
|
|
958
|
+
const stateContent = fs.readFileSync(statePath, 'utf-8');
|
|
959
|
+
// Extract up to the first 1K chars; focus on position/current status
|
|
960
|
+
const posMatch = stateContent.match(/(?:## Current Position|## Status|Current Plan:)[^\n]*([\s\S]{0,800})/i);
|
|
961
|
+
const stateSnippet = posMatch
|
|
962
|
+
? posMatch[0].trim()
|
|
963
|
+
: stateContent.slice(0, ELICITATION_BUDGET.projectState);
|
|
964
|
+
sections.push('## Project State\n' + truncate(stateSnippet, ELICITATION_BUDGET.projectState));
|
|
965
|
+
}
|
|
966
|
+
catch {
|
|
967
|
+
// Missing STATE.md — omit section
|
|
968
|
+
}
|
|
969
|
+
return sections.join('\n\n');
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Route an elicitation question through a single-round multi-backend discussion
|
|
973
|
+
* and return the consensus answer text.
|
|
974
|
+
*
|
|
975
|
+
* Calls runDiscussion() with rounds=1 for speed. Falls back to the first
|
|
976
|
+
* non-skipped participant response if synthesis fails. Returns '' when all
|
|
977
|
+
* participants are unavailable.
|
|
978
|
+
*
|
|
979
|
+
* @param question - The elicitation question to resolve
|
|
980
|
+
* @param context - Context string from buildElicitationContext()
|
|
981
|
+
* @param options - participants, synthesizer, and cwd
|
|
982
|
+
* @returns The resolved answer text, or '' if resolution is not possible
|
|
983
|
+
*/
|
|
984
|
+
function resolveElicitation(question, context, options) {
|
|
985
|
+
const { participants, synthesizer, cwd } = options;
|
|
986
|
+
const topic = [
|
|
987
|
+
context,
|
|
988
|
+
'',
|
|
989
|
+
'## Instructions',
|
|
990
|
+
'Based on the context above, answer the question concisely and make a concrete decision.',
|
|
991
|
+
'Do not ask clarifying questions. Provide a direct, actionable answer.',
|
|
992
|
+
].join('\n');
|
|
993
|
+
let result;
|
|
994
|
+
try {
|
|
995
|
+
result = runDiscussion(topic, participants, {
|
|
996
|
+
rounds: 1,
|
|
997
|
+
synthesizer,
|
|
998
|
+
cwd,
|
|
999
|
+
type: 'elicitation',
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
catch {
|
|
1003
|
+
return '';
|
|
1004
|
+
}
|
|
1005
|
+
// Happy path: synthesis has response text
|
|
1006
|
+
const synthText = result.synthesis &&
|
|
1007
|
+
typeof result.synthesis.response_text === 'string'
|
|
1008
|
+
? result.synthesis.response_text.trim()
|
|
1009
|
+
: '';
|
|
1010
|
+
if (synthText)
|
|
1011
|
+
return synthText;
|
|
1012
|
+
// Fallback: find first non-skipped round entry
|
|
1013
|
+
const round0 = result.rounds[0];
|
|
1014
|
+
if (!round0)
|
|
1015
|
+
return '';
|
|
1016
|
+
for (const entry of round0) {
|
|
1017
|
+
if (!('skipped' in entry) && entry.response_text && entry.response_text.trim()) {
|
|
1018
|
+
return entry.response_text.trim();
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
return '';
|
|
1022
|
+
}
|
|
1023
|
+
// --- Exports -----------------------------------------------------------------
|
|
1024
|
+
module.exports = {
|
|
1025
|
+
dispatchToBackend,
|
|
1026
|
+
runDiscussion,
|
|
1027
|
+
listDiscussions,
|
|
1028
|
+
readDiscussion,
|
|
1029
|
+
runPrePlanningDiscussion,
|
|
1030
|
+
runPreExecutionDiscussion,
|
|
1031
|
+
reviewPlanViaBackend,
|
|
1032
|
+
reviewCodeViaBackend,
|
|
1033
|
+
reviewPRViaBackend,
|
|
1034
|
+
detectElicitation,
|
|
1035
|
+
buildElicitationContext,
|
|
1036
|
+
resolveElicitation,
|
|
1037
|
+
DISCUSSION_SONNET_MODEL,
|
|
1038
|
+
BACKEND_CLI_MAP,
|
|
1039
|
+
DEFAULT_DISPATCH_TIMEOUT_MS,
|
|
1040
|
+
};
|
|
1041
|
+
//# sourceMappingURL=discussion.js.map
|