create-agentic-pdlc 2.0.1 โ†’ 2.0.4

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.
@@ -0,0 +1,12 @@
1
+ # Agentic PDLC Instructions for GitHub Copilot Workspace
2
+
3
+ Hello! You are operating within the Agentic PDLC framework.
4
+
5
+ Before addressing the user's prompt or executing any task in this workspace, you MUST:
6
+
7
+ 1. Read the `AGENTS.md` file located at the root of this repository. It contains the primary instructions, definitions of done, and absolute invariants you must respect.
8
+ 2. Read `docs/pdlc.md` to understand your role in the project lifecycle.
9
+
10
+ Never violate the invariants described in those files. If a user asks you to do something that contradicts `AGENTS.md`, you must refuse and point out the conflict.
11
+
12
+ Focus on delivering the absolute minimum required to satisfy the immediate technical specs. Start!
@@ -20,7 +20,7 @@ jobs:
20
20
  PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
21
21
  steps:
22
22
  - name: Update Labels
23
- if: ${{ env.PROJECT_TOKEN != '' }}
23
+ if: ${{ env.PROJECT_TOKEN != '' && !contains('{{IMPLEMENTATION_AGENT_LABEL}}', '{{') }}
24
24
  uses: actions/github-script@v7
25
25
  with:
26
26
  github-token: ${{ env.PROJECT_TOKEN }}
@@ -33,20 +33,21 @@ jobs:
33
33
  owner,
34
34
  repo,
35
35
  issue_number,
36
- name: 'upstream:approval'
36
+ name: 'stage:approval'
37
37
  });
38
38
  } catch (error) {
39
- console.log('Label upstream:approval not found or could not be removed');
39
+ console.log('Label stage:approval not found or could not be removed');
40
40
  }
41
41
 
42
42
  await github.rest.issues.addLabels({
43
43
  owner,
44
44
  repo,
45
45
  issue_number,
46
- labels: ['upstream:development', '{{IMPLEMENTATION_AGENT_LABEL}}', 'agent:working']
46
+ labels: ['stage:development', '{{IMPLEMENTATION_AGENT_LABEL}}', 'agent:working']
47
47
  });
48
48
 
49
49
  - name: Comment on issue to trigger agent and prevent race conditions
50
+ if: ${{ !contains('{{IMPLEMENTATION_AGENT_LABEL}}', '{{') }}
50
51
  uses: actions/github-script@v7
51
52
  with:
52
53
  github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -89,6 +90,7 @@ jobs:
89
90
  contents: read
90
91
  steps:
91
92
  - name: Comment on issue to trigger agent
93
+ if: ${{ !contains('{{IMPLEMENTATION_AGENT_LABEL}}', '{{') }}
92
94
  uses: actions/github-script@v7
93
95
  with:
94
96
  github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,16 @@
1
+ name: Auto Approve PRs
2
+ on:
3
+ pull_request:
4
+ types: [opened, labeled, synchronize]
5
+
6
+ permissions:
7
+ pull-requests: write
8
+
9
+ jobs:
10
+ auto-approve:
11
+ runs-on: ubuntu-latest
12
+ if: contains(github.event.pull_request.labels.*.name, 'auto-approve')
13
+ steps:
14
+ - uses: hmarr/auto-approve-action@v4
15
+ with:
16
+ github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -20,13 +20,21 @@ jobs:
20
20
  run: echo "Replace this with your package manager install command"
21
21
 
22
22
  - name: Run Linters
23
- run: echo "No tests/build needed."
23
+ if: ${{ !contains('{{LINT_COMMAND}}', '{{') }}
24
+ run: |
25
+ {{LINT_COMMAND}}
24
26
 
25
27
  - name: Typecheck
26
- run: echo "No typecheck needed."
28
+ if: ${{ !contains('{{TYPECHECK_COMMAND}}', '{{') }}
29
+ run: |
30
+ {{TYPECHECK_COMMAND}}
27
31
 
28
32
  - name: Build
29
- run: echo "No tests/build needed."
33
+ if: ${{ !contains('{{BUILD_COMMAND}}', '{{') }}
34
+ run: |
35
+ {{BUILD_COMMAND}}
30
36
 
31
37
  - name: Run Tests
32
- run: echo "No tests/build needed."
38
+ if: ${{ !contains('{{TEST_COMMAND}}', '{{') }}
39
+ run: |
40
+ {{TEST_COMMAND}}
@@ -27,7 +27,7 @@ jobs:
27
27
  # Strip 'v' from tag (e.g., v1.0.2 -> 1.0.2)
