create-agentic-pdlc 2.3.0 → 3.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.
Files changed (64) hide show
  1. package/.agentic-pdlc/hooks/pdlc-stage-gate.sh +37 -10
  2. package/.agentic-pdlc/metrics/raw/2026-W22.jsonl +114 -0
  3. package/.claude/settings.json +18 -0
  4. package/.coderabbit.yaml +35 -0
  5. package/.github/ISSUE_TEMPLATE/bug.md +53 -0
  6. package/.github/ISSUE_TEMPLATE/feature.md +54 -0
  7. package/.github/ISSUE_TEMPLATE/task.md +33 -0
  8. package/.github/workflows/add-to-board.yml +1 -1
  9. package/.github/workflows/agent-trigger.yml +4 -4
  10. package/.github/workflows/ci.yml +1 -1
  11. package/.github/workflows/npm-publish.yml +2 -2
  12. package/.github/workflows/pdlc-health-check.yml +1 -1
  13. package/.github/workflows/pdlc-stage-gate.yml +2 -2
  14. package/.github/workflows/project-automation.yml +25 -40
  15. package/AGENTS.md +50 -8
  16. package/CLAUDE.md +3 -1
  17. package/README.md +33 -32
  18. package/SETUP.md +2 -1
  19. package/adapters/claude-code/skill.md +39 -14
  20. package/adapters/hooks/pdlc-stage-gate.sh +3 -8
  21. package/bin/cli.js +555 -194
  22. package/docs/pdlc.md +5 -5
  23. package/docs/superpowers/plans/2026-05-28-jules-label-pat-split.md +240 -0
  24. package/docs/superpowers/plans/2026-05-29-agentic-pulse-rework-taxonomy.md +474 -0
  25. package/docs/superpowers/plans/2026-05-29-qa-gate-enforcement.md +354 -0
  26. package/docs/superpowers/plans/2026-06-04-spec-format-issue-template.md +160 -0
  27. package/docs/superpowers/plans/2026-06-04-two-tier-installer.md +1056 -0
  28. package/docs/superpowers/specs/2026-05-29-agentic-pulse-rework-taxonomy-design.md +122 -0
  29. package/docs/superpowers/specs/2026-06-04-spec-format-issue-template-design.md +46 -0
  30. package/package.json +2 -2
  31. package/templates/.github/ISSUE_TEMPLATE/bug.md +53 -0
  32. package/templates/.github/ISSUE_TEMPLATE/feature.md +54 -0
  33. package/templates/.github/ISSUE_TEMPLATE/task.md +33 -0
  34. package/templates/.github/workflows/add-to-board.yml +4 -4
  35. package/templates/.github/workflows/agent-trigger.yml +22 -13
  36. package/{.agentic-pdlc/templates → templates}/.github/workflows/agentic-metrics.yml +150 -27
  37. package/templates/.github/workflows/ci.yml +1 -1
  38. package/templates/.github/workflows/pdlc-health-check.yml +1 -1
  39. package/templates/.github/workflows/pdlc-stage-gate.yml +2 -2
  40. package/templates/.github/workflows/project-automation.yml +71 -32
  41. package/templates/.github/workflows/qa-agent.yml +32 -18
  42. package/templates/.github/workflows/qa-gate.yml +51 -0
  43. package/templates/full/AGENTS.md +143 -0
  44. package/templates/full/CLAUDE.md +30 -0
  45. package/templates/{docs → full/docs}/pdlc.md +4 -4
  46. package/templates/lite/AGENTS.md +121 -0
  47. package/templates/lite/CLAUDE.md +44 -0
  48. package/tests/cli.test.js +32 -0
  49. package/.agentic-pdlc/templates/.github/CODEOWNERS +0 -5
  50. package/.agentic-pdlc/templates/.github/copilot-instructions.md +0 -12
  51. package/.agentic-pdlc/templates/.github/workflows/add-to-board.yml +0 -38
  52. package/.agentic-pdlc/templates/.github/workflows/agent-trigger.yml +0 -146
  53. package/.agentic-pdlc/templates/.github/workflows/auto-approve.yml +0 -16
  54. package/.agentic-pdlc/templates/.github/workflows/ci.yml +0 -54
  55. package/.agentic-pdlc/templates/.github/workflows/pdlc-health-check.yml +0 -121
  56. package/.agentic-pdlc/templates/.github/workflows/pdlc-stage-gate.yml +0 -51
  57. package/.agentic-pdlc/templates/.github/workflows/project-automation.yml +0 -274
  58. package/.agentic-pdlc/templates/.github/workflows/protect-workflows.yml +0 -21
  59. package/.agentic-pdlc/templates/.github/workflows/qa-agent.yml +0 -128
  60. package/.agentic-pdlc/templates/AGENTS.md +0 -104
  61. package/.agentic-pdlc/templates/docs/pdlc.md +0 -123
  62. package/.github/workflows/agentic-metrics.yml +0 -422
  63. package/.github/workflows/qa-agent.yml +0 -128
  64. package/templates/AGENTS.md +0 -115
