@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
package/lib/roadmap.ts
ADDED
|
@@ -0,0 +1,775 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GRD Roadmap Operations -- ROADMAP.md parsing, phase queries, schedule computation
|
|
5
|
+
*
|
|
6
|
+
* Extracted from bin/grd-tools.js during Phase 03 modularization.
|
|
7
|
+
* Depends on: lib/utils.ts (safeReadFile, normalizePhaseName, stripShippedSections, output, error)
|
|
8
|
+
* Depends on: lib/paths.ts (phasesDir)
|
|
9
|
+
* Depends on: lib/frontmatter.js (extractFrontmatter)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
// Type-only import to establish module scope (no runtime effect)
|
|
14
|
+
import type {} from './types';
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const {
|
|
19
|
+
safeReadFile,
|
|
20
|
+
safeReadMarkdown,
|
|
21
|
+
normalizePhaseName,
|
|
22
|
+
stripShippedSections,
|
|
23
|
+
output,
|
|
24
|
+
error,
|
|
25
|
+
} = require('./utils');
|
|
26
|
+
const { phasesDir: getPhasesDirPath } = require('./paths');
|
|
27
|
+
|
|
28
|
+
// ─── Types ──────────────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Parsed milestone from ROADMAP.md with optional start/target dates.
|
|
32
|
+
*/
|
|
33
|
+
interface ParsedMilestone {
|
|
34
|
+
version: string;
|
|
35
|
+
heading: string;
|
|
36
|
+
start: string | null;
|
|
37
|
+
target: string | null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Internal milestone position for schedule computation.
|
|
42
|
+
*/
|
|
43
|
+
interface MilestonePosition {
|
|
44
|
+
version: string;
|
|
45
|
+
heading: string;
|
|
46
|
+
index: number;
|
|
47
|
+
start: string | null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* A phase entry with schedule dates computed from milestone start + duration.
|
|
52
|
+
*/
|
|
53
|
+
interface PhaseScheduleEntry {
|
|
54
|
+
number: string;
|
|
55
|
+
name: string;
|
|
56
|
+
duration_days: number;
|
|
57
|
+
milestone: string | null;
|
|
58
|
+
start_date: string | null;
|
|
59
|
+
due_date: string | null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Internal phase parsed from ROADMAP.md before schedule computation.
|
|
64
|
+
*/
|
|
65
|
+
interface ParsedPhase {
|
|
66
|
+
number: string;
|
|
67
|
+
name: string;
|
|
68
|
+
duration_days: number;
|
|
69
|
+
milestone: string | null;
|
|
70
|
+
start_date?: string | null;
|
|
71
|
+
due_date?: string | null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Result of computeSchedule() with milestone and phase schedules.
|
|
76
|
+
*/
|
|
77
|
+
interface ScheduleResult {
|
|
78
|
+
milestones: ParsedMilestone[];
|
|
79
|
+
phases: PhaseScheduleEntry[];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Milestone heading info returned by analyzeRoadmap.
|
|
84
|
+
*/
|
|
85
|
+
interface AnalyzedMilestone {
|
|
86
|
+
heading: string;
|
|
87
|
+
version: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Phase analysis entry returned by analyzeRoadmap with disk status and metadata.
|
|
92
|
+
*/
|
|
93
|
+
interface AnalyzedPhaseEntry {
|
|
94
|
+
number: string;
|
|
95
|
+
name: string;
|
|
96
|
+
goal: string | null;
|
|
97
|
+
depends_on: string | null;
|
|
98
|
+
plan_count: number;
|
|
99
|
+
summary_count: number;
|
|
100
|
+
has_context: boolean;
|
|
101
|
+
has_research: boolean;
|
|
102
|
+
disk_status: string;
|
|
103
|
+
roadmap_complete: boolean;
|
|
104
|
+
line: number;
|
|
105
|
+
warnings: string[];
|
|
106
|
+
duration_days: number;
|
|
107
|
+
start_date: string | null;
|
|
108
|
+
due_date: string | null;
|
|
109
|
+
_duration_days?: number;
|
|
110
|
+
_milestone?: string | null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Full roadmap analysis result returned by analyzeRoadmap().
|
|
115
|
+
*/
|
|
116
|
+
interface AnalyzedRoadmap {
|
|
117
|
+
error?: string;
|
|
118
|
+
milestones: AnalyzedMilestone[];
|
|
119
|
+
phases: AnalyzedPhaseEntry[];
|
|
120
|
+
phase_count: number;
|
|
121
|
+
completed_phases: number;
|
|
122
|
+
total_plans: number;
|
|
123
|
+
total_summaries: number;
|
|
124
|
+
progress_percent: number;
|
|
125
|
+
current_phase: string | null;
|
|
126
|
+
next_phase: string | null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ─── Schedule Helpers ───────────────────────────────────────────────────────
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Format a Date object as a YYYY-MM-DD string.
|
|
133
|
+
* @param date - Date object to format
|
|
134
|
+
* @returns Date formatted as 'YYYY-MM-DD'
|
|
135
|
+
*/
|
|
136
|
+
function formatScheduleDate(date: Date): string {
|
|
137
|
+
const y: number = date.getFullYear();
|
|
138
|
+
const m: string = String(date.getMonth() + 1).padStart(2, '0');
|
|
139
|
+
const d: string = String(date.getDate()).padStart(2, '0');
|
|
140
|
+
return `${y}-${m}-${d}`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Add N days to a Date, returning a new Date object.
|
|
145
|
+
* @param date - Starting date
|
|
146
|
+
* @param days - Number of days to add
|
|
147
|
+
* @returns New Date object with the days added
|
|
148
|
+
*/
|
|
149
|
+
function addDays(date: Date, days: number): Date {
|
|
150
|
+
const result = new Date(date);
|
|
151
|
+
result.setDate(result.getDate() + days);
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Compute milestone and phase schedule from ROADMAP.md durations and start dates.
|
|
157
|
+
* @param cwd - Project working directory
|
|
158
|
+
* @returns Schedule with computed start/due dates per phase
|
|
159
|
+
*/
|
|
160
|
+
function computeSchedule(cwd: string): ScheduleResult {
|
|
161
|
+
const roadmapPath: string = path.join(cwd, '.planning', 'ROADMAP.md');
|
|
162
|
+
const configPath: string = path.join(cwd, '.planning', 'config.json');
|
|
163
|
+
const roadmapContent: string | null = safeReadMarkdown(roadmapPath);
|
|
164
|
+
if (!roadmapContent) return { milestones: [], phases: [] };
|
|
165
|
+
const activeContent: string = stripShippedSections(roadmapContent);
|
|
166
|
+
|
|
167
|
+
// Read default_duration_days from config
|
|
168
|
+
let defaultDuration = 7;
|
|
169
|
+
const configRaw: string | null = safeReadFile(configPath);
|
|
170
|
+
if (configRaw) {
|
|
171
|
+
try {
|
|
172
|
+
const config = JSON.parse(configRaw) as Record<string, unknown>;
|
|
173
|
+
const tracker = config.tracker as Record<string, unknown> | undefined;
|
|
174
|
+
const mcp = tracker && (tracker.mcp_atlassian as Record<string, unknown> | undefined);
|
|
175
|
+
if (mcp && mcp.default_duration_days) {
|
|
176
|
+
defaultDuration = parseInt(String(mcp.default_duration_days), 10) || 7;
|
|
177
|
+
}
|
|
178
|
+
} catch {
|
|
179
|
+
// Invalid JSON config; use default duration
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Parse milestones with Start/Target dates
|
|
184
|
+
const milestoneRegex = /^##\s*(.*v(\d+\.\d+(?:\.\d+)?)[^(\n]*)/gim;
|
|
185
|
+
const milestones: ParsedMilestone[] = [];
|
|
186
|
+
const milestonePositions: MilestonePosition[] = [];
|
|
187
|
+
let mMatch: RegExpExecArray | null;
|
|
188
|
+
while ((mMatch = milestoneRegex.exec(activeContent)) !== null) {
|
|
189
|
+
const heading: string = mMatch[1].trim();
|
|
190
|
+
const version = 'v' + mMatch[2];
|
|
191
|
+
const afterHeading: string = activeContent.slice(mMatch.index, mMatch.index + 500);
|
|
192
|
+
const startMatch: RegExpMatchArray | null = afterHeading.match(
|
|
193
|
+
/\*\*Start:\*\*\s*(\d{4}-\d{2}-\d{2})/
|
|
194
|
+
);
|
|
195
|
+
const targetMatch: RegExpMatchArray | null = afterHeading.match(
|
|
196
|
+
/\*\*Target:\*\*\s*(\d{4}-\d{2}-\d{2})/
|
|
197
|
+
);
|
|
198
|
+
milestones.push({
|
|
199
|
+
version,
|
|
200
|
+
heading,
|
|
201
|
+
start: startMatch ? startMatch[1] : null,
|
|
202
|
+
target: targetMatch ? targetMatch[1] : null,
|
|
203
|
+
});
|
|
204
|
+
milestonePositions.push({
|
|
205
|
+
version,
|
|
206
|
+
heading,
|
|
207
|
+
index: mMatch.index,
|
|
208
|
+
start: startMatch ? startMatch[1] : null,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Parse phases with Duration
|
|
213
|
+
const phaseRegex = /#{2,}\s*Phase\s+(\d+(?:\.\d+)?)\s*:\s*([^\n]+)/gi;
|
|
214
|
+
const phases: ParsedPhase[] = [];
|
|
215
|
+
let pMatch: RegExpExecArray | null;
|
|
216
|
+
while ((pMatch = phaseRegex.exec(activeContent)) !== null) {
|
|
217
|
+
const number: string = pMatch[1];
|
|
218
|
+
const name: string = pMatch[2].replace(/\(INSERTED\)/i, '').trim();
|
|
219
|
+
// Extract section text up to the next heading (or end of content).
|
|
220
|
+
// Use [ \t] instead of \s so we don't accidentally match \n##\n sequences.
|
|
221
|
+
const sectionStart: number = pMatch.index;
|
|
222
|
+
const restContent: string = activeContent.slice(sectionStart + pMatch[0].length);
|
|
223
|
+
const nextHeading: RegExpMatchArray | null = restContent.match(/\n#{2,}[ \t]/);
|
|
224
|
+
const sectionText: string = nextHeading
|
|
225
|
+
? activeContent.slice(
|
|
226
|
+
sectionStart,
|
|
227
|
+
sectionStart + pMatch[0].length + (nextHeading.index as number)
|
|
228
|
+
)
|
|
229
|
+
: activeContent.slice(sectionStart);
|
|
230
|
+
const durationMatch: RegExpMatchArray | null = sectionText.match(/\*\*Duration:\*\*\s*(\d+)d/);
|
|
231
|
+
const durationDays: number = durationMatch ? parseInt(durationMatch[1], 10) : defaultDuration;
|
|
232
|
+
|
|
233
|
+
// Determine milestone
|
|
234
|
+
let milestone: string | null =
|
|
235
|
+
milestonePositions.length > 0 ? milestonePositions[0].version : null;
|
|
236
|
+
for (const ms of milestonePositions) {
|
|
237
|
+
if (pMatch.index > ms.index) milestone = ms.version;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
phases.push({ number, name, duration_days: durationDays, milestone });
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Compute dates per milestone group
|
|
244
|
+
const milestoneStartMap: Record<string, string> = {};
|
|
245
|
+
for (const ms of milestonePositions) {
|
|
246
|
+
if (ms.start) milestoneStartMap[ms.version] = ms.start;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
let currentDate: Date | null = null;
|
|
250
|
+
let currentMilestone: string | null = null;
|
|
251
|
+
for (const phase of phases) {
|
|
252
|
+
if (phase.milestone !== currentMilestone) {
|
|
253
|
+
currentMilestone = phase.milestone;
|
|
254
|
+
const msStart: string | undefined = currentMilestone
|
|
255
|
+
? milestoneStartMap[currentMilestone]
|
|
256
|
+
: undefined;
|
|
257
|
+
currentDate = msStart ? new Date(msStart + 'T00:00:00') : null;
|
|
258
|
+
}
|
|
259
|
+
if (currentDate) {
|
|
260
|
+
phase.start_date = formatScheduleDate(currentDate);
|
|
261
|
+
const endDate: Date = addDays(currentDate, phase.duration_days - 1);
|
|
262
|
+
phase.due_date = formatScheduleDate(endDate);
|
|
263
|
+
currentDate = addDays(endDate, 1); // next phase starts day after
|
|
264
|
+
} else {
|
|
265
|
+
phase.start_date = null;
|
|
266
|
+
phase.due_date = null;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
milestones,
|
|
272
|
+
phases: phases as PhaseScheduleEntry[],
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Look up a phase schedule entry by phase number.
|
|
278
|
+
* @param schedule - Schedule object from computeSchedule
|
|
279
|
+
* @param phaseNum - Phase number to look up
|
|
280
|
+
* @returns Phase schedule entry with start_date, due_date, duration_days, or null
|
|
281
|
+
*/
|
|
282
|
+
function getScheduleForPhase(
|
|
283
|
+
schedule: ScheduleResult,
|
|
284
|
+
phaseNum: string | number
|
|
285
|
+
): PhaseScheduleEntry | null {
|
|
286
|
+
const num: string = String(phaseNum);
|
|
287
|
+
return schedule.phases.find((p: PhaseScheduleEntry) => p.number === num) || null;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Look up a milestone schedule entry by version string.
|
|
292
|
+
* @param schedule - Schedule object from computeSchedule
|
|
293
|
+
* @param version - Milestone version to look up (e.g., 'v1.0')
|
|
294
|
+
* @returns Milestone schedule entry with start and target dates, or null
|
|
295
|
+
*/
|
|
296
|
+
function getScheduleForMilestone(
|
|
297
|
+
schedule: ScheduleResult,
|
|
298
|
+
version: string
|
|
299
|
+
): ParsedMilestone | null {
|
|
300
|
+
return schedule.milestones.find((m: ParsedMilestone) => m.version === version) || null;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ─── Roadmap Commands ───────────────────────────────────────────────────────
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* CLI command: Get phase info (name, goal, full section text) from ROADMAP.md.
|
|
307
|
+
* @param cwd - Project working directory
|
|
308
|
+
* @param phaseNum - Phase number to look up
|
|
309
|
+
* @param raw - Output raw section text instead of JSON
|
|
310
|
+
*/
|
|
311
|
+
function cmdRoadmapGetPhase(cwd: string, phaseNum: string, raw: boolean): void {
|
|
312
|
+
const roadmapPath: string = path.join(cwd, '.planning', 'ROADMAP.md');
|
|
313
|
+
|
|
314
|
+
if (!fs.existsSync(roadmapPath)) {
|
|
315
|
+
output({ found: false, error: 'ROADMAP.md not found' }, raw, '');
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
try {
|
|
320
|
+
const content: string | null = safeReadMarkdown(roadmapPath);
|
|
321
|
+
if (!content) {
|
|
322
|
+
output({ found: false, error: 'ROADMAP.md could not be read' }, raw, '');
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const activeContent: string = stripShippedSections(content);
|
|
326
|
+
|
|
327
|
+
// Escape special regex chars in phase number, handle decimal
|
|
328
|
+
const escapedPhase: string = phaseNum.replace(/\./g, '\\.');
|
|
329
|
+
|
|
330
|
+
// Match "## Phase X:" or "### Phase X.Y:" with optional name
|
|
331
|
+
const phasePattern = new RegExp(`#{2,}\\s*Phase\\s+${escapedPhase}:\\s*([^\\n]+)`, 'i');
|
|
332
|
+
const headerMatch: RegExpMatchArray | null = activeContent.match(phasePattern);
|
|
333
|
+
|
|
334
|
+
if (!headerMatch) {
|
|
335
|
+
output({ found: false, phase_number: phaseNum }, raw, '');
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const phaseName: string = headerMatch[1].trim();
|
|
340
|
+
const headerIndex: number = headerMatch.index as number;
|
|
341
|
+
|
|
342
|
+
// Find the end of this section (next ### or end of file)
|
|
343
|
+
const restOfContent: string = activeContent.slice(headerIndex);
|
|
344
|
+
const nextHeaderMatch: RegExpMatchArray | null = restOfContent.match(/\n#{2,}\s+Phase\s+\d/i);
|
|
345
|
+
const sectionEnd: number = nextHeaderMatch
|
|
346
|
+
? headerIndex + (nextHeaderMatch.index as number)
|
|
347
|
+
: activeContent.length;
|
|
348
|
+
|
|
349
|
+
const section: string = activeContent.slice(headerIndex, sectionEnd).trim();
|
|
350
|
+
|
|
351
|
+
// Extract goal if present
|
|
352
|
+
const goalMatch: RegExpMatchArray | null = section.match(/\*\*Goal:?\*\*:?\s*([^\n]+)/i);
|
|
353
|
+
const goal: string | null = goalMatch ? goalMatch[1].trim() : null;
|
|
354
|
+
|
|
355
|
+
output(
|
|
356
|
+
{
|
|
357
|
+
found: true,
|
|
358
|
+
phase_number: phaseNum,
|
|
359
|
+
phase_name: phaseName,
|
|
360
|
+
goal,
|
|
361
|
+
section,
|
|
362
|
+
},
|
|
363
|
+
raw,
|
|
364
|
+
section
|
|
365
|
+
);
|
|
366
|
+
} catch (e: unknown) {
|
|
367
|
+
error('Failed to read ROADMAP.md: ' + (e as Error).message);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// ─── Phase Next Decimal ─────────────────────────────────────────────────────
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* CLI command: Compute the next available decimal phase number for insertion.
|
|
375
|
+
* @param cwd - Project working directory
|
|
376
|
+
* @param basePhase - Base phase number to find next decimal for (e.g., '06')
|
|
377
|
+
* @param raw - Output raw next decimal string instead of JSON
|
|
378
|
+
*/
|
|
379
|
+
function cmdPhaseNextDecimal(cwd: string, basePhase: string, raw: boolean): void {
|
|
380
|
+
const phasesDir: string = getPhasesDirPath(cwd);
|
|
381
|
+
const normalized: string = normalizePhaseName(basePhase);
|
|
382
|
+
|
|
383
|
+
// Check if phases directory exists
|
|
384
|
+
if (!fs.existsSync(phasesDir)) {
|
|
385
|
+
output(
|
|
386
|
+
{
|
|
387
|
+
found: false,
|
|
388
|
+
base_phase: normalized,
|
|
389
|
+
next: `${normalized}.1`,
|
|
390
|
+
existing: [],
|
|
391
|
+
},
|
|
392
|
+
raw,
|
|
393
|
+
`${normalized}.1`
|
|
394
|
+
);
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
try {
|
|
399
|
+
const entries: Array<{ isDirectory: () => boolean; name: string }> = fs.readdirSync(phasesDir, {
|
|
400
|
+
withFileTypes: true,
|
|
401
|
+
});
|
|
402
|
+
const dirs: string[] = entries
|
|
403
|
+
.filter((e: { isDirectory: () => boolean }) => e.isDirectory())
|
|
404
|
+
.map((e: { name: string }) => e.name);
|
|
405
|
+
|
|
406
|
+
// Check if base phase exists
|
|
407
|
+
const baseExists: boolean = dirs.some(
|
|
408
|
+
(d: string) => d.startsWith(normalized + '-') || d === normalized
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
// Find existing decimal phases for this base
|
|
412
|
+
const decimalPattern = new RegExp(`^${normalized}\\.(\\d+)`);
|
|
413
|
+
const existingDecimals: string[] = [];
|
|
414
|
+
|
|
415
|
+
for (const dir of dirs) {
|
|
416
|
+
const match: RegExpMatchArray | null = dir.match(decimalPattern);
|
|
417
|
+
if (match) {
|
|
418
|
+
existingDecimals.push(`${normalized}.${match[1]}`);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Sort numerically
|
|
423
|
+
existingDecimals.sort((a: string, b: string) => {
|
|
424
|
+
const aNum: number = parseFloat(a);
|
|
425
|
+
const bNum: number = parseFloat(b);
|
|
426
|
+
return aNum - bNum;
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
// Calculate next decimal
|
|
430
|
+
let nextDecimal: string;
|
|
431
|
+
if (existingDecimals.length === 0) {
|
|
432
|
+
nextDecimal = `${normalized}.1`;
|
|
433
|
+
} else {
|
|
434
|
+
const lastDecimal: string = existingDecimals[existingDecimals.length - 1];
|
|
435
|
+
const lastNum: number = parseInt(lastDecimal.split('.')[1], 10);
|
|
436
|
+
nextDecimal = `${normalized}.${lastNum + 1}`;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
output(
|
|
440
|
+
{
|
|
441
|
+
found: baseExists,
|
|
442
|
+
base_phase: normalized,
|
|
443
|
+
next: nextDecimal,
|
|
444
|
+
existing: existingDecimals,
|
|
445
|
+
},
|
|
446
|
+
raw,
|
|
447
|
+
nextDecimal
|
|
448
|
+
);
|
|
449
|
+
} catch (e: unknown) {
|
|
450
|
+
error('Failed to calculate next decimal phase: ' + (e as Error).message);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// ─── Roadmap Analyze ────────────────────────────────────────────────────────
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Analyze the full roadmap structure with disk status, schedule, and progress.
|
|
458
|
+
* Returns the result object directly without calling output() or process.exit().
|
|
459
|
+
* Used internally by cmdRoadmapAnalyze and by dependency analysis (lib/deps.js).
|
|
460
|
+
* @param cwd - Project working directory
|
|
461
|
+
* @returns Roadmap analysis with milestones, phases, progress, etc.
|
|
462
|
+
*/
|
|
463
|
+
function analyzeRoadmap(cwd: string): AnalyzedRoadmap {
|
|
464
|
+
const roadmapPath: string = path.join(cwd, '.planning', 'ROADMAP.md');
|
|
465
|
+
|
|
466
|
+
if (!fs.existsSync(roadmapPath)) {
|
|
467
|
+
return {
|
|
468
|
+
error: 'ROADMAP.md not found',
|
|
469
|
+
milestones: [],
|
|
470
|
+
phases: [],
|
|
471
|
+
phase_count: 0,
|
|
472
|
+
completed_phases: 0,
|
|
473
|
+
total_plans: 0,
|
|
474
|
+
total_summaries: 0,
|
|
475
|
+
progress_percent: 0,
|
|
476
|
+
current_phase: null,
|
|
477
|
+
next_phase: null,
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const content: string | null = safeReadMarkdown(roadmapPath);
|
|
482
|
+
if (!content) {
|
|
483
|
+
return {
|
|
484
|
+
error: 'ROADMAP.md could not be read',
|
|
485
|
+
milestones: [],
|
|
486
|
+
phases: [],
|
|
487
|
+
phase_count: 0,
|
|
488
|
+
completed_phases: 0,
|
|
489
|
+
total_plans: 0,
|
|
490
|
+
total_summaries: 0,
|
|
491
|
+
progress_percent: 0,
|
|
492
|
+
current_phase: null,
|
|
493
|
+
next_phase: null,
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
const activeContent: string = stripShippedSections(content);
|
|
497
|
+
const phasesDir: string = getPhasesDirPath(cwd);
|
|
498
|
+
|
|
499
|
+
// Read default_duration_days from config (same logic as computeSchedule, no re-read needed).
|
|
500
|
+
let defaultDuration = 7;
|
|
501
|
+
const configPath: string = path.join(cwd, '.planning', 'config.json');
|
|
502
|
+
const configRaw: string | null = safeReadFile(configPath);
|
|
503
|
+
if (configRaw) {
|
|
504
|
+
try {
|
|
505
|
+
const config = JSON.parse(configRaw) as Record<string, unknown>;
|
|
506
|
+
const tracker = config.tracker as Record<string, unknown> | undefined;
|
|
507
|
+
const mcp = tracker && (tracker.mcp_atlassian as Record<string, unknown> | undefined);
|
|
508
|
+
if (mcp && mcp.default_duration_days) {
|
|
509
|
+
defaultDuration = parseInt(String(mcp.default_duration_days), 10) || 7;
|
|
510
|
+
}
|
|
511
|
+
} catch {
|
|
512
|
+
// Invalid JSON config; use default duration
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Parse milestone positions with Start dates from activeContent (already in memory).
|
|
517
|
+
const milestoneRegexLocal = /^##\s*(.*v(\d+\.\d+(?:\.\d+)?)[^(\n]*)/gim;
|
|
518
|
+
const milestonePositions: MilestonePosition[] = [];
|
|
519
|
+
let mMatchLocal: RegExpExecArray | null;
|
|
520
|
+
while ((mMatchLocal = milestoneRegexLocal.exec(activeContent)) !== null) {
|
|
521
|
+
const version = 'v' + mMatchLocal[2];
|
|
522
|
+
const heading: string = mMatchLocal[1].trim();
|
|
523
|
+
const afterHeading: string = activeContent.slice(mMatchLocal.index, mMatchLocal.index + 500);
|
|
524
|
+
const startMatch: RegExpMatchArray | null = afterHeading.match(
|
|
525
|
+
/\*\*Start:\*\*\s*(\d{4}-\d{2}-\d{2})/
|
|
526
|
+
);
|
|
527
|
+
milestonePositions.push({
|
|
528
|
+
version,
|
|
529
|
+
heading,
|
|
530
|
+
index: mMatchLocal.index,
|
|
531
|
+
start: startMatch ? startMatch[1] : null,
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Read phases directory once before the loop to avoid N repeated readdirSync calls.
|
|
536
|
+
let phasesDirNames: string[] = [];
|
|
537
|
+
try {
|
|
538
|
+
const phasesDirEntries: Array<{ isDirectory: () => boolean; name: string }> = fs.readdirSync(
|
|
539
|
+
phasesDir,
|
|
540
|
+
{ withFileTypes: true }
|
|
541
|
+
);
|
|
542
|
+
phasesDirNames = phasesDirEntries
|
|
543
|
+
.filter((e: { isDirectory: () => boolean }) => e.isDirectory())
|
|
544
|
+
.map((e: { name: string }) => e.name);
|
|
545
|
+
} catch (dirErr: unknown) {
|
|
546
|
+
const err = dirErr as { code?: string; message?: string } | null;
|
|
547
|
+
if (err && err.code && err.code !== 'ENOENT') {
|
|
548
|
+
process.stderr.write(`[roadmap] phases directory read error (${err.code}): ${err.message}\n`);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Extract all phase headings: ## Phase N: Name or ### Phase N: Name
|
|
553
|
+
const phasePattern = /#{2,}\s*Phase\s+(\d+(?:\.\d+)?)\s*:\s*([^\n]+)/gi;
|
|
554
|
+
const phases: AnalyzedPhaseEntry[] = [];
|
|
555
|
+
let match: RegExpExecArray | null;
|
|
556
|
+
|
|
557
|
+
while ((match = phasePattern.exec(activeContent)) !== null) {
|
|
558
|
+
const phaseNum: string = match[1];
|
|
559
|
+
const phaseName: string = match[2].replace(/\(INSERTED\)/i, '').trim();
|
|
560
|
+
|
|
561
|
+
// Compute line number of heading in ROADMAP.md
|
|
562
|
+
const lineNumber: number = activeContent.substring(0, match.index).split('\n').length;
|
|
563
|
+
|
|
564
|
+
// Extract goal from the section
|
|
565
|
+
const sectionStart: number = match.index;
|
|
566
|
+
const restOfContent: string = activeContent.slice(sectionStart);
|
|
567
|
+
const nextHeader: RegExpMatchArray | null = restOfContent.match(/\n#{2,}\s+Phase\s+\d/i);
|
|
568
|
+
const sectionEnd: number = nextHeader
|
|
569
|
+
? sectionStart + (nextHeader.index as number)
|
|
570
|
+
: activeContent.length;
|
|
571
|
+
const section: string = activeContent.slice(sectionStart, sectionEnd);
|
|
572
|
+
|
|
573
|
+
const goalMatch: RegExpMatchArray | null = section.match(/\*\*Goal:?\*\*:?\s*([^\n]+)/i);
|
|
574
|
+
const goal: string | null = goalMatch ? goalMatch[1].trim() : null;
|
|
575
|
+
|
|
576
|
+
const dependsMatch: RegExpMatchArray | null = section.match(
|
|
577
|
+
/\*\*Depends on:?\*\*:?\s*([^\n]+)/i
|
|
578
|
+
);
|
|
579
|
+
const depends_on: string | null = dependsMatch ? dependsMatch[1].trim() : null;
|
|
580
|
+
|
|
581
|
+
// Extract duration for schedule computation (reuse the already-sliced section text).
|
|
582
|
+
const durationMatch: RegExpMatchArray | null = section.match(/\*\*Duration:\*\*\s*(\d+)d/);
|
|
583
|
+
const durationDays: number = durationMatch ? parseInt(durationMatch[1], 10) : defaultDuration;
|
|
584
|
+
|
|
585
|
+
// Determine which milestone this phase belongs to.
|
|
586
|
+
let phaseMilestone: string | null =
|
|
587
|
+
milestonePositions.length > 0 ? milestonePositions[0].version : null;
|
|
588
|
+
for (const ms of milestonePositions) {
|
|
589
|
+
if (match.index > ms.index) phaseMilestone = ms.version;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// Build warnings array
|
|
593
|
+
const warnings: string[] = [];
|
|
594
|
+
if (!goal) {
|
|
595
|
+
warnings.push(`Phase ${phaseNum} (line ${lineNumber}): missing goal`);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// Check completion on disk
|
|
599
|
+
const normalized: string = normalizePhaseName(phaseNum);
|
|
600
|
+
let diskStatus = 'no_directory';
|
|
601
|
+
let planCount = 0;
|
|
602
|
+
let summaryCount = 0;
|
|
603
|
+
let hasContext = false;
|
|
604
|
+
let hasResearch = false;
|
|
605
|
+
|
|
606
|
+
try {
|
|
607
|
+
const dirMatch: string | undefined = phasesDirNames.find(
|
|
608
|
+
(d: string) => d.startsWith(normalized + '-') || d === normalized
|
|
609
|
+
);
|
|
610
|
+
|
|
611
|
+
if (dirMatch) {
|
|
612
|
+
const phaseFiles: string[] = fs.readdirSync(path.join(phasesDir, dirMatch));
|
|
613
|
+
planCount = phaseFiles.filter(
|
|
614
|
+
(f: string) => f.endsWith('-PLAN.md') || f === 'PLAN.md'
|
|
615
|
+
).length;
|
|
616
|
+
summaryCount = phaseFiles.filter(
|
|
617
|
+
(f: string) => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md'
|
|
618
|
+
).length;
|
|
619
|
+
hasContext = phaseFiles.some(
|
|
620
|
+
(f: string) => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md'
|
|
621
|
+
);
|
|
622
|
+
hasResearch = phaseFiles.some(
|
|
623
|
+
(f: string) => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md'
|
|
624
|
+
);
|
|
625
|
+
|
|
626
|
+
if (summaryCount >= planCount && planCount > 0) diskStatus = 'complete';
|
|
627
|
+
else if (summaryCount > 0) diskStatus = 'partial';
|
|
628
|
+
else if (planCount > 0) diskStatus = 'planned';
|
|
629
|
+
else if (hasResearch) diskStatus = 'researched';
|
|
630
|
+
else if (hasContext) diskStatus = 'discussed';
|
|
631
|
+
else diskStatus = 'empty';
|
|
632
|
+
}
|
|
633
|
+
} catch (scanErr: unknown) {
|
|
634
|
+
const err = scanErr as { code?: string; message?: string } | null;
|
|
635
|
+
if (err && err.code && err.code !== 'ENOENT') {
|
|
636
|
+
process.stderr.write(
|
|
637
|
+
`[roadmap] phase directory scan error (${err.code}): ${err.message}\n`
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// Check ROADMAP checkbox status
|
|
643
|
+
const checkboxPattern = new RegExp(
|
|
644
|
+
`-\\s*\\[(x| )\\]\\s*.*Phase\\s+${phaseNum.replace('.', '\\.')}`,
|
|
645
|
+
'i'
|
|
646
|
+
);
|
|
647
|
+
const checkboxMatch: RegExpMatchArray | null = activeContent.match(checkboxPattern);
|
|
648
|
+
const roadmapComplete: boolean = checkboxMatch ? checkboxMatch[1] === 'x' : false;
|
|
649
|
+
|
|
650
|
+
phases.push({
|
|
651
|
+
number: phaseNum,
|
|
652
|
+
name: phaseName,
|
|
653
|
+
goal,
|
|
654
|
+
depends_on,
|
|
655
|
+
plan_count: planCount,
|
|
656
|
+
summary_count: summaryCount,
|
|
657
|
+
has_context: hasContext,
|
|
658
|
+
has_research: hasResearch,
|
|
659
|
+
disk_status: diskStatus,
|
|
660
|
+
roadmap_complete: roadmapComplete,
|
|
661
|
+
line: lineNumber,
|
|
662
|
+
warnings,
|
|
663
|
+
_duration_days: durationDays,
|
|
664
|
+
_milestone: phaseMilestone,
|
|
665
|
+
duration_days: durationDays,
|
|
666
|
+
start_date: null,
|
|
667
|
+
due_date: null,
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// Build milestones array from already-parsed positions -- no second regex pass needed.
|
|
672
|
+
// Only heading and version to preserve the original analyzeRoadmap output shape.
|
|
673
|
+
const milestones: AnalyzedMilestone[] = milestonePositions.map((ms: MilestonePosition) => ({
|
|
674
|
+
heading: ms.heading,
|
|
675
|
+
version: ms.version,
|
|
676
|
+
}));
|
|
677
|
+
|
|
678
|
+
// Compute dates inline using already-parsed milestone positions -- no second parse needed.
|
|
679
|
+
const milestoneStartMap: Record<string, string> = {};
|
|
680
|
+
for (const ms of milestonePositions) {
|
|
681
|
+
if (ms.start) milestoneStartMap[ms.version] = ms.start;
|
|
682
|
+
}
|
|
683
|
+
let currentDate: Date | null = null;
|
|
684
|
+
let currentMilestone: string | null = null;
|
|
685
|
+
for (const phase of phases) {
|
|
686
|
+
if (phase._milestone !== currentMilestone) {
|
|
687
|
+
currentMilestone = phase._milestone ?? null;
|
|
688
|
+
const msStart: string | undefined = currentMilestone
|
|
689
|
+
? milestoneStartMap[currentMilestone]
|
|
690
|
+
: undefined;
|
|
691
|
+
currentDate = msStart ? new Date(msStart + 'T00:00:00') : null;
|
|
692
|
+
}
|
|
693
|
+
phase.duration_days = phase._duration_days as number;
|
|
694
|
+
if (currentDate) {
|
|
695
|
+
phase.start_date = formatScheduleDate(currentDate);
|
|
696
|
+
const endDate: Date = addDays(currentDate, phase._duration_days as number);
|
|
697
|
+
phase.due_date = formatScheduleDate(endDate);
|
|
698
|
+
currentDate = addDays(endDate, 1);
|
|
699
|
+
} else {
|
|
700
|
+
phase.start_date = null;
|
|
701
|
+
phase.due_date = null;
|
|
702
|
+
}
|
|
703
|
+
delete phase._duration_days;
|
|
704
|
+
delete phase._milestone;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// Find current and next phase
|
|
708
|
+
const currentPhaseEntry: AnalyzedPhaseEntry | undefined = phases.find(
|
|
709
|
+
(p: AnalyzedPhaseEntry) => p.disk_status === 'planned' || p.disk_status === 'partial'
|
|
710
|
+
);
|
|
711
|
+
const nextPhase: AnalyzedPhaseEntry | undefined = phases.find(
|
|
712
|
+
(p: AnalyzedPhaseEntry) =>
|
|
713
|
+
p.disk_status === 'empty' ||
|
|
714
|
+
p.disk_status === 'no_directory' ||
|
|
715
|
+
p.disk_status === 'discussed' ||
|
|
716
|
+
p.disk_status === 'researched'
|
|
717
|
+
);
|
|
718
|
+
|
|
719
|
+
// Aggregated stats
|
|
720
|
+
const totalPlans: number = phases.reduce(
|
|
721
|
+
(sum: number, p: AnalyzedPhaseEntry) => sum + p.plan_count,
|
|
722
|
+
0
|
|
723
|
+
);
|
|
724
|
+
const totalSummaries: number = phases.reduce(
|
|
725
|
+
(sum: number, p: AnalyzedPhaseEntry) => sum + p.summary_count,
|
|
726
|
+
0
|
|
727
|
+
);
|
|
728
|
+
const completedPhases: number = phases.filter(
|
|
729
|
+
(p: AnalyzedPhaseEntry) => p.disk_status === 'complete'
|
|
730
|
+
).length;
|
|
731
|
+
|
|
732
|
+
return {
|
|
733
|
+
milestones,
|
|
734
|
+
phases,
|
|
735
|
+
phase_count: phases.length,
|
|
736
|
+
completed_phases: completedPhases,
|
|
737
|
+
total_plans: totalPlans,
|
|
738
|
+
total_summaries: totalSummaries,
|
|
739
|
+
progress_percent: totalPlans > 0 ? Math.round((totalSummaries / totalPlans) * 100) : 0,
|
|
740
|
+
current_phase: currentPhaseEntry ? currentPhaseEntry.number : null,
|
|
741
|
+
next_phase: nextPhase ? nextPhase.number : null,
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* CLI command: Analyze the full roadmap structure with disk status, schedule, and progress.
|
|
747
|
+
* Thin wrapper around analyzeRoadmap that outputs the result via output().
|
|
748
|
+
* @param cwd - Project working directory
|
|
749
|
+
* @param raw - Output raw text instead of JSON
|
|
750
|
+
*/
|
|
751
|
+
function cmdRoadmapAnalyze(cwd: string, raw: boolean): void {
|
|
752
|
+
const result: AnalyzedRoadmap = analyzeRoadmap(cwd);
|
|
753
|
+
output(
|
|
754
|
+
result,
|
|
755
|
+
raw,
|
|
756
|
+
`${result.phase_count} phases, ${result.completed_phases} complete, ${result.progress_percent}% done`
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// ─── Exports ────────────────────────────────────────────────────────────────
|
|
761
|
+
|
|
762
|
+
module.exports = {
|
|
763
|
+
// Schedule helpers (used by tracker code too)
|
|
764
|
+
formatScheduleDate,
|
|
765
|
+
addDays,
|
|
766
|
+
computeSchedule,
|
|
767
|
+
getScheduleForPhase,
|
|
768
|
+
getScheduleForMilestone,
|
|
769
|
+
// Roadmap commands
|
|
770
|
+
cmdRoadmapGetPhase,
|
|
771
|
+
cmdPhaseNextDecimal,
|
|
772
|
+
cmdRoadmapAnalyze,
|
|
773
|
+
// Internal (used by lib/deps.js)
|
|
774
|
+
analyzeRoadmap,
|
|
775
|
+
};
|