agent-templates 0.1.0 → 0.2.0

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