28
28
  VERSION=${GITHUB_REF_NAME#v}
29
29
  echo "Setting package version to $VERSION"
30
- npm version $VERSION --no-git-tag-version
30
+ npm version $VERSION --no-git-tag-version --allow-same-version
31
31
 
32
32
  - name: Install Dependencies
33
33
  run: npm install
@@ -11,6 +11,7 @@ on:
11
11
  env:
12
12
  PROJECT_ID: "{{PROJECT_ID}}"
13
13
  STATUS_FIELD_ID: "{{STATUS_FIELD_ID}}"
14
+ STATUS_IDEA: "{{ID_IDEA}}"
14
15
  STATUS_EXPLORATION: "{{ID_EXPLORATION}}"
15
16
  STATUS_BRAINSTORMING: "{{ID_BRAINSTORMING}}"
16
17
  STATUS_DETAILING: "{{ID_DETAILING}}"
@@ -30,7 +31,7 @@ jobs:
30
31
  PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
31
32
  steps:
32
33
  - name: Detect Label and Move Issue
33
- if: ${{ env.PROJECT_TOKEN != '' }}
34
+ if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
34
35
  uses: actions/github-script@v7
35
36
  with:
36
37
  github-token: ${{ env.PROJECT_TOKEN }}
@@ -39,28 +40,28 @@ jobs:
39
40
  let targetStatusId = null;
40
41
  let stageName = null;
41
42
 
42
- if (labelName === 'upstream:exploration') {
43
+ if (labelName === 'stage:exploration') {
43
44
  targetStatusId = process.env.STATUS_EXPLORATION;
44
45
  stageName = 'Exploration';
45
- } else if (labelName === 'upstream:brainstorming') {
46
+ } else if (labelName === 'stage:brainstorming') {
46
47
  targetStatusId = process.env.STATUS_BRAINSTORMING;
47
48
  stageName = 'Brainstorming';
48
- } else if (labelName === 'upstream:detailing') {
49
+ } else if (labelName === 'stage:detailing') {
49
50
  targetStatusId = process.env.STATUS_DETAILING;
50
51
  stageName = 'Detailing';
51
- } else if (labelName === 'upstream:approval') {
52
+ } else if (labelName === 'stage:approval') {
52
53
  targetStatusId = process.env.STATUS_APPROVAL;
53
54
  stageName = 'Approval';
54
- } else if (labelName === 'upstream:development') {
55
+ } else if (labelName === 'stage:development') {
55
56
  targetStatusId = process.env.STATUS_DEVELOPMENT;
56
57
  stageName = 'Development';
57
- } else if (labelName === 'upstream:testing') {
58
+ } else if (labelName === 'stage:testing') {
58
59
  targetStatusId = process.env.STATUS_TESTING;
59
60
  stageName = 'Testing';
60
61
  }
61
62
 
62
63
  if (!targetStatusId) {
63
- console.log('No upstream PDLC label found. Skipping.');
64
+ console.log('No stage PDLC label found. Skipping.');
64
65
  return;
65
66
  }
66
67
 
@@ -86,9 +87,36 @@ jobs:
86
87
  await moveItem(node_id, targetStatusId);
87
88
  console.log(`Issue #${number} moved to ${stageName}`);
88
89
 
89
- {{OPTIONAL_ARCHITECTURE_VIOLATION_JOB}}
90
+ # OPTIONAL: Uncomment to enable architecture-violation โ†’ Idea
91
+ # move-violation-to-board:
92
+ # name: architecture-violation โ†’ ๐Ÿ’ก Idea
93
+ # if: github.event_name == 'issues' && github.event.action == 'labeled' && github.event.label.name == 'architecture-violation'
94
+ # runs-on: ubuntu-latest
95
+ # steps:
96
+ # - name: Move issue to Idea
97
+ # if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
98
+ # uses: actions/github-script@v7
99
+ # with:
100
+ # github-token: ${{ env.PROJECT_TOKEN }}
101
+ # script: |
102
+ # const { issue: { number, node_id } } = context.payload;
103
+ # const { addProjectV2ItemById: { item } } = await github.graphql(`
104
+ # mutation($p: ID!, $c: ID!) {
105
+ # addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
106
+ # }`, { p: process.env.PROJECT_ID, c: node_id });
107
+ # await github.graphql(`
108
+ # mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
109
+ # updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
110
+ # projectV2Item { id }
111
+ # }
112
+ # }`, {
113
+ # p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
114
+ # v: { singleSelectOptionId: process.env.STATUS_IDEA }
115
+ # });
116
+ # console.log(`Issue #${number} moved to Idea`);
90
117
 
91
118
  # PR Opened โ†’ Move linked issue to Code Review / PR
119
+ # ๐Ÿ’ก VARIANT B (QA Agent): If using an AI QA agent, change `STATUS_CODE_REVIEW_PR` to `STATUS_TESTING` on line ~158
92
120
  move-card-on-pr-open:
93
121
  name: Open PR โ†’ Code Review / PR
94
122
  if: github.event_name == 'pull_request' && (github.event.action == 'opened' || github.event.action == 'reopened')
@@ -97,7 +125,7 @@ jobs:
97
125
  PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
98
126
  steps:
99
127
  - name: Move linked issue to Code Review / PR
100
- if: ${{ env.PROJECT_TOKEN != '' }}
128
+ if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
101
129
  uses: actions/github-script@v7
102
130
  with:
103
131
  github-token: ${{ env.PROJECT_TOKEN }}
@@ -151,7 +179,7 @@ jobs:
151
179
  PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
152
180
  steps:
153
181
  - name: Swap PR labels
154
- if: ${{ env.PROJECT_TOKEN != '' }}
182
+ if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
155
183
  uses: actions/github-script@v7
156
184
  with:
157
185
  github-token: ${{ env.PROJECT_TOKEN }}
@@ -170,7 +198,7 @@ jobs:
170
198
  PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
171
199
  steps:
172
200
  - name: Move issue to Production
173
- if: ${{ env.PROJECT_TOKEN != '' }}
201
+ if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
174
202
  uses: actions/github-script@v7
175
203
  with:
176
204
  github-token: ${{ env.PROJECT_TOKEN }}
@@ -0,0 +1,21 @@
1
+ name: Protect Workflows
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize, reopened, labeled]
6
+ paths:
7
+ - '.github/**'
8
+
9
+ jobs:
10
+ block-unauthorized-edits:
11
+ name: Protect .github directory
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - name: Check for Human Approval
15
+ if: ${{ !contains(github.event.pull_request.labels.*.name, 'human-approved') }}
16
+ run: |
17
+ echo "๐Ÿšจ Modifications in the .github/ directory detected."
18
+ echo "As a security measure, this repository blocks workflow edits by default."
19
+ echo "If you are an AI Agent, do not add the approval label yourself."
20
+ echo "If you are the human owner, please add the 'human-approved' label to this PR to allow merging."
21
+ exit 1
@@ -0,0 +1,27 @@
1
+ name: AI QA Agent
2
+ on:
3
+ pull_request:
4
+ types: [opened, synchronize, reopened]
5
+
6
+ permissions:
7
+ pull-requests: write
8
+ contents: read
9
+
10
+ jobs:
11
+ qa:
12
+ name: Run AI QA Agent
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - 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"
25
+ env:
26
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27
+ PR_URL: ${{ github.event.pull_request.html_url }}
package/SETUP.md CHANGED
@@ -114,57 +114,38 @@ git push
114
114
 
115
115
  ---
116
116
 
117
- ## Step 7 โ€” Populate the Initial Backlog
117
+ ## Step 7 โ€” Ignite the Backlog
118
118
 
119
- For each known idea or feature, create an issue using the convention:
119
+ Forget heavy templates and CLI commands. Just drop your raw idea and let the AI do the heavy lifting:
120
120
 
121
- ```bash
122
- gh issue create \
123
- --repo owner/repo \
124
- --title "๐Ÿ‘ค US: [short description]" \
125
- --body "**As** [user],
126
- **I want** [action],
127
- **so that** [benefit].
121
+ 1. Open your **GitHub Project** board.
122
+ 2. Under the **Idea** column, click **`+ Add item`**.
123
+ 3. Type your feature title and hit **Enter**.
124
+ 4. Select **Blank issue**.
125
+ 5. In the right sidebar, add a brief description of what you want.
126
+ 6. Ask your AI Assistant to read the issue and write the full specification!
127
+
128
+ Your AI will handle the refinement and automatically move it to the `Specification` stage.
128
129
 
129
130
  ---
130
131
 
131
- Initial idea issue. Spec to be detailed."
132
- ```
132
+ ## (Optional) Architecture Violation Integration
133
+
134
+ If your project uses an automated architecture auditing tool (e.g., a CI job that creates issues with an `architecture-violation` label), you can easily integrate it with your project board.
133
135
 
134
- Move the issues to the `Idea` column on the board matching your setup.
136
+ Simply open `.github/workflows/project-automation.yml` and uncomment the `move-violation-to-board` job in the `jobs` section. This will automatically move any issues labeled with `architecture-violation` to the `Idea` column on your board.
135
137
 
136
138
  ---
137
139
 
138
- ## (Optional) Architecture Violation Integration
140
+ ## (Optional) AI QA Agent Integration (Variant B)
139
141
 
140
- If your project uses an automated architecture auditing tool (e.g., a CI job that creates issues with an `architecture-violation` label), the Setup Mode can automatically add a GitHub Actions job to `project-automation.yml` that moves these issues to the `Idea` column.
141
-
142
- If you skipped this during setup but want to add it later, you can append the following job to `.github/workflows/project-automation.yml` under the `jobs` section:
143
-
144
- ```yaml
145
- move-violation-to-board:
146
- name: architecture-violation โ†’ ๐Ÿ’ก Idea
147
- if: github.event_name == 'issues' && github.event.label.name == 'architecture-violation'
148
- runs-on: ubuntu-latest
149
- steps:
150
- - uses: actions/github-script@v7
151
- with:
152
- github-token: ${{ secrets.PROJECT_TOKEN }}
153
- script: |
154
- const issueNodeId = context.payload.issue.node_id;
155
- const addResult = await github.graphql(`
156
- mutation($p: ID!, $c: ID!) {
157
- addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
158
- }`, { p: process.env.PROJECT_ID, c: issueNodeId });
159
- const itemId = addResult.addProjectV2ItemById.item.id;
160
- await github.graphql(`
161
- mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
162
- updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
163
- projectV2Item { id }
164
- }
165
- }`, { p: process.env.PROJECT_ID, i: itemId, f: process.env.STATUS_FIELD_ID,
166
- v: { singleSelectOptionId: process.env.STATUS_IDEA } });
167
- ```
142
+ If you use an AI QA Agent (e.g., QAWolf, a secondary AI script) to test your PRs before Code Review, you can switch to **Variant B**.
143
+
144
+ Simply open `.github/workflows/project-automation.yml`:
145
+ 1. In the `move-card-on-pr-open` job, change the PR destination from `STATUS_CODE_REVIEW_PR` to `STATUS_TESTING`.
146
+ 2. Uncomment the `move-card-on-qa-pass` job at the bottom of the file to move tested issues to `Code Review / PR` upon receiving a `qa:pass` label.
147
+
148
+ If you don't use this, you can safely delete `templates/.github/workflows/qa-agent.yml`.
168
149
 
169
150
  ---
170
151
 
@@ -19,18 +19,21 @@ Specifically, check for:
19
19
  - `.github/workflows/pdlc-health-check.yml`
20
20
 
21
21
  If any of these files are missing, you are in **Setup Mode**. Do not proceed with feature requests until setup is complete.
22
- 1. Acknowledge that the framework is not yet set up.
23
- 2. Interactively ask the user for required values **one group at a time**:
22
+ 1. **Language Detection:** Analyze the user's previous prompts and preferred language. Conduct this entire Setup Mode and ask all your interactive questions in that same language.
23
+ 2. Acknowledge that the framework is not yet set up.
24
+ 3. Interactively ask the user for required values **one group at a time**:
24
25
  - **Project basics:** Project Name, Description, Technical Stack (Structure), and GitHub Username (for CODEOWNERS security).
25
26
  - **Commands:** Test command, Lint command, Build command.
26
27
  - **Invariants:** Critical business rules agents must never violate (e.g. Human-in-the-loop).
