create-agentic-pdlc 2.1.6 → 2.2.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 (46) hide show
  1. package/.agentic-pdlc/SETUP_PROMPT.md +73 -0
  2. package/.agentic-pdlc/hooks/pdlc-stage-gate.sh +39 -0
  3. package/.agentic-pdlc/metrics/.gitkeep +0 -0
  4. package/.agentic-pdlc/metrics/2026-W19.md +21 -0
  5. package/.agentic-pdlc/metrics/raw/2026-W19.jsonl +6 -0
  6. package/.agentic-pdlc/metrics/raw/2026-W20.jsonl +1 -0
  7. package/.agentic-pdlc/templates/.github/CODEOWNERS +5 -0
  8. package/.agentic-pdlc/templates/.github/copilot-instructions.md +12 -0
  9. package/.agentic-pdlc/templates/.github/workflows/add-to-board.yml +38 -0
  10. package/.agentic-pdlc/templates/.github/workflows/agent-trigger.yml +146 -0
  11. package/.agentic-pdlc/templates/.github/workflows/agentic-metrics.yml +412 -0
  12. package/.agentic-pdlc/templates/.github/workflows/auto-approve.yml +16 -0
  13. package/.agentic-pdlc/templates/.github/workflows/ci.yml +40 -0
  14. package/.agentic-pdlc/templates/.github/workflows/pdlc-health-check.yml +123 -0
  15. package/.agentic-pdlc/templates/.github/workflows/pdlc-stage-gate.yml +51 -0
  16. package/.agentic-pdlc/templates/.github/workflows/project-automation.yml +278 -0
  17. package/.agentic-pdlc/templates/.github/workflows/protect-workflows.yml +21 -0
  18. package/.agentic-pdlc/templates/.github/workflows/qa-agent.yml +128 -0
  19. package/.agentic-pdlc/templates/AGENTS.md +81 -0
  20. package/.agentic-pdlc/templates/docs/pdlc.md +15 -5
  21. package/.agentic-setup-prompt.md +73 -0
  22. package/.agentic-setup.md +73 -0
  23. package/.claude/settings.json +15 -0
  24. package/.cursorrules +9 -0
  25. package/.github/ISSUE_TEMPLATE/pulse-feedback.md +11 -0
  26. package/.github/workflows/add-to-board.yml +38 -0
  27. package/.github/workflows/agent-trigger.yml +30 -43
  28. package/.github/workflows/agentic-metrics.yml +412 -0
  29. package/.github/workflows/pdlc-health-check.yml +10 -10
  30. package/.github/workflows/pdlc-stage-gate.yml +51 -0
  31. package/.github/workflows/project-automation.yml +68 -18
  32. package/.github/workflows/qa-agent.yml +112 -11
  33. package/CLAUDE.md +9 -0
  34. package/SETUP.md +28 -0
  35. package/adapters/claude-code/skill.md +41 -3
  36. package/adapters/hooks/pdlc-stage-gate.sh +44 -0
  37. package/bin/cli.js +28 -5
  38. package/docs/pdlc.md +15 -5
  39. package/package.json +1 -1
  40. package/pr_comments.json +20 -0
  41. package/templates/.github/workflows/add-to-board.yml +38 -0
  42. package/templates/.github/workflows/agent-trigger.yml +34 -4
  43. package/templates/.github/workflows/pdlc-stage-gate.yml +51 -0
  44. package/templates/.github/workflows/project-automation.yml +78 -54
  45. package/templates/.github/workflows/qa-agent.yml +14 -13
  46. package/templates/docs/pdlc.md +15 -5
@@ -6,22 +6,123 @@ on:
6
6
  permissions:
7
7
  pull-requests: write
8
8
  contents: read
9
+ issues: read
10
+ models: read
9
11
 
10
12
  jobs:
11
13
  qa:
12
- name: Run AI QA Agent
14
+ name: AC Coverage Verification (GitHub Models)
13
15
  runs-on: ubuntu-latest
16
+ env:
17
+ PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
18
+ PROJECT_ID: "PVT_kwHODpFFL84BXg7h"
19
+ STATUS_FIELD_ID: "PVTSSF_lAHODpFFL84BXg7hzhStRHI"
20
+ STATUS_CODE_REVIEW_PR: "86ca9720"
14
21
  steps:
15
22
  - uses: actions/checkout@v4
16
- - name: Execute QA Tests
17
- run: |
18
- echo "Run your QA Agent here."
19
- echo "This could be QAWolf, a custom LLM script, or a secondary agent."
20
- echo "If tests pass: gh pr edit $PR_URL --add-label 'qa:pass'"
21
- echo "If tests fail: gh pr edit $PR_URL --add-label 'qa:fail'"
22
-
23
- # Example success:
24
- # gh pr edit ${{ github.event.pull_request.html_url }} --add-label "qa:pass"
23
+ with:
24
+ fetch-depth: 0
25
+
26
+ - name: Verify AC Coverage via GitHub Models
25
27
  env:
