@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
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Skills — Agent 3 · Generators & Templates
|
|
2
|
+
|
|
3
|
+
> This file is read by Agent 3 before starting its work.
|
|
4
|
+
|
|
5
|
+
## Template function signature
|
|
6
|
+
|
|
7
|
+
Every template file must export exactly these two functions:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
export function claudeMd(stack: StackInfo): string
|
|
11
|
+
export function workflow(stack: StackInfo): string
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The `workflow()` function returns a markdown string. The workflowGenerator
|
|
15
|
+
is responsible for parsing that string into an `Agent[]` array.
|
|
16
|
+
|
|
17
|
+
## Agent type
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
export interface Agent {
|
|
21
|
+
number: number // 1, 2, 3…
|
|
22
|
+
slug: string // 'infra', 'auth', 'features'…
|
|
23
|
+
name: string // 'Infra & Setup', 'Auth & Supabase'…
|
|
24
|
+
scope: string // one-line description
|
|
25
|
+
outputs: string[]
|
|
26
|
+
criterion: string // the runnable bash command
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Blueprint parsing
|
|
31
|
+
|
|
32
|
+
When `blueprintContent` is provided, parse `## Feature` sections
|
|
33
|
+
using simple line splitting — no external markdown parser needed.
|
|
34
|
+
Extract bullet points under each `##` heading and use them to name
|
|
35
|
+
and scope the generated agents.
|
|
36
|
+
|
|
37
|
+
## playbookGenerator rules
|
|
38
|
+
|
|
39
|
+
The PLAYBOOK.md must always start with the one-instruction block:
|
|
40
|
+
> "Read PLAYBOOK.md and execute the procedure."
|
|
41
|
+
|
|
42
|
+
The retry limit is always 3. The escalation section is always present.
|
|
43
|
+
Do not make these values configurable — consistency is the point.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Skills — Agent 4 · Commands CLI
|
|
2
|
+
|
|
3
|
+
> This file is read by Agent 4 before starting its work.
|
|
4
|
+
|
|
5
|
+
## Commander.js setup
|
|
6
|
+
|
|
7
|
+
The CLI binary is `agentkit`. The three subcommands are:
|
|
8
|
+
- `init [options]` with `--blueprint <path>`
|
|
9
|
+
- `add [options]` with `--feature <description>`
|
|
10
|
+
- `status`
|
|
11
|
+
|
|
12
|
+
## init command behavior
|
|
13
|
+
|
|
14
|
+
1. Run gitDetector — warn but don't block if not a git repo
|
|
15
|
+
2. Run stackDetector on process.cwd()
|
|
16
|
+
3. If --blueprint provided: read file, warn if path doesn't exist
|
|
17
|
+
4. Call claudeMdGenerator(stack, blueprintContent?)
|
|
18
|
+
5. Call workflowGenerator(stack, blueprintContent?) → { markdown, agents }
|
|
19
|
+
6. Call playbookGenerator(agents, projectName)
|
|
20
|
+
7. Call skillsGenerator(agents)
|
|
21
|
+
8. Write all files — never overwrite existing files without --force flag
|
|
22
|
+
|
|
23
|
+
## add command behavior
|
|
24
|
+
|
|
25
|
+
1. Check AGENT_WORKFLOW.md exists — error if not (run init first)
|
|
26
|
+
2. Parse existing agents to find the last number
|
|
27
|
+
3. Generate new agent block from --feature description
|
|
28
|
+
4. Append to AGENT_WORKFLOW.md
|
|
29
|
+
5. Create agents/agent-{N+1}-{slug}/skills.md
|
|
30
|
+
6. Regenerate PLAYBOOK.md entirely (not append — full regeneration)
|
|
31
|
+
|
|
32
|
+
## Output rules
|
|
33
|
+
|
|
34
|
+
- Use logger.ts for all output — never console.log directly
|
|
35
|
+
- Use ora spinner during file generation
|
|
36
|
+
- Use chalk.green for success, chalk.yellow for warnings, chalk.red for errors
|
|
37
|
+
- Always print a summary of generated files at the end of init
|
package/dist/cli.cjs
CHANGED
|
@@ -114,25 +114,6 @@ async function isGitRepo(projectPath) {
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
// src/utils/blueprintParser.ts
|
|
118
|
-
function parseBlueprint(content) {
|
|
119
|
-
const features = [];
|
|
120
|
-
const sectionRegex = /^## (.+)$/gm;
|
|
121
|
-
const sections = [];
|
|
122
|
-
let m;
|
|
123
|
-
while ((m = sectionRegex.exec(content)) !== null) {
|
|
124
|
-
sections.push({ name: m[1].trim(), start: m.index });
|
|
125
|
-
}
|
|
126
|
-
for (let i = 0; i < sections.length; i++) {
|
|
127
|
-
const section = sections[i];
|
|
128
|
-
const end = i + 1 < sections.length ? sections[i + 1].start : content.length;
|
|
129
|
-
const body = content.slice(section.start, end);
|
|
130
|
-
const items = [...body.matchAll(/^[-*]\s+(.+)$/gm)].map((r) => r[1].trim());
|
|
131
|
-
features.push({ name: section.name, items });
|
|
132
|
-
}
|
|
133
|
-
return features;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
117
|
// src/templates/react.ts
|
|
137
118
|
function claudeMd(stack) {
|
|
138
119
|
const lang = stack.hasTypeScript ? "TypeScript" : "JavaScript";
|
|
@@ -567,73 +548,17 @@ function generateClaudeMd(stack, blueprintContent) {
|
|
|
567
548
|
base = claudeMd7(stack);
|
|
568
549
|
}
|
|
569
550
|
if (!blueprintContent) return base;
|
|
570
|
-
const
|
|
571
|
-
if (features.length === 0) return base;
|
|
572
|
-
const featureLines = features.map((f, i) => {
|
|
573
|
-
const sub = f.items.length > 0 ? "\n" + f.items.map((it) => ` - ${it}`).join("\n") : "";
|
|
574
|
-
return `${i + 1}. **${f.name}**${sub}`;
|
|
575
|
-
}).join("\n");
|
|
576
|
-
const featureSection = `
|
|
577
|
-
## Features (Blueprint)
|
|
578
|
-
|
|
579
|
-
${featureLines}
|
|
580
|
-
`;
|
|
551
|
+
const blueprintNote = "\n> A PROJECT_BLUEPRINT.md is present \u2014 Claude Code will read it during Phase 0.\n";
|
|
581
552
|
const conventionsIdx = base.indexOf("\n## Conventions");
|
|
582
553
|
if (conventionsIdx !== -1) {
|
|
583
|
-
return base.slice(0, conventionsIdx) +
|
|
584
|
-
}
|
|
585
|
-
return base + featureSection;
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// src/utils/agentParser.ts
|
|
589
|
-
function toSlug(name) {
|
|
590
|
-
return name.toLowerCase().replace(/[·•&]/g, " ").replace(/[^\w\s-]/g, "").trim().replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
591
|
-
}
|
|
592
|
-
function getFieldValue(lines, pattern) {
|
|
593
|
-
for (const line of lines) {
|
|
594
|
-
const m = line.match(pattern);
|
|
595
|
-
if (m) return (m[1] ?? "").trim();
|
|
596
|
-
}
|
|
597
|
-
return "";
|
|
598
|
-
}
|
|
599
|
-
function extractAgentsFromWorkflow(content) {
|
|
600
|
-
const agents = [];
|
|
601
|
-
const blocks = content.split(/(?=^### Agent \d)/m).filter((b) => /^### Agent \d/.test(b.trimStart()));
|
|
602
|
-
for (const block of blocks) {
|
|
603
|
-
const lines = block.split("\n");
|
|
604
|
-
const headerMatch = lines[0].match(/^### Agent (\d+)\s*[·•]\s*(.+)$/);
|
|
605
|
-
if (!headerMatch) continue;
|
|
606
|
-
const number = parseInt(headerMatch[1], 10);
|
|
607
|
-
const name = headerMatch[2].trim();
|
|
608
|
-
const fullName = `Agent ${number} \xB7 ${name}`;
|
|
609
|
-
const slug = toSlug(name);
|
|
610
|
-
const scope = getFieldValue(lines, /Périmètre\s*:\s*(.+)/);
|
|
611
|
-
const criterion = getFieldValue(lines, /Critère[s]?\s*:\s*(.+)/);
|
|
612
|
-
const outputs = [];
|
|
613
|
-
const produitIdx = lines.findIndex((l) => /Produit\s*:/.test(l));
|
|
614
|
-
if (produitIdx !== -1) {
|
|
615
|
-
const inlineVal = (lines[produitIdx].match(/Produit\s*:\s*(.+)/)?.[1] ?? "").trim();
|
|
616
|
-
if (inlineVal) {
|
|
617
|
-
outputs.push(inlineVal);
|
|
618
|
-
} else {
|
|
619
|
-
for (let i = produitIdx + 1; i < lines.length; i++) {
|
|
620
|
-
const line = lines[i];
|
|
621
|
-
if (/^\s+[-]/.test(line)) {
|
|
622
|
-
outputs.push(line.trim().replace(/^-\s*/, ""));
|
|
623
|
-
} else if (line.trim() !== "" && !/^\s/.test(line)) {
|
|
624
|
-
break;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
agents.push({ number, name, fullName, slug, scope, outputs, criterion });
|
|
554
|
+
return base.slice(0, conventionsIdx) + blueprintNote + base.slice(conventionsIdx);
|
|
630
555
|
}
|
|
631
|
-
return
|
|
556
|
+
return base + blueprintNote;
|
|
632
557
|
}
|
|
633
558
|
|
|
634
559
|
// src/generators/workflowGenerator.ts
|
|
635
|
-
function generateWorkflow(stack, blueprintContent) {
|
|
636
|
-
if (blueprintContent) return
|
|
560
|
+
function generateWorkflow(stack, blueprintContent, projectName) {
|
|
561
|
+
if (blueprintContent) return blueprintPlaceholder(projectName ?? stack.framework);
|
|
637
562
|
switch (stack.framework) {
|
|
638
563
|
case "react":
|
|
639
564
|
return workflow(stack);
|
|
@@ -651,100 +576,177 @@ function generateWorkflow(stack, blueprintContent) {
|
|
|
651
576
|
return workflow7(stack);
|
|
652
577
|
}
|
|
653
578
|
}
|
|
654
|
-
function
|
|
655
|
-
|
|
656
|
-
const agentBlocks = features.map((feature, i) => {
|
|
657
|
-
const n = i + 1;
|
|
658
|
-
const slug = toSlug(feature.name);
|
|
659
|
-
const outputLines = feature.items.length > 0 ? feature.items.map((item) => ` - ${item}`).join("\n") : ` - src/${slug}/`;
|
|
660
|
-
return `### Agent ${n} \xB7 ${feature.name}
|
|
661
|
-
P\xE9rim\xE8tre : Impl\xE9menter la fonctionnalit\xE9 ${feature.name.toLowerCase()}
|
|
662
|
-
Produit :
|
|
663
|
-
${outputLines}
|
|
664
|
-
Crit\xE8re : npm test (tests ${feature.name.toLowerCase()} passent)`;
|
|
665
|
-
});
|
|
666
|
-
const ciN = features.length + 1;
|
|
667
|
-
agentBlocks.push(
|
|
668
|
-
`### Agent ${ciN} \xB7 Tests & CI
|
|
669
|
-
P\xE9rim\xE8tre : Couverture de tests compl\xE8te et configuration du pipeline CI
|
|
670
|
-
Produit :
|
|
671
|
-
- tests/
|
|
672
|
-
- .github/workflows/
|
|
673
|
-
Crit\xE8re : npm test passe, pipeline CI vert`
|
|
674
|
-
);
|
|
675
|
-
return `# Agent Workflow \u2014 ${stack.framework} (Blueprint)
|
|
579
|
+
function blueprintPlaceholder(projectName) {
|
|
580
|
+
return `# AGENT_WORKFLOW.md \u2014 ${projectName}
|
|
676
581
|
|
|
677
|
-
|
|
678
|
-
|
|
582
|
+
> This file will be filled in by Claude Code during Phase 0.
|
|
583
|
+
> Claude Code will read PROJECT_BLUEPRINT.md, propose a decomposition,
|
|
584
|
+
> and replace this content after human validation.
|
|
679
585
|
|
|
680
|
-
|
|
586
|
+
---
|
|
681
587
|
|
|
682
|
-
|
|
588
|
+
*Waiting for Phase 0 decomposition...*
|
|
683
589
|
`;
|
|
684
590
|
}
|
|
685
591
|
|
|
686
592
|
// src/generators/playbookGenerator.ts
|
|
687
|
-
function generatePlaybook({ agents, projectName }) {
|
|
593
|
+
function generatePlaybook({ agents, projectName, hasBlueprint }) {
|
|
688
594
|
const agentBlocks = agents.map((a) => agentBlock(a)).join("\n---\n\n");
|
|
595
|
+
const phase0 = hasBlueprint ? `## Phase 0 \u2014 Agent Decomposition (run this first)
|
|
596
|
+
|
|
597
|
+
> A \`PROJECT_BLUEPRINT.md\` was provided.
|
|
598
|
+
> Claude Code reads it and decomposes the project into specialized agents
|
|
599
|
+
> before writing a single line of code.
|
|
600
|
+
|
|
601
|
+
**Read these files in order:**
|
|
602
|
+
1. \`CLAUDE.md\`
|
|
603
|
+
2. \`PROJECT_BLUEPRINT.md\`
|
|
604
|
+
|
|
605
|
+
**Then decompose the project into agents** following these rules:
|
|
606
|
+
|
|
607
|
+
- One agent = one coherent technical layer (never mix two layers)
|
|
608
|
+
- Each agent must have a runnable success criterion (\`npm test\`, \`cargo build\`\u2026)
|
|
609
|
+
- Agents must be ordered by dependency (no feature without infra first)
|
|
610
|
+
- Maximum 6 agents \u2014 if you have more, group related ones
|
|
611
|
+
- Always respect this order:
|
|
612
|
+
1. Infra & Configuration
|
|
613
|
+
2. Data layer (DB schema, models, services)
|
|
614
|
+
3. External integrations (auth, APIs, local services like Ollama)
|
|
615
|
+
4. UI & pages
|
|
616
|
+
5. Advanced features (RAG, export, realtime\u2026)
|
|
617
|
+
6. Build & release (CI/CD, packaging, installers)
|
|
618
|
+
|
|
619
|
+
**Write the result directly into \`AGENT_WORKFLOW.md\`** \u2014 replace its current
|
|
620
|
+
content with your decomposition.
|
|
621
|
+
|
|
622
|
+
**Then ask for human validation:**
|
|
623
|
+
> "I have decomposed the project into N agents: [list them].
|
|
624
|
+
> Should I proceed with execution?"
|
|
625
|
+
|
|
626
|
+
Wait for confirmation before moving to Phase 1.
|
|
627
|
+
|
|
628
|
+
---
|
|
629
|
+
|
|
630
|
+
` : `## Phase 0 \u2014 Project Discovery (run this first)
|
|
631
|
+
|
|
632
|
+
> No \`PROJECT_BLUEPRINT.md\` was provided.
|
|
633
|
+
> Before writing any code, Claude Code asks the user what they want to build,
|
|
634
|
+
> then decomposes the project into agents \u2014 exactly as if a blueprint had been provided.
|
|
635
|
+
|
|
636
|
+
**Ask the user these questions and wait for their answers:**
|
|
637
|
+
|
|
638
|
+
1. What is this project? (one sentence describing the goal)
|
|
639
|
+
2. What are the main features you want to build? (list them)
|
|
640
|
+
3. Are there any tech constraints or architecture preferences?
|
|
641
|
+
(e.g. offline-only, specific DB, no auth, specific framework)
|
|
642
|
+
|
|
643
|
+
**Once you have the answers, decompose the project into agents**
|
|
644
|
+
following these rules:
|
|
645
|
+
|
|
646
|
+
- One agent = one coherent technical layer (never mix two layers)
|
|
647
|
+
- Each agent must have a runnable success criterion (\`npm test\`, \`cargo build\`\u2026)
|
|
648
|
+
- Agents must be ordered by dependency (no feature without infra first)
|
|
649
|
+
- Maximum 6 agents \u2014 if you have more, group related ones
|
|
650
|
+
- Always respect this order:
|
|
651
|
+
1. Infra & Configuration
|
|
652
|
+
2. Data layer (DB schema, models, services)
|
|
653
|
+
3. External integrations (auth, APIs, local services like Ollama)
|
|
654
|
+
4. UI & pages
|
|
655
|
+
5. Advanced features (RAG, export, realtime\u2026)
|
|
656
|
+
6. Build & release (CI/CD, packaging, installers)
|
|
657
|
+
|
|
658
|
+
**Write the result directly into \`AGENT_WORKFLOW.md\`** \u2014 replace its current
|
|
659
|
+
content with your decomposition.
|
|
660
|
+
|
|
661
|
+
**Then ask for human validation:**
|
|
662
|
+
> "I have decomposed the project into N agents: [list them].
|
|
663
|
+
> Should I proceed with execution?"
|
|
664
|
+
|
|
665
|
+
Wait for confirmation before moving to Phase 1.
|
|
666
|
+
|
|
667
|
+
---
|
|
668
|
+
|
|
669
|
+
`;
|
|
689
670
|
return `# PLAYBOOK.md \u2014 ${projectName}
|
|
690
671
|
|
|
691
|
-
>
|
|
672
|
+
> **One instruction to give Claude Code:**
|
|
673
|
+
> "Read PLAYBOOK.md and execute the procedure."
|
|
674
|
+
>
|
|
675
|
+
> Claude Code handles the rest autonomously \u2014 project discovery or blueprint reading,
|
|
676
|
+
> agent decomposition, execution, success validation, retries, and human escalation.
|
|
677
|
+
> No API key required. No additional cost beyond your LLM subscription.
|
|
692
678
|
|
|
693
|
-
|
|
679
|
+
---
|
|
694
680
|
|
|
695
|
-
|
|
696
|
-
1. Lire \`CLAUDE.md\`
|
|
697
|
-
2. Lire \`agents/agent-{N}-{slug}/skills.md\` (le fichier de l'agent courant)
|
|
681
|
+
## Global Execution Rules
|
|
698
682
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
- Apr\xE8s 3 \xE9checs cons\xE9cutifs \u2192 pause et demander validation humaine
|
|
704
|
-
- **Ne jamais passer \xE0 l'agent suivant sans crit\xE8re valid\xE9**
|
|
683
|
+
Before each agent:
|
|
684
|
+
1. Read \`CLAUDE.md\`
|
|
685
|
+
2. Read \`agents/agent-{N}-{slug}/skills.md\` (current agent's file)
|
|
686
|
+
3. Read the agent's section in \`AGENT_WORKFLOW.md\`
|
|
705
687
|
|
|
706
|
-
|
|
688
|
+
After each agent:
|
|
689
|
+
- Run the success criterion command
|
|
690
|
+
- \u2705 Passes \u2192 announce "\u2705 Agent N complete" and move to the next
|
|
691
|
+
- \u274C Fails \u2192 analyze the root cause, fix, rerun (max 3 attempts)
|
|
692
|
+
- After 3 consecutive failures \u2192 stop and ask for human validation
|
|
693
|
+
|
|
694
|
+
**Never move to the next agent without a passing success criterion.**
|
|
695
|
+
**Stay strictly within your current agent's defined scope.**
|
|
696
|
+
|
|
697
|
+
---
|
|
698
|
+
|
|
699
|
+
${phase0}## Phase 1 \u2014 Execution
|
|
707
700
|
|
|
708
701
|
${agentBlocks}
|
|
709
702
|
|
|
710
|
-
|
|
703
|
+
---
|
|
704
|
+
|
|
705
|
+
## Future Iterations
|
|
706
|
+
|
|
707
|
+
When a new agent is added via \`agentkit add --feature <description>\`:
|
|
708
|
+
1. A new agent block is appended to \`AGENT_WORKFLOW.md\`
|
|
709
|
+
2. The folder \`agents/agent-{N}-{slug}/\` is created with \`skills.md\`
|
|
710
|
+
3. This \`PLAYBOOK.md\` is regenerated to include the new agent
|
|
711
|
+
4. Execution resumes at the new agent only \u2014 completed agents are not rerun
|
|
711
712
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
2. Le dossier \`agents/agent-{N}-{slug}/\` est cr\xE9\xE9 avec \`skills.md\` et \`context.md\`
|
|
715
|
-
3. Ce \`PLAYBOOK.md\` est r\xE9g\xE9n\xE9r\xE9 automatiquement pour inclure le nouvel agent
|
|
716
|
-
4. L'ex\xE9cution reprend \xE0 ce nouvel agent uniquement \u2014 les agents pr\xE9c\xE9dents ne sont pas r\xE9ex\xE9cut\xE9s
|
|
713
|
+
When you receive the instruction to continue after an iteration:
|
|
714
|
+
> "Read PLAYBOOK.md and execute only the agents that haven't been completed yet."
|
|
717
715
|
|
|
718
|
-
|
|
716
|
+
---
|
|
719
717
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
- **
|
|
718
|
+
## Human Validation Required
|
|
719
|
+
|
|
720
|
+
Stop and wait for confirmation in these situations:
|
|
721
|
+
- **3 consecutive failures** on the same success criterion
|
|
722
|
+
- **Missing external dependency**: API key, env variable, unavailable service
|
|
723
|
+
- **Conflict** between the detected stack and the user's stated constraints
|
|
724
|
+
- **Destructive operation**: overwriting files not listed in deliverables
|
|
725
|
+
- **End of Phase 0**: agent decomposition must be validated before execution
|
|
724
726
|
`;
|
|
725
727
|
}
|
|
726
728
|
function agentBlock(agent) {
|
|
727
729
|
const skillsPath = `agents/agent-${agent.number}-${agent.slug}/skills.md`;
|
|
728
|
-
const outputLines = agent.outputs.length > 0 ? agent.outputs.map((o) => `- ${o}`).join("\n") : "- (
|
|
729
|
-
return `### ${agent.
|
|
730
|
+
const outputLines = agent.outputs.length > 0 ? agent.outputs.map((o) => `- ${o}`).join("\n") : "- (see skills.md for details)";
|
|
731
|
+
return `### Agent ${agent.number} \xB7 ${agent.name}
|
|
730
732
|
|
|
731
|
-
**
|
|
733
|
+
**Scope**: ${agent.scope}
|
|
732
734
|
|
|
733
|
-
**Skills
|
|
735
|
+
**Skills**: \`${skillsPath}\`
|
|
734
736
|
|
|
735
|
-
**
|
|
737
|
+
**Deliverables**:
|
|
736
738
|
${outputLines}
|
|
737
739
|
|
|
738
|
-
**
|
|
740
|
+
**Success criterion**:
|
|
739
741
|
\`\`\`bash
|
|
740
742
|
${agent.criterion || "npm run build && npm test"}
|
|
741
743
|
\`\`\`
|
|
742
744
|
|
|
743
|
-
**
|
|
744
|
-
1.
|
|
745
|
-
2.
|
|
746
|
-
3.
|
|
747
|
-
4.
|
|
745
|
+
**On failure**:
|
|
746
|
+
1. Read the full error output
|
|
747
|
+
2. Fix the root cause \u2014 not the symptoms
|
|
748
|
+
3. Rerun the success criterion (max 3 attempts)
|
|
749
|
+
4. After 3 failures \u2192 ask for human validation
|
|
748
750
|
`;
|
|
749
751
|
}
|
|
750
752
|
|
|
@@ -798,6 +800,52 @@ ${outputLines}
|
|
|
798
800
|
`;
|
|
799
801
|
}
|
|
800
802
|
|
|
803
|
+
// src/utils/agentParser.ts
|
|
804
|
+
function toSlug(name) {
|
|
805
|
+
return name.toLowerCase().replace(/[·•&]/g, " ").replace(/[^\w\s-]/g, "").trim().replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
806
|
+
}
|
|
807
|
+
function getFieldValue(lines, pattern) {
|
|
808
|
+
for (const line of lines) {
|
|
809
|
+
const m = line.match(pattern);
|
|
810
|
+
if (m) return (m[1] ?? "").trim();
|
|
811
|
+
}
|
|
812
|
+
return "";
|
|
813
|
+
}
|
|
814
|
+
function extractAgentsFromWorkflow(content) {
|
|
815
|
+
const agents = [];
|
|
816
|
+
const blocks = content.split(/(?=^### Agent \d)/m).filter((b) => /^### Agent \d/.test(b.trimStart()));
|
|
817
|
+
for (const block of blocks) {
|
|
818
|
+
const lines = block.split("\n");
|
|
819
|
+
const headerMatch = lines[0].match(/^### Agent (\d+)\s*[·•]\s*(.+)$/);
|
|
820
|
+
if (!headerMatch) continue;
|
|
821
|
+
const number = parseInt(headerMatch[1], 10);
|
|
822
|
+
const name = headerMatch[2].trim();
|
|
823
|
+
const fullName = `Agent ${number} \xB7 ${name}`;
|
|
824
|
+
const slug = toSlug(name);
|
|
825
|
+
const scope = getFieldValue(lines, /Périmètre\s*:\s*(.+)/);
|
|
826
|
+
const criterion = getFieldValue(lines, /Critère[s]?\s*:\s*(.+)/);
|
|
827
|
+
const outputs = [];
|
|
828
|
+
const produitIdx = lines.findIndex((l) => /Produit\s*:/.test(l));
|
|
829
|
+
if (produitIdx !== -1) {
|
|
830
|
+
const inlineVal = (lines[produitIdx].match(/Produit\s*:\s*(.+)/)?.[1] ?? "").trim();
|
|
831
|
+
if (inlineVal) {
|
|
832
|
+
outputs.push(inlineVal);
|
|
833
|
+
} else {
|
|
834
|
+
for (let i = produitIdx + 1; i < lines.length; i++) {
|
|
835
|
+
const line = lines[i];
|
|
836
|
+
if (/^\s+[-]/.test(line)) {
|
|
837
|
+
outputs.push(line.trim().replace(/^-\s*/, ""));
|
|
838
|
+
} else if (line.trim() !== "" && !/^\s/.test(line)) {
|
|
839
|
+
break;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
agents.push({ number, name, fullName, slug, scope, outputs, criterion });
|
|
845
|
+
}
|
|
846
|
+
return agents;
|
|
847
|
+
}
|
|
848
|
+
|
|
801
849
|
// src/utils/logger.ts
|
|
802
850
|
var import_chalk = __toESM(require("chalk"), 1);
|
|
803
851
|
var logger = {
|
|
@@ -897,9 +945,9 @@ function registerInit(program2) {
|
|
|
897
945
|
}
|
|
898
946
|
const genSpinner = (0, import_ora.default)("G\xE9n\xE9ration des fichiers\u2026").start();
|
|
899
947
|
const claudeMdContent = generateClaudeMd(stack, blueprintContent);
|
|
900
|
-
const workflowContent = generateWorkflow(stack, blueprintContent);
|
|
948
|
+
const workflowContent = generateWorkflow(stack, blueprintContent, projectName);
|
|
901
949
|
const agents = extractAgentsFromWorkflow(workflowContent);
|
|
902
|
-
const playbookContent = generatePlaybook({ agents, projectName });
|
|
950
|
+
const playbookContent = generatePlaybook({ agents, projectName, hasBlueprint: !!blueprintContent });
|
|
903
951
|
await (0, import_promises4.writeFile)(claudeMdPath, claudeMdContent, "utf-8");
|
|
904
952
|
await (0, import_promises4.writeFile)(workflowPath, workflowContent, "utf-8");
|
|
905
953
|
await (0, import_promises4.writeFile)(playbookPath, playbookContent, "utf-8");
|
|
@@ -927,7 +975,7 @@ async function addFeatureToProject(description, projectDir) {
|
|
|
927
975
|
try {
|
|
928
976
|
workflowContent = await (0, import_promises5.readFile)(workflowPath, "utf-8");
|
|
929
977
|
} catch {
|
|
930
|
-
throw new Error(`AGENT_WORKFLOW.md
|
|
978
|
+
throw new Error(`AGENT_WORKFLOW.md not found in ${projectDir} \u2014 run agentkit init first`);
|
|
931
979
|
}
|
|
932
980
|
const existingAgents = extractAgentsFromWorkflow(workflowContent);
|
|
933
981
|
const nextNumber = existingAgents.length + 1;
|
|
@@ -961,7 +1009,11 @@ Crit\xE8re : npm run build && npm test
|
|
|
961
1009
|
} catch {
|
|
962
1010
|
}
|
|
963
1011
|
const allAgents = [...existingAgents, newAgent];
|
|
964
|
-
const playbookContent = generatePlaybook({
|
|
1012
|
+
const playbookContent = generatePlaybook({
|
|
1013
|
+
agents: allAgents,
|
|
1014
|
+
projectName,
|
|
1015
|
+
hasBlueprint: false
|
|
1016
|
+
});
|
|
965
1017
|
await (0, import_promises5.writeFile)(playbookPath, playbookContent, "utf-8");
|
|
966
1018
|
return {
|
|
967
1019
|
agent: newAgent,
|
|
@@ -969,13 +1021,13 @@ Crit\xE8re : npm run build && npm test
|
|
|
969
1021
|
};
|
|
970
1022
|
}
|
|
971
1023
|
function registerAdd(program2) {
|
|
972
|
-
const addCmd = program2.command("add").description("
|
|
1024
|
+
const addCmd = program2.command("add").description("Add resources to the agentkit project").option("--feature <description>", "Add an agent from a feature description and regenerate PLAYBOOK.md").action(async (options) => {
|
|
973
1025
|
if (options.feature) {
|
|
974
1026
|
try {
|
|
975
1027
|
const result = await addFeatureToProject(options.feature, process.cwd());
|
|
976
|
-
logger.success(`Agent
|
|
977
|
-
logger.success(`
|
|
978
|
-
logger.success("PLAYBOOK.md :
|
|
1028
|
+
logger.success(`Agent added : ${result.agent.fullName}`);
|
|
1029
|
+
logger.success(`Folder created : agents/agent-${result.agent.number}-${result.agent.slug}/`);
|
|
1030
|
+
logger.success("PLAYBOOK.md : regenerated");
|
|
979
1031
|
} catch (err) {
|
|
980
1032
|
logger.error(err instanceof Error ? err.message : String(err));
|
|
981
1033
|
process.exit(1);
|
|
@@ -984,14 +1036,14 @@ function registerAdd(program2) {
|
|
|
984
1036
|
addCmd.help();
|
|
985
1037
|
}
|
|
986
1038
|
});
|
|
987
|
-
addCmd.command("agent").description("
|
|
1039
|
+
addCmd.command("agent").description("Add a new agent to AGENT_WORKFLOW.md (interactive)").action(async () => {
|
|
988
1040
|
const cwd = process.cwd();
|
|
989
1041
|
const workflowPath = (0, import_node_path6.join)(cwd, "AGENT_WORKFLOW.md");
|
|
990
1042
|
let existing = "";
|
|
991
1043
|
try {
|
|
992
1044
|
existing = await (0, import_promises5.readFile)(workflowPath, "utf-8");
|
|
993
1045
|
} catch {
|
|
994
|
-
logger.error("AGENT_WORKFLOW.md
|
|
1046
|
+
logger.error("AGENT_WORKFLOW.md not found \u2014 run agentkit init first");
|
|
995
1047
|
process.exit(1);
|
|
996
1048
|
}
|
|
997
1049
|
const agentCount = (existing.match(/^### Agent \d+/gm) ?? []).length;
|
|
@@ -1000,23 +1052,23 @@ function registerAdd(program2) {
|
|
|
1000
1052
|
{
|
|
1001
1053
|
type: "input",
|
|
1002
1054
|
name: "name",
|
|
1003
|
-
message: `
|
|
1055
|
+
message: `Agent name (e.g. "Agent ${nextNumber} \xB7 Feature X"):`,
|
|
1004
1056
|
default: `Agent ${nextNumber}`
|
|
1005
1057
|
},
|
|
1006
1058
|
{
|
|
1007
1059
|
type: "input",
|
|
1008
1060
|
name: "scope",
|
|
1009
|
-
message: "
|
|
1061
|
+
message: "Scope (one sentence):"
|
|
1010
1062
|
},
|
|
1011
1063
|
{
|
|
1012
1064
|
type: "input",
|
|
1013
1065
|
name: "outputs",
|
|
1014
|
-
message: "
|
|
1066
|
+
message: "Deliverables (comma-separated):"
|
|
1015
1067
|
},
|
|
1016
1068
|
{
|
|
1017
1069
|
type: "input",
|
|
1018
1070
|
name: "criterion",
|
|
1019
|
-
message: "
|
|
1071
|
+
message: "Success criterion:"
|
|
1020
1072
|
}
|
|
1021
1073
|
]);
|
|
1022
1074
|
const outputLines = answers.outputs.split(",").map((o) => ` - ${o.trim()}`).join("\n");
|
|
@@ -1028,7 +1080,7 @@ ${outputLines}
|
|
|
1028
1080
|
Crit\xE8re : ${answers.criterion}
|
|
1029
1081
|
`;
|
|
1030
1082
|
await (0, import_promises5.writeFile)(workflowPath, existing + agentSection, "utf-8");
|
|
1031
|
-
logger.success(`Agent "${answers.name}"
|
|
1083
|
+
logger.success(`Agent "${answers.name}" added to AGENT_WORKFLOW.md`);
|
|
1032
1084
|
});
|
|
1033
1085
|
}
|
|
1034
1086
|
|