27
- - **Board IDs:** PROJECT_ID, STATUS_FIELD_ID, column option IDs (provide standard PDLC options: Idea, Exploration, Brainstorming, Detail Solution, Approval, Development, Testing, Code Review / PR, Merge, Production). Allow user to answer "skip", which means you leave the placeholders intact.
28
- - **Architecture Violation:** Ask "Does your project use an automated architecture auditing tool (e.g., a CI job that creates issues with an `architecture-violation` label)?". If yes, replace `{{OPTIONAL_ARCHITECTURE_VIOLATION_JOB}}` in `project-automation.yml` with the job definition (available in the framework documentation). If no, ask if they would like help implementing one, reminding them that it significantly improves their agentic development process. If they decline, remove the placeholder.
28
+ - **Board IDs:** PROJECT_ID, STATUS_FIELD_ID, column option IDs (provide standard PDLC options: Idea, Exploration, Brainstorming, Detail Solution, Approval, Development, Testing, Code Review / PR, Production). Allow user to answer "skip", which means you leave the placeholders intact.
29
+ - **Architecture Violation:** Ask "Does your project use an automated architecture auditing tool (e.g., a CI job that creates issues with an `architecture-violation` label)?". If yes, uncomment the `move-violation-to-board` job inside `project-automation.yml`. If no, ask if they would like help implementing one, reminding them that it significantly improves their agentic development process. If they decline, you can leave the job commented out.
30
+ - **QA Agent (Variant B):** Ask "Do you plan to use an AI QA Agent (e.g. QAWolf or a secondary script) to verify your PRs before Code Review?". If yes, explain you will adopt Variant B: you will change `STATUS_CODE_REVIEW_PR` to `STATUS_TESTING` inside the `move-card-on-pr-open` job in `project-automation.yml` and uncomment the `move-card-on-qa-pass` job. If no, leave the workflow as Variant A (default) and delete the optional `.github/workflows/qa-agent.yml` template.
29
31
  - **Implementation agent handle:** e.g., `@google-labs-jules`, or "none".
30
32
  3. Generate and write the missing files replacing the `{{SCREAMING_SNAKE_CASE}}` placeholders using the templates logic you know (usually they reside in standard Agentic PDLC templates).
31
33
  4. Offer to run the `gh` commands for labels (`spec:approved`, `pr:in-review`, `pr:approved`, `architecture-violation`).
32
34
  5. Commit everything with the message: `chore: setup agentic-pdlc framework`.
33
- 6. Conclude Setup Mode.
35
+ 6. **IMPORTANT:** Delete this setup prompt file (e.g., `.agentic-setup.md`, `.agentic-setup-prompt.md`, or `.agentic-pdlc/SETUP_PROMPT.md`) from the root or `.agentic-pdlc/` directory to clean up the workspace.
36
+ 7. Conclude Setup Mode.
34
37
 
35
38
  ---
36
39
 
package/bin/cli.js CHANGED
@@ -3,6 +3,7 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const readline = require('readline');
6
+ const { execSync, execFileSync } = require('child_process');
6
7
 
7
8
  // The directory where CLI is executed
8
9
  const targetDir = process.cwd();
@@ -14,13 +15,72 @@ const rl = readline.createInterface({
14
15
  output: process.stdout
15
16
  });
16
17
 