26
28
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27
- PR_URL: ${{ github.event.pull_request.html_url }}
29
+ run: |
30
+ set -e
31
+
32
+ PR_NUMBER="${{ github.event.pull_request.number }}"
33
+ BASE="${{ github.event.pull_request.base.sha }}"
34
+ HEAD="${{ github.event.pull_request.head.sha }}"
35
+
36
+ # Get PR diff (truncated to 8000 chars to stay within context limits)
37
+ DIFF=$(git diff "$BASE" "$HEAD" | head -c 64000)
38
+
39
+ # Extract linked issues from PR body
40
+ PR_BODY=$(gh pr view "$PR_NUMBER" --json body --jq '.body // ""')
41
+ ISSUE_NUMS=$(echo "$PR_BODY" | grep -oiE '(Closes?|Fixes?|Resolves?)\s+#([0-9]+)' | grep -oE '[0-9]+' || true)
42
+
43
+ # Build acceptance criteria context
44
+ AC_CONTEXT=""
45
+ if [ -n "$ISSUE_NUMS" ]; then
46
+ for NUM in $ISSUE_NUMS; do
47
+ ISSUE_BODY=$(gh issue view "$NUM" --json body --jq '.body // ""' 2>/dev/null || echo "")
48
+ AC_CONTEXT="${AC_CONTEXT}\\n\\n--- Issue #${NUM} ---\\n${ISSUE_BODY}"
49
+ done
50
+ fi
51
+
52
+ if [ -z "$AC_CONTEXT" ]; then
53
+ AC_CONTEXT="No linked issue found. Evaluate if the PR description is self-contained."
54
+ fi
55
+
56
+ # Serialize prompt as JSON string and call GitHub Models API (30s timeout)
57
+ PROMPT_JSON=$(printf '%s' "You are a senior QA engineer. Review whether this PR diff satisfies the Acceptance Criteria below.\n\nACCEPTANCE CRITERIA:\n${AC_CONTEXT}\n\nPR DIFF:\n${DIFF}\n\nFirst line of your response must be exactly one word: PASS or FAIL. Second line: brief explanation (max 3 sentences)." | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')
58
+
59
+ RESPONSE=$(curl -sf -X POST \
60
+ "https://models.github.ai/inference/chat/completions" \
61
+ -H "Authorization: Bearer ${GITHUB_TOKEN}" \
62
+ -H "Content-Type: application/json" \
63
+ -d "{\"model\":\"gpt-4o-mini\",\"messages\":[{\"role\":\"user\",\"content\":${PROMPT_JSON}}]}" \
64
+ --max-time 30 || echo "API_ERROR")
65
+
66
+ if [ "$RESPONSE" = "API_ERROR" ]; then
67
+ gh pr edit "$PR_NUMBER" --add-label "infra:qa-broken"
68
+ gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not reach GitHub Models API. Manual review required."
69
+ exit 0
70
+ fi
71
+
72
+ VERDICT=$(echo "$RESPONSE" | python3 -c 'import json,sys,re; d=json.load(sys.stdin); t=d.get("choices",[{}])[0].get("message",{}).get("content","").strip(); first=t.split("\n")[0].upper() if t else ""; print("FAIL" if re.search(r"\bFAIL\b",first) else "PASS" if re.search(r"\bPASS\b",first) else "API_ERROR")')
73
+ EXPLANATION=$(echo "$RESPONSE" | python3 -c 'import json,sys; d=json.load(sys.stdin); t=d.get("choices",[{}])[0].get("message",{}).get("content","").strip(); lines=t.split("\n",1); print(lines[1].strip() if len(lines)>1 else "")')
74
+
75
+ if echo "$VERDICT" | grep -q "^PASS"; then
76
+ gh pr edit "$PR_NUMBER" --add-label "qa:approved"
77
+ gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** AC coverage verified. ${EXPLANATION}"
78
+ elif echo "$VERDICT" | grep -q "^FAIL"; then
79
+ gh pr edit "$PR_NUMBER" --add-label "qa:needs-work"
80
+ gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** AC coverage insufficient. ${EXPLANATION}"
81
+ else
82
+ gh pr edit "$PR_NUMBER" --add-label "infra:qa-broken"
83
+ gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not parse GitHub Models response. Manual review required."
84
+ fi
85
+
86
+ - name: Move board card to Code Review on qa:approved
87
+ if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
88
+ uses: actions/github-script@v7
89
+ with:
90
+ github-token: ${{ env.PROJECT_TOKEN }}
91
+ script: |
92
+ const prNumber = context.payload.pull_request.number;
93
+ const { owner, repo } = context.repo;
94
+
95
+ const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
96
+ if (!pr.labels.some(l => l.name === 'qa:approved')) {
97
+ console.log('qa:approved not on PR — skipping board move');
98
+ return;
99
+ }
100
+
101
+ const body = pr.body ?? '';
102
+ const linkedIssues = [...body.matchAll(/(?:Closes?|Fixes?|Resolves?)\s+#(\d+)/gi)]
103
+ .map(m => parseInt(m[1]));
104
+
105
+ const moveItem = async (nodeId) => {
106
+ const { addProjectV2ItemById: { item } } = await github.graphql(`
107
+ mutation($p: ID!, $c: ID!) {
108
+ addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
109
+ }`, { p: process.env.PROJECT_ID, c: nodeId });
110
+ await github.graphql(`
111
+ mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
112
+ updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
113
+ projectV2Item { id }
114
+ }
115
+ }`, { p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
116
+ v: { singleSelectOptionId: process.env.STATUS_CODE_REVIEW_PR } });
117
+ };
118
+
119
+ if (linkedIssues.length > 0) {
120
+ for (const n of linkedIssues) {
121
+ const { data: issue } = await github.rest.issues.get({ owner, repo, issue_number: n });
122
+ await moveItem(issue.node_id);
123
+ console.log(`Issue #${n} → Code Review / PR`);
124
+ }
125
+ } else {
126
+ await moveItem(pr.node_id);
127
+ console.log(`PR #${prNumber} → Code Review / PR (no linked issue)`);
128
+ }
package/CLAUDE.md ADDED
@@ -0,0 +1,9 @@
1
+ # PDLC Stage Gate
2
+
3
+ NEVER run `gh pr create` unless one of these is true:
4
+ - The linked issue has label `stage:approval`
5
+ - The branch name starts with `hotfix/`
6
+
7
+ Advance stages first: `exploration` → `brainstorming` → `detailing` → `approval`
8
+
9
+ The PreToolUse hook will block the action automatically if this rule is violated.
package/SETUP.md CHANGED
@@ -149,6 +149,34 @@ If you don't use this, you can safely delete `templates/.github/workflows/qa-age
149
149
 
150
150
  ---
151
151
 
152
+ ## (Optional) Agentic Metrics — Weekly Report
153
+
154
+ Every Sunday a `📊 Agentic Pulse` issue is created automatically in your repository with agentic-specific insights no off-the-shelf tool provides:
155
+
156
+ - **Orphan issues** — open 14+ days with no linked PR (forgotten or blocked work)
157
+ - **PR merge time trend** — week-over-week comparison (flow acceleration or slowdown)
158
+ - **Rework rate** — PRs merged without extra commit sessions (agent or human first-shot rate)
159
+ - **Unlinked PRs** — merged without `Closes #N` (traceability gaps)
160
+ - **Stage Residence Time** — included automatically if your team uses `stage:*` labels _(Milestone 2)_
161
+
162
+ The issue appears in your GitHub notifications automatically — zero extra setup, zero extra secrets.
163
+
164
+ **To activate:**
165
+
166
+ 1. Copy the workflow to your repository:
167
+ ```bash
168
+ cp .agentic-pdlc/templates/.github/workflows/agentic-metrics.yml .github/workflows/agentic-metrics.yml
169
+ ```
170
+
171
+ 2. Commit and push. The first pulse runs next Sunday, or trigger it manually:
172
+ ```bash
173
+ gh workflow run agentic-metrics.yml
174
+ ```
175
+
176
+ > **No additional secrets needed.** The workflow uses the standard `GITHUB_TOKEN` and creates a `metrics:weekly` label automatically on first run.
177
+
178
+ ---
179
+
152
180
  ## Final Verification Checklist
153
181
 
154
182
  - [ ] Board has 10 columns fully configured
@@ -42,7 +42,7 @@ If any of these files are missing, you are in **Setup Mode**. Do not proceed wit
42
42
  - c) **Yes, activate** — *Uncomment the `move-violation-to-board` job in `project-automation.yml`.* → Activate immediately.
43
43
  - **QA Agent:** Ask: *"Do you want to use a QA agent to verify PRs automatically before Code Review?"* Present the options:
44
44
  - a) **No (Variant A)** — *PRs go straight to Code Review. Standard and simpler.*
45
- - b) **Yes (Variant B), but I need help configuring it** — *PRs pass through a QA Agent before being reviewed. Requires a `GEMINI_API_KEY` secret (free tier available at ai.google.dev).* → Guide the user through configuration.
45
+ - b) **Yes (Variant B), but I need help configuring it** — *PRs pass through a QA Agent before being reviewed. Uses `GITHUB_TOKEN` zero additional secrets.* → Guide the user through configuration.
46
46
  - c) **Yes (Variant B), I already have it configured** — *PRs pass through a QA Agent before being reviewed.* → Activate Variant B immediately: change `STATUS_CODE_REVIEW_PR` to `STATUS_TESTING` in the `move-card-on-pr-open` job and uncomment the `move-card-on-qa-pass` job in `project-automation.yml`.
