@patricksardinha/agentkit-cli 0.2.0 → 0.4.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.
- package/AGENT_WORKFLOW.md +129 -55
- package/CLAUDE.md +59 -34
- package/PLAYBOOK.md +192 -0
- package/PROJECT_BLUEPRINT.md +52 -0
- package/README.md +248 -167
- package/agents/agent-1-infra/skills.md +46 -0
- package/agents/agent-2-detectors/skills.md +38 -0
- package/agents/agent-3-generators/skills.md +43 -0
- package/agents/agent-4-commands/skills.md +37 -0
- package/dist/cli.cjs +208 -156
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +208 -156
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/add.ts +22 -15
- package/src/commands/init.ts +2 -2
- package/src/generators/claudeMdGenerator.ts +3 -14
- package/src/generators/playbookGenerator.ts +136 -36
- package/src/generators/workflowGenerator.ts +9 -36
- package/tests/commands/add.test.ts +1 -1
- package/tests/generators/blueprintSupport.test.ts +35 -30
- package/tests/generators/claudeMdGenerator.test.ts +48 -0
- package/tests/generators/playbookGenerator.test.ts +140 -48
- package/tests/generators/workflowGenerator.test.ts +40 -0
|
@@ -3,46 +3,146 @@ import type { Agent } from '../types/agent.js'
|
|
|
3
3
|
export interface PlaybookInput {
|
|
4
4
|
agents: Agent[]
|
|
5
5
|
projectName: string
|
|
6
|
+
hasBlueprint: boolean
|
|
6
7
|
}
|
|
7
8
|
|
|
8
|
-
export function generatePlaybook({ agents, projectName }: PlaybookInput): string {
|
|
9
|
+
export function generatePlaybook({ agents, projectName, hasBlueprint }: PlaybookInput): string {
|
|
9
10
|
const agentBlocks = agents.map((a) => agentBlock(a)).join('\n---\n\n')
|
|
10
11
|
|
|
12
|
+
const phase0 = hasBlueprint
|
|
13
|
+
? `## Phase 0 — Agent Decomposition (run this first)
|
|
14
|
+
|
|
15
|
+
> A \`PROJECT_BLUEPRINT.md\` was provided.
|
|
16
|
+
> Claude Code reads it and decomposes the project into specialized agents
|
|
17
|
+
> before writing a single line of code.
|
|
18
|
+
|
|
19
|
+
**Read these files in order:**
|
|
20
|
+
1. \`CLAUDE.md\`
|
|
21
|
+
2. \`PROJECT_BLUEPRINT.md\`
|
|
22
|
+
|
|
23
|
+
**Then decompose the project into agents** following these rules:
|
|
24
|
+
|
|
25
|
+
- One agent = one coherent technical layer (never mix two layers)
|
|
26
|
+
- Each agent must have a runnable success criterion (\`npm test\`, \`cargo build\`…)
|
|
27
|
+
- Agents must be ordered by dependency (no feature without infra first)
|
|
28
|
+
- Maximum 6 agents — if you have more, group related ones
|
|
29
|
+
- Always respect this order:
|
|
30
|
+
1. Infra & Configuration
|
|
31
|
+
2. Data layer (DB schema, models, services)
|
|
32
|
+
3. External integrations (auth, APIs, local services like Ollama)
|
|
33
|
+
4. UI & pages
|
|
34
|
+
5. Advanced features (RAG, export, realtime…)
|
|
35
|
+
6. Build & release (CI/CD, packaging, installers)
|
|
36
|
+
|
|
37
|
+
**Write the result directly into \`AGENT_WORKFLOW.md\`** — replace its current
|
|
38
|
+
content with your decomposition.
|
|
39
|
+
|
|
40
|
+
**Then ask for human validation:**
|
|
41
|
+
> "I have decomposed the project into N agents: [list them].
|
|
42
|
+
> Should I proceed with execution?"
|
|
43
|
+
|
|
44
|
+
Wait for confirmation before moving to Phase 1.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
`
|
|
49
|
+
: `## Phase 0 — Project Discovery (run this first)
|
|
50
|
+
|
|
51
|
+
> No \`PROJECT_BLUEPRINT.md\` was provided.
|
|
52
|
+
> Before writing any code, Claude Code asks the user what they want to build,
|
|
53
|
+
> then decomposes the project into agents — exactly as if a blueprint had been provided.
|
|
54
|
+
|
|
55
|
+
**Ask the user these questions and wait for their answers:**
|
|
56
|
+
|
|
57
|
+
1. What is this project? (one sentence describing the goal)
|
|
58
|
+
2. What are the main features you want to build? (list them)
|
|
59
|
+
3. Are there any tech constraints or architecture preferences?
|
|
60
|
+
(e.g. offline-only, specific DB, no auth, specific framework)
|
|
61
|
+
|
|
62
|
+
**Once you have the answers, decompose the project into agents**
|
|
63
|
+
following these rules:
|
|
64
|
+
|
|
65
|
+
- One agent = one coherent technical layer (never mix two layers)
|
|
66
|
+
- Each agent must have a runnable success criterion (\`npm test\`, \`cargo build\`…)
|
|
67
|
+
- Agents must be ordered by dependency (no feature without infra first)
|
|
68
|
+
- Maximum 6 agents — if you have more, group related ones
|
|
69
|
+
- Always respect this order:
|
|
70
|
+
1. Infra & Configuration
|
|
71
|
+
2. Data layer (DB schema, models, services)
|
|
72
|
+
3. External integrations (auth, APIs, local services like Ollama)
|
|
73
|
+
4. UI & pages
|
|
74
|
+
5. Advanced features (RAG, export, realtime…)
|
|
75
|
+
6. Build & release (CI/CD, packaging, installers)
|
|
76
|
+
|
|
77
|
+
**Write the result directly into \`AGENT_WORKFLOW.md\`** — replace its current
|
|
78
|
+
content with your decomposition.
|
|
79
|
+
|
|
80
|
+
**Then ask for human validation:**
|
|
81
|
+
> "I have decomposed the project into N agents: [list them].
|
|
82
|
+
> Should I proceed with execution?"
|
|
83
|
+
|
|
84
|
+
Wait for confirmation before moving to Phase 1.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
`
|
|
89
|
+
|
|
11
90
|
return `# PLAYBOOK.md — ${projectName}
|
|
12
91
|
|
|
13
|
-
>
|
|
92
|
+
> **One instruction to give Claude Code:**
|
|
93
|
+
> "Read PLAYBOOK.md and execute the procedure."
|
|
94
|
+
>
|
|
95
|
+
> Claude Code handles the rest autonomously — project discovery or blueprint reading,
|
|
96
|
+
> agent decomposition, execution, success validation, retries, and human escalation.
|
|
97
|
+
> No API key required. No additional cost beyond your LLM subscription.
|
|
14
98
|
|
|
15
|
-
|
|
99
|
+
---
|
|
16
100
|
|
|
17
|
-
|
|
18
|
-
1. Lire \`CLAUDE.md\`
|
|
19
|
-
2. Lire \`agents/agent-{N}-{slug}/skills.md\` (le fichier de l'agent courant)
|
|
101
|
+
## Global Execution Rules
|
|
20
102
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
- Après 3 échecs consécutifs → pause et demander validation humaine
|
|
26
|
-
- **Ne jamais passer à l'agent suivant sans critère validé**
|
|
103
|
+
Before each agent:
|
|
104
|
+
1. Read \`CLAUDE.md\`
|
|
105
|
+
2. Read \`agents/agent-{N}-{slug}/skills.md\` (current agent's file)
|
|
106
|
+
3. Read the agent's section in \`AGENT_WORKFLOW.md\`
|
|
27
107
|
|
|
28
|
-
|
|
108
|
+
After each agent:
|
|
109
|
+
- Run the success criterion command
|
|
110
|
+
- ✅ Passes → announce "✅ Agent N complete" and move to the next
|
|
111
|
+
- ❌ Fails → analyze the root cause, fix, rerun (max 3 attempts)
|
|
112
|
+
- After 3 consecutive failures → stop and ask for human validation
|
|
113
|
+
|
|
114
|
+
**Never move to the next agent without a passing success criterion.**
|
|
115
|
+
**Stay strictly within your current agent's defined scope.**
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
${phase0}## Phase 1 — Execution
|
|
29
120
|
|
|
30
121
|
${agentBlocks}
|
|
31
122
|
|
|
32
|
-
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Future Iterations
|
|
33
126
|
|
|
34
|
-
|
|
35
|
-
1.
|
|
36
|
-
2.
|
|
37
|
-
3.
|
|
38
|
-
4.
|
|
127
|
+
When a new agent is added via \`agentkit add --feature <description>\`:
|
|
128
|
+
1. A new agent block is appended to \`AGENT_WORKFLOW.md\`
|
|
129
|
+
2. The folder \`agents/agent-{N}-{slug}/\` is created with \`skills.md\`
|
|
130
|
+
3. This \`PLAYBOOK.md\` is regenerated to include the new agent
|
|
131
|
+
4. Execution resumes at the new agent only — completed agents are not rerun
|
|
39
132
|
|
|
40
|
-
|
|
133
|
+
When you receive the instruction to continue after an iteration:
|
|
134
|
+
> "Read PLAYBOOK.md and execute only the agents that haven't been completed yet."
|
|
41
135
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Human Validation Required
|
|
139
|
+
|
|
140
|
+
Stop and wait for confirmation in these situations:
|
|
141
|
+
- **3 consecutive failures** on the same success criterion
|
|
142
|
+
- **Missing external dependency**: API key, env variable, unavailable service
|
|
143
|
+
- **Conflict** between the detected stack and the user's stated constraints
|
|
144
|
+
- **Destructive operation**: overwriting files not listed in deliverables
|
|
145
|
+
- **End of Phase 0**: agent decomposition must be validated before execution
|
|
46
146
|
`
|
|
47
147
|
}
|
|
48
148
|
|
|
@@ -51,26 +151,26 @@ function agentBlock(agent: Agent): string {
|
|
|
51
151
|
const outputLines =
|
|
52
152
|
agent.outputs.length > 0
|
|
53
153
|
? agent.outputs.map((o) => `- ${o}`).join('\n')
|
|
54
|
-
: '- (
|
|
154
|
+
: '- (see skills.md for details)'
|
|
55
155
|
|
|
56
|
-
return `### ${agent.
|
|
156
|
+
return `### Agent ${agent.number} · ${agent.name}
|
|
57
157
|
|
|
58
|
-
**
|
|
158
|
+
**Scope**: ${agent.scope}
|
|
59
159
|
|
|
60
|
-
**Skills
|
|
160
|
+
**Skills**: \`${skillsPath}\`
|
|
61
161
|
|
|
62
|
-
**
|
|
162
|
+
**Deliverables**:
|
|
63
163
|
${outputLines}
|
|
64
164
|
|
|
65
|
-
**
|
|
165
|
+
**Success criterion**:
|
|
66
166
|
\`\`\`bash
|
|
67
167
|
${agent.criterion || 'npm run build && npm test'}
|
|
68
168
|
\`\`\`
|
|
69
169
|
|
|
70
|
-
**
|
|
71
|
-
1.
|
|
72
|
-
2.
|
|
73
|
-
3.
|
|
74
|
-
4.
|
|
170
|
+
**On failure**:
|
|
171
|
+
1. Read the full error output
|
|
172
|
+
2. Fix the root cause — not the symptoms
|
|
173
|
+
3. Rerun the success criterion (max 3 attempts)
|
|
174
|
+
4. After 3 failures → ask for human validation
|
|
75
175
|
`
|
|
76
|
-
}
|
|
176
|
+
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import type { StackInfo } from '../detectors/stackDetector.js'
|
|
2
|
-
import { parseBlueprint } from '../utils/blueprintParser.js'
|
|
3
|
-
import { toSlug } from '../utils/agentParser.js'
|
|
4
2
|
import * as react from '../templates/react.js'
|
|
5
3
|
import * as nextjs from '../templates/nextjs.js'
|
|
6
4
|
import * as tauri from '../templates/tauri.js'
|
|
@@ -9,8 +7,8 @@ import * as express from '../templates/express.js'
|
|
|
9
7
|
import * as node from '../templates/node.js'
|
|
10
8
|
import * as unknown from '../templates/unknown.js'
|
|
11
9
|
|
|
12
|
-
export function generateWorkflow(stack: StackInfo, blueprintContent?: string): string {
|
|
13
|
-
if (blueprintContent) return
|
|
10
|
+
export function generateWorkflow(stack: StackInfo, blueprintContent?: string, projectName?: string): string {
|
|
11
|
+
if (blueprintContent) return blueprintPlaceholder(projectName ?? stack.framework)
|
|
14
12
|
|
|
15
13
|
switch (stack.framework) {
|
|
16
14
|
case 'react': return react.workflow(stack)
|
|
@@ -23,40 +21,15 @@ export function generateWorkflow(stack: StackInfo, blueprintContent?: string): s
|
|
|
23
21
|
}
|
|
24
22
|
}
|
|
25
23
|
|
|
26
|
-
function
|
|
27
|
-
|
|
24
|
+
function blueprintPlaceholder(projectName: string): string {
|
|
25
|
+
return `# AGENT_WORKFLOW.md — ${projectName}
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const outputLines =
|
|
33
|
-
feature.items.length > 0
|
|
34
|
-
? feature.items.map((item) => ` - ${item}`).join('\n')
|
|
35
|
-
: ` - src/${slug}/`
|
|
36
|
-
return `### Agent ${n} · ${feature.name}
|
|
37
|
-
Périmètre : Implémenter la fonctionnalité ${feature.name.toLowerCase()}
|
|
38
|
-
Produit :
|
|
39
|
-
${outputLines}
|
|
40
|
-
Critère : npm test (tests ${feature.name.toLowerCase()} passent)`
|
|
41
|
-
})
|
|
27
|
+
> This file will be filled in by Claude Code during Phase 0.
|
|
28
|
+
> Claude Code will read PROJECT_BLUEPRINT.md, propose a decomposition,
|
|
29
|
+
> and replace this content after human validation.
|
|
42
30
|
|
|
43
|
-
|
|
44
|
-
agentBlocks.push(
|
|
45
|
-
`### Agent ${ciN} · Tests & CI
|
|
46
|
-
Périmètre : Couverture de tests complète et configuration du pipeline CI
|
|
47
|
-
Produit :
|
|
48
|
-
- tests/
|
|
49
|
-
- .github/workflows/
|
|
50
|
-
Critère : npm test passe, pipeline CI vert`,
|
|
51
|
-
)
|
|
31
|
+
---
|
|
52
32
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
## Stack détectée
|
|
56
|
-
Framework: ${stack.framework} | Language: ${stack.language}
|
|
57
|
-
|
|
58
|
-
## Agents
|
|
59
|
-
|
|
60
|
-
${agentBlocks.join('\n\n')}
|
|
33
|
+
*Waiting for Phase 0 decomposition...*
|
|
61
34
|
`
|
|
62
35
|
}
|
|
@@ -116,7 +116,7 @@ describe('addFeatureToProject', () => {
|
|
|
116
116
|
it('throws an error when AGENT_WORKFLOW.md is missing', async () => {
|
|
117
117
|
tempDir = await mkdtemp(join(tmpdir(), 'agentkit-add-test-'))
|
|
118
118
|
await expect(addFeatureToProject('Add feature', tempDir)).rejects.toThrow(
|
|
119
|
-
'AGENT_WORKFLOW.md
|
|
119
|
+
'AGENT_WORKFLOW.md not found in',
|
|
120
120
|
)
|
|
121
121
|
})
|
|
122
122
|
|
|
@@ -63,27 +63,30 @@ describe('generateClaudeMd with blueprint', () => {
|
|
|
63
63
|
expect(generateClaudeMd(REACT_STACK)).toBe(generateClaudeMd(REACT_STACK, undefined))
|
|
64
64
|
})
|
|
65
65
|
|
|
66
|
-
it('
|
|
66
|
+
it('adds the blueprint note when blueprint is provided', () => {
|
|
67
67
|
const result = generateClaudeMd(REACT_STACK, BLUEPRINT)
|
|
68
|
-
expect(result).toContain('
|
|
69
|
-
expect(result).toContain('
|
|
70
|
-
expect(result).toContain('Dashboard')
|
|
71
|
-
expect(result).toContain('API')
|
|
68
|
+
expect(result).toContain('PROJECT_BLUEPRINT.md is present')
|
|
69
|
+
expect(result).toContain('Phase 0')
|
|
72
70
|
})
|
|
73
71
|
|
|
74
|
-
it('
|
|
72
|
+
it('does NOT include a Features (Blueprint) section', () => {
|
|
75
73
|
const result = generateClaudeMd(REACT_STACK, BLUEPRINT)
|
|
76
|
-
expect(result).toContain('
|
|
77
|
-
expect(result).toContain('User statistics')
|
|
74
|
+
expect(result).not.toContain('## Features (Blueprint)')
|
|
78
75
|
})
|
|
79
76
|
|
|
80
|
-
it('
|
|
77
|
+
it('does NOT include blueprint sub-items as feature bullets', () => {
|
|
81
78
|
const result = generateClaudeMd(REACT_STACK, BLUEPRINT)
|
|
82
|
-
|
|
79
|
+
expect(result).not.toContain('JWT tokens')
|
|
80
|
+
expect(result).not.toContain('User statistics')
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('places blueprint note before Conventions', () => {
|
|
84
|
+
const result = generateClaudeMd(REACT_STACK, BLUEPRINT)
|
|
85
|
+
const noteIdx = result.indexOf('PROJECT_BLUEPRINT.md is present')
|
|
83
86
|
const convIdx = result.indexOf('## Conventions')
|
|
84
|
-
expect(
|
|
87
|
+
expect(noteIdx).toBeGreaterThan(-1)
|
|
85
88
|
expect(convIdx).toBeGreaterThan(-1)
|
|
86
|
-
expect(
|
|
89
|
+
expect(noteIdx).toBeLessThan(convIdx)
|
|
87
90
|
})
|
|
88
91
|
|
|
89
92
|
it('still contains stack-specific content', () => {
|
|
@@ -98,33 +101,35 @@ describe('generateWorkflow with blueprint', () => {
|
|
|
98
101
|
expect(generateWorkflow(REACT_STACK)).toBe(generateWorkflow(REACT_STACK, undefined))
|
|
99
102
|
})
|
|
100
103
|
|
|
101
|
-
it('
|
|
104
|
+
it('returns a Phase 0 placeholder instead of agent blocks', () => {
|
|
102
105
|
const result = generateWorkflow(REACT_STACK, BLUEPRINT)
|
|
103
|
-
expect(result).toContain('
|
|
104
|
-
expect(result).toContain('
|
|
105
|
-
expect(result).toContain('
|
|
106
|
-
expect(result).toContain('
|
|
106
|
+
expect(result).toContain('AGENT_WORKFLOW.md')
|
|
107
|
+
expect(result).toContain('Phase 0')
|
|
108
|
+
expect(result).toContain('PROJECT_BLUEPRINT.md')
|
|
109
|
+
expect(result).toContain('Waiting for Phase 0 decomposition')
|
|
107
110
|
})
|
|
108
111
|
|
|
109
|
-
it('
|
|
112
|
+
it('does NOT generate agent blocks from blueprint sections', () => {
|
|
110
113
|
const result = generateWorkflow(REACT_STACK, BLUEPRINT)
|
|
111
|
-
|
|
112
|
-
expect(
|
|
113
|
-
expect(
|
|
114
|
-
expect(
|
|
115
|
-
expect(agents[3].name).toBe('Tests & CI')
|
|
116
|
-
expect(agents[3].slug).toBe('tests-ci')
|
|
114
|
+
expect(result).not.toContain('Agent 1')
|
|
115
|
+
expect(result).not.toContain('Authentication')
|
|
116
|
+
expect(result).not.toContain('Dashboard')
|
|
117
|
+
expect(result).not.toContain('Tests & CI')
|
|
117
118
|
})
|
|
118
119
|
|
|
119
|
-
it('
|
|
120
|
+
it('does NOT include blueprint feature items as outputs', () => {
|
|
120
121
|
const result = generateWorkflow(REACT_STACK, BLUEPRINT)
|
|
121
|
-
expect(result).toContain('JWT tokens')
|
|
122
|
-
expect(result).toContain('User statistics')
|
|
122
|
+
expect(result).not.toContain('JWT tokens')
|
|
123
|
+
expect(result).not.toContain('User statistics')
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('uses projectName in heading when provided', () => {
|
|
127
|
+
const result = generateWorkflow(REACT_STACK, BLUEPRINT, 'my-app')
|
|
128
|
+
expect(result).toContain('AGENT_WORKFLOW.md — my-app')
|
|
123
129
|
})
|
|
124
130
|
|
|
125
|
-
it('
|
|
131
|
+
it('falls back to framework name when projectName is omitted', () => {
|
|
126
132
|
const result = generateWorkflow(REACT_STACK, BLUEPRINT)
|
|
127
|
-
expect(result).toContain('react')
|
|
128
|
-
expect(result).toContain('typescript')
|
|
133
|
+
expect(result).toContain('AGENT_WORKFLOW.md — react')
|
|
129
134
|
})
|
|
130
135
|
})
|
|
@@ -83,4 +83,52 @@ describe('generateClaudeMd', () => {
|
|
|
83
83
|
expect(typeof result).toBe('string')
|
|
84
84
|
expect(result.length).toBeGreaterThan(0)
|
|
85
85
|
})
|
|
86
|
+
|
|
87
|
+
describe('blueprint note', () => {
|
|
88
|
+
const blueprint = `# My Project\n\n## Goal\nBuild something\n\n## Features\n- Auth\n- Dashboard\n`
|
|
89
|
+
|
|
90
|
+
it('adds the blueprint note when blueprintContent is provided', () => {
|
|
91
|
+
const result = generateClaudeMd(makeStack('react'), blueprint)
|
|
92
|
+
expect(result).toContain('PROJECT_BLUEPRINT.md is present')
|
|
93
|
+
expect(result).toContain('Phase 0')
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('does NOT list blueprint sections as features', () => {
|
|
97
|
+
const result = generateClaudeMd(makeStack('react'), blueprint)
|
|
98
|
+
expect(result).not.toContain('Features (Blueprint)')
|
|
99
|
+
expect(result).not.toContain('**Goal**')
|
|
100
|
+
expect(result).not.toContain('**Features**')
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('still contains the stack-based template content', () => {
|
|
104
|
+
const result = generateClaudeMd(makeStack('react'), blueprint)
|
|
105
|
+
expect(result).toContain('React')
|
|
106
|
+
expect(result).toContain('## Stack')
|
|
107
|
+
expect(result).toContain('## Commands')
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it('adds blueprint note for unknown stack with blueprint', () => {
|
|
111
|
+
const result = generateClaudeMd(makeStack('unknown'), blueprint)
|
|
112
|
+
expect(result).toContain('PROJECT_BLUEPRINT.md is present')
|
|
113
|
+
expect(result).toContain('Phase 0')
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('returns base template unchanged when blueprintContent is absent', () => {
|
|
117
|
+
const withBlueprint = generateClaudeMd(makeStack('react'), blueprint)
|
|
118
|
+
const withoutBlueprint = generateClaudeMd(makeStack('react'))
|
|
119
|
+
expect(withBlueprint).not.toBe(withoutBlueprint)
|
|
120
|
+
expect(withoutBlueprint).not.toContain('PROJECT_BLUEPRINT.md is present')
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('adds blueprint note for every framework', () => {
|
|
124
|
+
const frameworks: StackInfo['framework'][] = [
|
|
125
|
+
'react', 'nextjs', 'tauri', 'fastapi', 'express', 'node', 'unknown',
|
|
126
|
+
]
|
|
127
|
+
for (const framework of frameworks) {
|
|
128
|
+
const result = generateClaudeMd(makeStack(framework), blueprint)
|
|
129
|
+
expect(result).toContain('PROJECT_BLUEPRINT.md is present')
|
|
130
|
+
expect(result).not.toContain('Features (Blueprint)')
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
})
|
|
86
134
|
})
|