@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,806 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GRD Long-Term Roadmap Operations -- LONG-TERM-ROADMAP.md parsing, validation,
|
|
5
|
+
* generation, display formatting, and CRUD operations.
|
|
6
|
+
*
|
|
7
|
+
* Implements a flat LT-N milestone format where each LT milestone maps to
|
|
8
|
+
* one or more normal milestones in ROADMAP.md.
|
|
9
|
+
*
|
|
10
|
+
* Depends on: lib/frontmatter.ts (extractFrontmatter)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
import type { FrontmatterObject } from './types';
|
|
15
|
+
|
|
16
|
+
const {
|
|
17
|
+
extractFrontmatter,
|
|
18
|
+
}: {
|
|
19
|
+
extractFrontmatter: (content: string) => FrontmatterObject;
|
|
20
|
+
} = require('./frontmatter');
|
|
21
|
+
|
|
22
|
+
// ─── Domain Types ─────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* An entry in the normal milestone list, with optional note (e.g., "planned").
|
|
26
|
+
*/
|
|
27
|
+
interface NormalMilestoneEntry {
|
|
28
|
+
version: string;
|
|
29
|
+
note?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A parsed LT milestone from LONG-TERM-ROADMAP.md.
|
|
34
|
+
*/
|
|
35
|
+
interface LtMilestone {
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
status: string;
|
|
39
|
+
goal: string;
|
|
40
|
+
normal_milestones: NormalMilestoneEntry[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* A parsed LONG-TERM-ROADMAP.md document.
|
|
45
|
+
*/
|
|
46
|
+
interface LongTermRoadmap {
|
|
47
|
+
frontmatter: FrontmatterObject;
|
|
48
|
+
milestones: LtMilestone[];
|
|
49
|
+
refinement_history: RefinementHistoryEntry[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* A single refinement history table row.
|
|
54
|
+
*/
|
|
55
|
+
interface RefinementHistoryEntry {
|
|
56
|
+
date: string;
|
|
57
|
+
action: string;
|
|
58
|
+
details: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Validation result from validateLongTermRoadmap.
|
|
63
|
+
*/
|
|
64
|
+
interface ValidationResult {
|
|
65
|
+
valid: boolean;
|
|
66
|
+
errors: string[];
|
|
67
|
+
warnings: string[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Result of adding an LT milestone: updated content and new ID.
|
|
72
|
+
*/
|
|
73
|
+
interface AddLtMilestoneResult {
|
|
74
|
+
content: string;
|
|
75
|
+
id: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Error result from CRUD operations.
|
|
80
|
+
*/
|
|
81
|
+
interface ErrorResult {
|
|
82
|
+
error: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Extract a bold field value from text.
|
|
89
|
+
* @param text - Section text to search
|
|
90
|
+
* @param fieldName - Bold field name (e.g., 'Status', 'Goal')
|
|
91
|
+
* @returns The field value, or null if not found
|
|
92
|
+
*/
|
|
93
|
+
function extractBoldField(text: string, fieldName: string): string | null {
|
|
94
|
+
const pattern = new RegExp(`\\*\\*${fieldName}:\\*\\*\\s*(.+)`, 'i');
|
|
95
|
+
const match = text.match(pattern);
|
|
96
|
+
return match ? match[1].trim() : null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ─── Refinement History ──────────────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Parse the refinement history table from content.
|
|
103
|
+
* @param content - Full markdown content
|
|
104
|
+
* @returns Array of { date, action, details } objects
|
|
105
|
+
*/
|
|
106
|
+
function parseRefinementHistory(content: string): RefinementHistoryEntry[] {
|
|
107
|
+
const sectionMatch = content.match(/^##\s+Refinement History/m);
|
|
108
|
+
if (!sectionMatch || sectionMatch.index === undefined) return [];
|
|
109
|
+
|
|
110
|
+
const afterHeading = content.slice(sectionMatch.index + sectionMatch[0].length);
|
|
111
|
+
|
|
112
|
+
const lines = afterHeading.split('\n');
|
|
113
|
+
const entries: RefinementHistoryEntry[] = [];
|
|
114
|
+
let pastHeader = false;
|
|
115
|
+
|
|
116
|
+
for (const line of lines) {
|
|
117
|
+
const trimmed = line.trim();
|
|
118
|
+
if (trimmed.startsWith('#')) break;
|
|
119
|
+
if (trimmed.startsWith('|') && trimmed.includes('Date') && trimmed.includes('Action')) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (trimmed.match(/^\|[\s-|]+\|$/)) {
|
|
123
|
+
pastHeader = true;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (pastHeader && trimmed.startsWith('|')) {
|
|
127
|
+
const cells = trimmed
|
|
128
|
+
.split('|')
|
|
129
|
+
.map((c) => c.trim())
|
|
130
|
+
.filter((c) => c !== '');
|
|
131
|
+
if (cells.length >= 3) {
|
|
132
|
+
entries.push({
|
|
133
|
+
date: cells[0],
|
|
134
|
+
action: cells[1],
|
|
135
|
+
details: cells[2],
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return entries;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Append a row to the Refinement History markdown table.
|
|
146
|
+
* @param content - Raw LONG-TERM-ROADMAP.md content
|
|
147
|
+
* @param action - Action description
|
|
148
|
+
* @param details - Details of what was changed
|
|
149
|
+
* @returns Updated content string
|
|
150
|
+
*/
|
|
151
|
+
function updateRefinementHistory(content: string, action: string, details: string): string {
|
|
152
|
+
const sectionMatch = content.match(/^##\s+Refinement History/m);
|
|
153
|
+
if (!sectionMatch || sectionMatch.index === undefined) return content;
|
|
154
|
+
|
|
155
|
+
const today = new Date().toISOString().split('T')[0];
|
|
156
|
+
const newRow = `| ${today} | ${action} | ${details} |`;
|
|
157
|
+
|
|
158
|
+
const afterSection = content.slice(sectionMatch.index);
|
|
159
|
+
const lines = afterSection.split('\n');
|
|
160
|
+
|
|
161
|
+
let lastTableLineIdx = -1;
|
|
162
|
+
let inTable = false;
|
|
163
|
+
|
|
164
|
+
for (let i = 0; i < lines.length; i++) {
|
|
165
|
+
const trimmed = lines[i].trim();
|
|
166
|
+
if (i > 0 && trimmed.startsWith('#')) break;
|
|
167
|
+
if (trimmed.startsWith('|')) {
|
|
168
|
+
inTable = true;
|
|
169
|
+
lastTableLineIdx = i;
|
|
170
|
+
} else if (inTable && trimmed === '') {
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (lastTableLineIdx === -1) return content;
|
|
176
|
+
|
|
177
|
+
const beforeSection = content.slice(0, sectionMatch.index);
|
|
178
|
+
lines.splice(lastTableLineIdx + 1, 0, newRow);
|
|
179
|
+
|
|
180
|
+
return beforeSection + lines.join('\n');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ─── Normal Milestone List Parsing ───────────────────────────────────────────
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Parse comma-separated normal milestone list from field text.
|
|
187
|
+
* e.g. "v0.0.5, v0.2.0 (planned)" -> [{ version: 'v0.0.5' }, { version: 'v0.2.0', note: 'planned' }]
|
|
188
|
+
* Also handles "(none yet)" -> []
|
|
189
|
+
* @param fieldText - The field text after "Normal milestones:"
|
|
190
|
+
* @returns Array of { version, note? } objects
|
|
191
|
+
*/
|
|
192
|
+
function parseNormalMilestoneList(fieldText: string | null | undefined): NormalMilestoneEntry[] {
|
|
193
|
+
if (!fieldText || fieldText.trim() === '' || /\(none\s*yet\)/i.test(fieldText)) return [];
|
|
194
|
+
|
|
195
|
+
return fieldText
|
|
196
|
+
.split(',')
|
|
197
|
+
.map((s) => s.trim())
|
|
198
|
+
.filter((s) => s !== '')
|
|
199
|
+
.map((s): NormalMilestoneEntry => {
|
|
200
|
+
const noteMatch = s.match(/^(v[\d.]+)\s*\(([^)]+)\)$/);
|
|
201
|
+
if (noteMatch) {
|
|
202
|
+
return { version: noteMatch[1], note: noteMatch[2] };
|
|
203
|
+
}
|
|
204
|
+
const versionMatch = s.match(/^(v[\d.]+)$/);
|
|
205
|
+
if (versionMatch) {
|
|
206
|
+
return { version: versionMatch[1] };
|
|
207
|
+
}
|
|
208
|
+
return { version: s };
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Format normal milestone list back to string.
|
|
214
|
+
* @param milestones - Array of { version, note? }
|
|
215
|
+
* @returns Formatted string
|
|
216
|
+
*/
|
|
217
|
+
function formatNormalMilestoneList(milestones: NormalMilestoneEntry[] | null | undefined): string {
|
|
218
|
+
if (!milestones || milestones.length === 0) return '(none yet)';
|
|
219
|
+
return milestones.map((m) => (m.note ? `${m.version} (${m.note})` : m.version)).join(', ');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ─── LT Milestone Parsing ────────────────────────────────────────────────────
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Parse a single ## LT-N: section into a structured object.
|
|
226
|
+
* @param sectionText - Text of the section (after the ## heading)
|
|
227
|
+
* @param id - The LT id (e.g., 'LT-1')
|
|
228
|
+
* @param name - The name from the heading
|
|
229
|
+
* @returns Parsed LT milestone
|
|
230
|
+
*/
|
|
231
|
+
function parseLtMilestone(sectionText: string, id: string, name: string): LtMilestone {
|
|
232
|
+
const status = extractBoldField(sectionText, 'Status') || 'planned';
|
|
233
|
+
const goal = extractBoldField(sectionText, 'Goal') || '';
|
|
234
|
+
const normalField = extractBoldField(sectionText, 'Normal milestones');
|
|
235
|
+
const normal_milestones = parseNormalMilestoneList(normalField);
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
id,
|
|
239
|
+
name,
|
|
240
|
+
status,
|
|
241
|
+
goal,
|
|
242
|
+
normal_milestones,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Parse LONG-TERM-ROADMAP.md content into structured object (flat format).
|
|
248
|
+
* @param content - Raw markdown content
|
|
249
|
+
* @returns Parsed roadmap with frontmatter, milestones[], refinement_history[]
|
|
250
|
+
*/
|
|
251
|
+
function parseLongTermRoadmap(content: unknown): LongTermRoadmap | null {
|
|
252
|
+
if (!content || typeof content !== 'string') return null;
|
|
253
|
+
|
|
254
|
+
const frontmatter = extractFrontmatter(content);
|
|
255
|
+
|
|
256
|
+
// Match all ## LT-N: headings
|
|
257
|
+
const ltPattern = /^##\s+(LT-(\d+)):\s*(.+)/gm;
|
|
258
|
+
const milestones: LtMilestone[] = [];
|
|
259
|
+
const matches: Array<{
|
|
260
|
+
id: string;
|
|
261
|
+
num: number;
|
|
262
|
+
name: string;
|
|
263
|
+
index: number;
|
|
264
|
+
fullMatch: string;
|
|
265
|
+
}> = [];
|
|
266
|
+
let match: RegExpExecArray | null;
|
|
267
|
+
|
|
268
|
+
while ((match = ltPattern.exec(content)) !== null) {
|
|
269
|
+
matches.push({
|
|
270
|
+
id: match[1],
|
|
271
|
+
num: parseInt(match[2], 10),
|
|
272
|
+
name: match[3].trim(),
|
|
273
|
+
index: match.index,
|
|
274
|
+
fullMatch: match[0],
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (matches.length === 0 && Object.keys(frontmatter).length === 0) return null;
|
|
279
|
+
|
|
280
|
+
for (let i = 0; i < matches.length; i++) {
|
|
281
|
+
const startIdx = matches[i].index + matches[i].fullMatch.length;
|
|
282
|
+
// Find next ## heading (any ## heading, not just LT-)
|
|
283
|
+
const rest = content.slice(startIdx);
|
|
284
|
+
const nextH2 = rest.match(/^##\s/m);
|
|
285
|
+
const endIdx = nextH2 && nextH2.index !== undefined ? startIdx + nextH2.index : content.length;
|
|
286
|
+
|
|
287
|
+
const sectionText = content.slice(startIdx, endIdx).trim();
|
|
288
|
+
milestones.push(parseLtMilestone(sectionText, matches[i].id, matches[i].name));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const refinement_history = parseRefinementHistory(content);
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
frontmatter,
|
|
295
|
+
milestones,
|
|
296
|
+
refinement_history,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// ─── Validation ──────────────────────────────────────────────────────────────
|
|
301
|
+
|
|
302
|
+
const VALID_STATUSES: string[] = ['completed', 'active', 'planned'];
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Validate a parsed long-term roadmap object.
|
|
306
|
+
* @param parsed - Parsed roadmap from parseLongTermRoadmap
|
|
307
|
+
* @returns Validation result with errors and warnings
|
|
308
|
+
*/
|
|
309
|
+
function validateLongTermRoadmap(parsed: LongTermRoadmap | null): ValidationResult {
|
|
310
|
+
const errors: string[] = [];
|
|
311
|
+
const warnings: string[] = [];
|
|
312
|
+
|
|
313
|
+
if (!parsed) {
|
|
314
|
+
return { valid: false, errors: ['Parsed roadmap is null or undefined'], warnings: [] };
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (!parsed.frontmatter || !parsed.frontmatter.project) {
|
|
318
|
+
errors.push('Missing required frontmatter field: project');
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (!parsed.milestones || parsed.milestones.length === 0) {
|
|
322
|
+
errors.push('No LT milestones found');
|
|
323
|
+
} else {
|
|
324
|
+
const ids = new Set<string>();
|
|
325
|
+
let activeCount = 0;
|
|
326
|
+
|
|
327
|
+
for (const ms of parsed.milestones) {
|
|
328
|
+
// Duplicate ID check
|
|
329
|
+
if (ids.has(ms.id)) {
|
|
330
|
+
errors.push(`Duplicate milestone ID: ${ms.id}`);
|
|
331
|
+
}
|
|
332
|
+
ids.add(ms.id);
|
|
333
|
+
|
|
334
|
+
// Goal required
|
|
335
|
+
if (!ms.goal || ms.goal.trim() === '') {
|
|
336
|
+
errors.push(`${ms.id} (${ms.name}) is missing goal`);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Valid status
|
|
340
|
+
if (!VALID_STATUSES.includes(ms.status)) {
|
|
341
|
+
errors.push(
|
|
342
|
+
`${ms.id} has invalid status: ${ms.status}. Valid: ${VALID_STATUSES.join(', ')}`
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (ms.status === 'active') activeCount++;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (activeCount > 1) {
|
|
350
|
+
warnings.push(
|
|
351
|
+
`Multiple active LT milestones (${activeCount}). Consider having only one active.`
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (activeCount === 0 && parsed.milestones.some((m) => m.status !== 'completed')) {
|
|
356
|
+
warnings.push('No active LT milestone found');
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return {
|
|
361
|
+
valid: errors.length === 0,
|
|
362
|
+
errors,
|
|
363
|
+
warnings,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// ─── Generation ──────────────────────────────────────────────────────────────
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Generate LONG-TERM-ROADMAP.md content from structured milestone data.
|
|
371
|
+
* @param milestones - Array of LT milestones
|
|
372
|
+
* @param projectName - Project name for frontmatter
|
|
373
|
+
* @returns Complete LONG-TERM-ROADMAP.md content
|
|
374
|
+
*/
|
|
375
|
+
function generateLongTermRoadmap(milestones: LtMilestone[], projectName: string): string {
|
|
376
|
+
const today = new Date().toISOString().split('T')[0];
|
|
377
|
+
const lines: string[] = [];
|
|
378
|
+
|
|
379
|
+
lines.push('---');
|
|
380
|
+
lines.push(`project: ${projectName}`);
|
|
381
|
+
lines.push(`created: ${today}`);
|
|
382
|
+
lines.push(`last_refined: ${today}`);
|
|
383
|
+
lines.push('---');
|
|
384
|
+
lines.push('');
|
|
385
|
+
lines.push(`# Long-Term Roadmap: ${projectName}`);
|
|
386
|
+
lines.push('');
|
|
387
|
+
|
|
388
|
+
for (const ms of milestones) {
|
|
389
|
+
lines.push(`## ${ms.id}: ${ms.name}`);
|
|
390
|
+
lines.push(`**Status:** ${ms.status}`);
|
|
391
|
+
lines.push(`**Goal:** ${ms.goal}`);
|
|
392
|
+
lines.push(`**Normal milestones:** ${formatNormalMilestoneList(ms.normal_milestones)}`);
|
|
393
|
+
lines.push('');
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
lines.push('## Refinement History');
|
|
397
|
+
lines.push('');
|
|
398
|
+
lines.push('| Date | Action | Details |');
|
|
399
|
+
lines.push('|------|--------|---------|');
|
|
400
|
+
lines.push(`| ${today} | Initial roadmap | Created ${milestones.length} LT milestones |`);
|
|
401
|
+
lines.push('');
|
|
402
|
+
|
|
403
|
+
return lines.join('\n');
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// ─── Display Formatting ─────────────────────────────────────────────────────
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Format parsed long-term roadmap for human-readable display.
|
|
410
|
+
* @param parsed - Parsed roadmap from parseLongTermRoadmap
|
|
411
|
+
* @returns Formatted display string
|
|
412
|
+
*/
|
|
413
|
+
function formatLongTermRoadmap(parsed: LongTermRoadmap | null): string {
|
|
414
|
+
if (!parsed) return '';
|
|
415
|
+
|
|
416
|
+
const lines: string[] = [];
|
|
417
|
+
const project = (parsed.frontmatter?.project as string | undefined) || 'Unknown Project';
|
|
418
|
+
|
|
419
|
+
lines.push(`Long-Term Roadmap: ${project}`);
|
|
420
|
+
lines.push('');
|
|
421
|
+
|
|
422
|
+
if (parsed.milestones && parsed.milestones.length > 0) {
|
|
423
|
+
for (const ms of parsed.milestones) {
|
|
424
|
+
const icon =
|
|
425
|
+
ms.status === 'completed' ? '[done]' : ms.status === 'active' ? '[active]' : '[planned]';
|
|
426
|
+
const normalList = formatNormalMilestoneList(ms.normal_milestones);
|
|
427
|
+
lines.push(`${icon} ${ms.id}: ${ms.name}`);
|
|
428
|
+
lines.push(` ${ms.goal}`);
|
|
429
|
+
lines.push(` Normal milestones: ${normalList}`);
|
|
430
|
+
lines.push('');
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
return lines.join('\n');
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// ─── Shipped Version Detection ───────────────────────────────────────────────
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Extract shipped versions from ROADMAP.md content.
|
|
441
|
+
* Looks for `(shipped YYYY-MM-DD)` pattern in milestone bullet list.
|
|
442
|
+
* @param roadmapContent - Raw ROADMAP.md content
|
|
443
|
+
* @returns Array of shipped version strings
|
|
444
|
+
*/
|
|
445
|
+
function extractShippedVersions(roadmapContent: string | null | undefined): string[] {
|
|
446
|
+
if (!roadmapContent) return [];
|
|
447
|
+
|
|
448
|
+
const versions: string[] = [];
|
|
449
|
+
const pattern = /^-\s+(v[\d.]+)\b.*\(shipped\s+\d{4}-\d{2}-\d{2}\)/gm;
|
|
450
|
+
let match: RegExpExecArray | null;
|
|
451
|
+
while ((match = pattern.exec(roadmapContent)) !== null) {
|
|
452
|
+
versions.push(match[1]);
|
|
453
|
+
}
|
|
454
|
+
return versions;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// ─── ID Helpers ──────────────────────────────────────────────────────────────
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Compute the next LT-N id from parsed roadmap.
|
|
461
|
+
* @param parsed - Parsed roadmap (or null)
|
|
462
|
+
* @returns Next LT id (e.g., 'LT-3')
|
|
463
|
+
*/
|
|
464
|
+
function nextLtId(parsed: LongTermRoadmap | null | undefined): string {
|
|
465
|
+
if (!parsed || !parsed.milestones || parsed.milestones.length === 0) return 'LT-1';
|
|
466
|
+
|
|
467
|
+
const maxNum = Math.max(
|
|
468
|
+
...parsed.milestones.map((m) => {
|
|
469
|
+
const numMatch = m.id.match(/LT-(\d+)/);
|
|
470
|
+
return numMatch ? parseInt(numMatch[1], 10) : 0;
|
|
471
|
+
})
|
|
472
|
+
);
|
|
473
|
+
return `LT-${maxNum + 1}`;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// ─── CRUD Operations ─────────────────────────────────────────────────────────
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Append a new LT milestone before the Refinement History section.
|
|
480
|
+
* @param content - Raw LONG-TERM-ROADMAP.md content
|
|
481
|
+
* @param name - LT milestone name
|
|
482
|
+
* @param goal - LT milestone goal
|
|
483
|
+
* @returns Updated content and new ID
|
|
484
|
+
*/
|
|
485
|
+
function addLtMilestone(content: string, name: string, goal: string): AddLtMilestoneResult {
|
|
486
|
+
const parsed = parseLongTermRoadmap(content);
|
|
487
|
+
const id = nextLtId(parsed);
|
|
488
|
+
|
|
489
|
+
const newSection = [
|
|
490
|
+
`## ${id}: ${name}`,
|
|
491
|
+
`**Status:** planned`,
|
|
492
|
+
`**Goal:** ${goal}`,
|
|
493
|
+
`**Normal milestones:** (none yet)`,
|
|
494
|
+
'',
|
|
495
|
+
].join('\n');
|
|
496
|
+
|
|
497
|
+
// Insert before Refinement History
|
|
498
|
+
const historyMatch = content.match(/^##\s+Refinement History/m);
|
|
499
|
+
if (historyMatch && historyMatch.index !== undefined) {
|
|
500
|
+
const before = content.slice(0, historyMatch.index);
|
|
501
|
+
const after = content.slice(historyMatch.index);
|
|
502
|
+
return { content: before + newSection + '\n' + after, id };
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// No history section, append at end
|
|
506
|
+
return { content: content.trimEnd() + '\n\n' + newSection + '\n', id };
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Remove an LT milestone section. Protected: refuses if any linked normal milestone is shipped.
|
|
511
|
+
* @param content - Raw LONG-TERM-ROADMAP.md content
|
|
512
|
+
* @param id - LT milestone ID (e.g., 'LT-2')
|
|
513
|
+
* @param roadmapContent - Optional ROADMAP.md content for shipped detection
|
|
514
|
+
* @returns Updated content, or { error } if protected
|
|
515
|
+
*/
|
|
516
|
+
function removeLtMilestone(
|
|
517
|
+
content: string,
|
|
518
|
+
id: string,
|
|
519
|
+
roadmapContent?: string
|
|
520
|
+
): string | ErrorResult {
|
|
521
|
+
const parsed = parseLongTermRoadmap(content);
|
|
522
|
+
if (!parsed) return { error: 'Could not parse LONG-TERM-ROADMAP.md' };
|
|
523
|
+
|
|
524
|
+
const ms = parsed.milestones.find((m) => m.id === id);
|
|
525
|
+
if (!ms) return { error: `${id} not found` };
|
|
526
|
+
|
|
527
|
+
// Protection: check if any linked normal milestones are shipped
|
|
528
|
+
if (roadmapContent && ms.normal_milestones.length > 0) {
|
|
529
|
+
const shipped = extractShippedVersions(roadmapContent);
|
|
530
|
+
const shippedLinked = ms.normal_milestones.filter((m) => shipped.includes(m.version));
|
|
531
|
+
if (shippedLinked.length > 0) {
|
|
532
|
+
return {
|
|
533
|
+
error: `Cannot remove ${id}: linked milestone(s) ${shippedLinked.map((m) => m.version).join(', ')} already shipped`,
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Also refuse if status is completed
|
|
539
|
+
if (ms.status === 'completed') {
|
|
540
|
+
return { error: `Cannot remove ${id}: status is completed` };
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Find and remove the section
|
|
544
|
+
const escapedId = id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
545
|
+
const sectionPattern = new RegExp(`^##\\s+${escapedId}:\\s*[^\\n]+`, 'm');
|
|
546
|
+
const sectionMatch = content.match(sectionPattern);
|
|
547
|
+
if (!sectionMatch || sectionMatch.index === undefined) {
|
|
548
|
+
return { error: `${id} section not found in content` };
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
const startIdx = sectionMatch.index;
|
|
552
|
+
const afterHeading = content.slice(startIdx + sectionMatch[0].length);
|
|
553
|
+
const nextH2 = afterHeading.match(/^##\s/m);
|
|
554
|
+
const endIdx =
|
|
555
|
+
nextH2 && nextH2.index !== undefined
|
|
556
|
+
? startIdx + sectionMatch[0].length + nextH2.index
|
|
557
|
+
: content.length;
|
|
558
|
+
|
|
559
|
+
const result = content.slice(0, startIdx) + content.slice(endIdx);
|
|
560
|
+
return result;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Update fields of an LT milestone in-place.
|
|
565
|
+
* @param content - Raw LONG-TERM-ROADMAP.md content
|
|
566
|
+
* @param id - LT milestone ID
|
|
567
|
+
* @param updates - Fields to update: name, goal, status
|
|
568
|
+
* @returns Updated content, or { error }
|
|
569
|
+
*/
|
|
570
|
+
function updateLtMilestone(
|
|
571
|
+
content: string,
|
|
572
|
+
id: string,
|
|
573
|
+
updates: Partial<Pick<LtMilestone, 'name' | 'goal' | 'status'>>
|
|
574
|
+
): string | ErrorResult {
|
|
575
|
+
const parsed = parseLongTermRoadmap(content);
|
|
576
|
+
if (!parsed) return { error: 'Could not parse LONG-TERM-ROADMAP.md' };
|
|
577
|
+
|
|
578
|
+
const ms = parsed.milestones.find((m) => m.id === id);
|
|
579
|
+
if (!ms) return { error: `${id} not found` };
|
|
580
|
+
|
|
581
|
+
if (updates.status && !VALID_STATUSES.includes(updates.status)) {
|
|
582
|
+
return { error: `Invalid status: ${updates.status}. Valid: ${VALID_STATUSES.join(', ')}` };
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
let result = content;
|
|
586
|
+
|
|
587
|
+
// Update heading name
|
|
588
|
+
if (updates.name) {
|
|
589
|
+
const escapedId = id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
590
|
+
const headingPattern = new RegExp(`^(##\\s+${escapedId}:\\s*)(.+)$`, 'm');
|
|
591
|
+
result = result.replace(headingPattern, `$1${updates.name}`);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// Update status
|
|
595
|
+
if (updates.status) {
|
|
596
|
+
// Find this milestone's section and update status within it
|
|
597
|
+
const escapedId = id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
598
|
+
const sectionStart = result.match(new RegExp(`^##\\s+${escapedId}:`, 'm'));
|
|
599
|
+
if (sectionStart && sectionStart.index !== undefined) {
|
|
600
|
+
const afterSection = result.slice(sectionStart.index);
|
|
601
|
+
const nextH2 = afterSection.match(/\n##\s/);
|
|
602
|
+
const sectionEnd =
|
|
603
|
+
nextH2 && nextH2.index !== undefined ? sectionStart.index + nextH2.index : result.length;
|
|
604
|
+
const section = result.slice(sectionStart.index, sectionEnd);
|
|
605
|
+
const updatedSection = section.replace(
|
|
606
|
+
/\*\*Status:\*\*\s*.+/,
|
|
607
|
+
`**Status:** ${updates.status}`
|
|
608
|
+
);
|
|
609
|
+
result = result.slice(0, sectionStart.index) + updatedSection + result.slice(sectionEnd);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Update goal
|
|
614
|
+
if (updates.goal) {
|
|
615
|
+
const escapedId = id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
616
|
+
const sectionStart = result.match(new RegExp(`^##\\s+${escapedId}:`, 'm'));
|
|
617
|
+
if (sectionStart && sectionStart.index !== undefined) {
|
|
618
|
+
const afterSection = result.slice(sectionStart.index);
|
|
619
|
+
const nextH2 = afterSection.match(/\n##\s/);
|
|
620
|
+
const sectionEnd =
|
|
621
|
+
nextH2 && nextH2.index !== undefined ? sectionStart.index + nextH2.index : result.length;
|
|
622
|
+
const section = result.slice(sectionStart.index, sectionEnd);
|
|
623
|
+
const updatedSection = section.replace(/\*\*Goal:\*\*\s*.+/, `**Goal:** ${updates.goal}`);
|
|
624
|
+
result = result.slice(0, sectionStart.index) + updatedSection + result.slice(sectionEnd);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
return result;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Link a normal milestone version to an LT milestone.
|
|
633
|
+
* @param content - Raw LONG-TERM-ROADMAP.md content
|
|
634
|
+
* @param id - LT milestone ID
|
|
635
|
+
* @param version - Normal milestone version (e.g., 'v0.2.0')
|
|
636
|
+
* @param note - Optional note (e.g., 'planned')
|
|
637
|
+
* @returns Updated content, or { error }
|
|
638
|
+
*/
|
|
639
|
+
function linkNormalMilestone(
|
|
640
|
+
content: string,
|
|
641
|
+
id: string,
|
|
642
|
+
version: string,
|
|
643
|
+
note?: string
|
|
644
|
+
): string | ErrorResult {
|
|
645
|
+
const parsed = parseLongTermRoadmap(content);
|
|
646
|
+
if (!parsed) return { error: 'Could not parse LONG-TERM-ROADMAP.md' };
|
|
647
|
+
|
|
648
|
+
const ms = parsed.milestones.find((m) => m.id === id);
|
|
649
|
+
if (!ms) return { error: `${id} not found` };
|
|
650
|
+
|
|
651
|
+
// Check if already linked
|
|
652
|
+
if (ms.normal_milestones.some((m) => m.version === version)) {
|
|
653
|
+
return { error: `${version} is already linked to ${id}` };
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
const newEntry: NormalMilestoneEntry = note ? { version, note } : { version };
|
|
657
|
+
const updatedList = [...ms.normal_milestones, newEntry];
|
|
658
|
+
const newField = formatNormalMilestoneList(updatedList);
|
|
659
|
+
|
|
660
|
+
// Replace the Normal milestones field in this section
|
|
661
|
+
return replaceFieldInSection(content, id, 'Normal milestones', newField);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Unlink a normal milestone version from an LT milestone.
|
|
666
|
+
* Protected: refuses if the normal milestone is shipped.
|
|
667
|
+
* @param content - Raw LONG-TERM-ROADMAP.md content
|
|
668
|
+
* @param id - LT milestone ID
|
|
669
|
+
* @param version - Normal milestone version
|
|
670
|
+
* @param roadmapContent - Optional ROADMAP.md for shipped detection
|
|
671
|
+
* @returns Updated content, or { error }
|
|
672
|
+
*/
|
|
673
|
+
function unlinkNormalMilestone(
|
|
674
|
+
content: string,
|
|
675
|
+
id: string,
|
|
676
|
+
version: string,
|
|
677
|
+
roadmapContent?: string
|
|
678
|
+
): string | ErrorResult {
|
|
679
|
+
const parsed = parseLongTermRoadmap(content);
|
|
680
|
+
if (!parsed) return { error: 'Could not parse LONG-TERM-ROADMAP.md' };
|
|
681
|
+
|
|
682
|
+
const ms = parsed.milestones.find((m) => m.id === id);
|
|
683
|
+
if (!ms) return { error: `${id} not found` };
|
|
684
|
+
|
|
685
|
+
if (!ms.normal_milestones.some((m) => m.version === version)) {
|
|
686
|
+
return { error: `${version} is not linked to ${id}` };
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// Protection: check if shipped
|
|
690
|
+
if (roadmapContent) {
|
|
691
|
+
const shipped = extractShippedVersions(roadmapContent);
|
|
692
|
+
if (shipped.includes(version)) {
|
|
693
|
+
return { error: `Cannot unlink ${version} from ${id}: milestone is already shipped` };
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
const updatedList = ms.normal_milestones.filter((m) => m.version !== version);
|
|
698
|
+
const newField = formatNormalMilestoneList(updatedList);
|
|
699
|
+
|
|
700
|
+
return replaceFieldInSection(content, id, 'Normal milestones', newField);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Find an LT milestone by ID.
|
|
705
|
+
* @param content - Raw LONG-TERM-ROADMAP.md content
|
|
706
|
+
* @param id - LT milestone ID
|
|
707
|
+
* @returns Parsed milestone, or null
|
|
708
|
+
*/
|
|
709
|
+
function getLtMilestoneById(content: string, id: string): LtMilestone | null {
|
|
710
|
+
const parsed = parseLongTermRoadmap(content);
|
|
711
|
+
if (!parsed) return null;
|
|
712
|
+
return parsed.milestones.find((m) => m.id === id) || null;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Auto-group existing ROADMAP.md milestones into a single LT-1 milestone.
|
|
717
|
+
* All shipped + active milestones go into LT-1.
|
|
718
|
+
* @param roadmapContent - Raw ROADMAP.md content
|
|
719
|
+
* @param projectName - Project name
|
|
720
|
+
* @returns Generated LONG-TERM-ROADMAP.md content
|
|
721
|
+
*/
|
|
722
|
+
function initFromRoadmap(roadmapContent: string, projectName: string): string {
|
|
723
|
+
const shipped = extractShippedVersions(roadmapContent);
|
|
724
|
+
|
|
725
|
+
// Also find non-shipped milestones from the bullet list
|
|
726
|
+
const allVersions: string[] = [];
|
|
727
|
+
const bulletPattern = /^-\s+(v[\d.]+)\b/gm;
|
|
728
|
+
let match: RegExpExecArray | null;
|
|
729
|
+
while ((match = bulletPattern.exec(roadmapContent)) !== null) {
|
|
730
|
+
allVersions.push(match[1]);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
const normalMilestones: NormalMilestoneEntry[] = allVersions.map((v) => {
|
|
734
|
+
if (shipped.includes(v)) {
|
|
735
|
+
return { version: v };
|
|
736
|
+
}
|
|
737
|
+
return { version: v, note: 'planned' };
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
const hasShipped = shipped.length > 0;
|
|
741
|
+
const status = hasShipped ? 'active' : 'planned';
|
|
742
|
+
|
|
743
|
+
const milestones: LtMilestone[] = [
|
|
744
|
+
{
|
|
745
|
+
id: 'LT-1',
|
|
746
|
+
name: 'Initial Milestone Group',
|
|
747
|
+
status,
|
|
748
|
+
goal: 'Auto-grouped from existing ROADMAP.md milestones',
|
|
749
|
+
normal_milestones: normalMilestones,
|
|
750
|
+
},
|
|
751
|
+
];
|
|
752
|
+
|
|
753
|
+
return generateLongTermRoadmap(milestones, projectName);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
// ─── Internal Helpers ────────────────────────────────────────────────────────
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Replace a bold field value within a specific LT milestone section.
|
|
760
|
+
* @param content - Full LONG-TERM-ROADMAP.md content
|
|
761
|
+
* @param id - LT milestone ID
|
|
762
|
+
* @param fieldName - Bold field name
|
|
763
|
+
* @param newValue - New field value
|
|
764
|
+
* @returns Updated content
|
|
765
|
+
*/
|
|
766
|
+
function replaceFieldInSection(
|
|
767
|
+
content: string,
|
|
768
|
+
id: string,
|
|
769
|
+
fieldName: string,
|
|
770
|
+
newValue: string
|
|
771
|
+
): string {
|
|
772
|
+
const escapedId = id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
773
|
+
const sectionStart = content.match(new RegExp(`^##\\s+${escapedId}:`, 'm'));
|
|
774
|
+
if (!sectionStart || sectionStart.index === undefined) return content;
|
|
775
|
+
|
|
776
|
+
const afterSection = content.slice(sectionStart.index);
|
|
777
|
+
const nextH2 = afterSection.match(/\n##\s/);
|
|
778
|
+
const sectionEnd =
|
|
779
|
+
nextH2 && nextH2.index !== undefined ? sectionStart.index + nextH2.index : content.length;
|
|
780
|
+
|
|
781
|
+
const section = content.slice(sectionStart.index, sectionEnd);
|
|
782
|
+
const fieldPattern = new RegExp(`\\*\\*${fieldName}:\\*\\*\\s*.+`);
|
|
783
|
+
const updatedSection = section.replace(fieldPattern, `**${fieldName}:** ${newValue}`);
|
|
784
|
+
|
|
785
|
+
return content.slice(0, sectionStart.index) + updatedSection + content.slice(sectionEnd);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
module.exports = {
|
|
789
|
+
updateRefinementHistory,
|
|
790
|
+
parseNormalMilestoneList,
|
|
791
|
+
formatNormalMilestoneList,
|
|
792
|
+
parseLtMilestone,
|
|
793
|
+
parseLongTermRoadmap,
|
|
794
|
+
validateLongTermRoadmap,
|
|
795
|
+
generateLongTermRoadmap,
|
|
796
|
+
formatLongTermRoadmap,
|
|
797
|
+
extractShippedVersions,
|
|
798
|
+
nextLtId,
|
|
799
|
+
addLtMilestone,
|
|
800
|
+
removeLtMilestone,
|
|
801
|
+
updateLtMilestone,
|
|
802
|
+
linkNormalMilestone,
|
|
803
|
+
unlinkNormalMilestone,
|
|
804
|
+
getLtMilestoneById,
|
|
805
|
+
initFromRoadmap,
|
|
806
|
+
};
|