18
+ function askQuestion(query) {
19
+ return new Promise(resolve => rl.question(query, resolve));
20
+ }
21
+
22
+ // Detect language
23
+ const locale = Intl.DateTimeFormat().resolvedOptions().locale || 'en-US';
24
+ const isPt = locale.toLowerCase().startsWith('pt');
25
+ const isEs = locale.toLowerCase().startsWith('es');
26
+
27
+ function t(en, pt, es) {
28
+ if (isPt) return pt;
29
+ if (isEs) return es || en; // Fallback para inglรชs se faltar espanhol
30
+ return en;
31
+ }
32
+
33
+ const i18n = {
34
+ welcome: t('๐Ÿค– Welcome to Agentic PDLC Boilerplate Bootstrap! ๐Ÿค–', '๐Ÿค– Bem-vindo ao Agentic PDLC Boilerplate Bootstrap! ๐Ÿค–', '๐Ÿค– ยกBienvenido a Agentic PDLC Boilerplate Bootstrap! ๐Ÿค–'),
35
+ checking_gh: t('Checking GitHub CLI (gh) installation...', 'Verificando instalaรงรฃo do GitHub CLI (gh)...', 'Verificando la instalaciรณn de GitHub CLI (gh)...'),
36
+ gh_ok: t('โœ… GitHub CLI is authenticated.', 'โœ… GitHub CLI estรก autenticado.', 'โœ… GitHub CLI estรก autenticado.'),
37
+ gh_error: t('โŒ GitHub CLI (gh) is not installed or not authenticated.', 'โŒ GitHub CLI (gh) nรฃo estรก instalado ou nรฃo autenticado.', 'โŒ GitHub CLI (gh) no estรก instalado o no estรก autenticado.'),
38
+ gh_install: t('Please install it from https://cli.github.com/ and run "gh auth login" before continuing.\n', 'Por favor, instale em https://cli.github.com/ e rode "gh auth login" antes de continuar.\n', 'Por favor, instรกlalo desde https://cli.github.com/ y ejecuta "gh auth login" antes de continuar.\n'),
39
+ ask_agent: t('Which AI Agent will you use for the setup? (e.g. claude, cursor, copilot, antigravity, or other): ', 'Qual Agente de IA vocรช usarรก para o setup? (ex: claude, cursor, copilot, antigravity, ou outro): ', 'ยฟQuรฉ Agente de IA usarรกs para la configuraciรณn? (ej: claude, cursor, copilot, antigravity, u otro): '),
40
+ ask_repo: t('What is your GitHub repository URL? (e.g., https://github.com/YOUR_USER/repo_name): ', 'Qual รฉ a URL do seu repositรณrio no GitHub? (ex: https://github.com/SEU_USUARIO/repo_name): ', 'ยฟCuรกl es la URL de tu repositorio en GitHub? (ej: https://github.com/TU_USUARIO/repo_name): '),
41
+ invalid_repo: t('โŒ Invalid repository URL. Expected format: https://github.com/OWNER/REPO', 'โŒ URL de repositรณrio invรกlida. Formato esperado: https://github.com/OWNER/REPO', 'โŒ URL de repositorio invรกlida. Formato esperado: https://github.com/OWNER/REPO'),
42
+ ask_org: t('Does this repository belong to a personal User account (e.g., github.com/rafaeltcosta86) or an Organization (e.g., github.com/google-labs)? (user/org): ', 'Esse repositรณrio pertence a um Usuรกrio pessoal (ex: github.com/rafaeltcosta86) ou a uma Organizaรงรฃo (ex: github.com/google-labs)? (user/org): ', 'ยฟEste repositorio pertenece a un Usuario personal (ej: github.com/rafaeltcosta86) o a una Organizaciรณn (ej: github.com/google-labs)? (user/org): '),
43
+ ask_branch: t('What is your main branch name? (default: main): ', 'Qual o nome da sua branch principal? (padrรฃo: main): ', 'ยฟCuรกl es el nombre de tu rama principal? (por defecto: main): '),
44
+ starting_setup: t('Starting automated repository setup...', 'Iniciando o setup automatizado do repositรณrio...', 'Iniciando la configuraciรณn automatizada del repositorio...'),
45
+ creating_labels: t('[1/2] Creating repository labels...', '[1/2] Criando labels no repositรณrio...', '[1/2] Creando etiquetas (labels) en el repositorio...'),
46
+ label_ok: t('โœ… Label created: ', 'โœ… Label criada: ', 'โœ… Etiqueta creada: '),
47
+ label_warn: t('โš ๏ธ Failed to create label (might already exist): ', 'โš ๏ธ Falha ao criar label (talvez jรก exista): ', 'โš ๏ธ Fallo al crear etiqueta (quizรกs ya exista): '),
48
+ applying_protection: t('[2/3] Applying branch protection on ', '[2/3] Aplicando proteรงรฃo de branch em ', '[2/3] Aplicando protecciรณn de rama en '),
49
+ protection_ok: t('โœ… Branch protection applied to ', 'โœ… Proteรงรฃo de branch aplicada em ', 'โœ… Protecciรณn de rama aplicada a '),
50
+ protection_warn: t('โš ๏ธ Failed to apply branch protection. (Do you have GitHub Pro or is the repo Public?)', 'โš ๏ธ Falha ao aplicar proteรงรฃo de branch. (Vocรช tem GitHub Pro ou o repo รฉ Pรบblico?)', 'โš ๏ธ Fallo al aplicar protecciรณn de rama. (ยฟTienes GitHub Pro o el repositorio es Pรบblico?)'),
51
+ creating_project: t('[2/2] Creating Project V2 Board...', '[2/2] Criando Project V2 Board...', '[2/2] Creando Project V2 Board...'),
52
+ project_ok: t('โœ… Project created (ID: ', 'โœ… Projeto criado (ID: ', 'โœ… Proyecto creado (ID: '),
53
+ project_err: t('โŒ Failed to create project. Error: ', 'โŒ Falha ao criar o projeto. Erro: ', 'โŒ Fallo al crear el proyecto. Error: '),
54
+ config_columns: t('Configuring Project Columns...', 'Configurando colunas do Projeto...', 'Configurando columnas del Proyecto...'),
55
+ columns_ok: t('โœ… Project columns configured successfully.', 'โœ… Colunas do projeto configuradas com sucesso.', 'โœ… Columnas del proyecto configuradas con รฉxito.'),
56
+ columns_warn: t('โš ๏ธ Failed to configure project columns. You may need to add them manually.', 'โš ๏ธ Falha ao configurar colunas. Vocรช pode precisar adicionรก-las manualmente.', 'โš ๏ธ Fallo al configurar columnas. Es posible que debas agregarlas manualmente.'),
57
+ scaffolding: t('Scaffolding Agentic PDLC into your project...', 'Injetando Agentic PDLC no seu projeto...', 'Inyectando Agentic PDLC en tu proyecto...'),
58
+ templates_copied: t('โœ… Templates copied to .agentic-pdlc/templates/', 'โœ… Templates copiados para .agentic-pdlc/templates/', 'โœ… Plantillas copiadas a .agentic-pdlc/templates/'),
59
+ pdlc_prefilled: t('โœ… Pre-filled pdlc.md with Project ID, Status Field ID, and Column Option IDs.', 'โœ… pdlc.md preenchido com Project ID, Status Field ID, e Column Option IDs.', 'โœ… pdlc.md completado con Project ID, Status Field ID y Column Option IDs.'),
60
+ setup_written: t('โœ… Setup agent profile written to .agentic-setup.md\n', 'โœ… Perfil de setup do agente salvo em .agentic-setup.md\n', 'โœ… Perfil de configuraciรณn del agente guardado en .agentic-setup.md\n'),
61
+ framework_scaffolded: t('๐ŸŽ‰ Framework files scaffolded to .agentic-pdlc/templates/', '๐ŸŽ‰ Arquivos do framework injetados em .agentic-pdlc/templates/', '๐ŸŽ‰ Archivos del framework inyectados en .agentic-pdlc/templates/'),
62
+ next_steps: t('๐Ÿ‘‰ NEXT STEPS:', '๐Ÿ‘‰ PRร“XIMOS PASSOS:', '๐Ÿ‘‰ PRร“XIMOS PASOS:'),
63
+ step_1: t('1. Open your AI Assistant (Claude, Cursor, Copilot, etc).', '1. Abra o seu Assistente de IA (Claude, Cursor, Copilot, etc).', '1. Abre tu Asistente de IA (Claude, Cursor, Copilot, etc).'),
64
+ step_2: t('2. Ask it to read the .agentic-setup.md and start Setup Mode in any language you prefer. Example ๐Ÿ‘‡', '2. Peรงa para ele ler o .agentic-setup.md e iniciar o Setup Mode. Exemplo ๐Ÿ‘‡', '2. Pรญdele que lea .agentic-setup.md e inicie el Setup Mode. Ejemplo ๐Ÿ‘‡'),
65
+ note_cleanup: t('Note: The agent will clean up the .agentic-setup.md file automatically when finished.\n', 'Nota: O agente irรก limpar o arquivo .agentic-setup.md automaticamente quando terminar.\n', 'Nota: El agente limpiarรก el archivo .agentic-setup.md automรกticamente cuando termine.\n'),
66
+ missing_claude: t('โŒ Could not find instruction file at ', 'โŒ Nรฃo foi possรญvel encontrar o arquivo de instruรงรฃo em ', 'โŒ No se pudo encontrar el archivo de instrucciรณn en '),
67
+ cursor_rules_written: t('โœ… Default cursor rules written to .cursorrules', 'โœ… Regras padrรฃo do cursor salvas em .cursorrules', 'โœ… Reglas por defecto de cursor guardadas en .cursorrules'),
68
+ cursor_setup_written: t('โœ… Framework Setup Instructions written to .agentic-pdlc/SETUP_PROMPT.md', 'โœ… Instruรงรตes de Setup do Framework salvas em .agentic-pdlc/SETUP_PROMPT.md', 'โœ… Instrucciones de Setup del Framework guardadas en .agentic-pdlc/SETUP_PROMPT.md'),
69
+ cursor_done: t('๐ŸŽ‰ Done! To start the conversational setup:', '๐ŸŽ‰ Pronto! Para iniciar o setup conversacional:', '๐ŸŽ‰ ยกListo! Para iniciar la configuraciรณn conversacional:'),
70
+ cursor_step_1: t('\t1. Open Cursor', '\t1. Abra o Cursor', '\t1. Abre Cursor'),
71
+ cursor_step_2: t('\t2. Open Composer (Cmd+I or Cmd+L) and type: "@.agentic-pdlc/SETUP_PROMPT.md execute Setup Mode"\n', '\t2. Abra o Composer (Cmd+I ou Cmd+L) e digite: "@.agentic-pdlc/SETUP_PROMPT.md execute Setup Mode"\n', '\t2. Abre Composer (Cmd+I o Cmd+L) y escribe: "@.agentic-pdlc/SETUP_PROMPT.md execute Setup Mode"\n'),
72
+ generic_written: t('โœ… Agent generic setup instructions written to .agentic-setup.md', 'โœ… Instruรงรตes genรฉricas salvas em .agentic-setup.md', 'โœ… Instrucciones genรฉricas guardadas en .agentic-setup.md'),
73
+ generic_done: t('Tell your AI agent to read and execute the .agentic-setup.md file!\n', 'Diga ao seu agente para ler e executar o arquivo .agentic-setup.md!\n', 'ยกDile a tu agente de IA que lea y ejecute el archivo .agentic-setup.md!\n')
74
+ };
75
+
17
76
  const cyan = '\x1b[36m';
18
77
  const reset = '\x1b[0m';
19
78
  const green = '\x1b[32m';
20
79
  const yellow = '\x1b[33m';
80
+ const red = '\x1b[31m';
21
81
 
22
82
  console.log(`${cyan}================================================================${reset}`);
23
- console.log(`${cyan}๐Ÿค– Welcome to Agentic PDLC Boilerplate Bootstrap! ๐Ÿค–${reset}`);
83
+ console.log(`${cyan}${i18n.welcome}${reset}`);
24
84
  console.log(`${cyan}================================================================${reset}\n`);
25
85
 
26
86
  // Helper function to recursively copy directories
@@ -39,10 +99,169 @@ function copyDirSync(src, dest) {
39
99
  }
40
100
  }
41
101
 
