@danmoisan/drm-copilot-mcp 0.0.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/LICENSE +21 -0
- package/README.md +50 -0
- package/out/mcp-server.js +17323 -0
- package/package.json +36 -0
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/MEMORY.md +3 -0
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_repo_root_is_source_of_truth.md +11 -0
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_vsce_verify_package_location.md +19 -0
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/project_extension_location.md +11 -0
- package/resources/claude-customizations/.claude/agent-memory/prd-feature/MEMORY.md +1 -0
- package/resources/claude-customizations/.claude/agent-memory/prd-feature/project_push_down_pattern.md +13 -0
- package/resources/claude-customizations/.claude/agent-memory/task-researcher/MEMORY.md +3 -0
- package/resources/claude-customizations/.claude/agent-memory/task-researcher/project_push_down_claude_dir.md +11 -0
- package/resources/claude-customizations/.claude/agents/atomic-executor.md +135 -0
- package/resources/claude-customizations/.claude/agents/atomic-planner.md +71 -0
- package/resources/claude-customizations/.claude/agents/csharp-typed-engineer.md +69 -0
- package/resources/claude-customizations/.claude/agents/epic-review.md +40 -0
- package/resources/claude-customizations/.claude/agents/feature-review.md +136 -0
- package/resources/claude-customizations/.claude/agents/orchestrator.md +83 -0
- package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +80 -0
- package/resources/claude-customizations/.claude/agents/prd-feature.md +42 -0
- package/resources/claude-customizations/.claude/agents/python-typed-engineer.md +72 -0
- package/resources/claude-customizations/.claude/agents/staged-review.md +41 -0
- package/resources/claude-customizations/.claude/agents/status-updater.md +41 -0
- package/resources/claude-customizations/.claude/agents/task-researcher.md +81 -0
- package/resources/claude-customizations/.claude/agents/typescript-engineer.md +24 -0
- package/resources/claude-customizations/.claude/hooks/check-powershell-test-purity.ps1 +111 -0
- package/resources/claude-customizations/.claude/hooks/check-python-test-purity.ps1 +146 -0
- package/resources/claude-customizations/.claude/hooks/enforce-evidence-locations.ps1 +150 -0
- package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +238 -0
- package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +147 -0
- package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +235 -0
- package/resources/claude-customizations/.claude/hooks/validate-bash.ps1 +69 -0
- package/resources/claude-customizations/.claude/hooks/validate-executor-output.ps1 +296 -0
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage.ps1 +389 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +141 -0
- package/resources/claude-customizations/.claude/hooks/validate-planner-output.ps1 +288 -0
- package/resources/claude-customizations/.claude/hooks/validate-required-artifact-output.ps1 +171 -0
- package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +142 -0
- package/resources/claude-customizations/.claude/rules/csharp.md +62 -0
- package/resources/claude-customizations/.claude/rules/general-code-change.md +71 -0
- package/resources/claude-customizations/.claude/rules/general-unit-test.md +60 -0
- package/resources/claude-customizations/.claude/rules/powershell.md +97 -0
- package/resources/claude-customizations/.claude/rules/python-suppressions.md +143 -0
- package/resources/claude-customizations/.claude/rules/python.md +99 -0
- package/resources/claude-customizations/.claude/rules/self-explanatory-code-commenting.md +97 -0
- package/resources/claude-customizations/.claude/rules/tonality.md +80 -0
- package/resources/claude-customizations/.claude/rules/typescript-suppressions.md +66 -0
- package/resources/claude-customizations/.claude/rules/typescript.md +45 -0
- package/resources/claude-customizations/.claude/settings.json +144 -0
- package/resources/claude-customizations/.claude/skills/acceptance-criteria-tracking/SKILL.md +102 -0
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +189 -0
- package/resources/claude-customizations/.claude/skills/commit-message/SKILL.md +65 -0
- package/resources/claude-customizations/.claude/skills/csharp-change-budget-router/SKILL.md +90 -0
- package/resources/claude-customizations/.claude/skills/csharp-orchestration-state-machine/SKILL.md +58 -0
- package/resources/claude-customizations/.claude/skills/csharp-qa-gate/SKILL.md +77 -0
- package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +164 -0
- package/resources/claude-customizations/.claude/skills/execute-hard-lock/SKILL.md +82 -0
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +115 -0
- package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +167 -0
- package/resources/claude-customizations/.claude/skills/fill-feature-docs/SKILL.md +22 -0
- package/resources/claude-customizations/.claude/skills/invoke-csharp-engineer/SKILL.md +64 -0
- package/resources/claude-customizations/.claude/skills/invoke-powershell-engineer/SKILL.md +65 -0
- package/resources/claude-customizations/.claude/skills/invoke-python-engineer/SKILL.md +64 -0
- package/resources/claude-customizations/.claude/skills/make-skill-template/SKILL.md +147 -0
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +132 -0
- package/resources/claude-customizations/.claude/skills/policy-audit-template-usage/SKILL.md +49 -0
- package/resources/claude-customizations/.claude/skills/policy-compliance-order/SKILL.md +40 -0
- package/resources/claude-customizations/.claude/skills/powershell-change-budget-router/SKILL.md +49 -0
- package/resources/claude-customizations/.claude/skills/powershell-orchestration-state-machine/SKILL.md +58 -0
- package/resources/claude-customizations/.claude/skills/powershell-qa-gate/SKILL.md +77 -0
- package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +50 -0
- package/resources/claude-customizations/.claude/skills/pr-base-branch-merge-base/SKILL.md +56 -0
- package/resources/claude-customizations/.claude/skills/pr-context-artifacts/SKILL.md +30 -0
- package/resources/claude-customizations/.claude/skills/python-change-budget-router/SKILL.md +79 -0
- package/resources/claude-customizations/.claude/skills/python-qa-gate/SKILL.md +77 -0
- package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +40 -0
- package/resources/claude-customizations/.claude/skills/research-issue/SKILL.md +67 -0
- package/resources/claude-customizations/.claude/skills/review-epic/SKILL.md +21 -0
- package/resources/claude-customizations/.claude/skills/review-feature/SKILL.md +25 -0
- package/resources/claude-customizations/.claude/skills/review-staged/SKILL.md +21 -0
- package/resources/claude-customizations/.claude/skills/skill-canonical-location-audit/SKILL.md +49 -0
- package/resources/claude-customizations/.claude/skills/translate-copilot-to-claude/SKILL.md +295 -0
- package/resources/claude-customizations/.claude/skills/update-status/SKILL.md +21 -0
- package/resources/claude-dir-customizations/.mcp.json +8 -0
- package/resources/codex-and-agents-customizations/.agents/README.md +86 -0
- package/resources/codex-and-agents-customizations/.agents/skills/README.md +49 -0
- package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +107 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-executor/SKILL.md +73 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +194 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +87 -0
- package/resources/codex-and-agents-customizations/.agents/skills/commit-message/SKILL.md +70 -0
- package/resources/codex-and-agents-customizations/.agents/skills/commit-message-conventions/SKILL.md +95 -0
- package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +67 -0
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-change-budget-router/SKILL.md +94 -0
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-orchestration-state-machine/SKILL.md +64 -0
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +82 -0
- package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +168 -0
- package/resources/codex-and-agents-customizations/.agents/skills/execute-hard-lock/SKILL.md +88 -0
- package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +129 -0
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +106 -0
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +181 -0
- package/resources/codex-and-agents-customizations/.agents/skills/fill-feature-docs/SKILL.md +27 -0
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-csharp-engineer/SKILL.md +73 -0
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-powershell-engineer/SKILL.md +74 -0
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-python-engineer/SKILL.md +73 -0
- package/resources/codex-and-agents-customizations/.agents/skills/make-skill-template/SKILL.md +152 -0
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +143 -0
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +317 -0
- package/resources/codex-and-agents-customizations/.agents/skills/policy-audit-template-usage/SKILL.md +53 -0
- package/resources/codex-and-agents-customizations/.agents/skills/policy-compliance-order/SKILL.md +49 -0
- package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +102 -0
- package/resources/codex-and-agents-customizations/.agents/skills/powershell-change-budget-router/SKILL.md +53 -0
- package/resources/codex-and-agents-customizations/.agents/skills/powershell-orchestration-state-machine/SKILL.md +64 -0
- package/resources/codex-and-agents-customizations/.agents/skills/powershell-qa-gate/SKILL.md +83 -0
- package/resources/codex-and-agents-customizations/.agents/skills/pr-author/SKILL.md +55 -0
- package/resources/codex-and-agents-customizations/.agents/skills/pr-authoring/SKILL.md +124 -0
- package/resources/codex-and-agents-customizations/.agents/skills/pr-base-branch-merge-base/SKILL.md +60 -0
- package/resources/codex-and-agents-customizations/.agents/skills/pr-context-artifacts/SKILL.md +34 -0
- package/resources/codex-and-agents-customizations/.agents/skills/python/SKILL.md +104 -0
- package/resources/codex-and-agents-customizations/.agents/skills/python-change-budget-router/SKILL.md +84 -0
- package/resources/codex-and-agents-customizations/.agents/skills/python-qa-gate/SKILL.md +82 -0
- package/resources/codex-and-agents-customizations/.agents/skills/python-suppressions/SKILL.md +148 -0
- package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +49 -0
- package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/SKILL.md +142 -0
- package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/agents/openai.yaml +5 -0
- package/resources/codex-and-agents-customizations/.agents/skills/research-issue/SKILL.md +72 -0
- package/resources/codex-and-agents-customizations/.agents/skills/review-epic/SKILL.md +26 -0
- package/resources/codex-and-agents-customizations/.agents/skills/review-feature/SKILL.md +30 -0
- package/resources/codex-and-agents-customizations/.agents/skills/review-staged/SKILL.md +26 -0
- package/resources/codex-and-agents-customizations/.agents/skills/self-explanatory-code-commenting/SKILL.md +102 -0
- package/resources/codex-and-agents-customizations/.agents/skills/skill-canonical-location-audit/SKILL.md +52 -0
- package/resources/codex-and-agents-customizations/.agents/skills/translate-copilot-to-claude/SKILL.md +317 -0
- package/resources/codex-and-agents-customizations/.agents/skills/typescript/SKILL.md +50 -0
- package/resources/codex-and-agents-customizations/.agents/skills/typescript-suppressions/SKILL.md +71 -0
- package/resources/codex-and-agents-customizations/.agents/skills/update-status/SKILL.md +26 -0
- package/resources/codex-and-agents-customizations/.codex/agents/5.1-beast-adjusted.toml +23 -0
- package/resources/codex-and-agents-customizations/.codex/agents/5.1-thinking-beast-mode-adjusted.toml +23 -0
- package/resources/codex-and-agents-customizations/.codex/agents/api-architect.toml +23 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +151 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner.toml +93 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planning.toml +24 -0
- package/resources/codex-and-agents-customizations/.codex/agents/commentary-remediation.toml +23 -0
- package/resources/codex-and-agents-customizations/.codex/agents/commit-steward.toml +20 -0
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-atomic-executor.toml +24 -0
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-atomic-planning.toml +25 -0
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-orchestrator.toml +56 -0
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer.toml +97 -0
- package/resources/codex-and-agents-customizations/.codex/agents/epic-review.toml +52 -0
- package/resources/codex-and-agents-customizations/.codex/agents/expert-nextjs-developer.toml +23 -0
- package/resources/codex-and-agents-customizations/.codex/agents/expert-react-frontend-engineer.toml +23 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +149 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer.toml +60 -0
- package/resources/codex-and-agents-customizations/.codex/agents/gpt-5-beast-mode.toml +23 -0
- package/resources/codex-and-agents-customizations/.codex/agents/hlbpa.toml +23 -0
- package/resources/codex-and-agents-customizations/.codex/agents/mentor.toml +23 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +121 -0
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-atomic-executor.toml +24 -0
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-atomic-planning.toml +25 -0
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-di-unit-test-engineer.toml +24 -0
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-orchestrator.toml +56 -0
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +108 -0
- package/resources/codex-and-agents-customizations/.codex/agents/pr-author.toml +26 -0
- package/resources/codex-and-agents-customizations/.codex/agents/prd-feature.toml +53 -0
- package/resources/codex-and-agents-customizations/.codex/agents/prd.toml +23 -0
- package/resources/codex-and-agents-customizations/.codex/agents/pytest-unit-test-coding.toml +24 -0
- package/resources/codex-and-agents-customizations/.codex/agents/python-atomic-executor.toml +24 -0
- package/resources/codex-and-agents-customizations/.codex/agents/python-atomic-planning.toml +25 -0
- package/resources/codex-and-agents-customizations/.codex/agents/python-execution-only-typed.toml +24 -0
- package/resources/codex-and-agents-customizations/.codex/agents/python-orchestrator.toml +54 -0
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer.toml +100 -0
- package/resources/codex-and-agents-customizations/.codex/agents/staged-review.toml +53 -0
- package/resources/codex-and-agents-customizations/.codex/agents/status-updater.toml +53 -0
- package/resources/codex-and-agents-customizations/.codex/agents/task-researcher.toml +103 -0
- package/resources/codex-and-agents-customizations/.codex/agents/tdd-green.toml +23 -0
- package/resources/codex-and-agents-customizations/.codex/agents/tdd-red.toml +23 -0
- package/resources/codex-and-agents-customizations/.codex/agents/tdd-refactor.toml +23 -0
- package/resources/codex-and-agents-customizations/.codex/agents/typescript-engineer.toml +48 -0
- package/resources/codex-and-agents-customizations/.codex/agents/voidbeast-gpt41enhanced.toml +23 -0
- package/resources/codex-and-agents-customizations/.codex/codex-web-setup.plan.md +26 -0
- package/resources/codex-and-agents-customizations/.codex/codex-web-setup.sh +384 -0
- package/resources/codex-and-agents-customizations/.codex/config.toml +137 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/check-powershell-test-purity.ps1 +113 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/check-python-test-purity.ps1 +149 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-evidence-locations.ps1 +153 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +241 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +150 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +238 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-bash.ps1 +72 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-feature-review-coverage.ps1 +265 -0
- package/resources/codex-and-agents-customizations/.codex/prompts/feature-review-remediate.md +10 -0
- package/resources/codex-and-agents-customizations/.codex/prompts/generate-commit-message-repo.md +11 -0
- package/resources/codex-and-agents-customizations/.codex/prompts/generate-pr.md +15 -0
- package/resources/codex-and-agents-customizations/.codex/prompts/orchestrate-work.md +22 -0
- package/resources/codex-and-agents-customizations/AGENTS.md +317 -0
- package/resources/customizations/.github/agents/5.1-Beast-adjusted.agent.md +181 -0
- package/resources/customizations/.github/agents/5.1-Thinking-Beast-Mode-adjusted.agent.md +361 -0
- package/resources/customizations/.github/agents/Powershell DI Unit Test Engineer.agent.md +192 -0
- package/resources/customizations/.github/agents/api-architect.agent.md +40 -0
- package/resources/customizations/.github/agents/atomic_executor.agent.md +251 -0
- package/resources/customizations/.github/agents/atomic_planning.agent.md +658 -0
- package/resources/customizations/.github/agents/commentary-remediation.agent.md +35 -0
- package/resources/customizations/.github/agents/commit-steward.agent.md +200 -0
- package/resources/customizations/.github/agents/csharp-atomic-executor.agent.md +288 -0
- package/resources/customizations/.github/agents/csharp-atomic-planning.agent.md +354 -0
- package/resources/customizations/.github/agents/csharp-orchestrator.agent.md +375 -0
- package/resources/customizations/.github/agents/csharp-typed-engineer.agent.md +285 -0
- package/resources/customizations/.github/agents/epic-review.agent.md +374 -0
- package/resources/customizations/.github/agents/expert-nextjs-developer.agent.md +477 -0
- package/resources/customizations/.github/agents/expert-react-frontend-engineer.agent.md +739 -0
- package/resources/customizations/.github/agents/feature-review.agent.md +49 -0
- package/resources/customizations/.github/agents/gpt-5-beast-mode.agent.md +116 -0
- package/resources/customizations/.github/agents/hlbpa.agent.md +219 -0
- package/resources/customizations/.github/agents/mentor.agent.md +32 -0
- package/resources/customizations/.github/agents/orchestrator.agent.md +449 -0
- package/resources/customizations/.github/agents/powershell-atomic-executor.agent.md +287 -0
- package/resources/customizations/.github/agents/powershell-atomic-planning.agent.md +647 -0
- package/resources/customizations/.github/agents/powershell-orchestrator.agent.md +382 -0
- package/resources/customizations/.github/agents/powershell-typed-engineer.agent.md +293 -0
- package/resources/customizations/.github/agents/pr-author.agent.md +138 -0
- package/resources/customizations/.github/agents/prd-feature.agent.md +52 -0
- package/resources/customizations/.github/agents/prd.agent.md +202 -0
- package/resources/customizations/.github/agents/pytest-unit-test-coding.agent.md +202 -0
- package/resources/customizations/.github/agents/python-atomic-executor.agent.md +289 -0
- package/resources/customizations/.github/agents/python-atomic-planning.agent.md +429 -0
- package/resources/customizations/.github/agents/python-execution-only-typed.agent.md +217 -0
- package/resources/customizations/.github/agents/python-orchestrator.agent.md +380 -0
- package/resources/customizations/.github/agents/python-typed-engineer.agent.md +271 -0
- package/resources/customizations/.github/agents/staged-review.agent.md +246 -0
- package/resources/customizations/.github/agents/status_updater.agent.md +279 -0
- package/resources/customizations/.github/agents/task-researcher.agent.md +298 -0
- package/resources/customizations/.github/agents/tdd-green.agent.md +60 -0
- package/resources/customizations/.github/agents/tdd-red.agent.md +66 -0
- package/resources/customizations/.github/agents/tdd-refactor.agent.md +94 -0
- package/resources/customizations/.github/agents/typescript-engineer.agent.md +167 -0
- package/resources/customizations/.github/agents/voidbeast-gpt41enhanced.agent.md +230 -0
- package/resources/customizations/.github/codex/execute-hard-lock.prompt.md +105 -0
- package/resources/customizations/.github/codex/resume-hard-lock.prompt.md +92 -0
- package/resources/customizations/.github/copilot-instructions.md +7 -0
- package/resources/customizations/.github/instructions/csharp-code-change.instructions.md +184 -0
- package/resources/customizations/.github/instructions/csharp-unit-test.instructions.md +52 -0
- package/resources/customizations/.github/instructions/general-code-change.instructions.md +290 -0
- package/resources/customizations/.github/instructions/general-unit-test.instructions.md +106 -0
- package/resources/customizations/.github/instructions/github-actions-ci-cd-best-practices.instructions.md +607 -0
- package/resources/customizations/.github/instructions/github-actions.instructions.md +23 -0
- package/resources/customizations/.github/instructions/powershell-code-change.instructions.md +81 -0
- package/resources/customizations/.github/instructions/powershell-unit-test.instructions.md +69 -0
- package/resources/customizations/.github/instructions/python-code-change.instructions.md +232 -0
- package/resources/customizations/.github/instructions/python-suppressions.instructions.md +609 -0
- package/resources/customizations/.github/instructions/python-unit-test.instructions.md +71 -0
- package/resources/customizations/.github/instructions/self-explanatory-code-commenting.instructions.md +238 -0
- package/resources/customizations/.github/instructions/tonality.instructions.md +133 -0
- package/resources/customizations/.github/instructions/typescript-code-change.instructions.md +203 -0
- package/resources/customizations/.github/instructions/typescript-suppressions.instructions.md +157 -0
- package/resources/customizations/.github/instructions/typescript-unit-test.instructions.md +112 -0
- package/resources/customizations/.github/prompts/add-educational-comments.prompt.md +129 -0
- package/resources/customizations/.github/prompts/breakdown-bug-prd.prompt.md +29 -0
- package/resources/customizations/.github/prompts/breakdown-epic-arch.prompt.md +66 -0
- package/resources/customizations/.github/prompts/breakdown-epic-pm.prompt.md +58 -0
- package/resources/customizations/.github/prompts/breakdown-feature-implementation.prompt.md +128 -0
- package/resources/customizations/.github/prompts/breakdown-feature-prd.prompt.md +61 -0
- package/resources/customizations/.github/prompts/code-exemplars-blueprint-generator.prompt.md +126 -0
- package/resources/customizations/.github/prompts/drafts/create-github-issues-feature-from-implementation-plan.prompt.md +28 -0
- package/resources/customizations/.github/prompts/drafts/create-implementation-plan.prompt.md +158 -0
- package/resources/customizations/.github/prompts/drafts/create-technical-spike.prompt.md +231 -0
- package/resources/customizations/.github/prompts/drafts/potential-feature-prd.prompt.md +19 -0
- package/resources/customizations/.github/prompts/drafts/update-implementation-plan.prompt.md +158 -0
- package/resources/customizations/.github/prompts/execute-plan-template.md +21 -0
- package/resources/customizations/.github/prompts/export-chat.prompt.md +7 -0
- package/resources/customizations/.github/prompts/fillout-prd-feature.prompt.md +46 -0
- package/resources/customizations/.github/prompts/generate-atomic-plan.prompt.md +96 -0
- package/resources/customizations/.github/prompts/generate-commit-message-repo.prompt.md +108 -0
- package/resources/customizations/.github/prompts/generate-pr.prompt.md +151 -0
- package/resources/customizations/.github/prompts/javascript-typescript-jest.prompt.md +44 -0
- package/resources/customizations/.github/prompts/orchestrate-csharp-work.prompt.md +66 -0
- package/resources/customizations/.github/prompts/orchestrate-powershell-work.prompt.md +50 -0
- package/resources/customizations/.github/prompts/orchestrate-python-work.prompt.md +50 -0
- package/resources/customizations/.github/prompts/orchestrate-work.prompt.md +66 -0
- package/resources/customizations/.github/prompts/remediate-comments.prompt.md +53 -0
- package/resources/customizations/.github/prompts/research-issue.prompt.md +125 -0
- package/resources/customizations/.github/prompts/review-epic.prompt.md +94 -0
- package/resources/customizations/.github/prompts/review-feature.prompt.md +130 -0
- package/resources/customizations/.github/prompts/review-staged.prompt.md +43 -0
- package/resources/customizations/.github/prompts/update_status.prompt.md +68 -0
- package/resources/customizations/.github/skills/README.md +26 -0
- package/resources/customizations/.github/skills/acceptance-criteria-tracking/SKILL.md +102 -0
- package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +174 -0
- package/resources/customizations/.github/skills/csharp-change-budget-router/SKILL.md +48 -0
- package/resources/customizations/.github/skills/csharp-orchestration-state-machine/SKILL.md +57 -0
- package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +135 -0
- package/resources/customizations/.github/skills/feature-promotion-lifecycle/SKILL.md +121 -0
- package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +153 -0
- package/resources/customizations/.github/skills/make-skill-template/SKILL.md +147 -0
- package/resources/customizations/.github/skills/policy-audit-template-usage/SKILL.md +48 -0
- package/resources/customizations/.github/skills/policy-compliance-order/SKILL.md +37 -0
- package/resources/customizations/.github/skills/powershell-change-budget-router/SKILL.md +48 -0
- package/resources/customizations/.github/skills/powershell-orchestration-state-machine/SKILL.md +57 -0
- package/resources/customizations/.github/skills/pr-base-branch-merge-base/SKILL.md +55 -0
- package/resources/customizations/.github/skills/pr-context-artifacts/SKILL.md +29 -0
- package/resources/customizations/.github/skills/remediation-handoff-atomic-planner/SKILL.md +39 -0
- package/resources/customizations/.github/skills/skill-canonical-location-audit/SKILL.md +48 -0
- package/resources/feature-templates/bug/plan.yyyy-MM-ddTHH-mm.md +44 -0
- package/resources/feature-templates/bug/potential_bug.md +59 -0
- package/resources/feature-templates/bug/spec.md +99 -0
- package/resources/feature-templates/epic/initiative.md +43 -0
- package/resources/feature-templates/feature/plan.yyyy-MM-ddTHH-mm.md +53 -0
- package/resources/feature-templates/feature/spec.md +66 -0
- package/resources/feature-templates/feature/user-story.md +42 -0
- package/resources/feature-templates/potential/template.md +33 -0
- package/resources/feature-templates/refactor/plan.yyyy-MM-ddTHH-mm.md +52 -0
- package/resources/feature-templates/refactor/spec.md +69 -0
- package/resources/powershell/PoshQC/PoshQC.Analyzer.psm1 +254 -0
- package/resources/powershell/PoshQC/PoshQC.FileDiscovery.psm1 +138 -0
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +409 -0
- package/resources/powershell/PoshQC/PoshQC.psd1 +31 -0
- package/resources/powershell/PoshQC/PoshQC.psm1 +101 -0
- package/resources/powershell/PoshQC/README.md +80 -0
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +59 -0
- package/resources/powershell/PoshQC/settings/pssa.settings.psd1 +55 -0
- package/resources/scripts/dev_tools/__init__.py +0 -0
- package/resources/scripts/dev_tools/agentic_sync.py +819 -0
- package/resources/scripts/dev_tools/codex_native_converter/__init__.py +11 -0
- package/resources/scripts/dev_tools/codex_native_converter/__main__.py +6 -0
- package/resources/scripts/dev_tools/codex_native_converter/cli.py +11 -0
- package/resources/scripts/dev_tools/new_active_feature_folder.py +79 -0
- package/resources/scripts/dev_tools/new_active_feature_folder_docs.py +268 -0
- package/resources/scripts/dev_tools/new_active_feature_folder_flow.py +366 -0
- package/resources/scripts/dev_tools/new_active_feature_folder_io.py +306 -0
- package/resources/scripts/dev_tools/new_active_feature_folder_markdown.py +252 -0
- package/resources/scripts/dev_tools/new_active_feature_folder_models.py +136 -0
- package/resources/scripts/dev_tools/new_potential_bug_entry.py +465 -0
- package/resources/scripts/dev_tools/potential_to_issue.py +421 -0
- package/resources/scripts/dev_tools/potential_to_issue_content.py +212 -0
- package/resources/scripts/dev_tools/pr_context/__init__.py +0 -0
- package/resources/scripts/dev_tools/pr_context/collector.py +619 -0
- package/resources/scripts/dev_tools/pr_context/feature_docs.py +349 -0
- package/resources/scripts/dev_tools/pr_context/git.py +153 -0
- package/resources/scripts/dev_tools/pr_context/github.py +549 -0
- package/resources/scripts/dev_tools/pr_context/models.py +198 -0
- package/resources/scripts/dev_tools/pr_context/render.py +342 -0
- package/resources/scripts/dev_tools/pr_context/render_feature_excerpts.py +256 -0
- package/resources/scripts/dev_tools/pr_context/render_pr_helpers.py +291 -0
- package/resources/scripts/dev_tools/pr_context/summary_helpers.py +386 -0
- package/resources/scripts/dev_tools/pr_context/verification_evidence.py +171 -0
- package/resources/scripts/dev_tools/prompt_mode_contract.py +152 -0
- package/resources/scripts/dev_tools/push_down_claude_customizations.py +188 -0
- package/resources/scripts/dev_tools/push_down_codex_and_agents_customizations.py +139 -0
- package/resources/scripts/dev_tools/push_down_copilot_customizations.py +504 -0
- package/resources/scripts/dev_tools/push_down_copilot_customizations_filesystem.py +217 -0
- package/resources/scripts/dev_tools/push_down_copilot_customizations_rewrites.py +293 -0
- package/resources/scripts/dev_tools/resolve_file_prompt.py +457 -0
- package/resources/scripts/dev_tools/resolve_hard_lock_prompt.py +444 -0
- package/resources/scripts/dev_tools/validate_orchestration_artifacts.py +554 -0
- package/resources/templates/codex_native_converter.py +35 -0
- package/resources/templates/collect_commit_context.py +212 -0
- package/resources/templates/collect_pr_context.py +74 -0
- package/resources/templates/hello_pwsh.ps1 +3 -0
- package/resources/templates/hello_python.py +11 -0
- package/resources/templates/link-parent-child.ps1 +480 -0
- package/resources/templates/new-claude-worktree-session.ps1 +232 -0
- package/resources/templates/new-potential-entry.ps1 +187 -0
- package/resources/templates/new_active_feature_folder.py +67 -0
- package/resources/templates/new_potential_bug_entry.py +54 -0
- package/resources/templates/policy_audit/AGENTS.md +117 -0
- package/resources/templates/policy_audit/code-review.yyyy-MM-ddTHH-mm.md +165 -0
- package/resources/templates/policy_audit/feature-audit.yyyy-MM-ddTHH-mm.md +124 -0
- package/resources/templates/policy_audit/policy-audit.yyyy-MM-ddTHH-mm.md +649 -0
- package/resources/templates/potential_to_issue.py +55 -0
- package/resources/templates/push_down_claude_customizations.py +188 -0
- package/resources/templates/push_down_codex_and_agents_customizations.py +95 -0
- package/resources/templates/push_down_copilot_customizations.py +124 -0
- package/resources/templates/resolve_atomic_plan_prompt.py +75 -0
- package/resources/templates/resolve_hard_lock_prompt.py +65 -0
- package/resources/templates/run-poshqc-analyze-autofix.ps1 +16 -0
- package/resources/templates/run-poshqc-analyze.ps1 +26 -0
- package/resources/templates/run-poshqc-format.ps1 +26 -0
- package/resources/templates/run-poshqc-suite.ps1 +24 -0
- package/resources/templates/run-poshqc-test.ps1 +32 -0
- package/resources/templates/sync-agents-from-instructions.ps1 +400 -0
- package/resources/templates/validate_orchestration_artifacts.py +55 -0
- package/resources/templates/vscode-cli.helpers.ps1 +63 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
"""Feature-document excerpt helpers for PR context rendering."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
from .models import FeatureDocExcerpt, section, truncate
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from collections.abc import Iterable
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def parse_section(markdown: str, heading: str) -> str:
|
|
16
|
+
"""Extract markdown content under a top-level `##` heading."""
|
|
17
|
+
escaped = re.escape(heading)
|
|
18
|
+
pattern = rf"^##\s+{escaped}\s*\r?\n(.*?)(?=^##\s+|\Z)"
|
|
19
|
+
match = re.search(pattern, markdown, flags=re.MULTILINE | re.DOTALL)
|
|
20
|
+
if not match:
|
|
21
|
+
return ""
|
|
22
|
+
return match.group(1).strip()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _extract_issue_references(text: str) -> list[str]:
|
|
26
|
+
"""Extract normalized issue reference tokens from freeform text."""
|
|
27
|
+
if not text:
|
|
28
|
+
return []
|
|
29
|
+
matches = re.findall(r"(?<!\w)#\d+|\b[A-Z][A-Z0-9]+-\d+\b", text)
|
|
30
|
+
seen: set[str] = set()
|
|
31
|
+
ordered: list[str] = []
|
|
32
|
+
for item in matches:
|
|
33
|
+
if item not in seen:
|
|
34
|
+
seen.add(item)
|
|
35
|
+
ordered.append(item)
|
|
36
|
+
return ordered
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def completed_plan_tasks(markdown: str, *, limit: int = 10) -> list[str]:
|
|
40
|
+
"""Return up to `limit` completed checklist items from markdown."""
|
|
41
|
+
tasks: list[str] = []
|
|
42
|
+
for line in markdown.splitlines():
|
|
43
|
+
if re.search(r"\[x\]", line, flags=re.IGNORECASE):
|
|
44
|
+
cleaned = re.sub(r"^[-*]\s*\[[xX]\]\s*", "", line).strip()
|
|
45
|
+
tasks.append(cleaned)
|
|
46
|
+
if len(tasks) >= limit:
|
|
47
|
+
break
|
|
48
|
+
return tasks
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def directory_exists(path: Path) -> bool:
|
|
52
|
+
"""Return whether the provided path exists."""
|
|
53
|
+
return path.exists()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def resolve_feature_dir(base_dir: Path, feature: str) -> Path | None:
|
|
57
|
+
"""Resolve feature directory by exact, strong-pattern, then weak match."""
|
|
58
|
+
direct = base_dir / feature
|
|
59
|
+
if directory_exists(direct):
|
|
60
|
+
return direct
|
|
61
|
+
|
|
62
|
+
if not directory_exists(base_dir):
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
pattern = re.compile(rf"(?:^|[-_]){re.escape(feature)}(?:[-_]|$)")
|
|
66
|
+
strong_matches: list[Path] = []
|
|
67
|
+
weak_matches: list[Path] = []
|
|
68
|
+
|
|
69
|
+
for candidate in sorted(base_dir.iterdir()):
|
|
70
|
+
if not candidate.is_dir():
|
|
71
|
+
continue
|
|
72
|
+
name = candidate.name
|
|
73
|
+
if pattern.search(name):
|
|
74
|
+
strong_matches.append(candidate)
|
|
75
|
+
elif feature in name:
|
|
76
|
+
weak_matches.append(candidate)
|
|
77
|
+
|
|
78
|
+
if strong_matches:
|
|
79
|
+
return strong_matches[0]
|
|
80
|
+
if weak_matches:
|
|
81
|
+
return weak_matches[0]
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def read_text_file(path: Path) -> str:
|
|
86
|
+
"""Read UTF-8 text if the path exists, otherwise return an empty string."""
|
|
87
|
+
return path.read_text(encoding="utf-8") if path.exists() else ""
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def extract_features_from_paths(changed_files: Iterable[str]) -> set[str]:
|
|
91
|
+
"""Extract feature directory names from `docs/features/active/**` paths."""
|
|
92
|
+
features: set[str] = set()
|
|
93
|
+
for raw in changed_files:
|
|
94
|
+
parts = Path(raw).parts
|
|
95
|
+
if (
|
|
96
|
+
len(parts) >= 4
|
|
97
|
+
and parts[0] == "docs"
|
|
98
|
+
and parts[1] == "features"
|
|
99
|
+
and parts[2] == "active"
|
|
100
|
+
):
|
|
101
|
+
features.add(parts[3])
|
|
102
|
+
return features
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def extract_spec_parts(spec_text: str) -> list[str]:
|
|
106
|
+
"""Extract high-value sections from a feature spec document."""
|
|
107
|
+
spec_parts: list[str] = []
|
|
108
|
+
for heading in (
|
|
109
|
+
"Context",
|
|
110
|
+
"Root Cause",
|
|
111
|
+
"Root Cause/Problem",
|
|
112
|
+
"Problem",
|
|
113
|
+
"Proposed Fix",
|
|
114
|
+
"Acceptance Criteria",
|
|
115
|
+
"Constraints & Risks",
|
|
116
|
+
"Behavior",
|
|
117
|
+
"Overview",
|
|
118
|
+
):
|
|
119
|
+
section_text = parse_section(spec_text, heading)
|
|
120
|
+
if section_text:
|
|
121
|
+
spec_parts.append(f"{heading}: {truncate(section_text)}")
|
|
122
|
+
return spec_parts
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def extract_plan_sections(plan_text: str) -> tuple[str, str]:
|
|
126
|
+
"""Extract completed tasks and verification notes from a plan document."""
|
|
127
|
+
plan_tasks = completed_plan_tasks(plan_text)
|
|
128
|
+
plan_section = "\n".join(f"- {task}" for task in plan_tasks) if plan_tasks else ""
|
|
129
|
+
# Keep fallback order aligned with feature_docs for consistent semantics.
|
|
130
|
+
test_plan_section = parse_section(plan_text, "Verification")
|
|
131
|
+
if not test_plan_section:
|
|
132
|
+
test_plan_section = parse_section(plan_text, "Test Plan")
|
|
133
|
+
verification_block = (
|
|
134
|
+
"Plan verification notes:\n" + truncate(test_plan_section)
|
|
135
|
+
if test_plan_section
|
|
136
|
+
else ""
|
|
137
|
+
)
|
|
138
|
+
return plan_section, verification_block
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def extract_story_parts(user_story_text: str, promoted_story_text: str) -> list[str]:
|
|
142
|
+
"""Extract story statement/problem snippets from user-story content."""
|
|
143
|
+
story_parts: list[str] = []
|
|
144
|
+
story_statements = parse_section(user_story_text, "Story Statement")
|
|
145
|
+
if story_statements:
|
|
146
|
+
story_lines = [
|
|
147
|
+
line.strip("- ") for line in story_statements.splitlines() if line.strip()
|
|
148
|
+
]
|
|
149
|
+
if story_lines:
|
|
150
|
+
story_parts.append(
|
|
151
|
+
"Story Statement:\n" + "\n".join(f"- {line}" for line in story_lines)
|
|
152
|
+
)
|
|
153
|
+
problem_section = parse_section(user_story_text, "Problem / Why")
|
|
154
|
+
if problem_section:
|
|
155
|
+
story_parts.append("Problem / Why:\n" + truncate(problem_section))
|
|
156
|
+
if not story_parts and promoted_story_text:
|
|
157
|
+
promoted_problem = parse_section(promoted_story_text, "Problem / Why")
|
|
158
|
+
if not promoted_problem:
|
|
159
|
+
promoted_problem = parse_section(promoted_story_text, "Summary")
|
|
160
|
+
if promoted_problem:
|
|
161
|
+
story_parts.append("Problem / Why:\n" + truncate(promoted_problem))
|
|
162
|
+
return story_parts
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def build_excerpt_text(
|
|
166
|
+
feature: str,
|
|
167
|
+
story_parts: list[str],
|
|
168
|
+
spec_parts: list[str],
|
|
169
|
+
plan_section: str,
|
|
170
|
+
verification_block: str,
|
|
171
|
+
) -> str:
|
|
172
|
+
"""Build a formatted feature excerpt block from collected sections."""
|
|
173
|
+
lines: list[str] = [section(f"Feature doc: {feature}")]
|
|
174
|
+
if story_parts:
|
|
175
|
+
lines.append("User story excerpts:\n" + "\n\n".join(story_parts))
|
|
176
|
+
if spec_parts:
|
|
177
|
+
lines.append("Spec excerpts:\n" + "\n\n".join(spec_parts))
|
|
178
|
+
if plan_section:
|
|
179
|
+
lines.append("Plan completed tasks:\n" + plan_section)
|
|
180
|
+
if verification_block:
|
|
181
|
+
lines.append(verification_block)
|
|
182
|
+
if len(lines) == 1:
|
|
183
|
+
lines.append("(no spec/plan/user-story excerpts found)")
|
|
184
|
+
return "\n".join(lines)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def gather_feature_excerpts(
|
|
188
|
+
root: Path, changed_files: Iterable[str]
|
|
189
|
+
) -> list[FeatureDocExcerpt]:
|
|
190
|
+
"""Gather feature excerpt payloads for changed active-feature files."""
|
|
191
|
+
features = extract_features_from_paths(changed_files)
|
|
192
|
+
excerpts: list[FeatureDocExcerpt] = []
|
|
193
|
+
base_dir = root / "docs" / "features" / "active"
|
|
194
|
+
promoted_dir = root / "docs" / "features" / "potential" / "promoted"
|
|
195
|
+
|
|
196
|
+
for feature in sorted(features):
|
|
197
|
+
feature_dir = resolve_feature_dir(base_dir, feature)
|
|
198
|
+
promoted_feature_dir = resolve_feature_dir(promoted_dir, feature)
|
|
199
|
+
if feature_dir is None and promoted_feature_dir is None:
|
|
200
|
+
continue
|
|
201
|
+
|
|
202
|
+
active_dir = feature_dir or promoted_feature_dir
|
|
203
|
+
if active_dir is None:
|
|
204
|
+
continue
|
|
205
|
+
|
|
206
|
+
spec_path = active_dir / "spec.md"
|
|
207
|
+
plan_path = active_dir / "plan.md"
|
|
208
|
+
user_story_path: Path = active_dir / "user-story.md"
|
|
209
|
+
promoted_story_path = (
|
|
210
|
+
promoted_feature_dir / "user-story.md"
|
|
211
|
+
if promoted_feature_dir is not None
|
|
212
|
+
else None
|
|
213
|
+
)
|
|
214
|
+
promoted_story_text = (
|
|
215
|
+
read_text_file(promoted_story_path) if promoted_story_path else ""
|
|
216
|
+
)
|
|
217
|
+
if promoted_story_path is not None and not user_story_path.exists():
|
|
218
|
+
user_story_path = promoted_story_path
|
|
219
|
+
|
|
220
|
+
user_story_text = read_text_file(user_story_path)
|
|
221
|
+
if (
|
|
222
|
+
not user_story_text
|
|
223
|
+
and promoted_story_text
|
|
224
|
+
and promoted_story_path is not None
|
|
225
|
+
):
|
|
226
|
+
user_story_text = promoted_story_text
|
|
227
|
+
user_story_path = promoted_story_path
|
|
228
|
+
|
|
229
|
+
spec_text = read_text_file(spec_path)
|
|
230
|
+
plan_text = read_text_file(plan_path)
|
|
231
|
+
|
|
232
|
+
spec_parts = extract_spec_parts(spec_text)
|
|
233
|
+
plan_section, verification_block = extract_plan_sections(plan_text)
|
|
234
|
+
story_parts = extract_story_parts(user_story_text, promoted_story_text)
|
|
235
|
+
excerpt_text = build_excerpt_text(
|
|
236
|
+
feature, story_parts, spec_parts, plan_section, verification_block
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
context_files = [
|
|
240
|
+
str(path.relative_to(root))
|
|
241
|
+
for path in (spec_path, plan_path, user_story_path)
|
|
242
|
+
if path and path.exists()
|
|
243
|
+
]
|
|
244
|
+
issue_refs = _extract_issue_references(
|
|
245
|
+
"\n".join([spec_text, plan_text, user_story_text])
|
|
246
|
+
)
|
|
247
|
+
excerpts.append(
|
|
248
|
+
FeatureDocExcerpt(
|
|
249
|
+
feature=feature,
|
|
250
|
+
excerpt=excerpt_text,
|
|
251
|
+
issue_refs=issue_refs,
|
|
252
|
+
context_files=context_files,
|
|
253
|
+
)
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
return excerpts
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"""PR context rendering utility helpers extracted from render module."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
from .models import (
|
|
10
|
+
CONVENTIONAL_TYPES,
|
|
11
|
+
IssueDetails,
|
|
12
|
+
PullRequestDetails,
|
|
13
|
+
format_list,
|
|
14
|
+
section,
|
|
15
|
+
truncate,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from collections.abc import Iterable
|
|
20
|
+
|
|
21
|
+
from .git import GitClient
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def select_default_base(git: GitClient) -> str | None:
|
|
25
|
+
"""Select the first existing base ref from standard default candidates."""
|
|
26
|
+
candidates = [
|
|
27
|
+
"origin/main",
|
|
28
|
+
"origin/master",
|
|
29
|
+
"main",
|
|
30
|
+
"master",
|
|
31
|
+
"origin/develop",
|
|
32
|
+
"develop",
|
|
33
|
+
]
|
|
34
|
+
for ref in candidates:
|
|
35
|
+
result = git.run(["rev-parse", "--verify", "--quiet", ref], allow_error=True)
|
|
36
|
+
if result.code == 0 and result.stdout.strip():
|
|
37
|
+
return ref
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def format_diff_path(path_text: str | None) -> str:
|
|
42
|
+
"""Normalize git diff path output, including rename syntax variants."""
|
|
43
|
+
if path_text is None:
|
|
44
|
+
return ""
|
|
45
|
+
if path_text.strip() == "":
|
|
46
|
+
return path_text
|
|
47
|
+
|
|
48
|
+
trimmed = path_text.strip().strip('"')
|
|
49
|
+
trimmed = re.sub(r"\{[^{}]*\s=>\s([^{}]*)\}", r"\1", trimmed)
|
|
50
|
+
|
|
51
|
+
arrow_match = re.match(r"^\s*(.+?)\s=>\s(.+?)\s*$", trimmed)
|
|
52
|
+
if arrow_match:
|
|
53
|
+
return arrow_match.group(2)
|
|
54
|
+
return trimmed
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def convert_numstat(numstat_text: str) -> tuple[int, int, list[str]]:
|
|
58
|
+
"""Convert git numstat output into totals and raw path list."""
|
|
59
|
+
adds = 0
|
|
60
|
+
dels = 0
|
|
61
|
+
files: list[str] = []
|
|
62
|
+
|
|
63
|
+
for raw_line in numstat_text.splitlines():
|
|
64
|
+
if not raw_line.strip():
|
|
65
|
+
continue
|
|
66
|
+
|
|
67
|
+
parts = raw_line.split("\t")
|
|
68
|
+
if len(parts) < 3:
|
|
69
|
+
continue
|
|
70
|
+
|
|
71
|
+
add_part, del_part, file_part = parts[0], parts[1], parts[2]
|
|
72
|
+
if add_part.isdigit():
|
|
73
|
+
adds += int(add_part)
|
|
74
|
+
if del_part.isdigit():
|
|
75
|
+
dels += int(del_part)
|
|
76
|
+
files.append(file_part)
|
|
77
|
+
|
|
78
|
+
return adds, dels, files
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def extension_summary(files: Iterable[str]) -> str:
|
|
82
|
+
"""Summarize changed files by extension."""
|
|
83
|
+
counts: dict[str, int] = {}
|
|
84
|
+
for raw in files:
|
|
85
|
+
name = format_diff_path(raw)
|
|
86
|
+
ext = "(unknown)"
|
|
87
|
+
try:
|
|
88
|
+
suffix = Path(name).suffix
|
|
89
|
+
ext = suffix if suffix else "(noext)"
|
|
90
|
+
except ValueError:
|
|
91
|
+
fallback = re.search(r"\.([A-Za-z0-9_]+)$", name)
|
|
92
|
+
ext = f".{fallback.group(1)}" if fallback else "(unknown)"
|
|
93
|
+
|
|
94
|
+
counts[ext] = counts.get(ext, 0) + 1
|
|
95
|
+
|
|
96
|
+
lines = [f"{counts[k]:8d} {k}" for k in sorted(counts)]
|
|
97
|
+
return "\n".join(lines)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def extract_issue_references(text: str) -> list[str]:
|
|
101
|
+
"""Extract issue tokens like #123 and ABC-123 in encounter order."""
|
|
102
|
+
if not text:
|
|
103
|
+
return []
|
|
104
|
+
matches = re.findall(r"(?<!\w)#\d+|\b[A-Z][A-Z0-9]+-\d+\b", text)
|
|
105
|
+
seen: set[str] = set()
|
|
106
|
+
ordered: list[str] = []
|
|
107
|
+
for item in matches:
|
|
108
|
+
if item not in seen:
|
|
109
|
+
seen.add(item)
|
|
110
|
+
ordered.append(item)
|
|
111
|
+
return ordered
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def extract_merge_pr_numbers(subjects: Iterable[str]) -> list[str]:
|
|
115
|
+
"""Extract merged PR numbers from commit subject lines."""
|
|
116
|
+
numbers: set[str] = set()
|
|
117
|
+
pattern = re.compile(r"Merge pull request #(\d+)", re.IGNORECASE)
|
|
118
|
+
for subj in subjects:
|
|
119
|
+
match = pattern.search(subj)
|
|
120
|
+
if match:
|
|
121
|
+
numbers.add(f"#{match.group(1)}")
|
|
122
|
+
return sorted(numbers)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def summarize_conventional_commits(subjects: str) -> str:
|
|
126
|
+
"""Count conventional commit types in subject lines."""
|
|
127
|
+
counts = {key: 0 for key in CONVENTIONAL_TYPES}
|
|
128
|
+
counts["other"] = 0
|
|
129
|
+
|
|
130
|
+
for line in subjects.splitlines():
|
|
131
|
+
line = line.strip()
|
|
132
|
+
if not line:
|
|
133
|
+
continue
|
|
134
|
+
match = re.match(
|
|
135
|
+
r"(feat|fix|refactor|perf|docs|test|chore|build|ci|style)(\(|!|:)",
|
|
136
|
+
line,
|
|
137
|
+
)
|
|
138
|
+
label = match.group(1) if match else "other"
|
|
139
|
+
counts[label] += 1
|
|
140
|
+
|
|
141
|
+
non_zero = [(k, v) for k, v in counts.items() if v > 0]
|
|
142
|
+
if not non_zero:
|
|
143
|
+
return "(no recognizable conventional commit types)"
|
|
144
|
+
return "\n".join(f"{name:<9} : {value}" for name, value in non_zero)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def format_issue_details(issue: IssueDetails) -> str:
|
|
148
|
+
"""Render structured issue details for PR context appendix output."""
|
|
149
|
+
comments_text = format_list(issue.comments, "(no comments)")
|
|
150
|
+
lines = [
|
|
151
|
+
section(f"Issue {issue.number}: {issue.title}"),
|
|
152
|
+
f"State: {issue.state}",
|
|
153
|
+
f"Author: {issue.author}",
|
|
154
|
+
f"Labels: {', '.join(issue.labels) if issue.labels else '(none)'}",
|
|
155
|
+
f"Assignees: {', '.join(issue.assignees) if issue.assignees else '(none)'}",
|
|
156
|
+
f"Created: {issue.created_at}",
|
|
157
|
+
f"Updated: {issue.updated_at}",
|
|
158
|
+
"",
|
|
159
|
+
truncate(issue.body, 1200),
|
|
160
|
+
"",
|
|
161
|
+
"Comments:",
|
|
162
|
+
comments_text,
|
|
163
|
+
]
|
|
164
|
+
if issue.user_story_content:
|
|
165
|
+
lines.extend(
|
|
166
|
+
[
|
|
167
|
+
"",
|
|
168
|
+
f"User story ({issue.user_story_path or 'user-story.md'}):",
|
|
169
|
+
truncate(issue.user_story_content, 1200),
|
|
170
|
+
]
|
|
171
|
+
)
|
|
172
|
+
return "\n".join(lines)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def format_pr_details(pr: PullRequestDetails) -> str:
|
|
176
|
+
"""Render structured pull request details for PR context appendix output."""
|
|
177
|
+
return "\n".join(
|
|
178
|
+
[
|
|
179
|
+
section(f"Pull Request {pr.number}: {pr.title}"),
|
|
180
|
+
f"State: {pr.state}",
|
|
181
|
+
f"Author: {pr.author}",
|
|
182
|
+
f"Base: {pr.base_ref}",
|
|
183
|
+
f"Head: {pr.head_ref}",
|
|
184
|
+
f"Created: {pr.created_at}",
|
|
185
|
+
f"Updated: {pr.updated_at}",
|
|
186
|
+
f"Merged: {pr.merged_at or '(not merged)'}",
|
|
187
|
+
f"Labels: {', '.join(pr.labels) if pr.labels else '(none)'}",
|
|
188
|
+
f"Assignees: {', '.join(pr.assignees) if pr.assignees else '(none)'}",
|
|
189
|
+
truncate(pr.body, 1200),
|
|
190
|
+
"",
|
|
191
|
+
"Auto-close issues (from this PR):",
|
|
192
|
+
format_list(pr.closing_issues, "(none)"),
|
|
193
|
+
"",
|
|
194
|
+
"Files (first 15):",
|
|
195
|
+
format_list(pr.files_changed[:15], "(none)"),
|
|
196
|
+
]
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def build_close_candidates_section(
|
|
201
|
+
*,
|
|
202
|
+
verified: list[str],
|
|
203
|
+
author_asserted: list[str],
|
|
204
|
+
referenced: list[str],
|
|
205
|
+
verified_reason: str,
|
|
206
|
+
author_reason: str,
|
|
207
|
+
) -> str:
|
|
208
|
+
"""Render close-candidate section grouped by verification source."""
|
|
209
|
+
all_auto_close = set(verified + author_asserted + referenced)
|
|
210
|
+
author_auto_close = sorted(all_auto_close)
|
|
211
|
+
referenced_only = sorted(set(referenced) - all_auto_close)
|
|
212
|
+
|
|
213
|
+
return "\n".join(
|
|
214
|
+
[
|
|
215
|
+
section("Close candidates"),
|
|
216
|
+
"Auto-close issues (verified from GitHub PR metadata):",
|
|
217
|
+
format_list(verified, verified_reason),
|
|
218
|
+
"",
|
|
219
|
+
"Auto-close issues (author asserted):",
|
|
220
|
+
format_list(author_auto_close, author_reason),
|
|
221
|
+
"",
|
|
222
|
+
"Referenced issues (detected):",
|
|
223
|
+
format_list(referenced_only, "(none)"),
|
|
224
|
+
]
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def build_issues_to_autoclose_section(
|
|
229
|
+
*,
|
|
230
|
+
verified: list[str],
|
|
231
|
+
pending_primary: list[str],
|
|
232
|
+
readiness_signals: list[str],
|
|
233
|
+
) -> str:
|
|
234
|
+
"""Render approved autoclose section from verified and deterministic pending refs.
|
|
235
|
+
|
|
236
|
+
Purpose:
|
|
237
|
+
Build the summary section consumed by PR-generation prompts for allowed
|
|
238
|
+
autoclose declarations.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
verified: Issues verified from GitHub PR metadata (`closingIssuesReferences`).
|
|
242
|
+
pending_primary: Deterministic primary issue refs eligible when
|
|
243
|
+
readiness is PASS.
|
|
244
|
+
readiness_signals: Normalized readiness states observed in feature docs.
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
A formatted section with header
|
|
248
|
+
`===== Issues to autoclose (verified or pending) =====` and either a
|
|
249
|
+
deterministic list or conservative fallback text.
|
|
250
|
+
|
|
251
|
+
Side Effects:
|
|
252
|
+
None.
|
|
253
|
+
"""
|
|
254
|
+
# Preserve stable, deterministic ordering: verified issues first, then
|
|
255
|
+
# pending deterministic issues not already verified.
|
|
256
|
+
ordered: list[str] = []
|
|
257
|
+
for issue in verified + pending_primary:
|
|
258
|
+
if issue and issue not in ordered:
|
|
259
|
+
ordered.append(issue)
|
|
260
|
+
|
|
261
|
+
if ordered:
|
|
262
|
+
body = format_list(ordered, "(none)")
|
|
263
|
+
else:
|
|
264
|
+
# Use explicit conservative wording when readiness is missing/non-PASS.
|
|
265
|
+
if any(signal == "PASS" for signal in readiness_signals):
|
|
266
|
+
body = (
|
|
267
|
+
"None (no verified closing issues and no deterministic pending issue)"
|
|
268
|
+
)
|
|
269
|
+
else:
|
|
270
|
+
body = "None (no verified closing issues and readiness not PASS)"
|
|
271
|
+
|
|
272
|
+
return "\n".join([section("Issues to autoclose (verified or pending)"), body])
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def extract_changed_paths(context_text: str) -> list[str]:
|
|
276
|
+
"""Extract changed file paths from the 'Changed files' section text."""
|
|
277
|
+
paths: list[str] = []
|
|
278
|
+
capture = False
|
|
279
|
+
for line in context_text.splitlines():
|
|
280
|
+
if line.startswith("===== Changed files"):
|
|
281
|
+
capture = True
|
|
282
|
+
continue
|
|
283
|
+
if capture:
|
|
284
|
+
if line.startswith("====="):
|
|
285
|
+
break
|
|
286
|
+
if line.strip() and "\t" in line:
|
|
287
|
+
path_part = line.split("\t")[-1]
|
|
288
|
+
paths.append(format_diff_path(path_part.strip()))
|
|
289
|
+
elif line.strip():
|
|
290
|
+
paths.append(format_diff_path(line.strip()))
|
|
291
|
+
return paths
|