47
47
  - **Implementation Agent:** Ask: *"Do you use an autonomous implementation agent? (It implements the features you approve for development)"* Present the options:
48
48
  - a) **No** — *No autonomous implementation agent.*
@@ -86,7 +86,32 @@ This detects which optional agents (Jules, QA Agent, Sentinel) are already confi
86
86
 
87
87
  If `AGENTS.md` and `docs/pdlc.md` are present, you are in **Execution Mode**.
88
88
 
89
- ### 0. Board Labels Mandatory at Every State Transition
89
+ ### 0. [FIRST] Issue Type Identification
90
+
91
+ **Run before anything else — before `stage:exploration`, before reading code.**
92
+
93
+ Reading the issue title and body for type inference is exempt from the `stage:exploration` requirement: it is metadata already present in the request, not code reading or skill invocation.
94
+
95
+ 1. Check if issue already has a `type:*` label (`type:us`, `type:task`, `type:bug`, `type:spike`) → if yes, skip to Section 0.1.
96
+ 2. Read issue title + body (metadata only — no code reading at this step).
97
+ 3. Classify using these rules:
98
+ - `type:task` — operational change, config, rename, docs update, non-functional (no user-facing behavior change)
99
+ - `type:bug` — something broken that should work
100
+ - `type:spike` — research/evaluation spike, never reaches Development
101
+ - `type:us` — new feature, behavioral change, anything product-facing
102
+ 4. Confidence ≥ 85% → add inferred label: `gh issue edit <N> --add-label "type:<inferred>"`
103
+ 5. Confidence < 85% → default to `type:us`: `gh issue edit <N> --add-label "type:us"`
104
+
105
+ **Type drives the PDLC flow:**
106
+
107
+ | Type | Flow |
108
+ |---|---|
109
+ | `type:us` | Full flow: exploration → brainstorming → Gate 1 → detailing → approval |
110
+ | `type:task` | Skip brainstorming: exploration → detailing → approval |
111
+ | `type:bug` | Skip brainstorming: exploration → detailing → approval |
112
+ | `type:spike` | Skip brainstorming: exploration → detailing → conclusion comment (never reaches Development) |
113
+
114
+ ### 0.1 Board Labels — Mandatory at Every State Transition
90
115
 