42
- rl.question('Which AI Agent will you use for the setup? (e.g. claude, cursor, copilot, or other): ', (answer) => {
43
- const agent = answer.trim().toLowerCase();
44
-
45
- console.log(`\n${yellow}Scaffolding Agentic PDLC into your project...${reset}`);
102
+ async function runSetup() {
103
+ console.log(`${yellow}${i18n.checking_gh}${reset}`);
104
+ try {
105
+ execSync('gh auth status', { stdio: 'ignore' });
106
+ console.log(`${green}${i18n.gh_ok}${reset}\n`);
107
+ } catch (error) {
108
+ console.error(`${red}${i18n.gh_error}${reset}`);
109
+ console.error(`${i18n.gh_install}`);
110
+ process.exit(1);
111
+ }
112
+
113
+ const agentAnswer = await askQuestion(i18n.ask_agent);
114
+ const agent = agentAnswer.trim().toLowerCase();
115
+ if (!['claude', 'cursor', 'copilot'].includes(agent)) {
116
+ console.log(t(`โ„น๏ธ Generating Universal Setup for '${agent}' (Compatible with any Markdown-reading agent).`, `โ„น๏ธ Gerando Setup Universal para '${agent}' (Compatรญvel com qualquer agente que leia Markdown).`, `โ„น๏ธ Generando Setup Universal para '${agent}' (Compatible con cualquier agente que lea Markdown).`));
117
+ }
118
+
119
+ let repoOwner, repoName, repo;
120
+ while (true) {
121
+ let repoUrl = (await askQuestion(i18n.ask_repo)).trim();
122
+ if (repoUrl.endsWith('/')) repoUrl = repoUrl.slice(0, -1);
123
+ if (repoUrl.endsWith('.git')) repoUrl = repoUrl.slice(0, -4);
124
+ const repoParts = repoUrl.split('/');
125
+ if (repoParts.length >= 2) {
126
+ repoOwner = repoParts[repoParts.length - 2];
127
+ repoName = repoParts[repoParts.length - 1];
128
+ repo = `${repoOwner}/${repoName}`;
129
+ break;
130
+ }
131
+ console.log(`${red}${i18n.invalid_repo}${reset}`);
132
+ }
133
+
134
+ const askProjectName = t(`What is the project name for the board? (default: ${repoName.toUpperCase()}): `, `Qual o nome do projeto em que o board serรก configurado? (padrรฃo: ${repoName.toUpperCase()}): `, `ยฟCuรกl es el nombre del proyecto en el que se configurarรก el board? (por defecto: ${repoName.toUpperCase()}): `);
135
+ const projectNameAnswer = await askQuestion(askProjectName);
136
+ const projectName = projectNameAnswer.trim() ? projectNameAnswer.trim().toUpperCase() : repoName.toUpperCase();
137
+ const boardName = `BOARD - ${projectName}`;
138
+
139
+ let isOrg = false;
140
+ try {
141
+ const ownerType = execFileSync('gh', ['api', `repos/${repo}`, '--jq', '.owner.type']).toString().trim();
142
+ isOrg = ownerType === 'Organization';
143
+ } catch (err) {
144
+ const accountTypeAnswer = await askQuestion(i18n.ask_org);
145
+ isOrg = accountTypeAnswer.trim().toLowerCase() === 'org' || accountTypeAnswer.trim().toLowerCase() === 'organization';
146
+ }
147
+
148
+ let branchName = 'main';
149
+ try {
150
+ branchName = execFileSync('gh', ['api', `repos/${repo}`, '--jq', '.default_branch']).toString().trim() || 'main';
151
+ } catch (err) {
152
+ const branchAnswer = await askQuestion(i18n.ask_branch);
153
+ if (branchAnswer.trim()) branchName = branchAnswer.trim();
154
+ }
155
+
156
+ console.log(`\n${yellow}${i18n.starting_setup}${reset}`);
157
+
158
+ // Labels
159
+ const labels = [
160
+ { name: 'stage:exploration', color: '9b59b6', description: 'Issue is being evaluated' },
161
+ { name: 'stage:brainstorming', color: 'e84393', description: 'Proposed approaches awaiting PM gate' },
162
+ { name: 'stage:detailing', color: '3498db', description: 'Technical spec is being written' },
163
+ { name: 'stage:development', color: 'e67e22', description: 'Agent is implementing the spec' },
164
+ { name: 'stage:testing', color: '8e44ad', description: 'Agent is testing the implementation' },
165
+ { name: 'spec:approved', color: '0e8a16', description: 'Spec approved โ€” agent can implement' },
166
+ { name: 'pr:in-review', color: 'e4e669', description: 'PR awaiting code review' },
167
+ { name: 'pr:approved', color: '0e8a16', description: 'PR approved, ready for merge' },
168
+ { name: 'architecture-violation', color: 'd93f0b', description: 'Invariant violation detected by CI' },
169
+ { name: 'qa:approved', color: '0e8a16', description: 'QA Agent approved the implementation' },
170
+ { name: 'qa:needs-work', color: 'd93f0b', description: 'QA Agent found issues' },
171
+ { name: 'jules', color: '5319e7', description: 'Jules AI Agent' }
172
+ ];
173
+
174
+ console.log(`\n${cyan}${i18n.creating_labels}${reset}`);
175
+ for (const label of labels) {
176
+ try {
177
+ execFileSync('gh', ['label', 'create', label.name, '--color', label.color, '--description', label.description, '--repo', repo, '--force'], { stdio: 'ignore' });
178
+ console.log(` ${i18n.label_ok}${label.name}`);
179
+ } catch (err) {
180
+ console.log(` ${i18n.label_warn}${label.name}`);
181
+ }
182
+ }
183
+
184
+ // Project V2
185
+ console.log(`\n${cyan}${i18n.creating_project}${reset}`);
186
+ let ownerId, projectId;
187
+ try {
188
+ if (isOrg) {
189
+ const orgOutput = execFileSync('gh', ['api', 'graphql', '-f', 'query=query($login: String!) { organization(login: $login) { id } }', '-f', `login=${repoOwner}`, '--jq', '.data.organization.id']).toString().trim();
190
+ ownerId = orgOutput;
191
+ } else {
192
+ const userOutput = execFileSync('gh', ['api', 'graphql', '-f', 'query={ viewer { id } }', '--jq', '.data.viewer.id']).toString().trim();
193
+ ownerId = userOutput;
194
+ }
195
+
196
+ const projectCreateOutput = execFileSync('gh', ['api', 'graphql', '-f', 'query=mutation($owner: ID!, $title: String!) { createProjectV2(input: {ownerId: $owner, title: $title}) { projectV2 { id } } }', '-f', `owner=${ownerId}`, '-f', `title=${boardName}`, '--jq', '.data.createProjectV2.projectV2.id']).toString().trim();
197
+ projectId = projectCreateOutput;
198
+
199
+ console.log(` ${i18n.project_ok}${projectId})`);
200
+ } catch (err) {
201
+ console.log(` ${i18n.project_err}${err.message}`);
202
+ }
203
+
204
+ let statusFieldId;
205
+ let optionMap = {};
206
+
207
+ if (projectId) {
208
+ console.log(` ${cyan}${i18n.config_columns}${reset}`);
209
+ try {
210
+ const fieldsOutput = execFileSync('gh', ['api', 'graphql', '-f', 'query=query($projectId: ID!) { node(id: $projectId) { ... on ProjectV2 { fields(first: 20) { nodes { ... on ProjectV2SingleSelectField { id name } } } } } }', '-f', `projectId=${projectId}`, '--jq', '.data.node.fields.nodes[] | select(.name == "Status") | .id']).toString().trim();
211
+ statusFieldId = fieldsOutput;
212
+
213
+ if (statusFieldId) {
214
+ const columns = [
215
+ { name: "๐Ÿ’ก Idea", description: "Backlog", color: "GRAY" },
216
+ { name: "๐Ÿ” Exploration", description: "Claude is analyzing", color: "PURPLE" },
217
+ { name: "๐Ÿง  Brainstorming", description: "Awaiting PM gate", color: "PINK" },
218
+ { name: "๐Ÿ“ Detail Solution", description: "Technical spec", color: "BLUE" },
219
+ { name: "โœ… Approval", description: "Spec ready", color: "GREEN" },
220
+ { name: "โš™๏ธ Development", description: "Agent implementing", color: "ORANGE" },
221
+ { name: "๐Ÿงช Testing", description: "QA testing", color: "RED" },
222
+ { name: "๐Ÿ‘ Code Review / PR", description: "PR opened", color: "YELLOW" },
223
+ { name: "๐Ÿš€ Production", description: "Merged", color: "GREEN" }
224
+ ];
225
+
226
+ const updateFieldQuery = `mutation($projectId: ID!, $fieldId: ID!, $options: [ProjectV2SingleSelectFieldOptionInput!]) {
227
+ updateProjectV2Field(input: {
228
+ projectId: $projectId,
229
+ fieldId: $fieldId,
230
+ singleSelectOptions: $options
231
+ }) {
232
+ projectV2Field {
233
+ ... on ProjectV2SingleSelectField {
234
+ options { id name }
235
+ }
236
+ }
237
+ }
238
+ }`;
239
+
240
+ const queryPayload = JSON.stringify({
241
+ query: updateFieldQuery,
242
+ variables: {
243
+ projectId: projectId,
244
+ fieldId: statusFieldId,
245
+ options: columns
246
+ }
247
+ });
248
+
249
+ const updateOutput = execFileSync('gh', ['api', 'graphql', '--input', '-'], { input: queryPayload }).toString().trim();
250
+ const jsonResponse = updateOutput ? JSON.parse(updateOutput) : null;
251
+ const returnedOptions = jsonResponse?.data?.updateProjectV2Field?.projectV2Field?.options || [];
252
+
253
+ for (const opt of returnedOptions) {
254
+ optionMap[opt.name] = opt.id;
255
+ }
256
+
257
+ console.log(` ${i18n.columns_ok}`);
258
+ }
259
+ } catch (err) {
260
+ console.log(` ${i18n.columns_warn}`);
261
+ }
262
+ }
263
+
264
+ console.log(`\n${yellow}${i18n.scaffolding}${reset}`);
46
265
 
47
266
  // We copy the templates folder so the agent has the real text logic to replace and rename
48
267
  const sourceTemplates = path.join(sourceDir, 'templates');
@@ -50,7 +269,33 @@ rl.question('Which AI Agent will you use for the setup? (e.g. claude, cursor, co
50
269
 
51
270
  if (fs.existsSync(sourceTemplates)) {
52
271
  copyDirSync(sourceTemplates, targetTemplates);
53
- console.log(`โœ… Templates copied to .agentic-pdlc/templates/`);
272
+ console.log(`${i18n.templates_copied}`);
273
+
274
+ // Substitute values in docs/pdlc.md automatically
275
+ const pdlcDest = path.join(targetTemplates, 'docs', 'pdlc.md');
276
+ if (fs.existsSync(pdlcDest)) {
277
+ let pdlcContent = fs.readFileSync(pdlcDest, 'utf8');
278
+
279
+ if (projectId) pdlcContent = pdlcContent.replace(/\\{\\{PROJECT_ID\\}\\}/g, () => projectId);
280
+ if (statusFieldId) pdlcContent = pdlcContent.replace(/\\{\\{STATUS_FIELD_ID\\}\\}/g, () => statusFieldId);
281
+ pdlcContent = pdlcContent.replace(/\\{\\{REPO_OWNER\\}\\}/g, () => repoOwner);
282
+ pdlcContent = pdlcContent.replace(/\\{\\{REPO_NAME\\}\\}/g, () => repoName);
283
+
284
+ if (Object.keys(optionMap).length > 0) {
285
+ pdlcContent = pdlcContent.replace(/\{\{ID_IDEA\}\}/g, optionMap["๐Ÿ’ก Idea"] || 'MISSING_ID');
286
+ pdlcContent = pdlcContent.replace(/\{\{ID_EXPLORATION\}\}/g, optionMap["๐Ÿ” Exploration"] || 'MISSING_ID');
287
+ pdlcContent = pdlcContent.replace(/\{\{ID_BRAINSTORMING\}\}/g, optionMap["๐Ÿง  Brainstorming"] || 'MISSING_ID');
288
+ pdlcContent = pdlcContent.replace(/\{\{ID_DETAIL\}\}/g, optionMap["๐Ÿ“ Detail Solution"] || 'MISSING_ID');
289
+ pdlcContent = pdlcContent.replace(/\{\{ID_APPROVAL\}\}/g, optionMap["โœ… Approval"] || 'MISSING_ID');
290
+ pdlcContent = pdlcContent.replace(/\{\{ID_DEVELOPMENT\}\}/g, optionMap["โš™๏ธ Development"] || 'MISSING_ID');
291
+ pdlcContent = pdlcContent.replace(/\{\{ID_TESTING\}\}/g, optionMap["๐Ÿงช Testing"] || 'MISSING_ID');
292
+ pdlcContent = pdlcContent.replace(/\{\{ID_CODE_REVIEW_PR\}\}/g, optionMap["๐Ÿ‘ Code Review / PR"] || 'MISSING_ID');
293
+ pdlcContent = pdlcContent.replace(/\{\{ID_PRODUCTION\}\}/g, optionMap["๐Ÿš€ Production"] || 'MISSING_ID');
294
+ }
295
+
296
+ fs.writeFileSync(pdlcDest, pdlcContent);
297
+ console.log(`${i18n.pdlc_prefilled}`);
298
+ }
54
299
  }
55
300
 
56
301
  // Handle the specific setup instructions target
@@ -61,15 +306,19 @@ rl.question('Which AI Agent will you use for the setup? (e.g. claude, cursor, co
61
306
  if (fs.existsSync(claudeSetupSrc)) {
62
307
  const dest = path.join(targetDir, '.agentic-setup.md');
63
308
  fs.copyFileSync(claudeSetupSrc, dest);
64
- console.log(`โœ… Setup agent profile written to .agentic-setup.md`);
65
- console.log(`\n${green}๐ŸŽ‰ Done! To start the conversational setup:${reset}`);
66
- console.log(`${cyan}\tStep 1: Open the Claude Code CLI in your terminal (type 'claude')${reset}`);
67
- console.log(`${cyan}\t [Or open your preferred IDE Agent chat, like Antigravity, Cursor, Codex, GitHub Copilot, etc]${reset}`);
68
- console.log(`${cyan}\tStep 2: Paste this exact prompt:${reset}`);
69
- console.log(`${yellow}\t "read .agentic-setup.md to enter Setup Mode."${reset}`);
70
- console.log(`\nNote: Once setup is completed, the agent will typically delete .agentic-setup.md to keep your root clean.\n`);
309
+ console.log(`${i18n.setup_written}`);
310
+ console.log(`${green}============================================================${reset}`);
311
+ console.log(`${green}${i18n.framework_scaffolded}${reset}`);
312
+ console.log(`${green}============================================================${reset}\n`);
313
+ console.log(`${yellow}${i18n.next_steps}${reset}`);
314
+ console.log(`${cyan}${i18n.step_1}${reset}`);
315
+ console.log(`${cyan}${i18n.step_2}${reset}`);
316
+ console.log(`${cyan}>>> English: "Read .agentic-setup.md and guide me through the setup."${reset}`);
317
+ console.log(`${cyan}>>> Espaรฑol: "Lea el archivo .agentic-setup.md e inicie el Setup Mode"${reset}`);
318
+ console.log(`${cyan}>>> Portuguรชs: "Leia o arquivo .agentic-setup.md e inicie o Setup Mode."${reset}\n`);
319
+ console.log(`${i18n.note_cleanup}`);
71
320
  } else {
72
- console.error(`โŒ Could not find claude instruction file at ${claudeSetupSrc}`);
321
+ console.error(`${i18n.missing_claude}${claudeSetupSrc}`);
73
322
  }
74
323
  } else if (agent === 'cursor') {
75
324
  if (fs.existsSync(cursorSetupSrc)) {
@@ -81,22 +330,24 @@ rl.question('Which AI Agent will you use for the setup? (e.g. claude, cursor, co
81
330
  const setupPromptDest = path.join(targetDir, '.agentic-pdlc', 'SETUP_PROMPT.md');
82
331
  if (fs.existsSync(claudeSetupSrc)) fs.copyFileSync(claudeSetupSrc, setupPromptDest);
83
332
 
84
- console.log(`โœ… Default cursor rules written to .cursorrules`);
85
- console.log(`โœ… Framework Setup Instructions written to .agentic-pdlc/SETUP_PROMPT.md`);
86
- console.log(`\n${green}๐ŸŽ‰ Done! To start the conversational setup:${reset}`);
87
- console.log(`${cyan}\t1. Open Cursor${reset}`);
88
- console.log(`${cyan}\t2. Open Composer (Cmd+I or Cmd+L) and type: "@.agentic-pdlc/SETUP_PROMPT.md execute Setup Mode"${reset}\n`);
333
+ console.log(`${i18n.cursor_rules_written}`);
334
+ console.log(`${i18n.cursor_setup_written}`);
335
+ console.log(`\n${green}${i18n.cursor_done}${reset}`);
336
+ console.log(`${cyan}${i18n.cursor_step_1}${reset}`);
337
+ console.log(`${cyan}${i18n.cursor_step_2}${reset}`);
89
338
  } else {
90
- console.error(`โŒ Could not find cursor instruction file at ${cursorSetupSrc}`);
339
+ console.error(`${i18n.missing_claude}${cursorSetupSrc}`);
91
340
  }
92
341
  } else {
93
342
  // Generic fallback mapping
94
- const dest = path.join(targetDir, '.agentic-setup-prompt.md');
343
+ const dest = path.join(targetDir, '.agentic-setup.md');
95
344
  fs.copyFileSync(claudeSetupSrc, dest);
96
- console.log(`โœ… Agent generic setup instructions written to .agentic-setup-prompt.md`);
97
- console.log(`\n${green}๐ŸŽ‰ Done! To start the conversational setup:${reset}`);
98
- console.log(`${cyan}Provide the .agentic-setup-prompt.md file to your AI agent and ask it to execute Setup Mode!${reset}\n`);
345
+ console.log(`${i18n.generic_written}`);
346
+ console.log(`\n${green}${i18n.cursor_done}${reset}`);
347
+ console.log(`${cyan}>>> ${i18n.generic_done}${reset}`);
99
348
  }
100
349
 
101
350
  rl.close();
102
- });
351
+ }
352
+
353
+ runSetup();
package/docs/pdlc.md CHANGED
@@ -12,7 +12,6 @@
12
12
  | โš™๏ธ Development | Agent implementing the spec | Label `stage:development` |
13
13
  | ๐Ÿงช Testing | CI pipeline running | GitHub Actions |
14
14
  | ๐Ÿ‘ Code Review / PR | PR opened, awaiting human review | GitHub Actions |
15
- | ๐Ÿ”€ Merge | PR approved, awaiting merge | GitHub Actions |
16
15
  | ๐Ÿš€ Production | Merged | GitHub Actions |
17
16
 
18
17
  <!--
@@ -40,7 +39,6 @@ REPO = {{REPO_OWNER}}/{{REPO_NAME}}
40
39
  | โš™๏ธ Development | `{{ID_DEVELOPMENT}}` |
41
40
  | ๐Ÿงช Testing | `{{ID_TESTING}}` |
42
41
  | ๐Ÿ‘ Code Review / PR | `{{ID_CODE_REVIEW_PR}}` |
43
- | ๐Ÿ”€ Merge | `{{ID_MERGE}}` |
44
42
  | ๐Ÿš€ Production | `{{ID_PRODUCTION}}` |
45
43
 
46
44
  ## Agent ร— Phase Mapping
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-agentic-pdlc",
3
- "version": "2.0.1",
3
+ "version": "2.0.4",
4
4
  "description": "Agentic PDLC Framework - Conversational setup for your AI coding assistants",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -20,7 +20,7 @@ jobs:
20
20
  PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
21
21
  steps:
22
22
  - name: Update Labels
23
- if: ${{ env.PROJECT_TOKEN != '' }}
23
+ if: ${{ env.PROJECT_TOKEN != '' && !contains('{{IMPLEMENTATION_AGENT_LABEL}}', '{{') }}
24
24
  uses: actions/github-script@v7
25
25
  with:
26
26
  github-token: ${{ env.PROJECT_TOKEN }}
@@ -33,20 +33,21 @@ jobs:
33
33
  owner,
34
34
  repo,
35
35
  issue_number,
36
- name: 'upstream:approval'
36
+ name: 'stage:approval'
37
37
  });
