create-agentic-pdlc 1.2.1 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/CODEOWNERS +5 -0
- package/.github/assets/agentic-pdlc-flow.svg +255 -0
- package/.github/workflows/agent-trigger.yml +40 -1
- package/.github/workflows/ci.yml +3 -0
- package/.github/workflows/pdlc-health-check.yml +123 -0
- package/.github/workflows/project-automation.yml +17 -40
- package/AGENTS.md +9 -6
- package/README.md +12 -8
- package/SETUP.md +41 -2
- package/adapters/claude-code/skill.md +17 -2
- package/bin/cli.js +4 -2
- package/docs/flow.md +173 -0
- package/docs/pdlc.md +1 -1
- package/docs/spikes/04-upstream-flow-gap-analysis.md +39 -0
- package/package.json +2 -2
- package/templates/.github/CODEOWNERS +5 -0
- package/templates/.github/workflows/agent-trigger.yml +40 -1
- package/templates/.github/workflows/ci.yml +3 -0
- package/templates/.github/workflows/pdlc-health-check.yml +123 -0
- package/templates/.github/workflows/project-automation.yml +17 -40
- package/templates/.github/workflows/upstream-gate.yml +54 -0
- package/templates/AGENTS.md +34 -6
- package/templates/docs/pdlc.md +1 -1
|
@@ -16,9 +16,9 @@ env:
|
|
|
16
16
|
STATUS_DETAILING: "{{ID_DETAILING}}"
|
|
17
17
|
STATUS_APPROVAL: "{{ID_APPROVAL}}"
|
|
18
18
|
STATUS_DEVELOPMENT: "{{ID_DEVELOPMENT}}"
|
|
19
|
+
STATUS_TESTING: "{{ID_TESTING}}"
|
|
19
20
|
STATUS_CODE_REVIEW_PR: "{{ID_CODE_REVIEW_PR}}"
|
|
20
|
-
|
|
21
|
-
STATUS_PRODUCAO: "{{ID_PRODUCAO}}"
|
|
21
|
+
STATUS_PRODUCTION: "{{ID_PRODUCTION}}"
|
|
22
22
|
|
|
23
23
|
jobs:
|
|
24
24
|
# Issue Labeled → Move Upstream
|
|
@@ -39,21 +39,24 @@ jobs:
|
|
|
39
39
|
let targetStatusId = null;
|
|
40
40
|
let stageName = null;
|
|
41
41
|
|
|
42
|
-
if (labelName === '
|
|
42
|
+
if (labelName === 'upstream:exploration') {
|
|
43
43
|
targetStatusId = process.env.STATUS_EXPLORATION;
|
|
44
44
|
stageName = 'Exploration';
|
|
45
|
-
} else if (labelName === '
|
|
45
|
+
} else if (labelName === 'upstream:brainstorming') {
|
|
46
46
|
targetStatusId = process.env.STATUS_BRAINSTORMING;
|
|
47
47
|
stageName = 'Brainstorming';
|
|
48
|
-
} else if (labelName === '
|
|
48
|
+
} else if (labelName === 'upstream:detailing') {
|
|
49
49
|
targetStatusId = process.env.STATUS_DETAILING;
|
|
50
50
|
stageName = 'Detailing';
|
|
51
|
-
} else if (labelName === '
|
|
51
|
+
} else if (labelName === 'upstream:approval') {
|
|
52
52
|
targetStatusId = process.env.STATUS_APPROVAL;
|
|
53
53
|
stageName = 'Approval';
|
|
54
|
-
} else if (labelName === '
|
|
54
|
+
} else if (labelName === 'upstream:development') {
|
|
55
55
|
targetStatusId = process.env.STATUS_DEVELOPMENT;
|
|
56
56
|
stageName = 'Development';
|
|
57
|
+
} else if (labelName === 'upstream:testing') {
|
|
58
|
+
targetStatusId = process.env.STATUS_TESTING;
|
|
59
|
+
stageName = 'Testing';
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
if (!targetStatusId) {
|
|
@@ -83,6 +86,7 @@ jobs:
|
|
|
83
86
|
await moveItem(node_id, targetStatusId);
|
|
84
87
|
console.log(`Issue #${number} moved to ${stageName}`);
|
|
85
88
|
|
|
89
|
+
{{OPTIONAL_ARCHITECTURE_VIOLATION_JOB}}
|
|
86
90
|
|
|
87
91
|
# PR Opened → Move linked issue to Code Review / PR
|
|
88
92
|
move-card-on-pr-open:
|
|
@@ -136,17 +140,17 @@ jobs:
|
|
|
136
140
|
console.log(`PR #${prNumber} → Code Review / PR (no linked issue)`);
|
|
137
141
|
}
|
|
138
142
|
|
|
139
|
-
await github.rest.issues.addLabels({ owner, repo, issue_number: prNumber, labels: ['pr:review'] }).catch(() => {});
|
|
143
|
+
await github.rest.issues.addLabels({ owner, repo, issue_number: prNumber, labels: ['pr:in-review'] }).catch(() => {});
|
|
140
144
|
|
|
141
|
-
# Review Approved →
|
|
145
|
+
# Review Approved → Add Label
|
|
142
146
|
move-card-on-review-approved:
|
|
143
|
-
name: Approved PR →
|
|
147
|
+
name: Approved PR → Add Label
|
|
144
148
|
if: github.event_name == 'pull_request_review' && github.event.review.state == 'approved'
|
|
145
149
|
runs-on: ubuntu-latest
|
|
146
150
|
env:
|
|
147
151
|
PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
|
|
148
152
|
steps:
|
|
149
|
-
- name:
|
|
153
|
+
- name: Swap PR labels
|
|
150
154
|
if: ${{ env.PROJECT_TOKEN != '' }}
|
|
151
155
|
uses: actions/github-script@v7
|
|
152
156
|
with:
|
|
@@ -154,34 +158,7 @@ jobs:
|
|
|
154
158
|
script: |
|
|
155
159
|
const prNumber = context.payload.pull_request.number;
|
|
156
160
|
const { owner, repo } = context.repo;
|
|
157
|
-
|
|
158
|
-
const body = pr.body ?? '';
|
|
159
|
-
const linkedIssues = [...body.matchAll(/(?:Closes?|Fixes?|Resolves?)\s+#(\d+)/gi)].map(m => parseInt(m[1]));
|
|
160
|
-
|
|
161
|
-
const moveItem = async (nodeId) => {
|
|
162
|
-
const { addProjectV2ItemById: { item } } = await github.graphql(`
|
|
163
|
-
mutation($p: ID!, $c: ID!) {
|
|
164
|
-
addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
|
|
165
|
-
}`, { p: process.env.PROJECT_ID, c: nodeId });
|
|
166
|
-
await github.graphql(`
|
|
167
|
-
mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
|
|
168
|
-
updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
|
|
169
|
-
projectV2Item { id }
|
|
170
|
-
}
|
|
171
|
-
}`, { p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
|
|
172
|
-
v: { singleSelectOptionId: process.env.STATUS_MERGE } });
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
if (linkedIssues.length > 0) {
|
|
176
|
-
for (const n of linkedIssues) {
|
|
177
|
-
const { data: issue } = await github.rest.issues.get({ owner, repo, issue_number: n });
|
|
178
|
-
await moveItem(issue.node_id);
|
|
179
|
-
}
|
|
180
|
-
} else {
|
|
181
|
-
await moveItem(pr.node_id);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
try { await github.rest.issues.removeLabel({ owner, repo, issue_number: prNumber, name: 'pr:review' }); } catch {}
|
|
161
|
+
try { await github.rest.issues.removeLabel({ owner, repo, issue_number: prNumber, name: 'pr:in-review' }); } catch {}
|
|
185
162
|
await github.rest.issues.addLabels({ owner, repo, issue_number: prNumber, labels: ['pr:approved'] }).catch(() => {});
|
|
186
163
|
|
|
187
164
|
# PR Merged → Production
|
|
@@ -215,7 +192,7 @@ jobs:
|
|
|
215
192
|
projectV2Item { id }
|
|
216
193
|
}
|
|
217
194
|
}`, { p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
|
|
218
|
-
v: { singleSelectOptionId: process.env.
|
|
195
|
+
v: { singleSelectOptionId: process.env.STATUS_PRODUCTION } });
|
|
219
196
|
};
|
|
220
197
|
|
|
221
198
|
if (linkedIssues.length > 0) {
|
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
}
|
package/templates/AGENTS.md
CHANGED
|
@@ -30,12 +30,39 @@ Always start from the current `main` HEAD. Never work over stale snapshots.
|
|
|
30
30
|
## Mandatory Workflow
|
|
31
31
|
|
|
32
32
|
0. **Identity**: Always prefix your GitHub comments with `🤖 **Agent:** ` to distinguish yourself.
|
|
33
|
-
1.
|
|
34
|
-
2. Read
|
|
35
|
-
3. Read
|
|
36
|
-
4.
|
|
37
|
-
5.
|
|
38
|
-
6.
|
|
33
|
+
1. **Initial State**: When beginning work on a new issue, your very first action must be to apply the `stage:exploration` label using the GitHub CLI (`gh issue edit <N> --add-label "stage:exploration"`).
|
|
34
|
+
2. Read the issue entirely — understand its type (US/BUG/TASK/SPIKE) and the Acceptance Criteria.
|
|
35
|
+
3. Read `docs/pdlc.md` — understand the PDLC and the Definition of Done in this project.
|
|
36
|
+
4. Read all files mentioned in the issue's technical context.
|
|
37
|
+
5. Implement the **minimum viable change** that satisfies the ACs — do not refactor beyond scope.
|
|
38
|
+
6. Run tests: `{{TEST_COMMAND}}`
|
|
39
|
+
7. Run typecheck (if applicable): `{{TYPECHECK_COMMAND}}`
|
|
40
|
+
8. Create a Pull Request with `Closes #N` in the body — automation moves the board.
|
|
41
|
+
|
|
42
|
+
### Spec format (Upstream Agents)
|
|
43
|
+
|
|
44
|
+
When detailing a solution in an issue body, you must **always** include both the user story and the acceptance criteria. Never append only the ACs to an existing text; rewrite the full issue body in this standard format:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
**As** [user],
|
|
48
|
+
**I want** [action],
|
|
49
|
+
**so that** [benefit].
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Acceptance Criteria
|
|
54
|
+
|
|
55
|
+
**AC1 — ...**
|
|
56
|
+
- Given ...
|
|
57
|
+
- When ...
|
|
58
|
+
- Then ...
|
|
59
|
+
|
|
60
|
+
**AC2 — ...**
|
|
61
|
+
...
|
|
62
|
+
|
|
63
|
+
## Files to modify
|
|
64
|
+
- `path/to/file.ts` — what changes
|
|
65
|
+
```
|
|
39
66
|
|
|
40
67
|
## What NOT to do
|
|
41
68
|
|
|
@@ -49,5 +76,6 @@ Always start from the current `main` HEAD. Never work over stale snapshots.
|
|
|
49
76
|
|
|
50
77
|
- **Tests:** `{{TEST_COMMAND}}`
|
|
51
78
|
- **Lint/Types:** `{{LINT_COMMAND}}`
|
|
79
|
+
- **Typecheck:** `{{TYPECHECK_COMMAND}}`
|
|
52
80
|
- **Build:** `{{BUILD_COMMAND}}`
|
|
53
81
|
{{EXTRA_PATTERNS}}
|
package/templates/docs/pdlc.md
CHANGED
|
@@ -72,7 +72,7 @@ REPO = {{REPO_OWNER}}/{{REPO_NAME}}
|
|
|
72
72
|
| `stage:detailing` | Issue | Blue | Technical spec is being written |
|
|
73
73
|
| `stage:development` | Issue | Orange | Agent is implementing the spec |
|
|
74
74
|
| `spec:approved` | Issue | Green | Gate 2 — agent is cleared to implement |
|
|
75
|
-
| `pr:review` | PR | Yellow | Awaiting code review |
|
|
75
|
+
| `pr:in-review` | PR | Yellow | Awaiting code review |
|
|
76
76
|
| `pr:approved` | PR | Green | Code review approved |
|
|
77
77
|
|
|
78
78
|
## Approval Gates
|