91
116
  These label commands are non-negotiable. They run **before** the activity they announce — before reading code, before invoking any skill, before any other action.
92
117
 
@@ -98,8 +123,21 @@ These label commands are non-negotiable. They run **before** the activity they a
98
123
 
99
124
  No investigation, no skill invocation, no code reading happens before `stage:exploration` is applied. No architecture presentation starts before `stage:brainstorming` is set (and `stage:exploration` removed). No spec writing starts before `stage:detailing` is set (and `stage:brainstorming` removed).
100
125
 
126
+ ### 0.1 PR Stage Gate — Non-Negotiable
127
+
128
+ **NEVER run `gh pr create` unless the linked issue has label `stage:approval`.**
129
+
130
+ The PreToolUse hook enforces this automatically and will block the command. The only bypass is a branch prefixed with `hotfix/` — which requires explicit PM instruction, never agent self-authorization.
131
+
132
+ Hotfix flow (only when PM explicitly requests it):
133
+ ```bash
134
+ gh issue edit <N> --add-label "hotfix"
135
+ git checkout -b hotfix/<N>-<description>
136
+ # implement → gh pr create --label hotfix
137
+ ```
138
+
101
139
  ### 1. Daily Upstream Loop
102
- Your job is to move issues from "Idea" to "Detail Solution".
140
+ Your job is to move issues from "💡 Idea - don't move manually to Exploration" to "📐 Detail Solution".
103
141
  When asked to work on a feature, you will:
104
142
  - Explore the code context.
105
143
  - Present architectural approaches (Brainstorming).