38
38
  } catch (error) {
39
- console.log('Label upstream:approval not found or could not be removed');
39
+ console.log('Label stage:approval not found or could not be removed');
40
40
  }
41
41
 
42
42
  await github.rest.issues.addLabels({
43
43
  owner,
44
44
  repo,
45
45
  issue_number,
46
- labels: ['upstream:development', '{{IMPLEMENTATION_AGENT_LABEL}}', 'agent:working']
46
+ labels: ['stage:development', '{{IMPLEMENTATION_AGENT_LABEL}}', 'agent:working']
47
47
  });
48
48
 
49
49
  - name: Comment on issue to trigger agent and prevent race conditions
50
+ if: ${{ !contains('{{IMPLEMENTATION_AGENT_LABEL}}', '{{') }}
50
51
  uses: actions/github-script@v7
51
52
  with:
52
53
  github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -89,6 +90,7 @@ jobs:
89
90
  contents: read
90
91
  steps:
91
92
  - name: Comment on issue to trigger agent
93
+ if: ${{ !contains('{{IMPLEMENTATION_AGENT_LABEL}}', '{{') }}
92
94
  uses: actions/github-script@v7
93
95
  with:
94
96
  github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,16 @@
1
+ name: Auto Approve PRs
2
+ on:
3
+ pull_request:
4
+ types: [opened, labeled, synchronize]
5
+
6
+ permissions:
7
+ pull-requests: write
8
+
9
+ jobs:
10
+ auto-approve:
11
+ runs-on: ubuntu-latest
12
+ if: contains(github.event.pull_request.labels.*.name, 'auto-approve')
13
+ steps:
14
+ - uses: hmarr/auto-approve-action@v4
15
+ with:
16
+ github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -20,13 +20,21 @@ jobs:
20
20
  run: echo "Replace this with your package manager install command"
