create-agentic-pdlc 2.1.1 → 2.1.2
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.
|
@@ -25,6 +25,7 @@ If any of these files are missing, you are in **Setup Mode**. Do not proceed wit
|
|
|
25
25
|
3. **Pre-filled Context:** Before asking any questions, read the following files if they exist:
|
|
26
26
|
- `.agentic-pdlc/cli-context.json` — written by the CLI. Contains `projectName`, `repoOwner`, `repoName`. Use these values directly and skip the corresponding questions.
|
|
27
27
|
- `.agentic-pdlc/templates/docs/pdlc.md` — the CLI pre-fills PROJECT_ID, STATUS_FIELD_ID, REPO_OWNER, REPO_NAME, and all 9 column option IDs. If none of the values still contain `{{...}}` placeholders, skip the entire Board IDs question group.
|
|
28
|
+
- `.agentic-pdlc/templates/.github/workflows/project-automation.yml` — the CLI also pre-fills all ID placeholders here. When writing the workflow file, the remaining `{{...}}` placeholders are only non-ID ones (project name, commands, etc.).
|
|
28
29
|
4. Interactively ask the user only for the **missing values**, **one group at a time**:
|
|
29
30
|
- **Project basics:** Project Name (skip if present in `cli-context.json`), Description, Technical Stack/Structure. **Do not ask for GitHub Username** — use `repoOwner` from `cli-context.json` directly for CODEOWNERS.
|
|
30
31
|
- **Commands:** In the user's detected language, ask for each command with its purpose and concrete examples:
|
|
@@ -47,9 +48,23 @@ If any of these files are missing, you are in **Setup Mode**. Do not proceed wit
|
|
|
47
48
|
- c) **Other** — *Enter the agent's handle.*
|
|
48
49
|
5. Generate and write the missing files replacing the `{{SCREAMING_SNAKE_CASE}}` placeholders using the templates in `.agentic-pdlc/templates/`.
|
|
49
50
|
6. Offer to run the `gh` commands for labels (`spec:approved`, `pr:in-review`, `pr:approved`, `architecture-violation`).
|
|
50
|
-
7. **
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
7. **Set up the `PROJECT_PAT` secret (required for board automation):**
|
|
52
|
+
The board automation workflows need a GitHub Personal Access Token (classic) with `project` scope. Without it, all board card movements will silently skip — no error, no cards moving.
|
|
53
|
+
- Go to: **github.com/settings/tokens** → *Generate new token (classic)*
|
|
54
|
+
- Select scopes: ✅ `repo` + ✅ `project`
|
|
55
|
+
- Copy the token, then run:
|
|
56
|
+
```
|
|
57
|
+
gh secret set PROJECT_PAT --body "<your-token>"
|
|
58
|
+
```
|
|
59
|
+
Wait for the user to confirm the secret is set before continuing.
|
|
60
|
+
8. **IMPORTANT:** Delete the setup prompt file by running exactly:
|
|
61
|
+
```
|
|
62
|
+
rm -f .agentic-setup.md .agentic-setup-prompt.md .agentic-pdlc/SETUP_PROMPT.md
|
|
63
|
+
```
|
|
64
|
+
**Do NOT run `git add` or any other git command.** These files were never committed and do not exist in the git index. This command must run **before** the commit step.
|
|
65
|
+
9. Commit everything with the message: `chore: setup agentic-pdlc framework`.
|
|
66
|
+
10. Conclude Setup Mode. Read `projectNumber` from `.agentic-pdlc/cli-context.json` and show the user their board URL:
|
|
67
|
+
`https://github.com/users/{repoOwner}/projects/{projectNumber}/views/1?layout=board`
|
|
53
68
|
|
|
54
69
|
---
|
|
55
70
|
|
|
@@ -57,6 +72,18 @@ If any of these files are missing, you are in **Setup Mode**. Do not proceed wit
|
|
|
57
72
|
|
|
58
73
|
If `AGENTS.md` and `docs/pdlc.md` are present, you are in **Execution Mode**.
|
|
59
74
|
|
|
75
|
+
### 0. Board Labels — Mandatory at Every State Transition
|
|
76
|
+
|
|
77
|
+
These label commands are non-negotiable. They run **before** the activity they announce — before reading code, before invoking any skill, before any other action.
|
|
78
|
+
|
|
79
|
+
| When | Command |
|
|
80
|
+
|---|---|
|
|
81
|
+
| Before reading any code / invoking any skill | `gh issue edit <N> --add-label "stage:exploration"` |
|
|
82
|
+
| Before presenting architecture approaches | `gh issue edit <N> --add-label "stage:brainstorming" --remove-label "stage:exploration"` |
|
|
83
|
+
| Before writing the technical spec | `gh issue edit <N> --add-label "stage:detailing" --remove-label "stage:brainstorming"` |
|
|
84
|
+
|
|
85
|
+
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).
|
|
86
|
+
|
|
60
87
|
### 1. Daily Upstream Loop
|
|
61
88
|
Your job is to move issues from "Idea" to "Detail Solution".
|
|
62
89
|
When asked to work on a feature, you will:
|
|
@@ -83,7 +110,4 @@ Once approved, you will detail the solution directly into the GitHub Issue body.
|
|
|
83
110
|
Do not write code for downstream features! Your goal is to refine the Spec, so the human Tech Lead can label the issue `spec:approved`. This label triggers the downstream agent via `agent-trigger.yml`.
|
|
84
111
|
|
|
85
112
|
### 4. Moving the Board (Upstream States)
|
|
86
|
-
|
|
87
|
-
- Starting context evaluation: Run `gh issue edit <N> --add-label "stage:exploration"`
|
|
88
|
-
- Presenting architecture/approaches: Run `gh issue edit <N> --add-label "stage:brainstorming"`
|
|
89
|
-
- Starting to write the technical spec: Run `gh issue edit <N> --add-label "stage:detailing"`
|
|
113
|
+
See **Section 0** above for the mandatory label commands at each state transition.
|
package/bin/cli.js
CHANGED
|
@@ -197,7 +197,7 @@ async function runSetup() {
|
|
|
197
197
|
|
|
198
198
|
// Project V2
|
|
199
199
|
console.log(`\n${cyan}${i18n.creating_project}${reset}`);
|
|
200
|
-
let ownerId, projectId;
|
|
200
|
+
let ownerId, projectId, projectNumber;
|
|
201
201
|
try {
|
|
202
202
|
if (isOrg) {
|
|
203
203
|
const orgOutput = execFileSync('gh', ['api', 'graphql', '-f', 'query=query($login: String!) { organization(login: $login) { id } }', '-f', `login=${repoOwner}`, '--jq', '.data.organization.id']).toString().trim();
|
|
@@ -207,8 +207,10 @@ async function runSetup() {
|
|
|
207
207
|
ownerId = userOutput;
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
const
|
|
211
|
-
|
|
210
|
+
const projectCreateRaw = execFileSync('gh', ['api', 'graphql', '-f', 'query=mutation($owner: ID!, $title: String!) { createProjectV2(input: {ownerId: $owner, title: $title}) { projectV2 { id number } } }', '-f', `owner=${ownerId}`, '-f', `title=${boardName}`]).toString().trim();
|
|
211
|
+
const projectCreateData = JSON.parse(projectCreateRaw).data.createProjectV2.projectV2;
|
|
212
|
+
projectId = projectCreateData.id;
|
|
213
|
+
projectNumber = projectCreateData.number;
|
|
212
214
|
|
|
213
215
|
console.log(` ${i18n.project_ok}${projectId})`);
|
|
214
216
|
|
|
@@ -317,12 +319,32 @@ async function runSetup() {
|
|
|
317
319
|
fs.writeFileSync(pdlcDest, pdlcContent);
|
|
318
320
|
console.log(`${i18n.pdlc_prefilled}`);
|
|
319
321
|
}
|
|
322
|
+
|
|
323
|
+
// Pre-fill project-automation.yml with the same IDs so the agent doesn't need to map them
|
|
324
|
+
const workflowAutomationPath = path.join(targetTemplates, '.github', 'workflows', 'project-automation.yml');
|
|
325
|
+
if (fs.existsSync(workflowAutomationPath)) {
|
|
326
|
+
let wfContent = fs.readFileSync(workflowAutomationPath, 'utf8');
|
|
327
|
+
if (projectId) wfContent = wfContent.replace(/\{\{PROJECT_ID\}\}/g, () => projectId);
|
|
328
|
+
if (statusFieldId) wfContent = wfContent.replace(/\{\{STATUS_FIELD_ID\}\}/g, () => statusFieldId);
|
|
329
|
+
if (Object.keys(optionMap).length > 0) {
|
|
330
|
+
wfContent = wfContent.replace(/\{\{ID_IDEA\}\}/g, optionMap["💡 Idea"] || 'MISSING_ID');
|
|
331
|
+
wfContent = wfContent.replace(/\{\{ID_EXPLORATION\}\}/g, optionMap["🔍 Exploration"] || 'MISSING_ID');
|
|
332
|
+
wfContent = wfContent.replace(/\{\{ID_BRAINSTORMING\}\}/g, optionMap["🧠 Brainstorming"] || 'MISSING_ID');
|
|
333
|
+
wfContent = wfContent.replace(/\{\{ID_DETAILING\}\}/g, optionMap["📐 Detail Solution"] || 'MISSING_ID');
|
|
334
|
+
wfContent = wfContent.replace(/\{\{ID_APPROVAL\}\}/g, optionMap["✅ Approval"] || 'MISSING_ID');
|
|
335
|
+
wfContent = wfContent.replace(/\{\{ID_DEVELOPMENT\}\}/g, optionMap["⚙️ Development"] || 'MISSING_ID');
|
|
336
|
+
wfContent = wfContent.replace(/\{\{ID_TESTING\}\}/g, optionMap["🧪 Testing"] || 'MISSING_ID');
|
|
337
|
+
wfContent = wfContent.replace(/\{\{ID_CODE_REVIEW_PR\}\}/g, optionMap["👁 Code Review / PR"] || 'MISSING_ID');
|
|
338
|
+
wfContent = wfContent.replace(/\{\{ID_PRODUCTION\}\}/g, optionMap["🚀 Ready for Production"] || 'MISSING_ID');
|
|
339
|
+
}
|
|
340
|
+
fs.writeFileSync(workflowAutomationPath, wfContent);
|
|
341
|
+
}
|
|
320
342
|
}
|
|
321
343
|
|
|
322
344
|
// Write CLI context for the agent to consume in Setup Mode
|
|
323
345
|
try {
|
|
324
346
|
const cliContextPath = path.join(targetDir, '.agentic-pdlc', 'cli-context.json');
|
|
325
|
-
fs.writeFileSync(cliContextPath, JSON.stringify({ projectName, repoOwner, repoName }, null, 2));
|
|
347
|
+
fs.writeFileSync(cliContextPath, JSON.stringify({ projectName, repoOwner, repoName, projectNumber }, null, 2));
|
|
326
348
|
} catch (err) {
|
|
327
349
|
// Non-fatal — agent will ask for the values instead
|
|
328
350
|
}
|
package/package.json
CHANGED
|
@@ -16,14 +16,12 @@ jobs:
|
|
|
16
16
|
issues: write
|
|
17
17
|
pull-requests: write
|
|
18
18
|
contents: read
|
|
19
|
-
env:
|
|
20
|
-
PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
|
|
21
19
|
steps:
|
|
22
20
|
- name: Update Labels
|
|
23
|
-
if: ${{
|
|
21
|
+
if: ${{ !contains('{{IMPLEMENTATION_AGENT_LABEL}}', '{{') }}
|
|
24
22
|
uses: actions/github-script@v7
|
|
25
23
|
with:
|
|
26
|
-
github-token: ${{
|
|
24
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
27
25
|
script: |
|
|
28
26
|
const { owner, repo } = context.repo;
|
|
29
27
|
const issue_number = context.payload.issue.number;
|
|
@@ -28,13 +28,13 @@ jobs:
|
|
|
28
28
|
if: github.event_name == 'issues' && github.event.action == 'labeled'
|
|
29
29
|
runs-on: ubuntu-latest
|
|
30
30
|
env:
|
|
31
|
-
|
|
31
|
+
PROJECT_PAT: ${{ secrets.PROJECT_PAT }}
|
|
32
32
|
steps:
|
|
33
33
|
- name: Detect Label and Move Issue
|
|
34
|
-
if: ${{ env.
|
|
34
|
+
if: ${{ env.PROJECT_PAT != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
|
|
35
35
|
uses: actions/github-script@v7
|
|
36
36
|
with:
|
|
37
|
-
github-token: ${{ env.
|
|
37
|
+
github-token: ${{ env.PROJECT_PAT }}
|
|
38
38
|
script: |
|
|
39
39
|
const labelName = context.payload.label.name;
|
|
40
40
|
let targetStatusId = null;
|
|
@@ -94,10 +94,10 @@ jobs:
|
|
|
94
94
|
# runs-on: ubuntu-latest
|
|
95
95
|
# steps:
|
|
96
96
|
# - name: Move issue to Idea
|
|
97
|
-
# if: ${{ env.
|
|
97
|
+
# if: ${{ env.PROJECT_PAT != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
|
|
98
98
|
# uses: actions/github-script@v7
|
|
99
99
|
# with:
|
|
100
|
-
# github-token: ${{ env.
|
|
100
|
+
# github-token: ${{ env.PROJECT_PAT }}
|
|
101
101
|
# script: |
|
|
102
102
|
# const { issue: { number, node_id } } = context.payload;
|
|
103
103
|
# const { addProjectV2ItemById: { item } } = await github.graphql(`
|
|
@@ -122,13 +122,13 @@ jobs:
|
|
|
122
122
|
if: github.event_name == 'pull_request' && (github.event.action == 'opened' || github.event.action == 'reopened')
|
|
123
123
|
runs-on: ubuntu-latest
|
|
124
124
|
env:
|
|
125
|
-
|
|
125
|
+
PROJECT_PAT: ${{ secrets.PROJECT_PAT }}
|
|
126
126
|
steps:
|
|
127
127
|
- name: Move linked issue to Code Review / PR
|
|
128
|
-
if: ${{ env.
|
|
128
|
+
if: ${{ env.PROJECT_PAT != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
|
|
129
129
|
uses: actions/github-script@v7
|
|
130
130
|
with:
|
|
131
|
-
github-token: ${{ env.
|
|
131
|
+
github-token: ${{ env.PROJECT_PAT }}
|
|
132
132
|
script: |
|
|
133
133
|
const prNumber = context.payload.pull_request.number;
|
|
134
134
|
const { owner, repo } = context.repo;
|
|
@@ -176,13 +176,13 @@ jobs:
|
|
|
176
176
|
if: github.event_name == 'pull_request_review' && github.event.review.state == 'approved'
|
|
177
177
|
runs-on: ubuntu-latest
|
|
178
178
|
env:
|
|
179
|
-
|
|
179
|
+
PROJECT_PAT: ${{ secrets.PROJECT_PAT }}
|
|
180
180
|
steps:
|
|
181
181
|
- name: Swap PR labels
|
|
182
|
-
if: ${{ env.
|
|
182
|
+
if: ${{ env.PROJECT_PAT != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
|
|
183
183
|
uses: actions/github-script@v7
|
|
184
184
|
with:
|
|
185
|
-
github-token: ${{ env.
|
|
185
|
+
github-token: ${{ env.PROJECT_PAT }}
|
|
186
186
|
script: |
|
|
187
187
|
const prNumber = context.payload.pull_request.number;
|
|
188
188
|
const { owner, repo } = context.repo;
|
|
@@ -195,13 +195,13 @@ jobs:
|
|
|
195
195
|
if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true
|
|
196
196
|
runs-on: ubuntu-latest
|
|
197
197
|
env:
|
|
198
|
-
|
|
198
|
+
PROJECT_PAT: ${{ secrets.PROJECT_PAT }}
|
|
199
199
|
steps:
|
|
200
200
|
- name: Move issue to Production
|
|
201
|
-
if: ${{ env.
|
|
201
|
+
if: ${{ env.PROJECT_PAT != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
|
|
202
202
|
uses: actions/github-script@v7
|
|
203
203
|
with:
|
|
204
|
-
github-token: ${{ env.
|
|
204
|
+
github-token: ${{ env.PROJECT_PAT }}
|
|
205
205
|
script: |
|
|
206
206
|
const prNumber = context.payload.pull_request.number;
|
|
207
207
|
const { owner, repo } = context.repo;
|