@@ -0,0 +1,354 @@
1
+ # QA Gate Enforcement Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Block PR merges when QA Agent failed or hasn't run, by (A) making `qa-agent.yml` emit a failing exit code on infra/parse errors and (C) adding a dedicated `qa-gate.yml` status check that enforces label-based QA state — backed by branch protection configured automatically during `npx create-agentic-pdlc`.
6
+
7
+ **Architecture:** Two independent layers. Layer A: `qa-agent.yml` stops signalling success (`exit 0`) when it can't reach GitHub Models — now exits 1, making the check red. Layer C: `qa-gate.yml` is a separate required check that reads PR labels and blocks merge unless `qa:approved` is present. Branch protection wires both checks as required, enforced automatically in `cli.js` during scaffold.
8
+
9
+ **Tech Stack:** GitHub Actions YAML (bash), Node.js (cli.js)
10
+
11
+ ---
12
+
13
+ ## File Map
14
+
15
+ | Action | File | Responsibility |
16
+ |--------|------|----------------|
17
+ | Modify | `.github/workflows/qa-agent.yml:66-69` and `:82-84` | Change `exit 0` → `exit 1` on API error and parse error |
18
+ | Modify | `templates/.github/workflows/qa-agent.yml:63-66` and `:79-81` | Same fix in template |
19
+ | Create | `.github/workflows/qa-gate.yml` | Blocking check — reads PR labels, fails unless `qa:approved` |
20
+ | Create | `templates/.github/workflows/qa-gate.yml` | Template mirror of above |
21
+ | Modify | `bin/cli.js` | Add branch protection setup step after PAT provisioning |
22
+
23
+ ---
24
+
25
+ ### Task 1: Fix `qa-agent.yml` exit codes (repo + template)
26
+
27
+ **Files:**
28
+ - Modify: `.github/workflows/qa-agent.yml`
29
+ - Modify: `templates/.github/workflows/qa-agent.yml`
30
+
31
+ Currently both files call `exit 0` when the GitHub Models API is unreachable or when the response can't be parsed. This makes the CI check green, hiding the failure.
32
+
33
+ - [ ] **Step 1: Fix exit code on API_ERROR in `.github/workflows/qa-agent.yml`**
34
+
35
+ Find this block (around line 63-69):
36
+ ```yaml
37
+ if [ "$RESPONSE" = "API_ERROR" ]; then
38
+ GH_TOKEN="$PROJECT_TOKEN" gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels" --method POST -f 'labels[]=infra:qa-broken'
39
+ gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not reach GitHub Models API. Manual review required."
40
+ exit 0
41
+ fi
42
+ ```
43
+
44
+ Change to:
45
+ ```yaml
46
+ if [ "$RESPONSE" = "API_ERROR" ]; then
47
+ GH_TOKEN="$PROJECT_TOKEN" gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels" --method POST -f 'labels[]=infra:qa-broken'
48
+ gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not reach GitHub Models API. Manual review required."
49
+ exit 1
50
+ fi
51
+ ```
52
+
53
+ - [ ] **Step 2: Fix exit code on parse error in `.github/workflows/qa-agent.yml`**
54
+
55
+ Find this block (around line 82-84):
56
+ ```yaml
57
+ else
58
+ GH_TOKEN="$PROJECT_TOKEN" gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels" --method POST -f 'labels[]=infra:qa-broken'
59
+ gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not parse GitHub Models response. Manual review required."
60
+ fi
61
+ ```
62
+
63
+ Change to:
64
+ ```yaml
65
+ else
66
+ GH_TOKEN="$PROJECT_TOKEN" gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels" --method POST -f 'labels[]=infra:qa-broken'
67
+ gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not parse GitHub Models response. Manual review required."
68
+ exit 1
69
+ fi
70
+ ```
71
+
72
+ - [ ] **Step 3: Apply the same two fixes to `templates/.github/workflows/qa-agent.yml`**
73
+
74
+ The template uses `PROJECT_PAT` instead of `PROJECT_TOKEN` in the `GH_TOKEN=` prefix. The exit code change is identical.
75
+
76
+ In `templates/.github/workflows/qa-agent.yml`, find API_ERROR block (around line 63-66):
77
+ ```yaml
78
+ if [ "$RESPONSE" = "API_ERROR" ]; then
79
+ GH_TOKEN="$PROJECT_PAT" gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels" --method POST -f 'labels[]=infra:qa-broken'
80
+ gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not reach GitHub Models API. Manual review required."
81
+ exit 0
82
+ fi
83
+ ```
84
+
85
+ Change to:
86
+ ```yaml
87
+ if [ "$RESPONSE" = "API_ERROR" ]; then
88
+ GH_TOKEN="$PROJECT_PAT" gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels" --method POST -f 'labels[]=infra:qa-broken'
89
+ gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not reach GitHub Models API. Manual review required."
90
+ exit 1
91
+ fi
92
+ ```
93
+
94
+ Find parse error block (around line 79-81):
95
+ ```yaml
96
+ else
97
+ GH_TOKEN="$PROJECT_PAT" gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels" --method POST -f 'labels[]=infra:qa-broken'
98
+ gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not parse GitHub Models response. Manual review required."
99
+ fi
100
+ ```
101
+
102
+ Change to:
103
+ ```yaml
104
+ else
105
+ GH_TOKEN="$PROJECT_PAT" gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels" --method POST -f 'labels[]=infra:qa-broken'
106
+ gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not parse GitHub Models response. Manual review required."
107
+ exit 1
108
+ fi
109
+ ```
110
+
111
+ - [ ] **Step 4: Commit**
112
+
113
+ ```bash
114
+ git add .github/workflows/qa-agent.yml templates/.github/workflows/qa-agent.yml
115
+ git commit -m "fix(qa-agent): exit 1 on infra error and parse failure instead of exit 0"
116
+ ```
117
+
118
+ ---
119
+
120
+ ### Task 2: Create `qa-gate.yml` — dedicated blocking check
121
+
122
+ **Files:**
123
+ - Create: `.github/workflows/qa-gate.yml`
124
+ - Create: `templates/.github/workflows/qa-gate.yml`
125
+
126
+ This is a new, independent status check. It triggers on PR events (including `labeled`/`unlabeled` so it re-evaluates when qa-agent adds labels). It reads PR labels and blocks merge unless `qa:approved` is present. Hotfix PRs bypass the gate (same pattern as `pdlc-stage-gate.yml`).
127
+
128
+ The GitHub Actions check name exposed to branch protection is derived from the `name:` field of the job: **`QA Gate`**.
129
+
130
+ - [ ] **Step 5: Create `.github/workflows/qa-gate.yml`**
131
+
132
+ Write this exact content:
133
+
134
+ ```yaml
135
+ name: QA Gate
136
+
137
+ on:
138
+ pull_request:
139
+ types: [opened, synchronize, reopened, labeled, unlabeled]
140
+
141
+ permissions:
142
+ pull-requests: read
143
+
144
+ jobs:
145
+ qa-gate:
146
+ name: QA Gate
147
+ runs-on: ubuntu-latest
148
+ steps:
149
+ - name: Check QA status label
150
+ env:
151
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
152
+ run: |
153
+ set -e
154
+ PR_NUMBER="${{ github.event.pull_request.number }}"
155
+ REPO="${{ github.repository }}"
156
+
157
+ PR_LABELS=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json labels --jq '[.labels[].name] | join(" ")')
158
+
159
+ if echo "$PR_LABELS" | grep -qw "hotfix"; then
160
+ echo "✅ QA Gate: hotfix label — bypassed."
161
+ exit 0
162
+ fi
163
+
164
+ if echo "$PR_LABELS" | grep -qw "qa:approved"; then
165
+ echo "✅ QA Gate: qa:approved — merge allowed."
166
+ exit 0
167
+ fi
168
+
169
+ if echo "$PR_LABELS" | grep -qw "infra:qa-broken"; then
170
+ echo "❌ QA Gate: infra:qa-broken — GitHub Models API unreachable. Manual QA review required before merge."
171
+ exit 1
172
+ fi
173
+
174
+ if echo "$PR_LABELS" | grep -qw "qa:needs-work"; then
175
+ echo "❌ QA Gate: qa:needs-work — acceptance criteria not fully met. Fix required before merge."
176
+ exit 1
177
+ fi
178
+
179
+ echo "❌ QA Gate: no QA label found — AC Coverage Verification has not completed. Wait for the check to finish."
180
+ exit 1
181
+ ```
182
+
183
+ - [ ] **Step 6: Create `templates/.github/workflows/qa-gate.yml`**
184
+
185
+ Write the exact same content as Step 5. The template is identical — it uses `GITHUB_TOKEN` only (no extra secrets needed for the gate check).
186
+
187
+ - [ ] **Step 7: Commit**
188
+
189
+ ```bash
190
+ git add .github/workflows/qa-gate.yml templates/.github/workflows/qa-gate.yml
191
+ git commit -m "feat(qa-gate): add dedicated QA Gate blocking check for PR merges"
192
+ ```
193
+
194
+ ---
195
+
196
+ ### Task 3: Add branch protection setup to `cli.js`
197
+
198
+ **Files:**
199
+ - Modify: `bin/cli.js`
200
+
201
+ Without branch protection, the new checks are informational only — engineers can still click "Merge". This task wires the two required checks (`PDLC Stage Gate` and `QA Gate`) automatically during `npx create-agentic-pdlc`.
202
+
203
+ The branch protection API call uses `gh api PUT repos/{repo}/branches/main/protection --input -` which reads a JSON payload from stdin. `execFileSync` with the `input` option handles this correctly. The call is non-fatal: if it fails (e.g., org policy restrictions, insufficient permissions), a warning is printed with manual instructions.
204
+
205
+ - [ ] **Step 8: Add i18n strings to `bin/cli.js`**
206
+
207
+ In the `i18n` object (around line 34), after the `update_sentinel_ask` entry, add:
208
+
209
+ ```javascript
210
+ configuring_protection: t('[3/3] Configuring branch protection...', '[3/3] Configurando proteção de branch...', '[3/3] Configurando protección de rama...'),
211
+ protection_ok: t('✅ Branch protection set — required checks: PDLC Stage Gate, QA Gate.', '✅ Proteção de branch configurada — checks obrigatórios: PDLC Stage Gate, QA Gate.', '✅ Protección de rama configurada — checks requeridos: PDLC Stage Gate, QA Gate.'),
212
+ protection_warn: t('⚠️ Branch protection could not be set automatically.\n Set required checks manually: Settings → Branches → main → Required status checks.\n Required: "PDLC Stage Gate" and "QA Gate"', '⚠️ Proteção de branch não pôde ser configurada automaticamente.\n Configure manualmente: Settings → Branches → main → Required status checks.\n Obrigatórios: "PDLC Stage Gate" e "QA Gate"', '⚠️ No se pudo configurar la protección de rama automáticamente.\n Configúralo en: Settings → Branches → main → Required status checks.\n Requeridos: "PDLC Stage Gate" y "QA Gate"'),
213
+ ```
214
+
215
+ - [ ] **Step 9: Update step counters in `bin/cli.js`**
216
+
217
+ Find:
218
+ ```javascript
219
+ creating_labels: t('[1/2] Creating repository labels...', '[1/2] Criando labels no repositório...', '[1/2] Creando etiquetas (labels) en el repositorio...'),
220
+ ```
221
+ Change to:
222
+ ```javascript
223
+ creating_labels: t('[1/3] Creating repository labels...', '[1/3] Criando labels no repositório...', '[1/3] Creando etiquetas (labels) en el repositorio...'),
224
+ ```
225
+
226
+ Find:
227
+ ```javascript
228
+ creating_project: t('[2/2] Creating Project V2 Board...', '[2/2] Criando Project V2 Board...', '[2/2] Creando Project V2 Board...'),
229
+ ```
230
+ Change to:
231
+ ```javascript
232
+ creating_project: t('[2/3] Creating Project V2 Board...', '[2/3] Criando Project V2 Board...', '[2/3] Creando Project V2 Board...'),
233
+ ```
234
+
235
+ - [ ] **Step 10: Add branch protection setup block to `bin/cli.js`**
236
+
237
+ Find the block that starts with the PAT auto-provision section and ends before the scaffolding section. After the closing brace of the PAT block (around line 356, after `} else if (projectId && isOrg) { ... }`), add:
238
+
239
+ ```javascript
240
+ // Branch protection — require PDLC Stage Gate + QA Gate on main
241
+ console.log(`\n${cyan}${i18n.configuring_protection}${reset}`);
242
+ try {
243
+ const protectionPayload = JSON.stringify({
244
+ required_status_checks: {
245
+ strict: false,
246
+ contexts: ['PDLC Stage Gate', 'QA Gate']
247
+ },
248
+ enforce_admins: false,
249
+ required_pull_request_reviews: null,
250
+ restrictions: null
251
+ });
252
+ execFileSync('gh', [
253
+ 'api', `repos/${repo}/branches/main/protection`,
254
+ '--method', 'PUT',
255
+ '--input', '-'
256
+ ], { input: protectionPayload, stdio: ['pipe', 'ignore', 'pipe'] });
257
+ console.log(` ${green}${i18n.protection_ok}${reset}`);
258
+ } catch (_) {
259
+ console.log(` ${yellow}${i18n.protection_warn}${reset}`);
260
+ }
261
+ ```
262
+
263
+ - [ ] **Step 11: Verify cli.js changes compile (no syntax errors)**
264
+
265
+ ```bash
266
+ node --check bin/cli.js
267
+ ```
268
+
269
+ Expected: no output (exit 0).
270
+
271
+ - [ ] **Step 12: Commit**
272
+
273
+ ```bash
274
+ git add bin/cli.js
275
+ git commit -m "feat(cli): auto-configure branch protection with required QA Gate + PDLC Stage Gate checks"
276
+ ```
277
+
278
+ ---
279
+
280
+ ### Task 4: Enable branch protection on this repo (verification)
281
+
282
+ **Files:** none — GitHub API call only.
283
+
284
+ This repo was already not protected (`404 Branch not protected`). Task 3 adds the automation for new installs; this task activates it for the existing repo.
285
+
286
+ - [ ] **Step 13: Apply branch protection to this repo**
287
+
288
+ ```bash
289
+ gh api repos/rafaeltcosta86/agentic-pdlc/branches/main/protection \
290
+ --method PUT \
291
+ --input - <<'EOF'
292
+ {
293
+ "required_status_checks": {
294
+ "strict": false,
295
+ "contexts": ["PDLC Stage Gate", "QA Gate"]
296
+ },
297
+ "enforce_admins": false,
298
+ "required_pull_request_reviews": null,
299
+ "restrictions": null
300
+ }
301
+ EOF
302
+ ```
303
+
304
+ Expected: JSON response with `url` field containing `branches/main/protection`.
305
+
306
+ - [ ] **Step 14: Verify branch protection is active**
307
+
308
+ ```bash
309
+ gh api repos/rafaeltcosta86/agentic-pdlc/branches/main/protection \
310
+ --jq '.required_status_checks.contexts'
311
+ ```
312
+
313
+ Expected output:
314
+ ```json
315
+ [
316
+ "PDLC Stage Gate",
317
+ "QA Gate"
318
+ ]
319
+ ```
320
+
321
+ - [ ] **Step 15: Open a test PR to verify end-to-end behavior**
322
+
323
+ Create a scratch branch, open a draft PR against main without `qa:approved` label:
324
+
325
+ ```bash
326
+ git checkout -b test/qa-gate-verification
327
+ git commit --allow-empty -m "test: verify qa gate enforcement"
328
+ gh pr create --title "test: QA Gate verification" --body "Closes #136" --draft
329
+ ```
330
+
331
+ Expected: `QA Gate` check appears and fails with "no QA label found". `AC Coverage Verification (GitHub Models)` check runs; if API is reachable it adds `qa:approved` automatically and QA Gate re-evaluates to pass. Merge button should be disabled until QA Gate passes.
332
+
333
+ - [ ] **Step 16: Close the test PR and delete the branch**
334
+
335
+ ```bash
336
+ gh pr close --delete-branch
337
+ ```
338
+
339
+ ---
340
+
341
+ ## Self-Review
342
+
343
+ **Spec coverage:**
344
+ - ✅ `infra:qa-broken` no longer allows silent bypass — Task 1 (exit 1) + Task 2 (qa-gate fails on that label)
345
+ - ✅ `qa:needs-work` also blocked — qa-gate checks for it explicitly
346
+ - ✅ "no QA label" state blocked — qa-gate fails if no QA label present
347
+ - ✅ Hotfix bypass preserved — same `grep -qw "hotfix"` pattern as pdlc-stage-gate
348
+ - ✅ Template updated — Tasks 1 and 2 update both repo + template files
349
+ - ✅ Enforcement mechanism (branch protection) included — Task 3 + Task 4
350
+ - ✅ New installs get protection automatically — cli.js step in Task 3
351
+
352
+ **Placeholder scan:** None found. All code blocks are complete and runnable.
353
+
354
+ **Type consistency:** No functions/types defined across tasks — all changes are self-contained YAML and JS.
@@ -0,0 +1,160 @@
1
+ # Spec-Format Issue Template Installation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Make `npx create-agentic-pdlc` install `.github/ISSUE_TEMPLATE/` directly into the target project so GitHub shows the spec-format template when users create issues.
6
+
7
+ **Architecture:** Single change in `bin/cli.js` — inside `runSetup()`, after the existing template copy block, add a `copyDirSync` call that copies `templates/.github/ISSUE_TEMPLATE/` directly to `targetDir/.github/ISSUE_TEMPLATE/`. No placeholder substitution needed.
8
+
9
+ **Tech Stack:** Node.js, `fs`, `path` — all already imported. No new dependencies.
10
+
11
+ ---
12
+
13
+ ### Task 1: Add i18n string
14
+
15
+ **Files:**
16
+ - Modify: `bin/cli.js:77` (inside `i18n` object, before the closing `}`)
17
+
18
+ No test infrastructure exists in this project — verification is manual (Task 2).
19
+
20
+ - [ ] **Step 1: Add the i18n string**
21
+
22
+ In [bin/cli.js](bin/cli.js), on line 77 (right before the closing `};` of the `i18n` object), add:
23
+
24
+ ```js
25
+ protection_warn: t('⚠️ Branch protection could not be set automatically.\n Set required checks manually: Settings → Branches → main → Required status checks.\n Required: "PDLC Stage Gate" and "QA Gate"', '⚠️ Proteção de branch não pôde ser configurada automaticamente.\n Configure manualmente: Settings → Branches → main → Required status checks.\n Obrigatórios: "PDLC Stage Gate" e "QA Gate"', '⚠️ No se pudo configurar la protección de rama automáticamente.\n Configúralo en: Settings → Branches → main → Required status checks.\n Requeridos: "PDLC Stage Gate" y "QA Gate"'),
26
+ issue_templates_copied: t(
27
+ '✅ Issue templates copied to .github/ISSUE_TEMPLATE/',
28
+ '✅ Issue templates copiados para .github/ISSUE_TEMPLATE/',
29
+ '✅ Issue templates copiados a .github/ISSUE_TEMPLATE/'
30
+ ),
31
+ };
32
+ ```
33
+
34
+ (Replace the existing `protection_warn` line + closing `};` with the block above — adds the new key before `};`.)
35
+
36
+ ---
37
+
38
+ ### Task 2: Add copyDirSync call in runSetup()
39
+
40
+ **Files:**
41
+ - Modify: `bin/cli.js:387` (inside `if (fs.existsSync(sourceTemplates))` block, after the `templates_copied` log line)
42
+
43
+ - [ ] **Step 1: Add the copy block**
44
+
45
+ In [bin/cli.js](bin/cli.js), after line 387 (`console.log(`${i18n.templates_copied}`)`), insert:
46
+
47
+ ```js
48
+ // Copy issue templates directly to .github/ISSUE_TEMPLATE/ so GitHub picks them up
49
+ const sourceIssueTemplates = path.join(sourceDir, 'templates', '.github', 'ISSUE_TEMPLATE');
50
+ const targetIssueTemplates = path.join(targetDir, '.github', 'ISSUE_TEMPLATE');
51
+ if (fs.existsSync(sourceIssueTemplates)) {
52
+ copyDirSync(sourceIssueTemplates, targetIssueTemplates);
53
+ console.log(i18n.issue_templates_copied);
54
+ }
55
+ ```
56
+
57
+ The result in context should look like:
58
+
59
+ ```js
60
+ if (fs.existsSync(sourceTemplates)) {
61
+ copyDirSync(sourceTemplates, targetTemplates);
62
+ console.log(`${i18n.templates_copied}`);
63
+
64
+ // Copy issue templates directly to .github/ISSUE_TEMPLATE/ so GitHub picks them up
65
+ const sourceIssueTemplates = path.join(sourceDir, 'templates', '.github', 'ISSUE_TEMPLATE');
66
+ const targetIssueTemplates = path.join(targetDir, '.github', 'ISSUE_TEMPLATE');
67
+ if (fs.existsSync(sourceIssueTemplates)) {
68
+ copyDirSync(sourceIssueTemplates, targetIssueTemplates);
69
+ console.log(i18n.issue_templates_copied);
70
+ }
71
+
72
+ // Substitute values in docs/pdlc.md automatically
73
+ const pdlcDest = path.join(targetTemplates, 'docs', 'pdlc.md');
74
+ ```
75
+
76
+ - [ ] **Step 2: Verify syntax is valid**
77
+
78
+ ```bash
79
+ node --check bin/cli.js
80
+ ```
81
+
82
+ Expected: no output (exit code 0). Any output means a syntax error — fix before continuing.
83
+
84
+ ---
85
+
86
+ ### Task 3: Manual verification
87
+
88
+ - [ ] **Step 1: Create a temp target directory and run the copy logic in isolation**
89
+
90
+ ```bash
91
+ node -e "
92
+ const fs = require('fs');
93
+ const path = require('path');
94
+ const sourceDir = '.';
95
+ const targetDir = '/tmp/pdlc-test-157';
96
+
97
+ function copyDirSync(src, dest) {
98
+ if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
99
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
100
+ const s = path.join(src, entry.name);
101
+ const d = path.join(dest, entry.name);
102
+ entry.isDirectory() ? copyDirSync(s, d) : fs.copyFileSync(s, d);
103
+ }
104
+ }
105
+
106
+ const sourceIssueTemplates = path.join(sourceDir, 'templates', '.github', 'ISSUE_TEMPLATE');
107
+ const targetIssueTemplates = path.join(targetDir, '.github', 'ISSUE_TEMPLATE');
108
+ if (fs.existsSync(sourceIssueTemplates)) {
109
+ copyDirSync(sourceIssueTemplates, targetIssueTemplates);
110
+ console.log('copied');
111
+ } else {
112
+ console.log('source not found');
113
+ }
114
+ "
115
+ ```
116
+
117
+ Expected output: `copied`
118
+
119
+ - [ ] **Step 2: Verify files are in the right place**
120
+
121
+ ```bash
122
+ ls /tmp/pdlc-test-157/.github/ISSUE_TEMPLATE/
123
+ ```
124
+
125
+ Expected output:
126
+ ```
127
+ bug.md
128
+ feature.md
129
+ task.md
130
+ ```
131
+
132
+ - [ ] **Step 3: Verify .github/ was created recursively (didn't exist before)**
133
+
134
+ ```bash
135
+ ls /tmp/pdlc-test-157/.github/
136
+ ```
137
+
138
+ Expected output:
139
+ ```
140
+ ISSUE_TEMPLATE
141
+ ```
142
+
143
+ - [ ] **Step 4: Clean up**
144
+
145
+ ```bash
146
+ rm -rf /tmp/pdlc-test-157
147
+ ```
148
+
149
+ ---
150
+
151
+ ### Task 4: Commit
152
+
153
+ - [ ] **Step 1: Stage and commit**
154
+
155
+ ```bash
156
+ git add bin/cli.js
157
+ git commit -m "feat(cli): install issue templates to .github/ISSUE_TEMPLATE/ during setup
158
+
159
+ Closes #157"
160
+ ```