21
21
 
22
22
  - name: Run Linters
23
- run: {{LINT_COMMAND}}
23
+ if: ${{ !contains('{{LINT_COMMAND}}', '{{') }}
24
+ run: |
25
+ {{LINT_COMMAND}}
24
26
 
25
27
  - name: Typecheck
26
- run: {{TYPECHECK_COMMAND}}
28
+ if: ${{ !contains('{{TYPECHECK_COMMAND}}', '{{') }}
29
+ run: |
30
+ {{TYPECHECK_COMMAND}}
27
31
 
28
32
  - name: Build
29
- run: {{BUILD_COMMAND}}
33
+ if: ${{ !contains('{{BUILD_COMMAND}}', '{{') }}
34
+ run: |
35
+ {{BUILD_COMMAND}}
30
36
 
31
37
  - name: Run Tests
32
- run: {{TEST_COMMAND}}
38
+ if: ${{ !contains('{{TEST_COMMAND}}', '{{') }}
39
+ run: |
40
+ {{TEST_COMMAND}}
@@ -11,6 +11,7 @@ on:
11
11
  env:
12
12
  PROJECT_ID: "{{PROJECT_ID}}"
13
13
  STATUS_FIELD_ID: "{{STATUS_FIELD_ID}}"
14
+ STATUS_IDEA: "{{ID_IDEA}}"
14
15
  STATUS_EXPLORATION: "{{ID_EXPLORATION}}"
15
16
  STATUS_BRAINSTORMING: "{{ID_BRAINSTORMING}}"
16
17
  STATUS_DETAILING: "{{ID_DETAILING}}"
@@ -30,7 +31,7 @@ jobs:
30
31
  PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
31
32
  steps:
32
33
  - name: Detect Label and Move Issue
33
- if: ${{ env.PROJECT_TOKEN != '' }}
34
+ if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
34
35
  uses: actions/github-script@v7
35
36
  with:
36
37
  github-token: ${{ env.PROJECT_TOKEN }}
@@ -39,28 +40,28 @@ jobs:
39
40
  let targetStatusId = null;
40
41
  let stageName = null;
41
42
 
