agent-templates 0.1.0 → 0.2.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/ADOPTING.md +57 -57
- package/CLAUDE.md +128 -125
- package/LICENSE +21 -21
- package/README.md +32 -32
- package/package.json +32 -32
- package/patterns/three-agent-architect-builder-reviewer/README.md +164 -153
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/agents/architect.md +31 -31
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/agents/builder.md +25 -25
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/agents/reviewer.md +33 -33
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/agents/triage.md +31 -31
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/commands/breakdown-prd.md +18 -18
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/commands/nightly-issues.md +14 -14
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/commands/review-ticket.md +14 -14
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/commands/start-all.md +17 -0
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/commands/start-milestone.md +15 -15
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/commands/verify-delivery.md +20 -20
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/hooks/guard-main-session-writes.mjs +53 -53
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/scripts/milestone-dag.mjs +94 -0
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/scripts/publish-tickets.mjs +263 -263
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/settings.json +15 -15
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/workflows/nightly-issues.js +141 -139
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/workflows/run-milestone.js +225 -223
- package/patterns/three-agent-architect-builder-reviewer/scaffold/.claude/workflows/start-all.js +120 -0
- package/patterns/three-agent-architect-builder-reviewer/scaffold/INSTALL.md +65 -65
- package/patterns/three-agent-architect-builder-reviewer/scaffold/claude-md-snippet.md +38 -37
- package/scripts/adopt.mjs +207 -177
- package/scripts/build-site.mjs +366 -264
- package/scripts/cli.mjs +52 -52
- package/templates/pattern-README.template.md +65 -65
- package/templates/ticket.template.md +104 -104
- package/templates/tracker/github/ISSUE_TEMPLATE/bug-report.md +28 -28
- package/templates/tracker/github/ISSUE_TEMPLATE/decision-record.md +25 -25
- package/templates/tracker/github/ISSUE_TEMPLATE/task.md +36 -36
- package/templates/tracker/github/PULL_REQUEST_TEMPLATE.md +54 -54
- package/templates/tracker/gitlab/issue_templates/bug-report.md +23 -23
- package/templates/tracker/gitlab/issue_templates/decision-record.md +20 -20
- package/templates/tracker/gitlab/issue_templates/task.md +31 -31
- package/templates/tracker/gitlab/merge_request_templates/default.md +55 -55
package/scripts/adopt.mjs
CHANGED
|
@@ -1,177 +1,207 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// adopt.mjs — one-command pattern installer for new and existing projects.
|
|
3
|
-
//
|
|
4
|
-
// Usage (run from a checkout of the agent-templates catalog):
|
|
5
|
-
// node scripts/adopt.mjs <pattern-name> <target-dir> [--platform gh|glab] [--force]
|
|
6
|
-
//
|
|
7
|
-
// Installs into <target-dir>:
|
|
8
|
-
// .claude/ from the pattern's scaffold (per-file; existing files skipped)
|
|
9
|
-
// templates/ticket.template.md the universal ticket format
|
|
10
|
-
// .github/ or .gitlab/ universal tracker templates (issues + PR/MR) for the platform
|
|
11
|
-
// docs/PRD.md copied from a root PRD.md if present and docs/PRD.md is absent
|
|
12
|
-
// docs/prd/ docs/adr/ docs/plans/ the docs skeleton the pipeline assumes
|
|
13
|
-
// CLAUDE.md created from the snippet, or snippet appended once (marker-checked)
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// re-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
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
|
-
let
|
|
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
|
-
const
|
|
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
|
-
if (
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
console.log(
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// adopt.mjs — one-command pattern installer for new and existing projects.
|
|
3
|
+
//
|
|
4
|
+
// Usage (run from a checkout of the agent-templates catalog):
|
|
5
|
+
// node scripts/adopt.mjs <pattern-name> <target-dir> [--platform gh|glab] [--force]
|
|
6
|
+
//
|
|
7
|
+
// Installs into <target-dir>:
|
|
8
|
+
// .claude/ from the pattern's scaffold (per-file; existing files skipped)
|
|
9
|
+
// templates/ticket.template.md the universal ticket format
|
|
10
|
+
// .github/ or .gitlab/ universal tracker templates (issues + PR/MR) for the platform
|
|
11
|
+
// docs/PRD.md copied from a root PRD.md if present and docs/PRD.md is absent
|
|
12
|
+
// docs/prd/ docs/adr/ docs/plans/ the docs skeleton the pipeline assumes
|
|
13
|
+
// CLAUDE.md created from the snippet, or snippet appended once (marker-checked)
|
|
14
|
+
// .gitattributes eol=lf rules for scaffold runtime files, appended once (marker-checked)
|
|
15
|
+
//
|
|
16
|
+
// Idempotent: re-running skips everything that exists (--force overwrites files, never
|
|
17
|
+
// re-appends the snippet). Exit 0 = installed/verified; exit 1 = bad invocation.
|
|
18
|
+
|
|
19
|
+
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'
|
|
20
|
+
import { execFileSync } from 'node:child_process'
|
|
21
|
+
import { basename, dirname, join, relative, resolve } from 'node:path'
|
|
22
|
+
import { fileURLToPath } from 'node:url'
|
|
23
|
+
|
|
24
|
+
const CATALOG = fileURLToPath(new URL('..', import.meta.url))
|
|
25
|
+
const argv = process.argv.slice(2)
|
|
26
|
+
const FORCE = argv.includes('--force')
|
|
27
|
+
|
|
28
|
+
const pIx = argv.indexOf('--platform')
|
|
29
|
+
let PLATFORM = pIx !== -1 ? argv[pIx + 1] || '' : ''
|
|
30
|
+
if (pIx !== -1 && (!PLATFORM || PLATFORM.startsWith('--'))) {
|
|
31
|
+
console.error('missing or invalid --platform value (expected gh or glab)')
|
|
32
|
+
process.exit(1)
|
|
33
|
+
}
|
|
34
|
+
const positional = argv.filter((a, i) => !a.startsWith('--') && (pIx === -1 || i !== pIx + 1))
|
|
35
|
+
const [pattern, targetArg] = positional
|
|
36
|
+
if (!pattern || !targetArg) {
|
|
37
|
+
console.error('usage: node scripts/adopt.mjs <pattern-name> <target-dir> [--platform gh|glab] [--force]')
|
|
38
|
+
process.exit(1)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const scaffold = join(CATALOG, 'patterns', pattern, 'scaffold')
|
|
42
|
+
if (!existsSync(scaffold)) {
|
|
43
|
+
const available = existsSync(join(CATALOG, 'patterns'))
|
|
44
|
+
? readdirSync(join(CATALOG, 'patterns')).filter((d) => existsSync(join(CATALOG, 'patterns', d, 'scaffold')))
|
|
45
|
+
: []
|
|
46
|
+
console.error(`unknown pattern: ${pattern}\navailable: ${available.join(', ') || '(none)'}`)
|
|
47
|
+
process.exit(1)
|
|
48
|
+
}
|
|
49
|
+
const target = resolve(targetArg)
|
|
50
|
+
let targetOk = false
|
|
51
|
+
try { targetOk = statSync(target).isDirectory() } catch {}
|
|
52
|
+
if (!targetOk) {
|
|
53
|
+
console.error(`target is not a directory: ${target}`)
|
|
54
|
+
process.exit(1)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!PLATFORM) {
|
|
58
|
+
try {
|
|
59
|
+
const origin = execFileSync('git', ['-C', target, 'remote', 'get-url', 'origin'], {
|
|
60
|
+
encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'],
|
|
61
|
+
}).trim()
|
|
62
|
+
const host = (origin.match(/(?:@|:\/\/)([^/:]+)[/:]/) || [])[1] || ''
|
|
63
|
+
PLATFORM = host.includes('gitlab') ? 'glab' : 'gh'
|
|
64
|
+
console.log(`platform: ${PLATFORM} (autodetected from ${host || origin}; override with --platform)`)
|
|
65
|
+
} catch {
|
|
66
|
+
PLATFORM = 'gh'
|
|
67
|
+
console.log('platform: gh (no origin remote detected; override with --platform glab)')
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (PLATFORM !== 'gh' && PLATFORM !== 'glab') {
|
|
71
|
+
console.error(`unknown platform: ${PLATFORM} (expected gh or glab)`)
|
|
72
|
+
process.exit(1)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let installed = 0
|
|
76
|
+
let skipped = 0
|
|
77
|
+
const note = (line) => console.log(line)
|
|
78
|
+
|
|
79
|
+
function* walk(dir) {
|
|
80
|
+
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
81
|
+
const f = join(dir, e.name)
|
|
82
|
+
if (e.isDirectory()) yield* walk(f)
|
|
83
|
+
else yield f
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Installed text files are ALWAYS written with LF line endings: the Claude Code
|
|
88
|
+
// Workflow tool rejects scripts containing \r ("control characters that would be
|
|
89
|
+
// hidden in the approval dialog") — observed in the field on a Windows checkout
|
|
90
|
+
// (catalog issue #21). CRLF can sneak in via git autocrlf on the CATALOG checkout,
|
|
91
|
+
// so normalization happens here at install time, regardless of the source state.
|
|
92
|
+
const TEXT_EXT = /\.(md|mjs|js|json|ya?ml|txt)$/i
|
|
93
|
+
const copyFile = (src, dst, label) => {
|
|
94
|
+
if (existsSync(dst) && !FORCE) {
|
|
95
|
+
console.log(`= exists ${label}`)
|
|
96
|
+
skipped++
|
|
97
|
+
return false
|
|
98
|
+
}
|
|
99
|
+
mkdirSync(dirname(dst), { recursive: true })
|
|
100
|
+
if (TEXT_EXT.test(src)) {
|
|
101
|
+
writeFileSync(dst, readFileSync(src, 'utf8').replace(/\r\n/g, '\n'))
|
|
102
|
+
} else {
|
|
103
|
+
cpSync(src, dst)
|
|
104
|
+
}
|
|
105
|
+
console.log(`+ install ${label}`)
|
|
106
|
+
installed++
|
|
107
|
+
return true
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 1. scaffold .claude/ (per-file so re-runs skip; settings.json conflicts get a manual-merge note)
|
|
111
|
+
for (const src of walk(join(scaffold, '.claude'))) {
|
|
112
|
+
const rel = relative(scaffold, src).replaceAll('\\', '/')
|
|
113
|
+
const dst = join(target, rel)
|
|
114
|
+
const existed = existsSync(dst)
|
|
115
|
+
copyFile(src, dst, rel)
|
|
116
|
+
if (existed && !FORCE && rel === '.claude/settings.json') {
|
|
117
|
+
note(' (note) existing .claude/settings.json kept — merge the hooks.PreToolUse entry and permissions.allow from the scaffold manually')
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// 2. universal ticket template
|
|
122
|
+
copyFile(join(CATALOG, 'templates', 'ticket.template.md'), join(target, 'templates', 'ticket.template.md'), 'templates/ticket.template.md')
|
|
123
|
+
|
|
124
|
+
// 3. platform tracker templates (issues + PR/MR)
|
|
125
|
+
const trackerSrc = join(CATALOG, 'templates', 'tracker', PLATFORM === 'gh' ? 'github' : 'gitlab')
|
|
126
|
+
const trackerDstRoot = join(target, PLATFORM === 'gh' ? '.github' : '.gitlab')
|
|
127
|
+
for (const src of walk(trackerSrc)) {
|
|
128
|
+
const rel = relative(trackerSrc, src).replaceAll('\\', '/')
|
|
129
|
+
copyFile(src, join(trackerDstRoot, rel), `${PLATFORM === 'gh' ? '.github' : '.gitlab'}/${rel}`)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 4. docs skeleton
|
|
133
|
+
for (const d of ['docs/prd', 'docs/adr', 'docs/plans']) {
|
|
134
|
+
const dir = join(target, d)
|
|
135
|
+
if (!existsSync(dir)) {
|
|
136
|
+
mkdirSync(dir, { recursive: true })
|
|
137
|
+
writeFileSync(join(dir, '.gitkeep'), '')
|
|
138
|
+
console.log(`+ mkdir ${d}/`)
|
|
139
|
+
installed++
|
|
140
|
+
} else {
|
|
141
|
+
console.log(`= exists ${d}/`)
|
|
142
|
+
skipped++
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// 5. root PRD.md -> docs/PRD.md (copy, never move — the pipeline reads docs/PRD.md)
|
|
147
|
+
const rootPrd = join(target, 'PRD.md')
|
|
148
|
+
const docsPrd = join(target, 'docs', 'PRD.md')
|
|
149
|
+
if (existsSync(rootPrd) && !existsSync(docsPrd)) {
|
|
150
|
+
cpSync(rootPrd, docsPrd)
|
|
151
|
+
console.log('+ install docs/PRD.md (copied from root PRD.md — the pipeline reads docs/PRD.md; delete the root copy when ready)')
|
|
152
|
+
installed++
|
|
153
|
+
} else if (existsSync(docsPrd)) {
|
|
154
|
+
console.log('= exists docs/PRD.md')
|
|
155
|
+
skipped++
|
|
156
|
+
} else {
|
|
157
|
+
note(' (note) no PRD.md found — write docs/PRD.md before running /breakdown-prd')
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// 6. CLAUDE.md: create from the snippet, or append it once (marker-checked, never duplicated)
|
|
161
|
+
const snippet = readFileSync(join(scaffold, 'claude-md-snippet.md'), 'utf8')
|
|
162
|
+
const MARKER = '## Delivery pipeline — three-agent Architect / Builder / Reviewer'
|
|
163
|
+
const claudeMd = join(target, 'CLAUDE.md')
|
|
164
|
+
if (!existsSync(claudeMd)) {
|
|
165
|
+
const header = `# ${basename(target)} — Project Constitution\n\n> Auto-loaded into every session. Installed by agent-templates adopt.mjs on ${new Date().toISOString().slice(0, 10)}.\n> Add your project facts and non-negotiable constraints above the pipeline section.\n\n`
|
|
166
|
+
writeFileSync(claudeMd, header + snippet)
|
|
167
|
+
console.log('+ install CLAUDE.md (seeded from the pattern snippet)')
|
|
168
|
+
installed++
|
|
169
|
+
} else if (!readFileSync(claudeMd, 'utf8').includes(MARKER)) {
|
|
170
|
+
writeFileSync(claudeMd, readFileSync(claudeMd, 'utf8').trimEnd() + '\n\n' + snippet)
|
|
171
|
+
console.log('+ append CLAUDE.md (pipeline snippet appended)')
|
|
172
|
+
installed++
|
|
173
|
+
} else {
|
|
174
|
+
console.log('= exists CLAUDE.md (pipeline snippet already present)')
|
|
175
|
+
skipped++
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 7. .gitattributes: pin scaffold runtime files to LF. Install-time normalization
|
|
179
|
+
// (above) is not enough on Windows — a later `git checkout` with autocrlf re-CRLFs
|
|
180
|
+
// them and the Workflow tool rejects the script content (catalog issue #23).
|
|
181
|
+
const GA_MARKER = '# agent-templates: Workflow tool rejects CRLF scripts (keep LF)'
|
|
182
|
+
const GA_RULES = `${GA_MARKER}\n.claude/workflows/*.js text eol=lf\n.claude/scripts/*.mjs text eol=lf\n`
|
|
183
|
+
const gaPath = join(target, '.gitattributes')
|
|
184
|
+
if (!existsSync(gaPath)) {
|
|
185
|
+
writeFileSync(gaPath, GA_RULES)
|
|
186
|
+
console.log('+ install .gitattributes (eol=lf for scaffold runtime files)')
|
|
187
|
+
installed++
|
|
188
|
+
} else if (!readFileSync(gaPath, 'utf8').includes(GA_MARKER)) {
|
|
189
|
+
writeFileSync(gaPath, readFileSync(gaPath, 'utf8').trimEnd() + '\n\n' + GA_RULES)
|
|
190
|
+
console.log('+ append .gitattributes (eol=lf rules for scaffold runtime files)')
|
|
191
|
+
installed++
|
|
192
|
+
} else {
|
|
193
|
+
console.log('= exists .gitattributes (eol=lf rules already present)')
|
|
194
|
+
skipped++
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
console.log(`\nadopt: ${installed} installed, ${skipped} already present. Pattern: ${pattern}, platform: ${PLATFORM}.`)
|
|
198
|
+
console.log(`
|
|
199
|
+
NEXT STEPS (details: ${join(CATALOG, 'ADOPTING.md')})
|
|
200
|
+
1. Review CLAUDE.md — set the Operating mode line (start: supervised) and add your
|
|
201
|
+
project facts; fill the Constraint check section of the PR/MR template.
|
|
202
|
+
2. Tracker: git remote + authenticated CLI (${PLATFORM} auth login). Node >= 18 on PATH.
|
|
203
|
+
3. In Claude Code, in the target repo: /breakdown-prd
|
|
204
|
+
(Architect decomposes docs/PRD.md into sub-PRDs + tickets, then stops for your review)
|
|
205
|
+
4. Gate 1 — review the breakdown, then: /start-milestone docs/prd/00-<module> supervised
|
|
206
|
+
5. Graduate to autonomous when the pattern holds; optional nightly sweep:
|
|
207
|
+
see the pattern's INSTALL.md § Nightly sweep.`)
|