-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
251 lines (226 loc) · 9.54 KB
/
check-skills.yml
File metadata and controls
251 lines (226 loc) · 9.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# check-skills.yml — Drop this into your library repo's .github/workflows/
#
# Checks intent skills after a release and opens or updates one review PR when
# existing skills, artifact coverage, or workspace package coverage need review.
#
# Triggers: new release published, or manual workflow_dispatch.
#
# intent-workflow-version: 2
#
# Template variables (replaced by `intent setup`):
# @tanstack/router — e.g. @tanstack/query or my-workspace workspace
name: Check Skills
on:
release:
types: [published]
workflow_dispatch: {}
permissions:
contents: write
pull-requests: write
jobs:
check:
name: Check intent skill coverage
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install intent
run: npm install -g @tanstack/intent
- name: Check skills
id: stale
run: |
set +e
intent stale --json > stale.json
STATUS=$?
set -e
cat stale.json
if [ "$STATUS" -ne 0 ]; then
echo "has_review=true" >> "$GITHUB_OUTPUT"
echo "check_failed=true" >> "$GITHUB_OUTPUT"
cat > review-items.json <<'JSON'
[
{
"type": "stale-check-failed",
"library": "@tanstack/router",
"subject": "intent stale --json",
"reasons": ["The stale check command failed. Review the workflow logs before updating skills."]
}
]
JSON
else
node <<'NODE'
const fs = require('fs')
const reports = JSON.parse(fs.readFileSync('stale.json', 'utf8'))
const items = []
for (const report of reports) {
for (const skill of report.skills ?? []) {
if (!skill?.needsReview) continue
items.push({
type: 'stale-skill',
library: report.library,
subject: skill.name,
reasons: skill.reasons ?? [],
})
}
for (const signal of report.signals ?? []) {
if (signal?.needsReview === false) continue
items.push({
type: signal?.type ?? 'review-signal',
library: signal?.library ?? report.library,
subject:
signal?.packageName ??
signal?.packageRoot ??
signal?.skill ??
signal?.artifactPath ??
signal?.subject ??
report.library,
reasons: signal?.reasons ?? [],
artifactPath: signal?.artifactPath,
packageName: signal?.packageName,
packageRoot: signal?.packageRoot,
skill: signal?.skill,
})
}
}
fs.writeFileSync('review-items.json', JSON.stringify(items, null, 2) + '\n')
fs.appendFileSync(
process.env.GITHUB_OUTPUT,
`has_review=${items.length > 0 ? 'true' : 'false'}\n`,
)
NODE
fi
{
echo "review_items<<EOF"
cat review-items.json
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Write clean summary
if: steps.stale.outputs.has_review == 'false'
run: |
{
echo "### Intent skill review"
echo ""
echo "No stale skills or coverage gaps found."
} >> "$GITHUB_STEP_SUMMARY"
- name: Build review PR body
if: steps.stale.outputs.has_review == 'true'
run: |
node <<'NODE'
const fs = require('fs')
const items = JSON.parse(fs.readFileSync('review-items.json', 'utf8'))
const grouped = new Map()
for (const item of items) {
grouped.set(item.type, (grouped.get(item.type) ?? 0) + 1)
}
const signalRows = [...grouped.entries()]
.sort(([a], [b]) => a.localeCompare(b))
.map(([type, count]) => `| \`${type}\` | ${count} |`)
const itemRows = items.map((item) => {
const subject = item.subject ? `\`${item.subject}\`` : '-'
const reasons = item.reasons?.length ? item.reasons.join('; ') : '-'
return `| \`${item.type}\` | ${subject} | \`${item.library}\` | ${reasons} |`
})
const prompt = [
'You are helping maintain Intent skills for this repository.',
'',
'Goal:',
'Resolve the Intent skill review signals below while preserving the existing scope, taxonomy, and maintainer-reviewed artifacts.',
'',
'Review signals:',
JSON.stringify(items, null, 2),
'',
'Required workflow:',
'1. Read the existing `_artifacts/*domain_map.yaml`, `_artifacts/*skill_tree.yaml`, and generated `skills/**/SKILL.md` files.',
'2. Read each flagged package package.json, public exports, README/docs if present, and source entry points.',
'3. Compare flagged packages against the existing domains, skills, tasks, packages, covers, sources, tensions, and cross-references in the artifacts.',
'4. For each signal, decide whether it means existing skill coverage, a missing generated skill, a new skill candidate, out-of-scope coverage, or deferred work.',
'',
'Maintainer questions:',
'Before editing skills or artifacts, ask the maintainer:',
'1. For each flagged package, is this package user-facing enough to need agent guidance?',
'2. If yes, should it extend an existing skill or become a new skill?',
'3. If it extends an existing skill, which current skill should own it?',
'4. If it is out of scope, what short reason should be recorded in artifact coverage ignores?',
'5. Are any of these packages experimental or unstable enough to exclude for now?',
'',
'Decision rules:',
'- Do not auto-generate skills.',
'- Do not create broad new skill areas without maintainer confirmation.',
'- Prefer adding package coverage to an existing skill when the package is an implementation variant of an existing domain.',
'- Create a new skill only when the package introduces a distinct developer task or failure mode.',
'- Preserve current naming, path, and package layout conventions.',
'- Keep generated skills under the package-local `skills/` directory.',
'- Keep repo-root `_artifacts` as the reviewed plan.',
'',
'If maintainer confirms updates:',
'1. Update the relevant `_artifacts/*domain_map.yaml` or `_artifacts/*skill_tree.yaml`.',
'2. Update or create `SKILL.md` files only for confirmed coverage changes.',
'3. Keep `sources` aligned between artifact skill entries and SKILL frontmatter.',
'4. Bump `library_version` only for skills whose covered source package version changed.',
'5. Run `npx @tanstack/intent@latest validate` on touched skill directories.',
'6. Summarize every package as one of: existing-skill coverage, new skill, ignored, or deferred.',
].join('\n')
const body = [
'## Intent Skill Review Needed',
'',
'Intent found skills, artifact coverage, or workspace package coverage that need maintainer review.',
'',
'### Summary',
'',
'| Signal | Count |',
'| --- | ---: |',
...signalRows,
'',
'### Review Items',
'',
'| Signal | Subject | Library | Reason |',
'| --- | --- | --- | --- |',
...itemRows,
'',
'### Agent Prompt',
'',
'Paste this into your coding agent:',
'',
'```text',
prompt,
'```',
'',
'This PR is a review reminder only. It does not update skills automatically.',
].join('\n')
fs.writeFileSync('pr-body.md', body + '\n')
fs.writeFileSync(process.env.GITHUB_STEP_SUMMARY, body + '\n')
NODE
- name: Open or update review PR
if: steps.stale.outputs.has_review == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ github.event.release.tag_name || 'manual' }}"
BRANCH="skills/review-${VERSION}"
BASE_BRANCH="${{ github.event.repository.default_branch }}"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git fetch origin "$BRANCH" || true
if git show-ref --verify --quiet "refs/remotes/origin/$BRANCH"; then
git checkout -B "$BRANCH" "origin/$BRANCH"
else
git checkout -b "$BRANCH"
git commit --allow-empty -m "chore: review intent skills for ${VERSION}"
git push origin "$BRANCH"
fi
PR_URL="$(gh pr list --head "$BRANCH" --json url --jq '.[0].url')"
if [ -n "$PR_URL" ]; then
gh pr edit "$PR_URL" --body-file pr-body.md
else
gh pr create \
--title "Review intent skills (${VERSION})" \
--body-file pr-body.md \
--head "$BRANCH" \
--base "$BASE_BRANCH"
fi