42
- if (labelName === 'upstream:exploration') {
43
+ if (labelName === 'stage:exploration') {
43
44
  targetStatusId = process.env.STATUS_EXPLORATION;
44
45
  stageName = 'Exploration';
45
- } else if (labelName === 'upstream:brainstorming') {
46
+ } else if (labelName === 'stage:brainstorming') {
46
47
  targetStatusId = process.env.STATUS_BRAINSTORMING;
47
48
  stageName = 'Brainstorming';
48
- } else if (labelName === 'upstream:detailing') {
49
+ } else if (labelName === 'stage:detailing') {
49
50
  targetStatusId = process.env.STATUS_DETAILING;
50
51
  stageName = 'Detailing';
51
- } else if (labelName === 'upstream:approval') {
52
+ } else if (labelName === 'stage:approval') {
52
53
  targetStatusId = process.env.STATUS_APPROVAL;
53
54
  stageName = 'Approval';
54
- } else if (labelName === 'upstream:development') {
55
+ } else if (labelName === 'stage:development') {
55
56
  targetStatusId = process.env.STATUS_DEVELOPMENT;
56
57
  stageName = 'Development';
57
- } else if (labelName === 'upstream:testing') {
58
+ } else if (labelName === 'stage:testing') {
58
59
  targetStatusId = process.env.STATUS_TESTING;
59
60
  stageName = 'Testing';
60
61
  }
61
62
 
62
63
  if (!targetStatusId) {
63
- console.log('No upstream PDLC label found. Skipping.');
64
+ console.log('No stage PDLC label found. Skipping.');
64
65
  return;
65
66
  }
66
67
 
@@ -86,9 +87,36 @@ jobs:
86
87
  await moveItem(node_id, targetStatusId);
87
88
  console.log(`Issue #${number} moved to ${stageName}`);
88
89
 
89
- {{OPTIONAL_ARCHITECTURE_VIOLATION_JOB}}
90
+ # OPTIONAL: Uncomment to enable architecture-violation โ†’ Idea
91
+ # move-violation-to-board:
92
+ # name: architecture-violation โ†’ ๐Ÿ’ก Idea
93
+ # if: github.event_name == 'issues' && github.event.action == 'labeled' && github.event.label.name == 'architecture-violation'
94
+ # runs-on: ubuntu-latest
95
+ # steps:
96
+ # - name: Move issue to Idea
97
+ # if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
98
+ # uses: actions/github-script@v7
99
+ # with:
100
+ # github-token: ${{ env.PROJECT_TOKEN }}
101
+ # script: |
102
+ # const { issue: { number, node_id } } = context.payload;
103
+ # const { addProjectV2ItemById: { item } } = await github.graphql(`
104
+ # mutation($p: ID!, $c: ID!) {
105
+ # addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
106
+ # }`, { p: process.env.PROJECT_ID, c: node_id });
107
+ # await github.graphql(`
108
+ # mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
109
+ # updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
110
+ # projectV2Item { id }
111
+ # }
112
+ # }`, {
113
+ # p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
114
+ # v: { singleSelectOptionId: process.env.STATUS_IDEA }
115
+ # });
116
+ # console.log(`Issue #${number} moved to Idea`);
90
117
 
91
118
  # PR Opened โ†’ Move linked issue to Code Review / PR
119
+ # ๐Ÿ’ก VARIANT B (QA Agent): If using an AI QA agent, change `STATUS_CODE_REVIEW_PR` to `STATUS_TESTING` on line ~158
92
120
  move-card-on-pr-open:
93
121
  name: Open PR โ†’ Code Review / PR
94
122
  if: github.event_name == 'pull_request' && (github.event.action == 'opened' || github.event.action == 'reopened')
@@ -97,7 +125,7 @@ jobs:
97
125
  PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
98
126
  steps:
99
127
  - name: Move linked issue to Code Review / PR
100
- if: ${{ env.PROJECT_TOKEN != '' }}
128
+ if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
101
129
  uses: actions/github-script@v7
102
130
  with:
103
131
  github-token: ${{ env.PROJECT_TOKEN }}
@@ -151,7 +179,7 @@ jobs:
151
179
  PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
152
180
  steps:
153
181
  - name: Swap PR labels
154
- if: ${{ env.PROJECT_TOKEN != '' }}
182
+ if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
155
183
  uses: actions/github-script@v7
156
184
  with:
157
185
  github-token: ${{ env.PROJECT_TOKEN }}
@@ -170,7 +198,7 @@ jobs:
170
198
  PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
171
199
  steps:
172
200
  - name: Move issue to Production
173
- if: ${{ env.PROJECT_TOKEN != '' }}
201
+ if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
174
202
  uses: actions/github-script@v7
175
203
  with:
176
204
  github-token: ${{ env.PROJECT_TOKEN }}
@@ -0,0 +1,21 @@
1
+ name: Protect Workflows
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize, reopened, labeled]
6
+ paths:
7
+ - '.github/**'
8
+
9
+ jobs:
10
+ block-unauthorized-edits:
11
+ name: Protect .github directory
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - name: Check for Human Approval
15
+ if: ${{ !contains(github.event.pull_request.labels.*.name, 'human-approved') }}
16
+ run: |
17
+ echo "๐Ÿšจ Modifications in the .github/ directory detected."
18
+ echo "As a security measure, this repository blocks workflow edits by default."
19
+ echo "If you are an AI Agent, do not add the approval label yourself."
20
+ echo "If you are the human owner, please add the 'human-approved' label to this PR to allow merging."
21
+ exit 1
@@ -0,0 +1,27 @@
1
+ name: AI QA Agent
2
+ on:
3
+ pull_request:
4
+ types: [opened, synchronize, reopened]
5
+
6
+ permissions:
7
+ pull-requests: write
8
+ contents: read
9
+
10
+ jobs:
11
+ qa:
12
+ name: Run AI QA Agent
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - 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"
25
+ env:
26
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27
+ PR_URL: ${{ github.event.pull_request.html_url }}
@@ -10,9 +10,8 @@
10
10
  | ๐Ÿ“ Detail Solution | Claude is writing the technical spec | Label `stage:detailing` |
11
11
  | โœ… Approval | Spec ready, awaiting `spec:approved` label | Label `spec:approved` |
12
12
  | โš™๏ธ Development | Agent implementing the spec | Label `stage:development` |
13
- | ๐Ÿงช Testing | CI pipeline running | GitHub Actions |
14
- | ๐Ÿ‘ Code Review / PR | PR opened, awaiting human review | GitHub Actions |
15
- | ๐Ÿ”€ Merge | PR approved, awaiting merge | GitHub Actions |
13
+ | ๐Ÿงช Testing | CI pipeline or AI QA Agent running (Variant B) | GitHub Actions / QA Agent |
14
+ | ๐Ÿ‘ Code Review / PR | PR opened (Variant A) or QA passed (Variant B) | GitHub Actions |
16
15
  | ๐Ÿš€ Production | Merged | GitHub Actions |
17
16
 
18
17
  <!--
@@ -20,6 +19,11 @@ Adapt columns as needed. The functional baseline is:
20
19
  ๐Ÿ’ก Idea โ†’ โš™๏ธ Development โ†’ ๐Ÿ‘ Code Review / PR โ†’ ๐Ÿš€ Production
21
20
  -->
22
21
 
22
+ ## Workflow Variants (QA Agent)
23
+
24
+ - **Variant A (Default):** PRs bypass the `Testing` column and land directly in `Code Review / PR`.
25
+ - **Variant B (QA Agent Enabled):** PRs land in the `Testing` column first. An AI QA agent verifies the PR, adding `qa:pass` or `qa:fail`. Only after a `qa:pass` is the issue moved to `Code Review / PR`.
26
+
23
27
  ## Board Identifiers (GitHub Projects)
24
28
 
25
29
  ```
@@ -40,7 +44,6 @@ REPO = {{REPO_OWNER}}/{{REPO_NAME}}
40
44
  | โš™๏ธ Development | `{{ID_DEVELOPMENT}}` |
41
45
  | ๐Ÿงช Testing | `{{ID_TESTING}}` |
42
46
  | ๐Ÿ‘ Code Review / PR | `{{ID_CODE_REVIEW_PR}}` |
43
- | ๐Ÿ”€ Merge | `{{ID_MERGE}}` |
44
47
  | ๐Ÿš€ Production | `{{ID_PRODUCTION}}` |
45
48
 
46
49
  ## Agent ร— Phase Mapping
@@ -1,54 +0,0 @@
1
- name: Upstream Gate 1
2
-
3
- on:
4
- issue_comment:
5
- types: [created]
6
-
7
- jobs:
8
- evaluate-gate:
9
- name: Evaluate Brainstorming Approval
10
- if: ${{ !github.event.issue.pull_request && contains(github.event.issue.labels.*.name, 'upstream:brainstorming') }}
11
- runs-on: ubuntu-latest
12
- env:
13
- PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
14
- steps:
15
- - name: Check for approval and swap label
16
- if: ${{ env.PROJECT_TOKEN != '' }}
17
- uses: actions/github-script@v7
18
- with:
19
- github-token: ${{ env.PROJECT_TOKEN }}
20
- script: |
21
- const comment = context.payload.comment.body.toLowerCase();
22
- const isApproved =
23
- comment.includes('approved') ||
24
- comment.includes('lgtm') ||
25
- /option\s+[a-z0-9]/i.test(comment) ||
26
- /go\s+with\s+[a-z0-9]/i.test(comment) ||
27
- /proceed/i.test(comment);
28
-
29
- if (isApproved) {
30
- const { owner, repo } = context.repo;
31
- const issue_number = context.payload.issue.number;
32
-
33
- console.log('Approval detected, swapping labels...');
34
-
35
- try {
36
- await github.rest.issues.removeLabel({
37
- owner,
38
- repo,
39
- issue_number,
40
- name: 'upstream:brainstorming'
41
- });
42
- } catch (e) {
43
- console.log('Could not remove upstream:brainstorming label');
44
- }
45
-
46
- await github.rest.issues.addLabels({
47
- owner,
48
- repo,
49
- issue_number,
50
- labels: ['upstream:detailing']
51
- });
52
- } else {
53
- console.log('No approval pattern detected in the comment.');
54
- }