@patricksardinha/agentkit-cli 0.1.0 → 0.3.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 +70 -45
- package/LICENSE +21 -0
- package/PLAYBOOK.md +192 -0
- package/PROJECT_BLUEPRINT.md +52 -0
- package/README.md +435 -327
- 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 +149 -49
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +149 -49
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/add.ts +22 -15
- package/src/commands/init.ts +1 -1
- package/src/generators/playbookGenerator.ts +136 -36
- package/tests/commands/add.test.ts +1 -1
- package/tests/generators/playbookGenerator.test.ts +140 -48
|
@@ -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
|
+
}
|
|
@@ -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
|
|
|
@@ -10,7 +10,7 @@ const sampleAgents: Agent[] = [
|
|
|
10
10
|
name: 'Infra & Setup',
|
|
11
11
|
fullName: 'Agent 1 · Infra & Setup',
|
|
12
12
|
slug: 'infra-setup',
|
|
13
|
-
scope: 'scaffolding
|
|
13
|
+
scope: 'project scaffolding',
|
|
14
14
|
outputs: ['package.json', 'tsconfig.json'],
|
|
15
15
|
criterion: 'npm run build',
|
|
16
16
|
},
|
|
@@ -19,76 +19,166 @@ const sampleAgents: Agent[] = [
|
|
|
19
19
|
name: 'Components',
|
|
20
20
|
fullName: 'Agent 2 · Components',
|
|
21
21
|
slug: 'components',
|
|
22
|
-
scope: '
|
|
22
|
+
scope: 'reusable UI components',
|
|
23
23
|
outputs: ['src/components/'],
|
|
24
24
|
criterion: 'npm test',
|
|
25
25
|
},
|
|
26
26
|
]
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
// ─── Common behaviour (both modes) ────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
describe('generatePlaybook (common)', () => {
|
|
31
|
+
for (const hasBlueprint of [true, false]) {
|
|
32
|
+
const label = hasBlueprint ? 'hasBlueprint: true' : 'hasBlueprint: false'
|
|
33
|
+
|
|
34
|
+
it(`[${label}] returns a non-empty string`, () => {
|
|
35
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint })
|
|
36
|
+
expect(typeof result).toBe('string')
|
|
37
|
+
expect(result.length).toBeGreaterThan(0)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it(`[${label}] contains the project name`, () => {
|
|
41
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint })
|
|
42
|
+
expect(result).toContain('my-app')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it(`[${label}] contains the one-instruction block`, () => {
|
|
46
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint })
|
|
47
|
+
expect(result).toContain('Read PLAYBOOK.md and execute the procedure')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it(`[${label}] contains global execution rules`, () => {
|
|
51
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint })
|
|
52
|
+
expect(result).toContain('Global Execution Rules')
|
|
53
|
+
expect(result).toContain('max 3 attempts')
|
|
54
|
+
expect(result).toContain('human validation')
|
|
55
|
+
expect(result).toContain('Never move to the next agent')
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it(`[${label}] always contains Phase 0`, () => {
|
|
59
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint })
|
|
60
|
+
expect(result).toContain('Phase 0')
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it(`[${label}] always contains Phase 1`, () => {
|
|
64
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint })
|
|
65
|
+
expect(result).toContain('Phase 1')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it(`[${label}] Phase 0 comes before Phase 1`, () => {
|
|
69
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint })
|
|
70
|
+
expect(result.indexOf('Phase 0')).toBeLessThan(result.indexOf('Phase 1'))
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it(`[${label}] contains a block for each agent`, () => {
|
|
74
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint })
|
|
75
|
+
for (const agent of sampleAgents) {
|
|
76
|
+
expect(result).toContain(agent.fullName)
|
|
77
|
+
expect(result).toContain(agent.scope)
|
|
78
|
+
expect(result).toContain(`agents/agent-${agent.number}-${agent.slug}/skills.md`)
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it(`[${label}] each agent block contains outputs and criterion`, () => {
|
|
83
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint })
|
|
84
|
+
expect(result).toContain('package.json')
|
|
85
|
+
expect(result).toContain('npm run build')
|
|
86
|
+
expect(result).toContain('src/components/')
|
|
87
|
+
expect(result).toContain('npm test')
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it(`[${label}] contains the future iterations section`, () => {
|
|
91
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint })
|
|
92
|
+
expect(result).toContain('Future Iterations')
|
|
93
|
+
expect(result).toContain('agentkit add --feature')
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it(`[${label}] contains the human validation section`, () => {
|
|
97
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint })
|
|
98
|
+
expect(result).toContain('Human Validation Required')
|
|
99
|
+
expect(result).toContain('3 consecutive failures')
|
|
100
|
+
expect(result).toContain('Missing external dependency')
|
|
101
|
+
expect(result).toContain('End of Phase 0')
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it(`[${label}] handles an empty agents list gracefully`, () => {
|
|
105
|
+
const result = generatePlaybook({ agents: [], projectName: 'empty-project', hasBlueprint })
|
|
106
|
+
expect(typeof result).toBe('string')
|
|
107
|
+
expect(result).toContain('empty-project')
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
// ─── Phase 0 with blueprint (Decomposition mode) ──────────────────────────────
|
|
113
|
+
|
|
114
|
+
describe('generatePlaybook Phase 0 — Decomposition (hasBlueprint: true)', () => {
|
|
115
|
+
it('contains the decomposition title', () => {
|
|
116
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint: true })
|
|
117
|
+
expect(result).toContain('Agent Decomposition')
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('references PROJECT_BLUEPRINT.md', () => {
|
|
121
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint: true })
|
|
122
|
+
expect(result).toContain('PROJECT_BLUEPRINT.md')
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it('contains decomposition rules', () => {
|
|
126
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint: true })
|
|
127
|
+
expect(result).toContain('Maximum 6 agents')
|
|
128
|
+
expect(result).toContain('AGENT_WORKFLOW.md')
|
|
33
129
|
})
|
|
34
130
|
|
|
35
|
-
it('contains the
|
|
36
|
-
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app' })
|
|
37
|
-
expect(result).toContain('
|
|
131
|
+
it('contains the validation gate', () => {
|
|
132
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint: true })
|
|
133
|
+
expect(result).toContain('Should I proceed')
|
|
38
134
|
})
|
|
39
135
|
|
|
40
|
-
it('
|
|
41
|
-
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app' })
|
|
42
|
-
expect(result).toContain(
|
|
43
|
-
expect(result).toContain(
|
|
136
|
+
it('does NOT contain Project Discovery language', () => {
|
|
137
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint: true })
|
|
138
|
+
expect(result).not.toContain('Project Discovery')
|
|
139
|
+
expect(result).not.toContain('Ask the user these questions')
|
|
44
140
|
})
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
// ─── Phase 0 without blueprint (Discovery mode) ───────────────────────────────
|
|
45
144
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
expect(result).toContain('
|
|
50
|
-
expect(result).toContain('validation humaine')
|
|
51
|
-
expect(result).toContain('Ne jamais passer')
|
|
145
|
+
describe('generatePlaybook Phase 0 — Discovery (hasBlueprint: false)', () => {
|
|
146
|
+
it('contains the discovery title', () => {
|
|
147
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint: false })
|
|
148
|
+
expect(result).toContain('Project Discovery')
|
|
52
149
|
})
|
|
53
150
|
|
|
54
|
-
it('
|
|
55
|
-
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app' })
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
expect(result).toContain(`agents/agent-${agent.number}-${agent.slug}/skills.md`)
|
|
60
|
-
}
|
|
151
|
+
it('instructs Claude Code to ask the user questions', () => {
|
|
152
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint: false })
|
|
153
|
+
expect(result).toContain('Ask the user these questions')
|
|
154
|
+
expect(result).toContain('What is this project')
|
|
155
|
+
expect(result).toContain('What are the main features')
|
|
61
156
|
})
|
|
62
157
|
|
|
63
|
-
it('
|
|
64
|
-
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app' })
|
|
65
|
-
expect(result).toContain('
|
|
66
|
-
expect(result).toContain('
|
|
67
|
-
expect(result).toContain('src/components/')
|
|
68
|
-
expect(result).toContain('npm test')
|
|
158
|
+
it('still contains decomposition rules', () => {
|
|
159
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint: false })
|
|
160
|
+
expect(result).toContain('Maximum 6 agents')
|
|
161
|
+
expect(result).toContain('AGENT_WORKFLOW.md')
|
|
69
162
|
})
|
|
70
163
|
|
|
71
|
-
it('contains the
|
|
72
|
-
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app' })
|
|
73
|
-
expect(result).toContain('
|
|
74
|
-
expect(result).toContain('agentkit add --feature')
|
|
164
|
+
it('still contains the validation gate', () => {
|
|
165
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint: false })
|
|
166
|
+
expect(result).toContain('Should I proceed')
|
|
75
167
|
})
|
|
76
168
|
|
|
77
|
-
it('
|
|
78
|
-
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app' })
|
|
79
|
-
expect(result).toContain('
|
|
80
|
-
expect(result).toContain('3 échecs consécutifs')
|
|
81
|
-
expect(result).toContain('Dépendance externe manquante')
|
|
82
|
-
expect(result).toContain('Conflit')
|
|
169
|
+
it('does NOT reference PROJECT_BLUEPRINT.md as a file to read', () => {
|
|
170
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint: false })
|
|
171
|
+
expect(result).not.toContain('A `PROJECT_BLUEPRINT.md` was provided')
|
|
83
172
|
})
|
|
84
173
|
|
|
85
|
-
it('
|
|
86
|
-
const result = generatePlaybook({ agents:
|
|
87
|
-
expect(
|
|
88
|
-
expect(result).toContain('empty-project')
|
|
174
|
+
it('does NOT contain Agent Decomposition title', () => {
|
|
175
|
+
const result = generatePlaybook({ agents: sampleAgents, projectName: 'my-app', hasBlueprint: false })
|
|
176
|
+
expect(result).not.toContain('Agent Decomposition (run this first)')
|
|
89
177
|
})
|
|
90
178
|
})
|
|
91
179
|
|
|
180
|
+
// ─── toSlug ───────────────────────────────────────────────────────────────────
|
|
181
|
+
|
|
92
182
|
describe('toSlug', () => {
|
|
93
183
|
it('converts name to lowercase hyphenated slug', () => {
|
|
94
184
|
expect(toSlug('Infra & Setup')).toBe('infra-setup')
|
|
@@ -104,6 +194,8 @@ describe('toSlug', () => {
|
|
|
104
194
|
})
|
|
105
195
|
})
|
|
106
196
|
|
|
197
|
+
// ─── extractAgentsFromWorkflow ────────────────────────────────────────────────
|
|
198
|
+
|
|
107
199
|
describe('extractAgentsFromWorkflow', () => {
|
|
108
200
|
it('extracts agents from a workflow string matching template format', () => {
|
|
109
201
|
const workflow = `# Agent Workflow — React Project
|
|
@@ -149,4 +241,4 @@ Critère : npm run build
|
|
|
149
241
|
it('returns empty array for content with no agent blocks', () => {
|
|
150
242
|
expect(extractAgentsFromWorkflow('# Just a title\nNo agents here.')).toEqual([])
|
|
151
243
|
})
|
|
152
|
-
})
|
|
244
|
+
})
|