gsd-remix 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +939 -0
- package/README.zh-CN.md +876 -0
- package/agents/gsd-advisor-researcher.md +127 -0
- package/agents/gsd-ai-researcher.md +133 -0
- package/agents/gsd-assumptions-analyzer.md +105 -0
- package/agents/gsd-code-fixer.md +517 -0
- package/agents/gsd-code-reviewer.md +371 -0
- package/agents/gsd-codebase-mapper.md +781 -0
- package/agents/gsd-debug-session-manager.md +314 -0
- package/agents/gsd-debugger.md +1452 -0
- package/agents/gsd-doc-classifier.md +168 -0
- package/agents/gsd-doc-synthesizer.md +204 -0
- package/agents/gsd-doc-verifier.md +217 -0
- package/agents/gsd-doc-writer.md +615 -0
- package/agents/gsd-domain-researcher.md +153 -0
- package/agents/gsd-eval-auditor.md +191 -0
- package/agents/gsd-eval-planner.md +154 -0
- package/agents/gsd-executor.md +603 -0
- package/agents/gsd-framework-selector.md +160 -0
- package/agents/gsd-integration-checker.md +470 -0
- package/agents/gsd-intel-updater.md +334 -0
- package/agents/gsd-nyquist-auditor.md +203 -0
- package/agents/gsd-pattern-mapper.md +335 -0
- package/agents/gsd-phase-researcher.md +841 -0
- package/agents/gsd-plan-checker.md +978 -0
- package/agents/gsd-planner.md +1251 -0
- package/agents/gsd-project-researcher.md +677 -0
- package/agents/gsd-research-synthesizer.md +247 -0
- package/agents/gsd-roadmapper.md +688 -0
- package/agents/gsd-security-auditor.md +155 -0
- package/agents/gsd-ui-auditor.md +495 -0
- package/agents/gsd-ui-checker.md +309 -0
- package/agents/gsd-ui-researcher.md +380 -0
- package/agents/gsd-user-profiler.md +171 -0
- package/agents/gsd-verifier.md +830 -0
- package/bin/install.js +7062 -0
- package/commands/gsd/add-backlog.md +79 -0
- package/commands/gsd/add-phase.md +43 -0
- package/commands/gsd/add-tests.md +41 -0
- package/commands/gsd/add-todo.md +47 -0
- package/commands/gsd/ai-integration-phase.md +36 -0
- package/commands/gsd/analyze-dependencies.md +34 -0
- package/commands/gsd/audit-fix.md +33 -0
- package/commands/gsd/audit-milestone.md +36 -0
- package/commands/gsd/audit-uat.md +24 -0
- package/commands/gsd/autonomous.md +46 -0
- package/commands/gsd/check-todos.md +45 -0
- package/commands/gsd/cleanup.md +23 -0
- package/commands/gsd/code-review-fix.md +52 -0
- package/commands/gsd/code-review.md +55 -0
- package/commands/gsd/complete-milestone.md +136 -0
- package/commands/gsd/debug.md +263 -0
- package/commands/gsd/discuss-phase.md +69 -0
- package/commands/gsd/do.md +30 -0
- package/commands/gsd/docs-update.md +48 -0
- package/commands/gsd/eval-review.md +32 -0
- package/commands/gsd/execute-phase.md +63 -0
- package/commands/gsd/explore.md +27 -0
- package/commands/gsd/extract_learnings.md +22 -0
- package/commands/gsd/fast.md +30 -0
- package/commands/gsd/forensics.md +56 -0
- package/commands/gsd/from-gsd2.md +47 -0
- package/commands/gsd/graphify.md +201 -0
- package/commands/gsd/health.md +22 -0
- package/commands/gsd/help.md +24 -0
- package/commands/gsd/import.md +37 -0
- package/commands/gsd/inbox.md +38 -0
- package/commands/gsd/ingest-docs.md +42 -0
- package/commands/gsd/insert-phase.md +32 -0
- package/commands/gsd/intel.md +179 -0
- package/commands/gsd/join-discord.md +19 -0
- package/commands/gsd/list-phase-assumptions.md +46 -0
- package/commands/gsd/list-workspaces.md +19 -0
- package/commands/gsd/manager.md +40 -0
- package/commands/gsd/map-codebase.md +71 -0
- package/commands/gsd/milestone-summary.md +51 -0
- package/commands/gsd/new-milestone.md +44 -0
- package/commands/gsd/new-project.md +46 -0
- package/commands/gsd/new-workspace.md +44 -0
- package/commands/gsd/next.md +28 -0
- package/commands/gsd/note.md +34 -0
- package/commands/gsd/pause-work.md +38 -0
- package/commands/gsd/plan-milestone-gaps.md +34 -0
- package/commands/gsd/plan-phase.md +52 -0
- package/commands/gsd/plan-review-convergence.md +52 -0
- package/commands/gsd/plant-seed.md +28 -0
- package/commands/gsd/pr-branch.md +25 -0
- package/commands/gsd/profile-user.md +46 -0
- package/commands/gsd/progress.md +25 -0
- package/commands/gsd/quick.md +173 -0
- package/commands/gsd/reapply-patches.md +331 -0
- package/commands/gsd/remove-phase.md +31 -0
- package/commands/gsd/remove-workspace.md +26 -0
- package/commands/gsd/research-phase.md +195 -0
- package/commands/gsd/resume-work.md +40 -0
- package/commands/gsd/review-backlog.md +62 -0
- package/commands/gsd/review.md +40 -0
- package/commands/gsd/scan.md +26 -0
- package/commands/gsd/secure-phase.md +35 -0
- package/commands/gsd/session-report.md +19 -0
- package/commands/gsd/set-profile.md +12 -0
- package/commands/gsd/settings.md +36 -0
- package/commands/gsd/ship.md +23 -0
- package/commands/gsd/sketch-wrap-up.md +31 -0
- package/commands/gsd/sketch.md +49 -0
- package/commands/gsd/spec-phase.md +62 -0
- package/commands/gsd/spike-wrap-up.md +31 -0
- package/commands/gsd/spike.md +46 -0
- package/commands/gsd/stats.md +18 -0
- package/commands/gsd/sync-skills.md +19 -0
- package/commands/gsd/thread.md +227 -0
- package/commands/gsd/ui-phase.md +34 -0
- package/commands/gsd/ui-review.md +32 -0
- package/commands/gsd/ultraplan-phase.md +33 -0
- package/commands/gsd/undo.md +34 -0
- package/commands/gsd/update.md +37 -0
- package/commands/gsd/validate-phase.md +35 -0
- package/commands/gsd/verify-work.md +38 -0
- package/commands/gsd/workstreams.md +69 -0
- package/get-shit-done/bin/gsd-tools.cjs +1263 -0
- package/get-shit-done/bin/lib/artifacts.cjs +52 -0
- package/get-shit-done/bin/lib/audit.cjs +757 -0
- package/get-shit-done/bin/lib/commands.cjs +1023 -0
- package/get-shit-done/bin/lib/config-schema.cjs +79 -0
- package/get-shit-done/bin/lib/config.cjs +463 -0
- package/get-shit-done/bin/lib/core.cjs +1794 -0
- package/get-shit-done/bin/lib/docs.cjs +267 -0
- package/get-shit-done/bin/lib/frontmatter.cjs +379 -0
- package/get-shit-done/bin/lib/graphify.cjs +494 -0
- package/get-shit-done/bin/lib/gsd2-import.cjs +511 -0
- package/get-shit-done/bin/lib/init.cjs +1878 -0
- package/get-shit-done/bin/lib/intel.cjs +639 -0
- package/get-shit-done/bin/lib/learnings.cjs +378 -0
- package/get-shit-done/bin/lib/milestone.cjs +283 -0
- package/get-shit-done/bin/lib/model-profiles.cjs +71 -0
- package/get-shit-done/bin/lib/phase.cjs +1058 -0
- package/get-shit-done/bin/lib/profile-output.cjs +1080 -0
- package/get-shit-done/bin/lib/profile-pipeline.cjs +539 -0
- package/get-shit-done/bin/lib/roadmap.cjs +523 -0
- package/get-shit-done/bin/lib/schema-detect.cjs +238 -0
- package/get-shit-done/bin/lib/security.cjs +504 -0
- package/get-shit-done/bin/lib/state.cjs +1649 -0
- package/get-shit-done/bin/lib/template.cjs +226 -0
- package/get-shit-done/bin/lib/uat.cjs +288 -0
- package/get-shit-done/bin/lib/verify.cjs +1184 -0
- package/get-shit-done/bin/lib/workstream.cjs +495 -0
- package/get-shit-done/bin/repair-sdk.cjs +177 -0
- package/get-shit-done/contexts/dev.md +21 -0
- package/get-shit-done/contexts/research.md +22 -0
- package/get-shit-done/contexts/review.md +22 -0
- package/get-shit-done/references/agent-contracts.md +79 -0
- package/get-shit-done/references/ai-evals.md +156 -0
- package/get-shit-done/references/ai-frameworks.md +186 -0
- package/get-shit-done/references/artifact-types.md +131 -0
- package/get-shit-done/references/autonomous-smart-discuss.md +277 -0
- package/get-shit-done/references/checkpoints.md +808 -0
- package/get-shit-done/references/common-bug-patterns.md +114 -0
- package/get-shit-done/references/context-budget.md +49 -0
- package/get-shit-done/references/continuation-format.md +253 -0
- package/get-shit-done/references/debugger-philosophy.md +76 -0
- package/get-shit-done/references/decimal-phase-calculation.md +64 -0
- package/get-shit-done/references/doc-conflict-engine.md +91 -0
- package/get-shit-done/references/domain-probes.md +125 -0
- package/get-shit-done/references/executor-examples.md +110 -0
- package/get-shit-done/references/few-shot-examples/plan-checker.md +73 -0
- package/get-shit-done/references/few-shot-examples/verifier.md +109 -0
- package/get-shit-done/references/gate-prompts.md +100 -0
- package/get-shit-done/references/gates.md +70 -0
- package/get-shit-done/references/git-integration.md +295 -0
- package/get-shit-done/references/git-planning-commit.md +40 -0
- package/get-shit-done/references/ios-scaffold.md +123 -0
- package/get-shit-done/references/mandatory-initial-read.md +2 -0
- package/get-shit-done/references/model-profile-resolution.md +38 -0
- package/get-shit-done/references/model-profiles.md +145 -0
- package/get-shit-done/references/phase-argument-parsing.md +61 -0
- package/get-shit-done/references/planner-antipatterns.md +89 -0
- package/get-shit-done/references/planner-gap-closure.md +62 -0
- package/get-shit-done/references/planner-reviews.md +39 -0
- package/get-shit-done/references/planner-revision.md +87 -0
- package/get-shit-done/references/planner-source-audit.md +73 -0
- package/get-shit-done/references/planning-config.md +460 -0
- package/get-shit-done/references/project-skills-discovery.md +19 -0
- package/get-shit-done/references/questioning.md +162 -0
- package/get-shit-done/references/revision-loop.md +97 -0
- package/get-shit-done/references/sketch-interactivity.md +41 -0
- package/get-shit-done/references/sketch-theme-system.md +94 -0
- package/get-shit-done/references/sketch-tooling.md +45 -0
- package/get-shit-done/references/sketch-variant-patterns.md +81 -0
- package/get-shit-done/references/tdd.md +330 -0
- package/get-shit-done/references/thinking-models-debug.md +44 -0
- package/get-shit-done/references/thinking-models-execution.md +50 -0
- package/get-shit-done/references/thinking-models-planning.md +62 -0
- package/get-shit-done/references/thinking-models-research.md +50 -0
- package/get-shit-done/references/thinking-models-verification.md +55 -0
- package/get-shit-done/references/thinking-partner.md +96 -0
- package/get-shit-done/references/ui-brand.md +160 -0
- package/get-shit-done/references/universal-anti-patterns.md +63 -0
- package/get-shit-done/references/user-profiling.md +681 -0
- package/get-shit-done/references/verification-overrides.md +227 -0
- package/get-shit-done/references/verification-patterns.md +612 -0
- package/get-shit-done/references/workstream-flag.md +111 -0
- package/get-shit-done/templates/AI-SPEC.md +246 -0
- package/get-shit-done/templates/DEBUG.md +169 -0
- package/get-shit-done/templates/README.md +76 -0
- package/get-shit-done/templates/SECURITY.md +61 -0
- package/get-shit-done/templates/UAT.md +265 -0
- package/get-shit-done/templates/UI-SPEC.md +100 -0
- package/get-shit-done/templates/VALIDATION.md +76 -0
- package/get-shit-done/templates/claude-md.md +145 -0
- package/get-shit-done/templates/codebase/architecture.md +255 -0
- package/get-shit-done/templates/codebase/concerns.md +310 -0
- package/get-shit-done/templates/codebase/conventions.md +307 -0
- package/get-shit-done/templates/codebase/integrations.md +280 -0
- package/get-shit-done/templates/codebase/stack.md +186 -0
- package/get-shit-done/templates/codebase/structure.md +285 -0
- package/get-shit-done/templates/codebase/testing.md +480 -0
- package/get-shit-done/templates/config.json +56 -0
- package/get-shit-done/templates/context.md +352 -0
- package/get-shit-done/templates/continue-here.md +78 -0
- package/get-shit-done/templates/copilot-instructions.md +7 -0
- package/get-shit-done/templates/debug-subagent-prompt.md +91 -0
- package/get-shit-done/templates/dev-preferences.md +21 -0
- package/get-shit-done/templates/discovery.md +146 -0
- package/get-shit-done/templates/discussion-log.md +63 -0
- package/get-shit-done/templates/milestone-archive.md +123 -0
- package/get-shit-done/templates/milestone.md +115 -0
- package/get-shit-done/templates/phase-prompt.md +610 -0
- package/get-shit-done/templates/planner-subagent-prompt.md +117 -0
- package/get-shit-done/templates/project.md +186 -0
- package/get-shit-done/templates/requirements.md +231 -0
- package/get-shit-done/templates/research-project/ARCHITECTURE.md +204 -0
- package/get-shit-done/templates/research-project/FEATURES.md +147 -0
- package/get-shit-done/templates/research-project/PITFALLS.md +200 -0
- package/get-shit-done/templates/research-project/STACK.md +120 -0
- package/get-shit-done/templates/research-project/SUMMARY.md +170 -0
- package/get-shit-done/templates/research.md +592 -0
- package/get-shit-done/templates/retrospective.md +54 -0
- package/get-shit-done/templates/roadmap.md +202 -0
- package/get-shit-done/templates/spec.md +307 -0
- package/get-shit-done/templates/state.md +184 -0
- package/get-shit-done/templates/summary-complex.md +59 -0
- package/get-shit-done/templates/summary-minimal.md +41 -0
- package/get-shit-done/templates/summary-standard.md +48 -0
- package/get-shit-done/templates/summary.md +248 -0
- package/get-shit-done/templates/user-profile.md +146 -0
- package/get-shit-done/templates/user-setup.md +311 -0
- package/get-shit-done/templates/verification-report.md +322 -0
- package/get-shit-done/workflows/add-phase.md +112 -0
- package/get-shit-done/workflows/add-tests.md +354 -0
- package/get-shit-done/workflows/add-todo.md +160 -0
- package/get-shit-done/workflows/ai-integration-phase.md +284 -0
- package/get-shit-done/workflows/analyze-dependencies.md +96 -0
- package/get-shit-done/workflows/audit-fix.md +175 -0
- package/get-shit-done/workflows/audit-milestone.md +340 -0
- package/get-shit-done/workflows/audit-uat.md +109 -0
- package/get-shit-done/workflows/autonomous.md +789 -0
- package/get-shit-done/workflows/check-todos.md +179 -0
- package/get-shit-done/workflows/cleanup.md +154 -0
- package/get-shit-done/workflows/code-review-fix.md +497 -0
- package/get-shit-done/workflows/code-review.md +515 -0
- package/get-shit-done/workflows/complete-milestone.md +847 -0
- package/get-shit-done/workflows/diagnose-issues.md +238 -0
- package/get-shit-done/workflows/discovery-phase.md +291 -0
- package/get-shit-done/workflows/discuss-phase-assumptions.md +670 -0
- package/get-shit-done/workflows/discuss-phase-power.md +308 -0
- package/get-shit-done/workflows/discuss-phase.md +1378 -0
- package/get-shit-done/workflows/do.md +110 -0
- package/get-shit-done/workflows/docs-update.md +1155 -0
- package/get-shit-done/workflows/eval-review.md +155 -0
- package/get-shit-done/workflows/execute-phase.md +1677 -0
- package/get-shit-done/workflows/execute-plan.md +533 -0
- package/get-shit-done/workflows/explore.md +141 -0
- package/get-shit-done/workflows/extract_learnings.md +242 -0
- package/get-shit-done/workflows/fast.md +105 -0
- package/get-shit-done/workflows/forensics.md +265 -0
- package/get-shit-done/workflows/graduation.md +195 -0
- package/get-shit-done/workflows/health.md +314 -0
- package/get-shit-done/workflows/help.md +667 -0
- package/get-shit-done/workflows/import.md +246 -0
- package/get-shit-done/workflows/inbox.md +387 -0
- package/get-shit-done/workflows/ingest-docs.md +328 -0
- package/get-shit-done/workflows/insert-phase.md +130 -0
- package/get-shit-done/workflows/list-phase-assumptions.md +178 -0
- package/get-shit-done/workflows/list-workspaces.md +56 -0
- package/get-shit-done/workflows/manager.md +365 -0
- package/get-shit-done/workflows/map-codebase.md +393 -0
- package/get-shit-done/workflows/milestone-summary.md +223 -0
- package/get-shit-done/workflows/new-milestone.md +611 -0
- package/get-shit-done/workflows/new-project.md +1391 -0
- package/get-shit-done/workflows/new-workspace.md +239 -0
- package/get-shit-done/workflows/next.md +220 -0
- package/get-shit-done/workflows/node-repair.md +92 -0
- package/get-shit-done/workflows/note.md +158 -0
- package/get-shit-done/workflows/pause-work.md +243 -0
- package/get-shit-done/workflows/plan-milestone-gaps.md +273 -0
- package/get-shit-done/workflows/plan-phase.md +1349 -0
- package/get-shit-done/workflows/plan-review-convergence.md +254 -0
- package/get-shit-done/workflows/plant-seed.md +172 -0
- package/get-shit-done/workflows/pr-branch.md +157 -0
- package/get-shit-done/workflows/profile-user.md +452 -0
- package/get-shit-done/workflows/progress.md +619 -0
- package/get-shit-done/workflows/quick.md +970 -0
- package/get-shit-done/workflows/remove-phase.md +155 -0
- package/get-shit-done/workflows/remove-workspace.md +92 -0
- package/get-shit-done/workflows/research-phase.md +89 -0
- package/get-shit-done/workflows/resume-project.md +326 -0
- package/get-shit-done/workflows/review.md +344 -0
- package/get-shit-done/workflows/scan.md +102 -0
- package/get-shit-done/workflows/secure-phase.md +166 -0
- package/get-shit-done/workflows/session-report.md +146 -0
- package/get-shit-done/workflows/settings.md +319 -0
- package/get-shit-done/workflows/ship.md +302 -0
- package/get-shit-done/workflows/sketch-wrap-up.md +283 -0
- package/get-shit-done/workflows/sketch.md +286 -0
- package/get-shit-done/workflows/spec-phase.md +262 -0
- package/get-shit-done/workflows/spike-wrap-up.md +281 -0
- package/get-shit-done/workflows/spike.md +362 -0
- package/get-shit-done/workflows/stats.md +60 -0
- package/get-shit-done/workflows/sync-skills.md +182 -0
- package/get-shit-done/workflows/transition.md +693 -0
- package/get-shit-done/workflows/ui-phase.md +323 -0
- package/get-shit-done/workflows/ui-review.md +190 -0
- package/get-shit-done/workflows/ultraplan-phase.md +189 -0
- package/get-shit-done/workflows/undo.md +314 -0
- package/get-shit-done/workflows/update.md +587 -0
- package/get-shit-done/workflows/validate-phase.md +176 -0
- package/get-shit-done/workflows/verify-phase.md +465 -0
- package/get-shit-done/workflows/verify-work.md +740 -0
- package/hooks/dist/gsd-check-update-worker.js +108 -0
- package/hooks/dist/gsd-check-update.js +64 -0
- package/hooks/dist/gsd-context-monitor.js +192 -0
- package/hooks/dist/gsd-phase-boundary.sh +28 -0
- package/hooks/dist/gsd-prompt-guard.js +97 -0
- package/hooks/dist/gsd-read-guard.js +82 -0
- package/hooks/dist/gsd-read-injection-scanner.js +152 -0
- package/hooks/dist/gsd-session-state.sh +34 -0
- package/hooks/dist/gsd-statusline.js +293 -0
- package/hooks/dist/gsd-validate-commit.sh +48 -0
- package/hooks/dist/gsd-workflow-guard.js +94 -0
- package/hooks/gsd-check-update-worker.js +108 -0
- package/hooks/gsd-check-update.js +64 -0
- package/hooks/gsd-context-monitor.js +192 -0
- package/hooks/gsd-phase-boundary.sh +28 -0
- package/hooks/gsd-prompt-guard.js +97 -0
- package/hooks/gsd-read-guard.js +82 -0
- package/hooks/gsd-read-injection-scanner.js +152 -0
- package/hooks/gsd-session-state.sh +34 -0
- package/hooks/gsd-statusline.js +293 -0
- package/hooks/gsd-validate-commit.sh +48 -0
- package/hooks/gsd-workflow-guard.js +94 -0
- package/package.json +59 -0
- package/scripts/base64-scan.sh +262 -0
- package/scripts/build-hooks.js +95 -0
- package/scripts/gen-inventory-manifest.cjs +109 -0
- package/scripts/prompt-injection-scan.sh +201 -0
- package/scripts/run-tests.cjs +33 -0
- package/scripts/secret-scan.sh +227 -0
- package/sdk/package-lock.json +1998 -0
- package/sdk/package.json +52 -0
- package/sdk/prompts/agents/gsd-executor.md +110 -0
- package/sdk/prompts/agents/gsd-phase-researcher.md +158 -0
- package/sdk/prompts/agents/gsd-plan-checker.md +160 -0
- package/sdk/prompts/agents/gsd-planner.md +214 -0
- package/sdk/prompts/agents/gsd-project-researcher.md +323 -0
- package/sdk/prompts/agents/gsd-research-synthesizer.md +237 -0
- package/sdk/prompts/agents/gsd-roadmapper.md +670 -0
- package/sdk/prompts/agents/gsd-verifier.md +159 -0
- package/sdk/prompts/templates/project.md +186 -0
- package/sdk/prompts/templates/requirements.md +231 -0
- package/sdk/prompts/templates/research-project/ARCHITECTURE.md +204 -0
- package/sdk/prompts/templates/research-project/FEATURES.md +147 -0
- package/sdk/prompts/templates/research-project/PITFALLS.md +200 -0
- package/sdk/prompts/templates/research-project/STACK.md +120 -0
- package/sdk/prompts/templates/research-project/SUMMARY.md +170 -0
- package/sdk/prompts/templates/roadmap.md +202 -0
- package/sdk/prompts/templates/state.md +175 -0
- package/sdk/prompts/workflows/discuss-phase.md +126 -0
- package/sdk/prompts/workflows/execute-plan.md +106 -0
- package/sdk/prompts/workflows/plan-phase.md +84 -0
- package/sdk/prompts/workflows/research-phase.md +45 -0
- package/sdk/prompts/workflows/verify-phase.md +142 -0
- package/sdk/src/assembled-prompts.test.ts +349 -0
- package/sdk/src/cli-transport.test.ts +388 -0
- package/sdk/src/cli-transport.ts +130 -0
- package/sdk/src/cli.test.ts +383 -0
- package/sdk/src/cli.ts +670 -0
- package/sdk/src/config.test.ts +168 -0
- package/sdk/src/config.ts +177 -0
- package/sdk/src/context-engine.test.ts +295 -0
- package/sdk/src/context-engine.ts +170 -0
- package/sdk/src/context-truncation.test.ts +163 -0
- package/sdk/src/context-truncation.ts +233 -0
- package/sdk/src/e2e.integration.test.ts +178 -0
- package/sdk/src/errors.ts +72 -0
- package/sdk/src/event-stream.test.ts +661 -0
- package/sdk/src/event-stream.ts +441 -0
- package/sdk/src/failure-memory.test.ts +457 -0
- package/sdk/src/failure-memory.ts +1324 -0
- package/sdk/src/golden/capture.ts +95 -0
- package/sdk/src/golden/fixtures/generate-slug.golden.json +1 -0
- package/sdk/src/golden/fixtures/profile-sample-sessions/demo-project/sample.jsonl +3 -0
- package/sdk/src/golden/fixtures/summary-extract-sample.md +26 -0
- package/sdk/src/golden/fixtures/uat-render-checkpoint-sample.md +15 -0
- package/sdk/src/golden/golden-integration-covered.ts +30 -0
- package/sdk/src/golden/golden-mutation-covered.ts +7 -0
- package/sdk/src/golden/golden-policy.test.ts +8 -0
- package/sdk/src/golden/golden-policy.ts +112 -0
- package/sdk/src/golden/golden.integration.test.ts +373 -0
- package/sdk/src/golden/init-golden-normalize.ts +15 -0
- package/sdk/src/golden/read-only-golden-rows.ts +77 -0
- package/sdk/src/golden/read-only-parity.integration.test.ts +125 -0
- package/sdk/src/golden/registry-canonical-commands.ts +31 -0
- package/sdk/src/gsd-tools.test.ts +409 -0
- package/sdk/src/gsd-tools.ts +595 -0
- package/sdk/src/headless-prompts.test.ts +159 -0
- package/sdk/src/index.ts +333 -0
- package/sdk/src/init-e2e.integration.test.ts +136 -0
- package/sdk/src/init-runner.test.ts +783 -0
- package/sdk/src/init-runner.ts +735 -0
- package/sdk/src/lifecycle-e2e.integration.test.ts +258 -0
- package/sdk/src/logger.test.ts +149 -0
- package/sdk/src/logger.ts +113 -0
- package/sdk/src/milestone-runner.test.ts +421 -0
- package/sdk/src/phase-prompt.test.ts +538 -0
- package/sdk/src/phase-prompt.ts +264 -0
- package/sdk/src/phase-runner-types.test.ts +421 -0
- package/sdk/src/phase-runner.integration.test.ts +377 -0
- package/sdk/src/phase-runner.test.ts +2333 -0
- package/sdk/src/phase-runner.ts +1203 -0
- package/sdk/src/plan-parser.test.ts +528 -0
- package/sdk/src/plan-parser.ts +427 -0
- package/sdk/src/prompt-builder.test.ts +306 -0
- package/sdk/src/prompt-builder.ts +193 -0
- package/sdk/src/prompt-sanitizer.test.ts +260 -0
- package/sdk/src/prompt-sanitizer.ts +71 -0
- package/sdk/src/query/QUERY-HANDLERS.md +317 -0
- package/sdk/src/query/audit-open.ts +722 -0
- package/sdk/src/query/check-auto-mode.test.ts +77 -0
- package/sdk/src/query/check-auto-mode.ts +50 -0
- package/sdk/src/query/check-completion.test.ts +113 -0
- package/sdk/src/query/check-completion.ts +182 -0
- package/sdk/src/query/check-gates.test.ts +103 -0
- package/sdk/src/query/check-gates.ts +112 -0
- package/sdk/src/query/check-ship-ready.test.ts +77 -0
- package/sdk/src/query/check-ship-ready.ts +103 -0
- package/sdk/src/query/check-verification-status.test.ts +143 -0
- package/sdk/src/query/check-verification-status.ts +160 -0
- package/sdk/src/query/commit.test.ts +202 -0
- package/sdk/src/query/commit.ts +301 -0
- package/sdk/src/query/config-gates.test.ts +89 -0
- package/sdk/src/query/config-gates.ts +69 -0
- package/sdk/src/query/config-mutation.test.ts +365 -0
- package/sdk/src/query/config-mutation.ts +497 -0
- package/sdk/src/query/config-query.test.ts +161 -0
- package/sdk/src/query/config-query.ts +190 -0
- package/sdk/src/query/context-history.test.ts +165 -0
- package/sdk/src/query/context-history.ts +467 -0
- package/sdk/src/query/decomposed-handlers.test.ts +365 -0
- package/sdk/src/query/detect-custom-files.ts +97 -0
- package/sdk/src/query/detect-phase-type.test.ts +105 -0
- package/sdk/src/query/detect-phase-type.ts +141 -0
- package/sdk/src/query/docs-init.ts +257 -0
- package/sdk/src/query/failure-capture.ts +58 -0
- package/sdk/src/query/frontmatter-array.test.ts +14 -0
- package/sdk/src/query/frontmatter-mutation.test.ts +259 -0
- package/sdk/src/query/frontmatter-mutation.ts +343 -0
- package/sdk/src/query/frontmatter.test.ts +281 -0
- package/sdk/src/query/frontmatter.ts +397 -0
- package/sdk/src/query/helpers.test.ts +426 -0
- package/sdk/src/query/helpers.ts +482 -0
- package/sdk/src/query/index.ts +586 -0
- package/sdk/src/query/init-complex.test.ts +232 -0
- package/sdk/src/query/init-complex.ts +578 -0
- package/sdk/src/query/init.test.ts +522 -0
- package/sdk/src/query/init.ts +1046 -0
- package/sdk/src/query/intel.test.ts +90 -0
- package/sdk/src/query/intel.ts +404 -0
- package/sdk/src/query/normalize-query-command.test.ts +50 -0
- package/sdk/src/query/normalize-query-command.ts +56 -0
- package/sdk/src/query/phase-lifecycle.test.ts +1126 -0
- package/sdk/src/query/phase-lifecycle.ts +1799 -0
- package/sdk/src/query/phase-list-queries.test.ts +88 -0
- package/sdk/src/query/phase-list-queries.ts +152 -0
- package/sdk/src/query/phase-ready.test.ts +65 -0
- package/sdk/src/query/phase-ready.ts +158 -0
- package/sdk/src/query/phase.test.ts +307 -0
- package/sdk/src/query/phase.ts +340 -0
- package/sdk/src/query/pipeline.test.ts +169 -0
- package/sdk/src/query/pipeline.ts +243 -0
- package/sdk/src/query/plan-execution-route.test.ts +166 -0
- package/sdk/src/query/plan-execution-route.ts +209 -0
- package/sdk/src/query/plan-task-structure.test.ts +65 -0
- package/sdk/src/query/plan-task-structure.ts +63 -0
- package/sdk/src/query/profile-extract-messages.ts +247 -0
- package/sdk/src/query/profile-output.ts +908 -0
- package/sdk/src/query/profile-questionnaire-data.ts +181 -0
- package/sdk/src/query/profile-sample.ts +184 -0
- package/sdk/src/query/profile-scan-sessions.ts +174 -0
- package/sdk/src/query/profile.test.ts +74 -0
- package/sdk/src/query/profile.ts +337 -0
- package/sdk/src/query/progress.test.ts +156 -0
- package/sdk/src/query/progress.ts +566 -0
- package/sdk/src/query/registry.test.ts +216 -0
- package/sdk/src/query/registry.ts +174 -0
- package/sdk/src/query/requirements-extract-from-plans.test.ts +58 -0
- package/sdk/src/query/requirements-extract-from-plans.ts +86 -0
- package/sdk/src/query/roadmap-update-plan-progress.ts +132 -0
- package/sdk/src/query/roadmap.test.ts +359 -0
- package/sdk/src/query/roadmap.ts +591 -0
- package/sdk/src/query/route-next-action.test.ts +61 -0
- package/sdk/src/query/route-next-action.ts +345 -0
- package/sdk/src/query/runtime-health.ts +7 -0
- package/sdk/src/query/schema-detect.ts +189 -0
- package/sdk/src/query/skill-manifest.ts +214 -0
- package/sdk/src/query/skills.test.ts +80 -0
- package/sdk/src/query/skills.ts +62 -0
- package/sdk/src/query/state-mutation.test.ts +450 -0
- package/sdk/src/query/state-mutation.ts +1444 -0
- package/sdk/src/query/state-project-load.ts +109 -0
- package/sdk/src/query/state.test.ts +347 -0
- package/sdk/src/query/state.ts +397 -0
- package/sdk/src/query/summary.test.ts +95 -0
- package/sdk/src/query/summary.ts +296 -0
- package/sdk/src/query/template.test.ts +180 -0
- package/sdk/src/query/template.ts +242 -0
- package/sdk/src/query/uat.test.ts +77 -0
- package/sdk/src/query/uat.ts +314 -0
- package/sdk/src/query/utils.test.ts +82 -0
- package/sdk/src/query/utils.ts +92 -0
- package/sdk/src/query/validate.test.ts +656 -0
- package/sdk/src/query/validate.ts +807 -0
- package/sdk/src/query/verify.test.ts +414 -0
- package/sdk/src/query/verify.ts +645 -0
- package/sdk/src/query/websearch.test.ts +31 -0
- package/sdk/src/query/websearch.ts +82 -0
- package/sdk/src/query/workspace.test.ts +119 -0
- package/sdk/src/query/workspace.ts +131 -0
- package/sdk/src/query/workstream.test.ts +51 -0
- package/sdk/src/query/workstream.ts +434 -0
- package/sdk/src/research-gate.test.ts +190 -0
- package/sdk/src/research-gate.ts +94 -0
- package/sdk/src/runtime-health.test.ts +176 -0
- package/sdk/src/runtime-health.ts +387 -0
- package/sdk/src/session-runner.test.ts +98 -0
- package/sdk/src/session-runner.ts +299 -0
- package/sdk/src/tool-scoping.test.ts +160 -0
- package/sdk/src/tool-scoping.ts +61 -0
- package/sdk/src/types.ts +917 -0
- package/sdk/src/workstream-utils.ts +33 -0
- package/sdk/src/ws-flag.test.ts +285 -0
- package/sdk/src/ws-transport.test.ts +161 -0
- package/sdk/src/ws-transport.ts +93 -0
- package/sdk/tsconfig.json +20 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context engine — resolves which .planning/ state files exist per phase type.
|
|
3
|
+
*
|
|
4
|
+
* Different phases need different subsets of context files. The execute phase
|
|
5
|
+
* only needs STATE.md + config.json (minimal). Research needs STATE.md +
|
|
6
|
+
* ROADMAP.md + CONTEXT.md. Plan needs all files. Verify needs STATE.md +
|
|
7
|
+
* ROADMAP.md + REQUIREMENTS.md + PLAN/SUMMARY files.
|
|
8
|
+
*
|
|
9
|
+
* Context reduction (issue #1614):
|
|
10
|
+
* - Large files are truncated to keep prompts cache-friendly
|
|
11
|
+
* - ROADMAP.md is narrowed to the current milestone when possible
|
|
12
|
+
* - Truncation preserves headings + first paragraph per section
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { readFile, access } from 'node:fs/promises';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
import { constants } from 'node:fs';
|
|
18
|
+
|
|
19
|
+
import type { ContextFiles } from './types.js';
|
|
20
|
+
import { PhaseType } from './types.js';
|
|
21
|
+
import type { GSDLogger } from './logger.js';
|
|
22
|
+
import {
|
|
23
|
+
truncateMarkdown,
|
|
24
|
+
extractCurrentMilestone,
|
|
25
|
+
DEFAULT_TRUNCATION_OPTIONS,
|
|
26
|
+
type TruncationOptions,
|
|
27
|
+
} from './context-truncation.js';
|
|
28
|
+
import { relPlanningPath } from './workstream-utils.js';
|
|
29
|
+
|
|
30
|
+
// ─── File manifest per phase ─────────────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
interface FileSpec {
|
|
33
|
+
key: keyof ContextFiles;
|
|
34
|
+
filename: string;
|
|
35
|
+
required: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Define which files each phase needs. Required files emit warnings when missing;
|
|
40
|
+
* optional files silently return undefined.
|
|
41
|
+
*/
|
|
42
|
+
const PHASE_FILE_MANIFEST: Record<PhaseType, FileSpec[]> = {
|
|
43
|
+
[PhaseType.Execute]: [
|
|
44
|
+
{ key: 'state', filename: 'STATE.md', required: true },
|
|
45
|
+
{ key: 'config', filename: 'config.json', required: false },
|
|
46
|
+
],
|
|
47
|
+
[PhaseType.Research]: [
|
|
48
|
+
{ key: 'state', filename: 'STATE.md', required: true },
|
|
49
|
+
{ key: 'roadmap', filename: 'ROADMAP.md', required: true },
|
|
50
|
+
{ key: 'context', filename: 'CONTEXT.md', required: true },
|
|
51
|
+
{ key: 'requirements', filename: 'REQUIREMENTS.md', required: false },
|
|
52
|
+
],
|
|
53
|
+
[PhaseType.Plan]: [
|
|
54
|
+
{ key: 'state', filename: 'STATE.md', required: true },
|
|
55
|
+
{ key: 'roadmap', filename: 'ROADMAP.md', required: true },
|
|
56
|
+
{ key: 'context', filename: 'CONTEXT.md', required: true },
|
|
57
|
+
{ key: 'research', filename: 'RESEARCH.md', required: false },
|
|
58
|
+
{ key: 'requirements', filename: 'REQUIREMENTS.md', required: false },
|
|
59
|
+
],
|
|
60
|
+
[PhaseType.Verify]: [
|
|
61
|
+
{ key: 'state', filename: 'STATE.md', required: true },
|
|
62
|
+
{ key: 'roadmap', filename: 'ROADMAP.md', required: true },
|
|
63
|
+
{ key: 'requirements', filename: 'REQUIREMENTS.md', required: false },
|
|
64
|
+
{ key: 'plan', filename: 'PLAN.md', required: false },
|
|
65
|
+
{ key: 'summary', filename: 'SUMMARY.md', required: false },
|
|
66
|
+
],
|
|
67
|
+
[PhaseType.Repair]: [
|
|
68
|
+
{ key: 'state', filename: 'STATE.md', required: true },
|
|
69
|
+
{ key: 'config', filename: 'config.json', required: false },
|
|
70
|
+
{ key: 'plan', filename: 'PLAN.md', required: false },
|
|
71
|
+
],
|
|
72
|
+
[PhaseType.Discuss]: [
|
|
73
|
+
{ key: 'state', filename: 'STATE.md', required: true },
|
|
74
|
+
{ key: 'roadmap', filename: 'ROADMAP.md', required: false },
|
|
75
|
+
{ key: 'context', filename: 'CONTEXT.md', required: false },
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// ─── ContextEngine class ─────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
export class ContextEngine {
|
|
82
|
+
private readonly planningDir: string;
|
|
83
|
+
private readonly logger?: GSDLogger;
|
|
84
|
+
private readonly truncation: TruncationOptions;
|
|
85
|
+
|
|
86
|
+
constructor(projectDir: string, logger?: GSDLogger, truncation?: Partial<TruncationOptions>, workstream?: string) {
|
|
87
|
+
this.planningDir = join(projectDir, relPlanningPath(workstream));
|
|
88
|
+
this.logger = logger;
|
|
89
|
+
this.truncation = { ...DEFAULT_TRUNCATION_OPTIONS, ...truncation };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Resolve context files appropriate for the given phase type.
|
|
94
|
+
* Reads each file defined in the phase manifest, returning undefined
|
|
95
|
+
* for missing optional files and warning for missing required files.
|
|
96
|
+
*
|
|
97
|
+
* Files exceeding the truncation threshold are reduced to headings +
|
|
98
|
+
* first paragraphs. ROADMAP.md is narrowed to the current milestone.
|
|
99
|
+
*/
|
|
100
|
+
async resolveContextFiles(phaseType: PhaseType): Promise<ContextFiles> {
|
|
101
|
+
const manifest = PHASE_FILE_MANIFEST[phaseType];
|
|
102
|
+
const result: ContextFiles = {};
|
|
103
|
+
|
|
104
|
+
for (const spec of manifest) {
|
|
105
|
+
const filePath = join(this.planningDir, spec.filename);
|
|
106
|
+
const content = await this.readFileIfExists(filePath);
|
|
107
|
+
|
|
108
|
+
if (content !== undefined) {
|
|
109
|
+
result[spec.key] = content;
|
|
110
|
+
} else if (spec.required) {
|
|
111
|
+
this.logger?.warn(`Required context file missing for ${phaseType} phase: ${spec.filename}`, {
|
|
112
|
+
phase: phaseType,
|
|
113
|
+
file: spec.filename,
|
|
114
|
+
path: filePath,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Apply context reduction: milestone extraction then truncation
|
|
120
|
+
if (result.roadmap && result.state) {
|
|
121
|
+
const before = result.roadmap.length;
|
|
122
|
+
result.roadmap = extractCurrentMilestone(result.roadmap, result.state);
|
|
123
|
+
if (result.roadmap.length < before) {
|
|
124
|
+
this.logger?.debug?.('ROADMAP.md narrowed to current milestone', {
|
|
125
|
+
before,
|
|
126
|
+
after: result.roadmap.length,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Truncate oversized files (skip config.json — structured data, not markdown)
|
|
132
|
+
const truncatable: Array<{ key: keyof ContextFiles; filename: string }> = [
|
|
133
|
+
{ key: 'roadmap', filename: 'ROADMAP.md' },
|
|
134
|
+
{ key: 'context', filename: 'CONTEXT.md' },
|
|
135
|
+
{ key: 'research', filename: 'RESEARCH.md' },
|
|
136
|
+
{ key: 'requirements', filename: 'REQUIREMENTS.md' },
|
|
137
|
+
{ key: 'plan', filename: 'PLAN.md' },
|
|
138
|
+
{ key: 'summary', filename: 'SUMMARY.md' },
|
|
139
|
+
];
|
|
140
|
+
|
|
141
|
+
for (const { key, filename } of truncatable) {
|
|
142
|
+
const raw = result[key];
|
|
143
|
+
if (raw && raw.length > this.truncation.maxContentLength) {
|
|
144
|
+
const before = raw.length;
|
|
145
|
+
result[key] = truncateMarkdown(raw, filename, this.truncation);
|
|
146
|
+
this.logger?.debug?.(`${filename} truncated`, {
|
|
147
|
+
before,
|
|
148
|
+
after: result[key]!.length,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Check if a file exists and read it. Returns undefined if not found.
|
|
158
|
+
*/
|
|
159
|
+
private async readFileIfExists(filePath: string): Promise<string | undefined> {
|
|
160
|
+
try {
|
|
161
|
+
await access(filePath, constants.R_OK);
|
|
162
|
+
return await readFile(filePath, 'utf-8');
|
|
163
|
+
} catch {
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export { PHASE_FILE_MANIFEST };
|
|
170
|
+
export type { FileSpec };
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
truncateMarkdown,
|
|
4
|
+
extractCurrentMilestone,
|
|
5
|
+
DEFAULT_TRUNCATION_OPTIONS,
|
|
6
|
+
} from './context-truncation.js';
|
|
7
|
+
|
|
8
|
+
// ─── truncateMarkdown ───────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
describe('truncateMarkdown', () => {
|
|
11
|
+
it('returns content unchanged when below threshold', () => {
|
|
12
|
+
const content = '# Title\n\nShort content.';
|
|
13
|
+
const result = truncateMarkdown(content, 'TEST.md');
|
|
14
|
+
expect(result).toBe(content);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('truncates content above threshold, keeping headings and first paragraphs', () => {
|
|
18
|
+
const sections = [];
|
|
19
|
+
for (let i = 0; i < 20; i++) {
|
|
20
|
+
sections.push(`## Section ${i}\n\nFirst paragraph of section ${i}.\n\nSecond paragraph with lots of detail.\nMore detail here.\nEven more detail.`);
|
|
21
|
+
}
|
|
22
|
+
const content = `# Title\n\n${sections.join('\n\n')}`;
|
|
23
|
+
const result = truncateMarkdown(content, 'BIG.md', { maxContentLength: 100 });
|
|
24
|
+
|
|
25
|
+
// Headings preserved
|
|
26
|
+
expect(result).toContain('# Title');
|
|
27
|
+
expect(result).toContain('## Section 0');
|
|
28
|
+
expect(result).toContain('## Section 19');
|
|
29
|
+
|
|
30
|
+
// First paragraphs preserved
|
|
31
|
+
expect(result).toContain('First paragraph of section 0.');
|
|
32
|
+
expect(result).toContain('First paragraph of section 19.');
|
|
33
|
+
|
|
34
|
+
// Second paragraphs omitted
|
|
35
|
+
expect(result).not.toContain('Second paragraph');
|
|
36
|
+
expect(result).not.toContain('More detail here.');
|
|
37
|
+
|
|
38
|
+
// Truncation markers present
|
|
39
|
+
expect(result).toContain('[...');
|
|
40
|
+
expect(result).toContain('lines omitted]');
|
|
41
|
+
expect(result).toContain('[Truncated: read .planning/BIG.md for full content]');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('preserves YAML frontmatter entirely', () => {
|
|
45
|
+
const content = `---\nphase: "01"\nstatus: active\n---\n\n# Title\n\nParagraph 1.\n\nParagraph 2.\n${'x'.repeat(10000)}`;
|
|
46
|
+
const result = truncateMarkdown(content, 'STATE.md', { maxContentLength: 100 });
|
|
47
|
+
|
|
48
|
+
expect(result).toContain('---\nphase: "01"\nstatus: active\n---');
|
|
49
|
+
expect(result).toContain('# Title');
|
|
50
|
+
expect(result).toContain('Paragraph 1.');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('is smaller than original when truncated', () => {
|
|
54
|
+
const longContent = Array.from({ length: 200 }, (_, i) =>
|
|
55
|
+
`## Section ${i}\n\nFirst paragraph.\n\nLong detail paragraph ${'x'.repeat(100)}.`
|
|
56
|
+
).join('\n\n');
|
|
57
|
+
|
|
58
|
+
const result = truncateMarkdown(longContent, 'HUGE.md', { maxContentLength: 100 });
|
|
59
|
+
expect(result.length).toBeLessThan(longContent.length);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('handles content with no headings', () => {
|
|
63
|
+
const content = `First line.\n\nSecond paragraph.\n\nThird paragraph.\n${'x'.repeat(10000)}`;
|
|
64
|
+
const result = truncateMarkdown(content, 'FLAT.md', { maxContentLength: 100 });
|
|
65
|
+
|
|
66
|
+
// Should still truncate — first paragraph kept
|
|
67
|
+
expect(result).toContain('First line.');
|
|
68
|
+
expect(result.length).toBeLessThan(content.length);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('default threshold is 8192 characters', () => {
|
|
72
|
+
expect(DEFAULT_TRUNCATION_OPTIONS.maxContentLength).toBe(8192);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// ─── extractCurrentMilestone ────────────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
describe('extractCurrentMilestone', () => {
|
|
79
|
+
const makeRoadmap = () => `# Project Roadmap
|
|
80
|
+
|
|
81
|
+
## Milestone 1: Foundation
|
|
82
|
+
### Phase 01: Setup
|
|
83
|
+
Requirements for setup.
|
|
84
|
+
### Phase 02: Core
|
|
85
|
+
Requirements for core.
|
|
86
|
+
|
|
87
|
+
## Milestone 2: Features
|
|
88
|
+
### Phase 03: Auth
|
|
89
|
+
Requirements for auth.
|
|
90
|
+
### Phase 04: API
|
|
91
|
+
Requirements for API.
|
|
92
|
+
|
|
93
|
+
## Milestone 3: Polish
|
|
94
|
+
### Phase 05: UI
|
|
95
|
+
Requirements for UI.`;
|
|
96
|
+
|
|
97
|
+
it('returns full roadmap when no state provided', () => {
|
|
98
|
+
const roadmap = makeRoadmap();
|
|
99
|
+
expect(extractCurrentMilestone(roadmap)).toBe(roadmap);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('returns full roadmap when milestone not found in state', () => {
|
|
103
|
+
const roadmap = makeRoadmap();
|
|
104
|
+
const state = '# State\nstatus: active';
|
|
105
|
+
expect(extractCurrentMilestone(roadmap, state)).toBe(roadmap);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('extracts current milestone section by name', () => {
|
|
109
|
+
const roadmap = makeRoadmap();
|
|
110
|
+
const state = 'Current Milestone: Features';
|
|
111
|
+
const result = extractCurrentMilestone(roadmap, state);
|
|
112
|
+
|
|
113
|
+
expect(result).toContain('## Milestone 2: Features');
|
|
114
|
+
expect(result).toContain('### Phase 03: Auth');
|
|
115
|
+
expect(result).toContain('### Phase 04: API');
|
|
116
|
+
|
|
117
|
+
// Other milestones omitted
|
|
118
|
+
expect(result).not.toContain('### Phase 01: Setup');
|
|
119
|
+
expect(result).not.toContain('### Phase 05: UI');
|
|
120
|
+
expect(result).toContain('other milestone(s) omitted');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('matches milestone name case-insensitively', () => {
|
|
124
|
+
const roadmap = makeRoadmap();
|
|
125
|
+
const state = 'current milestone: features';
|
|
126
|
+
const result = extractCurrentMilestone(roadmap, state);
|
|
127
|
+
|
|
128
|
+
expect(result).toContain('## Milestone 2: Features');
|
|
129
|
+
expect(result).not.toContain('### Phase 01: Setup');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('matches milestone from "milestone:" field in state', () => {
|
|
133
|
+
const roadmap = makeRoadmap();
|
|
134
|
+
const state = '# State\nmilestone: Foundation\nphase: 01';
|
|
135
|
+
const result = extractCurrentMilestone(roadmap, state);
|
|
136
|
+
|
|
137
|
+
expect(result).toContain('## Milestone 1: Foundation');
|
|
138
|
+
expect(result).toContain('### Phase 01: Setup');
|
|
139
|
+
expect(result).not.toContain('### Phase 03: Auth');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('matches milestone from Current Position block', () => {
|
|
143
|
+
const roadmap = makeRoadmap();
|
|
144
|
+
const state = `# State
|
|
145
|
+
|
|
146
|
+
## Current Position
|
|
147
|
+
milestone: Polish
|
|
148
|
+
phase: 05`;
|
|
149
|
+
const result = extractCurrentMilestone(roadmap, state);
|
|
150
|
+
|
|
151
|
+
expect(result).toContain('## Milestone 3: Polish');
|
|
152
|
+
expect(result).toContain('### Phase 05: UI');
|
|
153
|
+
expect(result).not.toContain('### Phase 01: Setup');
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('preserves roadmap title in output', () => {
|
|
157
|
+
const roadmap = makeRoadmap();
|
|
158
|
+
const state = 'Current Milestone: Features';
|
|
159
|
+
const result = extractCurrentMilestone(roadmap, state);
|
|
160
|
+
|
|
161
|
+
expect(result).toContain('# Project Roadmap');
|
|
162
|
+
});
|
|
163
|
+
});
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context truncation — reduces large .planning/ files to cache-friendly sizes.
|
|
3
|
+
*
|
|
4
|
+
* Two strategies:
|
|
5
|
+
* 1. Markdown-aware truncation: keeps headings + first paragraph per section,
|
|
6
|
+
* replaces the rest with a pointer to the full file.
|
|
7
|
+
* 2. Milestone extraction: pulls only the current milestone from ROADMAP.md.
|
|
8
|
+
*
|
|
9
|
+
* All functions are pure — no I/O, no side effects.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// ─── Types ──────────────────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
export interface TruncationOptions {
|
|
15
|
+
/** Max content length in characters before truncation kicks in. Default: 8192 */
|
|
16
|
+
maxContentLength: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const DEFAULT_TRUNCATION_OPTIONS: TruncationOptions = {
|
|
20
|
+
maxContentLength: 8192,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// ─── Markdown-aware truncation ──────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Truncate markdown content while preserving structure.
|
|
27
|
+
*
|
|
28
|
+
* Strategy: keep YAML frontmatter, all headings, and the first paragraph under
|
|
29
|
+
* each heading. Collapse everything else with a line count summary.
|
|
30
|
+
*
|
|
31
|
+
* Returns the original content unchanged if below maxContentLength.
|
|
32
|
+
*/
|
|
33
|
+
export function truncateMarkdown(
|
|
34
|
+
content: string,
|
|
35
|
+
filename: string,
|
|
36
|
+
options: TruncationOptions = DEFAULT_TRUNCATION_OPTIONS,
|
|
37
|
+
): string {
|
|
38
|
+
if (content.length <= options.maxContentLength) return content;
|
|
39
|
+
|
|
40
|
+
const lines = content.split('\n');
|
|
41
|
+
const kept: string[] = [];
|
|
42
|
+
let inFrontmatter = false;
|
|
43
|
+
let frontmatterDone = false;
|
|
44
|
+
let currentSectionLines = 0;
|
|
45
|
+
let paragraphKept = false;
|
|
46
|
+
let omittedLines = 0;
|
|
47
|
+
let inParagraph = false;
|
|
48
|
+
|
|
49
|
+
for (let i = 0; i < lines.length; i++) {
|
|
50
|
+
const line = lines[i];
|
|
51
|
+
|
|
52
|
+
// Handle YAML frontmatter (preserve entirely)
|
|
53
|
+
if (i === 0 && line.trim() === '---') {
|
|
54
|
+
inFrontmatter = true;
|
|
55
|
+
kept.push(line);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (inFrontmatter) {
|
|
59
|
+
kept.push(line);
|
|
60
|
+
if (line.trim() === '---') {
|
|
61
|
+
inFrontmatter = false;
|
|
62
|
+
frontmatterDone = true;
|
|
63
|
+
}
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Heading — always keep, reset paragraph tracking
|
|
68
|
+
if (/^#{1,6}\s/.test(line)) {
|
|
69
|
+
if (omittedLines > 0) {
|
|
70
|
+
kept.push(`[... ${omittedLines} lines omitted]`);
|
|
71
|
+
omittedLines = 0;
|
|
72
|
+
}
|
|
73
|
+
kept.push(line);
|
|
74
|
+
currentSectionLines = 0;
|
|
75
|
+
paragraphKept = false;
|
|
76
|
+
inParagraph = false;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Empty line — paragraph boundary
|
|
81
|
+
if (line.trim() === '') {
|
|
82
|
+
if (inParagraph && !paragraphKept) {
|
|
83
|
+
// End of first paragraph — mark it kept
|
|
84
|
+
paragraphKept = true;
|
|
85
|
+
}
|
|
86
|
+
if (!paragraphKept || currentSectionLines === 0) {
|
|
87
|
+
kept.push(line);
|
|
88
|
+
} else {
|
|
89
|
+
omittedLines++;
|
|
90
|
+
}
|
|
91
|
+
inParagraph = false;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Content line
|
|
96
|
+
currentSectionLines++;
|
|
97
|
+
if (!paragraphKept) {
|
|
98
|
+
// Still in the first paragraph — keep it
|
|
99
|
+
kept.push(line);
|
|
100
|
+
inParagraph = true;
|
|
101
|
+
} else {
|
|
102
|
+
omittedLines++;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (omittedLines > 0) {
|
|
107
|
+
kept.push(`[... ${omittedLines} lines omitted]`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const totalOmitted = lines.length - kept.length;
|
|
111
|
+
if (totalOmitted > 0) {
|
|
112
|
+
kept.push('');
|
|
113
|
+
kept.push(`[Truncated: read .planning/${filename} for full content]`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return kept.join('\n');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ─── Milestone extraction ───────────────────────────────────────────────────
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Extract the current milestone section from a ROADMAP.md.
|
|
123
|
+
*
|
|
124
|
+
* Parses STATE.md to find the current milestone name, then extracts only
|
|
125
|
+
* that milestone's section from the roadmap. Falls back to full content
|
|
126
|
+
* if the milestone can't be identified or found.
|
|
127
|
+
*/
|
|
128
|
+
export function extractCurrentMilestone(
|
|
129
|
+
roadmapContent: string,
|
|
130
|
+
stateContent?: string,
|
|
131
|
+
): string {
|
|
132
|
+
if (!stateContent) return roadmapContent;
|
|
133
|
+
|
|
134
|
+
// Find current milestone from STATE.md
|
|
135
|
+
// Patterns: "Current Milestone: X", "milestone: X", "## Current Position" block
|
|
136
|
+
const milestonePatterns = [
|
|
137
|
+
/current\s*milestone\s*:\s*(.+)/i,
|
|
138
|
+
/^milestone\s*:\s*(.+)/im,
|
|
139
|
+
/##\s*current\s*position[\s\S]*?milestone\s*:\s*(.+)/i,
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
let milestoneName: string | undefined;
|
|
143
|
+
for (const pattern of milestonePatterns) {
|
|
144
|
+
const match = stateContent.match(pattern);
|
|
145
|
+
if (match) {
|
|
146
|
+
milestoneName = match[1].trim();
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!milestoneName) return roadmapContent;
|
|
152
|
+
|
|
153
|
+
// Find the milestone section in roadmap
|
|
154
|
+
// Look for heading containing the milestone name
|
|
155
|
+
const lines = roadmapContent.split('\n');
|
|
156
|
+
let sectionStart = -1;
|
|
157
|
+
let sectionEnd = lines.length;
|
|
158
|
+
let sectionHeadingLevel = 0;
|
|
159
|
+
|
|
160
|
+
for (let i = 0; i < lines.length; i++) {
|
|
161
|
+
const headingMatch = lines[i].match(/^(#{1,6})\s+(.+)/);
|
|
162
|
+
if (!headingMatch) continue;
|
|
163
|
+
|
|
164
|
+
const level = headingMatch[1].length;
|
|
165
|
+
const title = headingMatch[2];
|
|
166
|
+
|
|
167
|
+
if (sectionStart === -1) {
|
|
168
|
+
// Looking for the milestone heading
|
|
169
|
+
if (title.toLowerCase().includes(milestoneName.toLowerCase())) {
|
|
170
|
+
sectionStart = i;
|
|
171
|
+
sectionHeadingLevel = level;
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
// Found start — look for next heading at same or higher level
|
|
175
|
+
if (level <= sectionHeadingLevel) {
|
|
176
|
+
sectionEnd = i;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (sectionStart === -1) return roadmapContent;
|
|
183
|
+
|
|
184
|
+
// Extract preamble (everything before first milestone heading at the same level)
|
|
185
|
+
const preamble: string[] = [];
|
|
186
|
+
for (let i = 0; i < lines.length; i++) {
|
|
187
|
+
const headingMatch = lines[i].match(/^(#{1,6})\s/);
|
|
188
|
+
if (headingMatch && headingMatch[1].length === sectionHeadingLevel && i !== sectionStart) {
|
|
189
|
+
// Hit another milestone-level heading before our section
|
|
190
|
+
if (i < sectionStart) {
|
|
191
|
+
break; // preamble ends at first milestone heading
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (i < sectionStart) {
|
|
195
|
+
// Keep top-level title and intro
|
|
196
|
+
if (i === 0 || lines[i].match(/^#\s/) || !lines[i].match(/^#{1,6}\s/)) {
|
|
197
|
+
preamble.push(lines[i]);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const milestoneSection = lines.slice(sectionStart, sectionEnd).join('\n');
|
|
203
|
+
const otherMilestones = countOtherMilestones(lines, sectionHeadingLevel, sectionStart);
|
|
204
|
+
|
|
205
|
+
const result = [
|
|
206
|
+
...preamble,
|
|
207
|
+
'',
|
|
208
|
+
milestoneSection,
|
|
209
|
+
];
|
|
210
|
+
|
|
211
|
+
if (otherMilestones > 0) {
|
|
212
|
+
result.push('');
|
|
213
|
+
result.push(`[${otherMilestones} other milestone(s) omitted — read .planning/ROADMAP.md for full roadmap]`);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return result.join('\n').trim();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function countOtherMilestones(
|
|
220
|
+
lines: string[],
|
|
221
|
+
headingLevel: number,
|
|
222
|
+
excludeIndex: number,
|
|
223
|
+
): number {
|
|
224
|
+
let count = 0;
|
|
225
|
+
for (let i = 0; i < lines.length; i++) {
|
|
226
|
+
if (i === excludeIndex) continue;
|
|
227
|
+
const match = lines[i].match(/^(#{1,6})\s/);
|
|
228
|
+
if (match && match[1].length === headingLevel) {
|
|
229
|
+
count++;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return count;
|
|
233
|
+
}
|