@@ -0,0 +1,44 @@
1
+ #!/bin/bash
2
+ # PDLC Stage Gate — blocks gh pr create without stage:approval on linked issue.
3
+ # Bypass: branch prefix hotfix/ skips all checks.
4
+
5
+ INPUT=$(cat)
6
+ COMMAND=$(echo "$INPUT" | node -e "const d=JSON.parse(require('fs').readFileSync(0)); console.log(d.command || '')" 2>/dev/null || echo "")
7
+
8
+ if ! echo "$COMMAND" | grep -q "gh pr create"; then
9
+ exit 0
10
+ fi
11
+
12
+ BRANCH=$(git branch --show-current 2>/dev/null || echo "")
13
+
14
+ if echo "$BRANCH" | grep -qE "^hotfix/"; then
15
+ echo "✅ PDLC: Hotfix branch — stage gate bypassed."
16
+ exit 0
17
+ fi
18
+
19
+ ISSUE_NUM=$(echo "$BRANCH" | grep -oE '[0-9]+' | head -1)
20
+
21
+ if [ -z "$ISSUE_NUM" ]; then
22
+ echo "❌ PDLC Stage Gate: Cannot determine issue from branch '$BRANCH'."
23
+ echo " Use: feat/<issue-number>-<description> or hotfix/<issue-number>-<description>"
24
+ exit 1
25
+ fi
26
+
27
+ LABELS=$(gh issue view "$ISSUE_NUM" --json labels --jq '[.labels[].name] | join(" ")' 2>/dev/null || echo "")
28
+
29
+ if echo "$LABELS" | grep -qw "stage:approval"; then
30
+ echo "✅ PDLC: Issue #$ISSUE_NUM approved — gate passed."
31
+ exit 0
32
+ fi
33
+
34
+ if echo "$LABELS" | grep -qw "stage:development"; then
35
+ echo "✅ PDLC: Issue #$ISSUE_NUM in development (spec already approved) — gate passed."
36
+ exit 0
37
+ fi
38
+
39
+ STAGE=$(echo "$LABELS" | tr ' ' '\n' | grep "^stage:" | head -1 || echo "none")
40
+ echo "❌ PDLC Stage Gate: Issue #$ISSUE_NUM is not approved."
41
+ echo " Current stage: $STAGE"
42
+ echo " Required: stage:approval or stage:development label on the issue."
43
+ echo " Emergency bypass: rename branch to hotfix/<issue-number>-<description>."
44
+ exit 1
package/bin/cli.js CHANGED
@@ -68,8 +68,8 @@ const i18n = {
68
68
  update_jules_header: t('— Jules (autonomous implementation agent) —', '— Jules (agente de implementação autônomo) —', '— Jules (agente de implementación autónomo) —'),
69
69
  update_jules_ask: t(' Which agent? (a) @google-labs-jules (b) Other (c) Skip: ', ' Qual agente? (a) @google-labs-jules (b) Outro (c) Pular: ', ' ¿Qué agente? (a) @google-labs-jules (b) Otro (c) Omitir: '),
70
70
  update_jules_ask_handle: t(' Agent handle (e.g. @my-agent): ', ' Handle do agente (ex: @meu-agente): ', ' Handle del agente (ej: @mi-agente): '),
71
- update_qa_header: t('— QA Agent (AC verification via Geminifree tier) —', '— QA Agent (verificação de ACs via Geminifree tier) —', '— QA Agent (verificación de ACs via Geminifree tier) —'),
72
- update_qa_ask: t(' Activate? Requires GEMINI_API_KEY secret. (Y/n): ', ' Ativar? Requer secret GEMINI_API_KEY. (S/n): ', ' ¿Activar? Requiere el secret GEMINI_API_KEY. (S/n): '),
71
+ update_qa_header: t('— QA Agent (AC verification via GitHub Models zero secrets) —', '— QA Agent (verificação de ACs via GitHub Models zero secrets) —', '— QA Agent (verificación de ACs via GitHub Models zero secrets) —'),
72
+ update_qa_ask: t(' Activate? Uses GITHUB_TOKEN — no extra secrets needed. (Y/n): ', ' Ativar? Usa GITHUB_TOKEN — nenhum secret extra necessário. (S/n): ', ' ¿Activar? Usa GITHUB_TOKEN sin secrets adicionales. (S/n): '),
73
73
  update_sentinel_header: t('— Sentinel (architecture audit via Gemini Code Assist) —', '— Sentinel (auditoria de arquitetura via Gemini Code Assist) —', '— Sentinel (auditoría de arquitectura via Gemini Code Assist) —'),
74
74
  update_sentinel_ask: t(' Activate? Requires Gemini Code Assist CI job. (Y/n): ', ' Ativar? Requer CI job do Gemini Code Assist. (S/n): ', ' ¿Activar? Requiere CI job de Gemini Code Assist. (S/n): '),
75
75
  };
@@ -343,6 +343,29 @@ async function runSetup() {
343
343
  // Non-fatal — agent will ask for the values instead
344
344
  }
345
345
 
346
+ // Install PDLC stage gate hook (all agents)
347
+ const hookSrc = path.join(sourceDir, 'adapters', 'hooks', 'pdlc-stage-gate.sh');
348
+ const hookDir = path.join(targetDir, '.agentic-pdlc', 'hooks');
349
+ const hookDest = path.join(hookDir, 'pdlc-stage-gate.sh');
350
+ if (fs.existsSync(hookSrc)) {
351
+ fs.mkdirSync(hookDir, { recursive: true });
352
+ fs.copyFileSync(hookSrc, hookDest);
353
+ fs.chmodSync(hookDest, '755');
354
+ }
355
+ const claudeSettingsDir = path.join(targetDir, '.claude');
356
+ const claudeSettingsPath = path.join(claudeSettingsDir, 'settings.json');
357
+ if (!fs.existsSync(claudeSettingsPath)) {
358
+ fs.mkdirSync(claudeSettingsDir, { recursive: true });
359
+ fs.writeFileSync(claudeSettingsPath, JSON.stringify({
360
+ hooks: {
361
+ PreToolUse: [{
362
+ matcher: 'Bash',
363
+ hooks: [{ type: 'command', command: 'bash .agentic-pdlc/hooks/pdlc-stage-gate.sh' }]
364
+ }]
365
+ }
366
+ }, null, 2) + '\n');
367
+ }
368
+
346
369
  // Handle the specific setup instructions target
347
370
  const claudeSetupSrc = path.join(sourceDir, 'adapters', 'claude-code', 'skill.md');
348
371
  const cursorSetupSrc = path.join(sourceDir, 'adapters', 'cursor', 'rules.md');
@@ -536,9 +559,9 @@ async function runUpdate() {
536
559
  if (!['n', 'no', 'não', 'nao'].includes(answer)) {
537
560
  activateQaAgent(paPath);
538
561
  results.push(t(
539
- '✅ QA Agent configured — Variant B activated\n Next: gh secret set GEMINI_API_KEY --body "<your-key>"',
540
- '✅ QA Agent configurado — Variant B ativado\n Próximo: gh secret set GEMINI_API_KEY --body "<sua-chave>"',
541
- '✅ QA Agent configurado — Variant B activado\n Siguiente: gh secret set GEMINI_API_KEY --body "<tu-clave>"'
562
+ '✅ QA Agent configured — Variant B activated (uses GITHUB_TOKEN, no extra secrets needed)',
563
+ '✅ QA Agent configurado — Variant B ativado (usa GITHUB_TOKEN, nenhum secret extra necessário)',
564
+ '✅ QA Agent configurado — Variant B activado (usa GITHUB_TOKEN, sin secrets adicionales)'
542
565
  ));
543
566
  } else {
544
567
  results.push(t('⏭ QA Agent — skipped', '⏭ QA Agent — pulado', '⏭ QA Agent — omitido'));
package/docs/pdlc.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  | Column | Meaning | Who moves the card |
6
6
  |---|---|---|
7
- | 💡 Idea | Backlog — every new issue lands here | Manual |
7
+ | 💡 Idea — don't move manually to Exploration | Backlog — tell agent: "work on issue #XX" | Don't move manually |
8
8
  | 🔍 Exploration | AI is analyzing code and context | Label `stage:exploration` |
9
9
  | 🧠 Brainstorming | AI proposed approaches and trade-offs | Label `stage:brainstorming` |
10
10
  | 📐 Detail Solution | AI is writing the technical spec | Label `stage:detailing` |
@@ -72,6 +72,10 @@ REPO = {{REPO_OWNER}}/{{REPO_NAME}}
72
72
  | `spec:approved` | Issue | Green | Gate 2 — agent is cleared to implement |
73
73
  | `pr:in-review` | PR | Yellow | Awaiting code review |
74
74
  | `pr:approved` | PR | Green | Code review approved |
75
+ | `type:us` | Issue | Blue | New feature or behavioral change — full flow |
76
+ | `type:task` | Issue | Yellow | Operational/non-functional change — skips brainstorming |
77
+ | `type:bug` | Issue | Red | Something broken — skips brainstorming |
78
+ | `type:spike` | Issue | Gray | Research/evaluation — never reaches Development |
75
79
 
76
80
  ## Approval Gates
77
81
 
@@ -85,10 +89,16 @@ This triggers the implementation agent via `agent-trigger.yml`.
85
89
 
86
90
  ## Shortcuts by Type
87
91
 
88
- - **BUG**Skips Brainstorming; enters Detail Solution with diagnostics + fix.
89
- - **TASK** — Skips Brainstorming; enters Detail Solution with operational steps.
90
- - **SPIKE** Never reaches Development; delivery is a concluding comment.
91
- - **US** — Full flow observing both gates.
92
+ The `type:*` label is the authoritative signal set automatically by the agent via type inference (see `adapters/claude-code/skill.md`). Title prefixes (`🔧 TASK:`, `👤 US:`) are hints for humans; the label drives the flow.
93
+
94
+ | Label | Flow |
95
+ |---|---|
96
+ | `type:us` | Full flow — exploration → brainstorming → Gate 1 → detailing → approval |
97
+ | `type:task` | Skips brainstorming — exploration → detailing → approval |
98
+ | `type:bug` | Skips brainstorming — exploration → detailing → approval |
99
+ | `type:spike` | Skips brainstorming — exploration → detailing → conclusion comment (never reaches Development) |
100
+
101
+ If no `type:*` label present and agent confidence < 85%, defaults to `type:us` (safe fallback — never skips gates by omission).
92
102
 
93
103
  ## Definition of Done
94
104
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-agentic-pdlc",
3
- "version": "2.1.6",
3
+ "version": "2.2.0",
4
4
  "description": "Agentic PDLC Framework - Conversational setup for your AI coding assistants",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -0,0 +1,20 @@
1
+ {
2
+ "body": "![security-high](https://www.gstatic.com/codereviewagent/security-high-priority.svg) ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)\n\nThe use of `execSync` with template literals containing user-provided variables (such as `${repo}`, `${repoOwner}`, `${repoName}`, and `${branchName}`) is vulnerable to command injection. If a user provides a malicious repository URL or branch name containing shell metacharacters (e.g., `; rm -rf /`), they could execute arbitrary shell commands. It is highly recommended to use `spawnSync` with an arguments array to avoid shell interpretation, or at least sanitize and quote the inputs strictly.",
3
+ "path": "bin/cli.js",
4
+ "line": 155
5
+ }
6
+ {
7
+ "body": "![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)\n\nThe required status check context `\"Sentinel / CI\"` does not match any of the workflow or job names defined in the provided templates (e.g., `PDLC Board Automation` or `Detect Project Board Drift`). This will cause pull requests to be permanently blocked as the required check will never be reported. Based on the provided templates, `\"Detect Project Board Drift\"` seems to be the intended health check job name.\n\n```suggestion\n required_status_checks: { strict: true, checks: [{ context: \"Detect Project Board Drift\" }] },\n```",
8
+ "path": "bin/cli.js",
9
+ "line": 165
10
+ }
11
+ {
12
+ "body": "![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)\n\nParsing `updateOutput` directly can throw a `SyntaxError` if the command fails or returns an empty/invalid response. Although it's inside a `try...catch` block, checking if the output is truthy before parsing and using optional chaining provides better resilience and prevents the script from crashing on unexpected API responses.\n\n```suggestion\n const jsonResponse = updateOutput ? JSON.parse(updateOutput) : null;\n const returnedOptions = jsonResponse?.data?.updateProjectV2SingleSelectField?.projectV2SingleSelectField?.options || [];\n```",
13
+ "path": "bin/cli.js",
14
+ "line": 248
15
+ }
16
+ {
17
+ "body": "![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)\n\nTypo in Spanish translation: \"arquivo\" is Portuguese. In Spanish, it should be \"archivo\".\n\n```suggestion\n console.log(`${cyan}>>> Español: \"Lea el archivo .agentic-setup.md e inicie el Setup Mode\"${reset}`);\n```",
18
+ "path": "bin/cli.js",
19
+ "line": 314
20
+ }
@@ -0,0 +1,38 @@
1
+ name: Add to Board on Open
2
+
3
+ on:
4
+ issues:
5
+ types: [opened]
6
+
7
+ env:
8
+ PROJECT_ID: "{{PROJECT_ID}}"
9
+ STATUS_FIELD_ID: "{{STATUS_FIELD_ID}}"
10
+ STATUS_IDEA: "{{ID_IDEA}}"
11
+
12
+ jobs:
13
+ add-to-board:
14
+ name: Auto-add new issue to board
15
+ runs-on: ubuntu-latest
16
+ env:
17
+ PROJECT_PAT: ${{ secrets.PROJECT_PAT }}
18
+ steps:
19
+ - name: Add issue to project board
20
+ if: ${{ env.PROJECT_PAT != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
21
+ uses: actions/github-script@v7
22
+ with:
23
+ github-token: ${{ env.PROJECT_PAT }}
24
+ script: |
25
+ const nodeId = context.payload.issue.node_id;
26
+ const number = context.payload.issue.number;
27
+ const { addProjectV2ItemById: { item } } = await github.graphql(`
28
+ mutation($p: ID!, $c: ID!) {
29
+ addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
30
+ }`, { p: process.env.PROJECT_ID, c: nodeId });
31
+ await github.graphql(`
32
+ mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
33
+ updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
34
+ projectV2Item { id }
35
+ }
36
+ }`, { p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
37
+ v: { singleSelectOptionId: process.env.STATUS_IDEA } });
38
+ console.log(`Issue #${number} added to board → Idea`);
@@ -16,16 +16,20 @@ jobs:
16
16
  issues: write
17
17
  pull-requests: write
18
18
  contents: read
19
+ env:
20
+ PROJECT_PAT: ${{ secrets.PROJECT_PAT }}
21
+ PROJECT_ID: "{{PROJECT_ID}}"
22
+ STATUS_FIELD_ID: "{{STATUS_FIELD_ID}}"
23
+ STATUS_DEVELOPMENT: "{{ID_DEVELOPMENT}}"
19
24
  steps:
20
25
  - name: Update Labels
21
- if: ${{ !contains('{{IMPLEMENTATION_AGENT_LABEL}}', '{{') }}
22
26
  uses: actions/github-script@v7
23
27
  with:
24
28
  github-token: ${{ secrets.GITHUB_TOKEN }}
25
29
  script: |
26
30
  const { owner, repo } = context.repo;
27
31
  const issue_number = context.payload.issue.number;
28
-
32
+
29
33
  try {
30
34
  await github.rest.issues.removeLabel({
31
35
  owner,
@@ -36,14 +40,40 @@ jobs:
36
40
  } catch (error) {
37
41
  console.log('Label stage:approval not found or could not be removed');
38
42
  }
39
-
43
+
44
+ const agentLabel = '{{IMPLEMENTATION_AGENT_LABEL}}';
45
+ const labelsToAdd = ['stage:development'];
46
+ if (!agentLabel.includes('{{')) labelsToAdd.push(agentLabel, 'agent:working');
47
+
40
48
  await github.rest.issues.addLabels({
41
49
  owner,
42
50
  repo,
43
51
  issue_number,
44
- labels: ['stage:development', '{{IMPLEMENTATION_AGENT_LABEL}}', 'agent:working']
52
+ labels: labelsToAdd
45
53
  });
46
54
 
55
+ - name: Move board card to Development
56
+ if: ${{ env.PROJECT_PAT != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
57
+ continue-on-error: true
58
+ uses: actions/github-script@v7
59
+ with:
60
+ github-token: ${{ env.PROJECT_PAT }}
61
+ script: |
62
+ const nodeId = context.payload.issue.node_id;
63
+ const number = context.payload.issue.number;
64
+ const { addProjectV2ItemById: { item } } = await github.graphql(`
65
+ mutation($p: ID!, $c: ID!) {
66
+ addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
67
+ }`, { p: process.env.PROJECT_ID, c: nodeId });
68
+ await github.graphql(`
69
+ mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
70
+ updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
71
+ projectV2Item { id }
72
+ }
73
+ }`, { p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
74
+ v: { singleSelectOptionId: process.env.STATUS_DEVELOPMENT } });
75
+ console.log(`Issue #${number} → Development`);
76
+
47
77
  - name: Comment on issue to trigger agent and prevent race conditions
48
78
  if: ${{ !contains('{{IMPLEMENTATION_AGENT_LABEL}}', '{{') }}
49
79
  uses: actions/github-script@v7
@@ -0,0 +1,51 @@
1
+ name: PDLC Stage Gate
2
+ on:
3
+ pull_request:
4
+ types: [opened, synchronize, reopened, labeled, unlabeled]
5
+
6
+ permissions:
7
+ pull-requests: read
8
+ issues: read
9
+
10
+ jobs:
11
+ stage-gate:
12
+ name: PDLC Stage Gate
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - name: Check stage:approval
16
+ env:
17
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
18
+ run: |
19
+ set -e
20
+ REPO="${{ github.repository }}"
21
+ PR_NUMBER="${{ github.event.pull_request.number }}"
22
+
23
+ PR_LABELS=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json labels --jq '[.labels[].name] | join(" ")')
24
+ if echo "$PR_LABELS" | grep -qw "hotfix"; then
25
+ echo "✅ Hotfix label — stage gate bypassed."
26
+ exit 0
27
+ fi
28
+
29
+ PR_BODY=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json body --jq '.body // ""')
30
+ ISSUE_NUMS=$(echo "$PR_BODY" | grep -oiE '(Closes?|Fixes?|Resolves?)\s+#([0-9]+)' | grep -oE '[0-9]+' || true)
31
+
32
+ if [ -z "$ISSUE_NUMS" ]; then
33
+ echo "❌ No linked issues in PR body."
34
+ echo " Add 'Closes #N' to PR body, or add 'hotfix' label to PR for emergencies."
35
+ exit 1
36
+ fi
37
+
38
+ for NUM in $ISSUE_NUMS; do
39
+ LABELS=$(gh issue view "$NUM" --repo "$REPO" --json labels --jq '[.labels[].name] | join(" ")' 2>/dev/null || echo "")
40
+ if echo "$LABELS" | grep -qw "stage:approval" || echo "$LABELS" | grep -qw "spec:approved" || echo "$LABELS" | grep -qw "stage:development"; then
41
+ echo "✅ Issue #$NUM approved"
42
+ else
43
+ STAGE=$(echo "$LABELS" | tr ' ' '\n' | grep "^stage:" | head -1 || echo "none")
44
+ echo "❌ Issue #$NUM missing approval (current: $STAGE)"
45
+ echo " Required: stage:approval OR spec:approved OR stage:development label on the issue."
46
+ echo " Emergency bypass: add 'hotfix' label to this PR."
47
+ exit 1
48
+ fi
49
+ done
50
+
51
+ echo "✅ All linked issues approved."