@patricksardinha/agentkit-cli 0.1.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 (52) hide show
  1. package/.gitattributes +2 -0
  2. package/.github/workflows/release.yml +31 -0
  3. package/AGENT_WORKFLOW.md +55 -0
  4. package/CLAUDE.md +45 -0
  5. package/README.md +327 -0
  6. package/dist/cli.cjs +1079 -0
  7. package/dist/cli.cjs.map +1 -0
  8. package/dist/cli.d.cts +1 -0
  9. package/dist/cli.d.ts +1 -0
  10. package/dist/cli.js +1056 -0
  11. package/dist/cli.js.map +1 -0
  12. package/package.json +45 -0
  13. package/src/cli.ts +18 -0
  14. package/src/commands/add.ts +166 -0
  15. package/src/commands/init.ts +130 -0
  16. package/src/commands/status.ts +57 -0
  17. package/src/detectors/gitDetector.ts +11 -0
  18. package/src/detectors/stackDetector.ts +88 -0
  19. package/src/generators/claudeMdGenerator.ts +42 -0
  20. package/src/generators/playbookGenerator.ts +76 -0
  21. package/src/generators/skillsGenerator.ts +56 -0
  22. package/src/generators/workflowGenerator.ts +62 -0
  23. package/src/templates/express.ts +64 -0
  24. package/src/templates/fastapi.ts +63 -0
  25. package/src/templates/nextjs.ts +63 -0
  26. package/src/templates/node.ts +54 -0
  27. package/src/templates/react.ts +61 -0
  28. package/src/templates/tauri.ts +65 -0
  29. package/src/templates/unknown.ts +45 -0
  30. package/src/types/agent.ts +9 -0
  31. package/src/types/inquirer.d.ts +36 -0
  32. package/src/utils/agentParser.ts +67 -0
  33. package/src/utils/blueprintParser.ts +28 -0
  34. package/src/utils/logger.ts +16 -0
  35. package/tests/commands/add.test.ts +130 -0
  36. package/tests/detectors/fixtures/express-app/package.json +9 -0
  37. package/tests/detectors/fixtures/fastapi-app/requirements.txt +3 -0
  38. package/tests/detectors/fixtures/nextjs-app/package.json +13 -0
  39. package/tests/detectors/fixtures/no-git/README.md +2 -0
  40. package/tests/detectors/fixtures/react-app/package.json +10 -0
  41. package/tests/detectors/fixtures/tauri-app/package.json +10 -0
  42. package/tests/detectors/fixtures/tauri-app/src-tauri/tauri.conf.json +12 -0
  43. package/tests/detectors/gitDetector.test.ts +29 -0
  44. package/tests/detectors/stackDetector.test.ts +50 -0
  45. package/tests/generators/blueprintSupport.test.ts +130 -0
  46. package/tests/generators/claudeMdGenerator.test.ts +86 -0
  47. package/tests/generators/playbookGenerator.test.ts +152 -0
  48. package/tests/generators/skillsGenerator.test.ts +94 -0
  49. package/tests/generators/workflowGenerator.test.ts +84 -0
  50. package/tsconfig.json +19 -0
  51. package/tsup.config.ts +11 -0
  52. package/vitest.config.ts +9 -0
package/dist/cli.js ADDED
@@ -0,0 +1,1056 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/commands/init.ts
7
+ import { writeFile as writeFile2, readFile as readFile2 } from "fs/promises";
8
+ import { join as join4 } from "path";
9
+ import inquirer from "inquirer";
10
+ import ora from "ora";
11
+
12
+ // src/detectors/stackDetector.ts
13
+ import { readFile, access } from "fs/promises";
14
+ import { join } from "path";
15
+ async function pathExists(p) {
16
+ try {
17
+ await access(p);
18
+ return true;
19
+ } catch {
20
+ return false;
21
+ }
22
+ }
23
+ async function readJson(p) {
24
+ try {
25
+ const raw = await readFile(p, "utf-8");
26
+ return JSON.parse(raw);
27
+ } catch {
28
+ return null;
29
+ }
30
+ }
31
+ async function readText(p) {
32
+ try {
33
+ return await readFile(p, "utf-8");
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+ async function detectStack(projectPath) {
39
+ const info = {
40
+ framework: "unknown",
41
+ language: "unknown",
42
+ hasTypeScript: false,
43
+ extras: []
44
+ };
45
+ const packageJson = await readJson(join(projectPath, "package.json"));
46
+ const requirementsTxt = await readText(join(projectPath, "requirements.txt"));
47
+ const hasTauriDir = await pathExists(join(projectPath, "src-tauri"));
48
+ const hasTsConfig = await pathExists(join(projectPath, "tsconfig.json"));
49
+ if (packageJson !== null) {
50
+ const deps = packageJson.dependencies ?? {};
51
+ const devDeps = packageJson.devDependencies ?? {};
52
+ const allDeps = { ...deps, ...devDeps };
53
+ info.hasTypeScript = "typescript" in allDeps || hasTsConfig;
54
+ info.language = info.hasTypeScript ? "typescript" : "javascript";
55
+ if ("next" in allDeps) {
56
+ info.framework = "nextjs";
57
+ } else if (hasTauriDir || "@tauri-apps/api" in allDeps || "@tauri-apps/cli" in allDeps) {
58
+ info.framework = "tauri";
59
+ } else if ("react" in allDeps) {
60
+ info.framework = "react";
61
+ } else if ("express" in allDeps) {
62
+ info.framework = "express";
63
+ } else {
64
+ info.framework = "node";
65
+ }
66
+ if ("vitest" in allDeps || "jest" in allDeps) info.extras.push("testing");
67
+ if ("prisma" in allDeps || "@prisma/client" in allDeps) info.extras.push("prisma");
68
+ if ("tailwindcss" in allDeps) info.extras.push("tailwind");
69
+ }
70
+ if (requirementsTxt !== null && info.framework === "unknown") {
71
+ info.language = "python";
72
+ if (/\bfastapi\b/i.test(requirementsTxt)) {
73
+ info.framework = "fastapi";
74
+ }
75
+ }
76
+ if (hasTauriDir && info.framework === "unknown") {
77
+ info.framework = "tauri";
78
+ }
79
+ return info;
80
+ }
81
+
82
+ // src/detectors/gitDetector.ts
83
+ import { access as access2 } from "fs/promises";
84
+ import { join as join2 } from "path";
85
+ async function isGitRepo(projectPath) {
86
+ try {
87
+ await access2(join2(projectPath, ".git"));
88
+ return true;
89
+ } catch {
90
+ return false;
91
+ }
92
+ }
93
+
94
+ // src/utils/blueprintParser.ts
95
+ function parseBlueprint(content) {
96
+ const features = [];
97
+ const sectionRegex = /^## (.+)$/gm;
98
+ const sections = [];
99
+ let m;
100
+ while ((m = sectionRegex.exec(content)) !== null) {
101
+ sections.push({ name: m[1].trim(), start: m.index });
102
+ }
103
+ for (let i = 0; i < sections.length; i++) {
104
+ const section = sections[i];
105
+ const end = i + 1 < sections.length ? sections[i + 1].start : content.length;
106
+ const body = content.slice(section.start, end);
107
+ const items = [...body.matchAll(/^[-*]\s+(.+)$/gm)].map((r) => r[1].trim());
108
+ features.push({ name: section.name, items });
109
+ }
110
+ return features;
111
+ }
112
+
113
+ // src/templates/react.ts
114
+ function claudeMd(stack) {
115
+ const lang = stack.hasTypeScript ? "TypeScript" : "JavaScript";
116
+ const testLine = stack.extras.includes("testing") ? "- `npm test` \u2014 run tests\n" : "";
117
+ return `# CLAUDE.md \u2014 React Project
118
+
119
+ ## Stack
120
+ - Framework : React (${lang})
121
+ - Language : ${lang}
122
+ - Build : Vite
123
+
124
+ ## Commands
125
+ - \`npm run dev\` \u2014 development server
126
+ - \`npm run build\` \u2014 production build
127
+ ${testLine}
128
+ ## Structure
129
+ src/
130
+ components/ \u2190 UI components (PascalCase)
131
+ hooks/ \u2190 custom hooks (prefix: use*)
132
+ pages/ \u2190 page-level components
133
+ utils/ \u2190 shared helpers
134
+
135
+ ## Conventions
136
+ 1. Components in PascalCase
137
+ 2. Hooks prefixed with \`use\`
138
+ 3. Props interfaces named \`*Props\`
139
+ 4. Tout output console passe par un logger centralis\xE9
140
+ `;
141
+ }
142
+ function workflow(stack) {
143
+ const lang = stack.hasTypeScript ? "TypeScript" : "JavaScript";
144
+ return `# Agent Workflow \u2014 React Project
145
+
146
+ ## Stack d\xE9tect\xE9e
147
+ Framework: React | Language: ${lang}
148
+
149
+ ## Agents
150
+
151
+ ### Agent 1 \xB7 Components
152
+ P\xE9rim\xE8tre : composants UI r\xE9utilisables
153
+ Produit : src/components/
154
+ Crit\xE8re : composants document\xE9s et test\xE9s
155
+
156
+ ### Agent 2 \xB7 State & Hooks
157
+ P\xE9rim\xE8tre : state management, hooks personnalis\xE9s
158
+ Produit : src/hooks/
159
+ Crit\xE8re : hooks test\xE9s unitairement
160
+
161
+ ### Agent 3 \xB7 Pages & Routing
162
+ P\xE9rim\xE8tre : assemblage des pages, react-router
163
+ Produit : src/pages/
164
+ Crit\xE8re : navigation fonctionnelle
165
+
166
+ ### Agent 4 \xB7 Tests & CI
167
+ P\xE9rim\xE8tre : couverture de tests, configuration CI
168
+ Produit : tests/, .github/workflows/
169
+ Crit\xE8re : npm test passe
170
+ `;
171
+ }
172
+
173
+ // src/templates/nextjs.ts
174
+ function claudeMd2(stack) {
175
+ const hasTailwind = stack.extras.includes("tailwind");
176
+ const hasPrisma = stack.extras.includes("prisma");
177
+ return `# CLAUDE.md \u2014 Next.js Project
178
+
179
+ ## Stack
180
+ - Framework : Next.js (TypeScript)
181
+ - Rendering : App Router (RSC + Client Components)
182
+ - Styling : ${hasTailwind ? "Tailwind CSS" : "CSS Modules"}
183
+ ${hasPrisma ? "- Database : Prisma ORM\n" : ""}
184
+ ## Commands
185
+ - \`npm run dev\` \u2014 development server (http://localhost:3000)
186
+ - \`npm run build\` \u2014 production build
187
+ - \`npm start\` \u2014 production server
188
+ - \`npm test\` \u2014 run tests
189
+
190
+ ## Structure
191
+ src/
192
+ app/ \u2190 App Router pages and layouts
193
+ components/ \u2190 shared UI components
194
+ lib/ \u2190 server utilities, db clients
195
+ utils/ \u2190 shared helpers
196
+
197
+ ## Conventions
198
+ 1. Server Components by default, \`'use client'\` only when needed
199
+ 2. API routes in \`src/app/api/\`
200
+ 3. Environment variables via \`src/env.ts\` (validated)
201
+ 4. Tout output console passe par un logger centralis\xE9
202
+ `;
203
+ }
204
+ function workflow2(stack) {
205
+ const hasPrisma = stack.extras.includes("prisma");
206
+ return `# Agent Workflow \u2014 Next.js Project
207
+
208
+ ## Stack d\xE9tect\xE9e
209
+ Framework: Next.js | Language: TypeScript
210
+
211
+ ## Agents
212
+
213
+ ### Agent 1 \xB7 Data Layer
214
+ P\xE9rim\xE8tre : sch\xE9ma${hasPrisma ? " Prisma" : ""}, types, server actions
215
+ Produit : src/lib/, ${hasPrisma ? "prisma/schema.prisma" : "src/types/"}
216
+ Crit\xE8re : types compilent, migrations propres
217
+
218
+ ### Agent 2 \xB7 UI Components
219
+ P\xE9rim\xE8tre : composants r\xE9utilisables (Server + Client)
220
+ Produit : src/components/
221
+ Crit\xE8re : composants rendus sans erreur
222
+
223
+ ### Agent 3 \xB7 Pages & Layout
224
+ P\xE9rim\xE8tre : App Router, layouts, pages
225
+ Produit : src/app/
226
+ Crit\xE8re : navigation fonctionnelle, build passe
227
+
228
+ ### Agent 4 \xB7 API & Tests
229
+ P\xE9rim\xE8tre : API routes, tests e2e/unitaires
230
+ Produit : src/app/api/, tests/
231
+ Crit\xE8re : npm test passe
232
+ `;
233
+ }
234
+
235
+ // src/templates/tauri.ts
236
+ function claudeMd3(stack) {
237
+ const lang = stack.hasTypeScript ? "TypeScript" : "JavaScript";
238
+ return `# CLAUDE.md \u2014 Tauri Project
239
+
240
+ ## Stack
241
+ - Framework : Tauri (Rust + ${lang} frontend)
242
+ - Language : Rust (backend) + ${lang} (frontend)
243
+ - Build : Cargo + Vite
244
+
245
+ ## Commands
246
+ - \`npm run tauri dev\` \u2014 development (hot reload)
247
+ - \`npm run tauri build\` \u2014 production bundle
248
+ - \`npm run build\` \u2014 frontend only
249
+ - \`npm test\` \u2014 run tests
250
+
251
+ ## Structure
252
+ src/ \u2190 frontend (${lang})
253
+ components/
254
+ utils/
255
+ src-tauri/ \u2190 Rust backend
256
+ src/
257
+ main.rs \u2190 Tauri entry point
258
+ commands.rs \u2190 Tauri commands (IPC)
259
+ tauri.conf.json
260
+
261
+ ## Conventions
262
+ 1. IPC commands defined in \`src-tauri/src/commands.rs\`
263
+ 2. Frontend invokes via \`@tauri-apps/api/tauri\`
264
+ 3. No direct filesystem access from frontend
265
+ 4. Tout output console passe par un logger centralis\xE9
266
+ `;
267
+ }
268
+ function workflow3(stack) {
269
+ const lang = stack.hasTypeScript ? "TypeScript" : "JavaScript";
270
+ return `# Agent Workflow \u2014 Tauri Project
271
+
272
+ ## Stack d\xE9tect\xE9e
273
+ Framework: Tauri | Language: Rust + ${lang}
274
+
275
+ ## Agents
276
+
277
+ ### Agent 1 \xB7 Rust Commands
278
+ P\xE9rim\xE8tre : commandes Tauri (IPC), permissions
279
+ Produit : src-tauri/src/commands.rs, tauri.conf.json
280
+ Crit\xE8re : \`cargo build\` passe
281
+
282
+ ### Agent 2 \xB7 Frontend UI
283
+ P\xE9rim\xE8tre : interface ${lang}, int\xE9gration IPC
284
+ Produit : src/components/, src/utils/
285
+ Crit\xE8re : appels IPC fonctionnels
286
+
287
+ ### Agent 3 \xB7 Build & Packaging
288
+ P\xE9rim\xE8tre : configuration build, ic\xF4nes, installeurs
289
+ Produit : src-tauri/tauri.conf.json, icons/
290
+ Crit\xE8re : \`npm run tauri build\` produit un bundle
291
+
292
+ ### Agent 4 \xB7 Tests
293
+ P\xE9rim\xE8tre : tests Rust + tests frontend
294
+ Produit : src-tauri/tests/, tests/
295
+ Crit\xE8re : \`cargo test\` + \`npm test\` passent
296
+ `;
297
+ }
298
+
299
+ // src/templates/fastapi.ts
300
+ function claudeMd4(_stack) {
301
+ return `# CLAUDE.md \u2014 FastAPI Project
302
+
303
+ ## Stack
304
+ - Framework : FastAPI (Python)
305
+ - Language : Python 3.11+
306
+ - Server : Uvicorn
307
+ - Validation: Pydantic v2
308
+
309
+ ## Commands
310
+ - \`uvicorn main:app --reload\` \u2014 development server (http://localhost:8000)
311
+ - \`pytest\` \u2014 run tests
312
+ - \`pip install -r requirements.txt\` \u2014 install dependencies
313
+
314
+ ## Structure
315
+ app/
316
+ main.py \u2190 FastAPI app entry point
317
+ routers/ \u2190 API route groups
318
+ models/ \u2190 Pydantic models
319
+ services/ \u2190 business logic
320
+ dependencies/ \u2190 FastAPI dependencies (DI)
321
+ tests/ \u2190 pytest tests
322
+
323
+ ## Conventions
324
+ 1. Routers grouped by domain in \`app/routers/\`
325
+ 2. Pydantic models for all request/response bodies
326
+ 3. Business logic in \`app/services/\`, not in routes
327
+ 4. Async endpoints by default (\`async def\`)
328
+ 5. Environment variables via \`python-dotenv\` + \`pydantic-settings\`
329
+ `;
330
+ }
331
+ function workflow4(_stack) {
332
+ return `# Agent Workflow \u2014 FastAPI Project
333
+
334
+ ## Stack d\xE9tect\xE9e
335
+ Framework: FastAPI | Language: Python
336
+
337
+ ## Agents
338
+
339
+ ### Agent 1 \xB7 Models & Schemas
340
+ P\xE9rim\xE8tre : mod\xE8les Pydantic, sch\xE9mas DB (SQLAlchemy/SQLModel)
341
+ Produit : app/models/
342
+ Crit\xE8re : mod\xE8les valid\xE9s, migrations propres
343
+
344
+ ### Agent 2 \xB7 Services
345
+ P\xE9rim\xE8tre : logique m\xE9tier, acc\xE8s base de donn\xE9es
346
+ Produit : app/services/
347
+ Crit\xE8re : services test\xE9s unitairement (pytest)
348
+
349
+ ### Agent 3 \xB7 Routers & API
350
+ P\xE9rim\xE8tre : routes FastAPI, d\xE9pendances, auth
351
+ Produit : app/routers/, app/dependencies/
352
+ Crit\xE8re : endpoints document\xE9s (OpenAPI), tests d'int\xE9gration
353
+
354
+ ### Agent 4 \xB7 Tests & CI
355
+ P\xE9rim\xE8tre : couverture pytest, configuration CI
356
+ Produit : tests/, .github/workflows/
357
+ Crit\xE8re : \`pytest\` passe \xE0 100%
358
+ `;
359
+ }
360
+
361
+ // src/templates/express.ts
362
+ function claudeMd5(stack) {
363
+ const lang = stack.hasTypeScript ? "TypeScript" : "JavaScript";
364
+ const hasPrisma = stack.extras.includes("prisma");
365
+ return `# CLAUDE.md \u2014 Express Project
366
+
367
+ ## Stack
368
+ - Framework : Express (${lang})
369
+ - Language : ${lang}
370
+ - Runtime : Node.js 20+
371
+ ${hasPrisma ? "- Database : Prisma ORM\n" : ""}
372
+ ## Commands
373
+ - \`npm run dev\` \u2014 development server (nodemon)
374
+ - \`npm run build\` \u2014 compile TypeScript
375
+ - \`npm start\` \u2014 production server
376
+ - \`npm test\` \u2014 run tests
377
+
378
+ ## Structure
379
+ src/
380
+ routes/ \u2190 Express routers (one per domain)
381
+ controllers/ \u2190 request handlers
382
+ services/ \u2190 business logic
383
+ middleware/ \u2190 Express middleware
384
+ utils/ \u2190 shared helpers
385
+
386
+ ## Conventions
387
+ 1. Routes grouped by domain in \`src/routes/\`
388
+ 2. Business logic in \`src/services/\`, not in controllers
389
+ 3. Middleware for cross-cutting concerns (auth, validation)
390
+ 4. Tout output console passe par un logger centralis\xE9
391
+ `;
392
+ }
393
+ function workflow5(stack) {
394
+ const lang = stack.hasTypeScript ? "TypeScript" : "JavaScript";
395
+ return `# Agent Workflow \u2014 Express Project
396
+
397
+ ## Stack d\xE9tect\xE9e
398
+ Framework: Express | Language: ${lang}
399
+
400
+ ## Agents
401
+
402
+ ### Agent 1 \xB7 Data & Models
403
+ P\xE9rim\xE8tre : mod\xE8les de donn\xE9es, acc\xE8s DB
404
+ Produit : src/models/, src/services/db.ts
405
+ Crit\xE8re : connexion DB fonctionnelle
406
+
407
+ ### Agent 2 \xB7 Services
408
+ P\xE9rim\xE8tre : logique m\xE9tier
409
+ Produit : src/services/
410
+ Crit\xE8re : services test\xE9s unitairement
411
+
412
+ ### Agent 3 \xB7 Routes & Controllers
413
+ P\xE9rim\xE8tre : routes Express, validation, auth
414
+ Produit : src/routes/, src/controllers/, src/middleware/
415
+ Crit\xE8re : endpoints r\xE9pondent correctement
416
+
417
+ ### Agent 4 \xB7 Tests & CI
418
+ P\xE9rim\xE8tre : tests d'int\xE9gration, configuration CI
419
+ Produit : tests/, .github/workflows/
420
+ Crit\xE8re : npm test passe
421
+ `;
422
+ }
423
+
424
+ // src/templates/node.ts
425
+ function claudeMd6(stack) {
426
+ const lang = stack.hasTypeScript ? "TypeScript" : "JavaScript";
427
+ return `# CLAUDE.md \u2014 Node.js Project
428
+
429
+ ## Stack
430
+ - Runtime : Node.js 20+
431
+ - Language : ${lang}
432
+
433
+ ## Commands
434
+ - \`npm run dev\` \u2014 development (with watch)
435
+ - \`npm run build\` \u2014 compile${stack.hasTypeScript ? " TypeScript" : ""}
436
+ - \`npm start\` \u2014 run production build
437
+ - \`npm test\` \u2014 run tests
438
+
439
+ ## Structure
440
+ src/
441
+ index.ts \u2190 entry point
442
+ lib/ \u2190 core library code
443
+ utils/ \u2190 shared helpers
444
+
445
+ ## Conventions
446
+ 1. Modules follow single-responsibility principle
447
+ 2. Async/await over callbacks
448
+ 3. Tout output console passe par un logger centralis\xE9
449
+ `;
450
+ }
451
+ function workflow6(stack) {
452
+ const lang = stack.hasTypeScript ? "TypeScript" : "JavaScript";
453
+ return `# Agent Workflow \u2014 Node.js Project
454
+
455
+ ## Stack d\xE9tect\xE9e
456
+ Runtime: Node.js | Language: ${lang}
457
+
458
+ ## Agents
459
+
460
+ ### Agent 1 \xB7 Core Library
461
+ P\xE9rim\xE8tre : logique principale
462
+ Produit : src/lib/
463
+ Crit\xE8re : module fonctionne et test\xE9
464
+
465
+ ### Agent 2 \xB7 CLI / API
466
+ P\xE9rim\xE8tre : interface utilisateur (CLI ou API)
467
+ Produit : src/index.ts, src/cli.ts
468
+ Crit\xE8re : commandes fonctionnelles
469
+
470
+ ### Agent 3 \xB7 Tests & CI
471
+ P\xE9rim\xE8tre : couverture de tests, configuration CI
472
+ Produit : tests/, .github/workflows/
473
+ Crit\xE8re : npm test passe
474
+ `;
475
+ }
476
+
477
+ // src/templates/unknown.ts
478
+ function claudeMd7(_stack) {
479
+ return `# CLAUDE.md
480
+
481
+ ## Stack
482
+ Stack non d\xE9tect\xE9e automatiquement \u2014 \xE0 remplir manuellement.
483
+
484
+ ## Commands
485
+ - \xC0 d\xE9finir selon le projet
486
+
487
+ ## Structure
488
+ src/ \u2190 code source
489
+ tests/ \u2190 tests
490
+
491
+ ## Conventions
492
+ 1. Tout output console passe par un logger centralis\xE9
493
+ 2. \xC0 compl\xE9ter selon les conventions du projet
494
+ `;
495
+ }
496
+ function workflow7(_stack) {
497
+ return `# Agent Workflow
498
+
499
+ ## Stack d\xE9tect\xE9e
500
+ Stack inconnue \u2014 workflow g\xE9n\xE9rique.
501
+
502
+ ## Agents
503
+
504
+ ### Agent 1 \xB7 Setup
505
+ P\xE9rim\xE8tre : configuration initiale du projet
506
+ Produit : structure de base
507
+ Crit\xE8re : projet compilable
508
+
509
+ ### Agent 2 \xB7 Core
510
+ P\xE9rim\xE8tre : logique principale
511
+ Produit : src/
512
+ Crit\xE8re : fonctionnalit\xE9s principales op\xE9rationnelles
513
+
514
+ ### Agent 3 \xB7 Tests
515
+ P\xE9rim\xE8tre : couverture de tests
516
+ Produit : tests/
517
+ Crit\xE8re : tests passent
518
+ `;
519
+ }
520
+
521
+ // src/generators/claudeMdGenerator.ts
522
+ function generateClaudeMd(stack, blueprintContent) {
523
+ let base;
524
+ switch (stack.framework) {
525
+ case "react":
526
+ base = claudeMd(stack);
527
+ break;
528
+ case "nextjs":
529
+ base = claudeMd2(stack);
530
+ break;
531
+ case "tauri":
532
+ base = claudeMd3(stack);
533
+ break;
534
+ case "fastapi":
535
+ base = claudeMd4(stack);
536
+ break;
537
+ case "express":
538
+ base = claudeMd5(stack);
539
+ break;
540
+ case "node":
541
+ base = claudeMd6(stack);
542
+ break;
543
+ default:
544
+ base = claudeMd7(stack);
545
+ }
546
+ if (!blueprintContent) return base;
547
+ const features = parseBlueprint(blueprintContent);
548
+ if (features.length === 0) return base;
549
+ const featureLines = features.map((f, i) => {
550
+ const sub = f.items.length > 0 ? "\n" + f.items.map((it) => ` - ${it}`).join("\n") : "";
551
+ return `${i + 1}. **${f.name}**${sub}`;
552
+ }).join("\n");
553
+ const featureSection = `
554
+ ## Features (Blueprint)
555
+
556
+ ${featureLines}
557
+ `;
558
+ const conventionsIdx = base.indexOf("\n## Conventions");
559
+ if (conventionsIdx !== -1) {
560
+ return base.slice(0, conventionsIdx) + featureSection + base.slice(conventionsIdx);
561
+ }
562
+ return base + featureSection;
563
+ }
564
+
565
+ // src/utils/agentParser.ts
566
+ function toSlug(name) {
567
+ return name.toLowerCase().replace(/[·•&]/g, " ").replace(/[^\w\s-]/g, "").trim().replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
568
+ }
569
+ function getFieldValue(lines, pattern) {
570
+ for (const line of lines) {
571
+ const m = line.match(pattern);
572
+ if (m) return (m[1] ?? "").trim();
573
+ }
574
+ return "";
575
+ }
576
+ function extractAgentsFromWorkflow(content) {
577
+ const agents = [];
578
+ const blocks = content.split(/(?=^### Agent \d)/m).filter((b) => /^### Agent \d/.test(b.trimStart()));
579
+ for (const block of blocks) {
580
+ const lines = block.split("\n");
581
+ const headerMatch = lines[0].match(/^### Agent (\d+)\s*[·•]\s*(.+)$/);
582
+ if (!headerMatch) continue;
583
+ const number = parseInt(headerMatch[1], 10);
584
+ const name = headerMatch[2].trim();
585
+ const fullName = `Agent ${number} \xB7 ${name}`;
586
+ const slug = toSlug(name);
587
+ const scope = getFieldValue(lines, /Périmètre\s*:\s*(.+)/);
588
+ const criterion = getFieldValue(lines, /Critère[s]?\s*:\s*(.+)/);
589
+ const outputs = [];
590
+ const produitIdx = lines.findIndex((l) => /Produit\s*:/.test(l));
591
+ if (produitIdx !== -1) {
592
+ const inlineVal = (lines[produitIdx].match(/Produit\s*:\s*(.+)/)?.[1] ?? "").trim();
593
+ if (inlineVal) {
594
+ outputs.push(inlineVal);
595
+ } else {
596
+ for (let i = produitIdx + 1; i < lines.length; i++) {
597
+ const line = lines[i];
598
+ if (/^\s+[-]/.test(line)) {
599
+ outputs.push(line.trim().replace(/^-\s*/, ""));
600
+ } else if (line.trim() !== "" && !/^\s/.test(line)) {
601
+ break;
602
+ }
603
+ }
604
+ }
605
+ }
606
+ agents.push({ number, name, fullName, slug, scope, outputs, criterion });
607
+ }
608
+ return agents;
609
+ }
610
+
611
+ // src/generators/workflowGenerator.ts
612
+ function generateWorkflow(stack, blueprintContent) {
613
+ if (blueprintContent) return blueprintWorkflow(stack, blueprintContent);
614
+ switch (stack.framework) {
615
+ case "react":
616
+ return workflow(stack);
617
+ case "nextjs":
618
+ return workflow2(stack);
619
+ case "tauri":
620
+ return workflow3(stack);
621
+ case "fastapi":
622
+ return workflow4(stack);
623
+ case "express":
624
+ return workflow5(stack);
625
+ case "node":
626
+ return workflow6(stack);
627
+ default:
628
+ return workflow7(stack);
629
+ }
630
+ }
631
+ function blueprintWorkflow(stack, blueprintContent) {
632
+ const features = parseBlueprint(blueprintContent);
633
+ const agentBlocks = features.map((feature, i) => {
634
+ const n = i + 1;
635
+ const slug = toSlug(feature.name);
636
+ const outputLines = feature.items.length > 0 ? feature.items.map((item) => ` - ${item}`).join("\n") : ` - src/${slug}/`;
637
+ return `### Agent ${n} \xB7 ${feature.name}
638
+ P\xE9rim\xE8tre : Impl\xE9menter la fonctionnalit\xE9 ${feature.name.toLowerCase()}
639
+ Produit :
640
+ ${outputLines}
641
+ Crit\xE8re : npm test (tests ${feature.name.toLowerCase()} passent)`;
642
+ });
643
+ const ciN = features.length + 1;
644
+ agentBlocks.push(
645
+ `### Agent ${ciN} \xB7 Tests & CI
646
+ P\xE9rim\xE8tre : Couverture de tests compl\xE8te et configuration du pipeline CI
647
+ Produit :
648
+ - tests/
649
+ - .github/workflows/
650
+ Crit\xE8re : npm test passe, pipeline CI vert`
651
+ );
652
+ return `# Agent Workflow \u2014 ${stack.framework} (Blueprint)
653
+
654
+ ## Stack d\xE9tect\xE9e
655
+ Framework: ${stack.framework} | Language: ${stack.language}
656
+
657
+ ## Agents
658
+
659
+ ${agentBlocks.join("\n\n")}
660
+ `;
661
+ }
662
+
663
+ // src/generators/playbookGenerator.ts
664
+ function generatePlaybook({ agents, projectName }) {
665
+ const agentBlocks = agents.map((a) => agentBlock(a)).join("\n---\n\n");
666
+ return `# PLAYBOOK.md \u2014 ${projectName}
667
+
668
+ > Donne cette instruction \xE0 Claude Code : 'Lis PLAYBOOK.md et ex\xE9cute la proc\xE9dure.'
669
+
670
+ ## R\xE8gles d'ex\xE9cution globales
671
+
672
+ Avant chaque agent :
673
+ 1. Lire \`CLAUDE.md\`
674
+ 2. Lire \`agents/agent-{N}-{slug}/skills.md\` (le fichier de l'agent courant)
675
+
676
+ Apr\xE8s chaque agent :
677
+ - Ex\xE9cuter le crit\xE8re de succ\xE8s
678
+ - Si succ\xE8s \u2192 annoncer "\u2705 Agent N termin\xE9" et passer au suivant
679
+ - Si \xE9chec \u2192 analyser la cause racine, corriger, r\xE9ex\xE9cuter (max 3 tentatives)
680
+ - Apr\xE8s 3 \xE9checs cons\xE9cutifs \u2192 pause et demander validation humaine
681
+ - **Ne jamais passer \xE0 l'agent suivant sans crit\xE8re valid\xE9**
682
+
683
+ ## Agents
684
+
685
+ ${agentBlocks}
686
+
687
+ ## It\xE9rations futures
688
+
689
+ Lorsqu'un nouvel agent est ajout\xE9 via \`agentkit add --feature <description>\` :
690
+ 1. Un nouveau bloc agent est ajout\xE9 \xE0 la fin de \`AGENT_WORKFLOW.md\`
691
+ 2. Le dossier \`agents/agent-{N}-{slug}/\` est cr\xE9\xE9 avec \`skills.md\` et \`context.md\`
692
+ 3. Ce \`PLAYBOOK.md\` est r\xE9g\xE9n\xE9r\xE9 automatiquement pour inclure le nouvel agent
693
+ 4. L'ex\xE9cution reprend \xE0 ce nouvel agent uniquement \u2014 les agents pr\xE9c\xE9dents ne sont pas r\xE9ex\xE9cut\xE9s
694
+
695
+ ## Validation humaine requise
696
+
697
+ Les cas suivants n\xE9cessitent une pause et une confirmation humaine avant de continuer :
698
+ - **3 \xE9checs cons\xE9cutifs** sur le crit\xE8re de succ\xE8s d'un agent
699
+ - **D\xE9pendance externe manquante** : cl\xE9 API, variable d'environnement non d\xE9finie, service tiers inaccessible
700
+ - **Conflit** entre le blueprint fourni (\`--blueprint\`) et la stack d\xE9tect\xE9e automatiquement
701
+ `;
702
+ }
703
+ function agentBlock(agent) {
704
+ const skillsPath = `agents/agent-${agent.number}-${agent.slug}/skills.md`;
705
+ const outputLines = agent.outputs.length > 0 ? agent.outputs.map((o) => `- ${o}`).join("\n") : "- (voir skills.md pour le d\xE9tail)";
706
+ return `### ${agent.fullName}
707
+
708
+ **P\xE9rim\xE8tre** : ${agent.scope}
709
+
710
+ **Skills** : \`${skillsPath}\`
711
+
712
+ **Fichiers produits** :
713
+ ${outputLines}
714
+
715
+ **Crit\xE8re de succ\xE8s** :
716
+ \`\`\`bash
717
+ ${agent.criterion || "npm run build && npm test"}
718
+ \`\`\`
719
+
720
+ **En cas d'\xE9chec** :
721
+ 1. Analyser le message d'erreur complet
722
+ 2. Corriger la cause racine (pas les sympt\xF4mes)
723
+ 3. R\xE9ex\xE9cuter le crit\xE8re (max 3 tentatives)
724
+ 4. Apr\xE8s 3 \xE9checs \u2192 demander validation humaine
725
+ `;
726
+ }
727
+
728
+ // src/generators/skillsGenerator.ts
729
+ import { mkdir, writeFile } from "fs/promises";
730
+ import { join as join3 } from "path";
731
+ async function generateSkills(agents, outputDir) {
732
+ for (const agent of agents) {
733
+ const agentDir = join3(outputDir, "agents", `agent-${agent.number}-${agent.slug}`);
734
+ await mkdir(agentDir, { recursive: true });
735
+ await writeFile(join3(agentDir, "skills.md"), skillsMd(agent), "utf-8");
736
+ await writeFile(join3(agentDir, "context.md"), contextMd(agent), "utf-8");
737
+ }
738
+ }
739
+ function skillsMd(agent) {
740
+ return `# Skills \u2014 ${agent.fullName}
741
+
742
+ > Ce fichier est lu par l'agent avant de commencer.
743
+
744
+ ## Contexte technique
745
+
746
+ <!-- \xC0 remplir : biblioth\xE8ques, versions, d\xE9cisions d'architecture sp\xE9cifiques \xE0 cet agent -->
747
+
748
+ ## Documentation de r\xE9f\xE9rence
749
+
750
+ <!-- \xC0 remplir : liens vers docs, exemples, ADRs pertinents -->
751
+
752
+ ## Conventions sp\xE9cifiques
753
+
754
+ <!-- \xC0 remplir : r\xE8gles propres \xE0 cet agent (naming, patterns, structure de fichiers) -->
755
+ `;
756
+ }
757
+ function contextMd(agent) {
758
+ const outputLines = agent.outputs.length > 0 ? agent.outputs.map((o) => `- ${o}`).join("\n") : "- (voir AGENT_WORKFLOW.md)";
759
+ return `# Context \u2014 ${agent.fullName}
760
+
761
+ > Ce fichier fournit le contexte additionnel \xE0 l'agent avant ex\xE9cution.
762
+ > \xC0 compl\xE9ter avant de lancer cet agent.
763
+
764
+ ## P\xE9rim\xE8tre
765
+
766
+ ${agent.scope}
767
+
768
+ ## Fichiers produits attendus
769
+
770
+ ${outputLines}
771
+
772
+ ## Crit\xE8re de succ\xE8s
773
+
774
+ \`${agent.criterion || "npm run build && npm test"}\`
775
+ `;
776
+ }
777
+
778
+ // src/utils/logger.ts
779
+ import chalk from "chalk";
780
+ var logger = {
781
+ info: (message) => {
782
+ process.stdout.write(chalk.blue("\u2139") + " " + message + "\n");
783
+ },
784
+ success: (message) => {
785
+ process.stdout.write(chalk.green("\u2714") + " " + message + "\n");
786
+ },
787
+ warn: (message) => {
788
+ process.stdout.write(chalk.yellow("\u26A0") + " " + message + "\n");
789
+ },
790
+ error: (message) => {
791
+ process.stderr.write(chalk.red("\u2716") + " " + message + "\n");
792
+ }
793
+ };
794
+
795
+ // src/commands/init.ts
796
+ import { basename } from "path";
797
+ var FRAMEWORK_LABELS = {
798
+ react: "React",
799
+ nextjs: "Next.js",
800
+ tauri: "Tauri",
801
+ fastapi: "FastAPI (Python)",
802
+ express: "Express",
803
+ node: "Node.js",
804
+ unknown: "Unknown (generic)"
805
+ };
806
+ async function fileExists(path) {
807
+ try {
808
+ await readFile2(path);
809
+ return true;
810
+ } catch {
811
+ return false;
812
+ }
813
+ }
814
+ function registerInit(program2) {
815
+ program2.command("init").description("G\xE9n\xE8re CLAUDE.md et AGENT_WORKFLOW.md dans le dossier courant").option("-f, --force", "\xC9crase les fichiers existants sans confirmation").option("--blueprint <path>", "Fichier blueprint .md \xE0 utiliser pour personnaliser les fichiers g\xE9n\xE9r\xE9s").action(async (options) => {
816
+ const cwd = process.cwd();
817
+ const spinner = ora("D\xE9tection de la stack\u2026").start();
818
+ const [stack, isGit] = await Promise.all([detectStack(cwd), isGitRepo(cwd)]);
819
+ spinner.stop();
820
+ if (!isGit) {
821
+ logger.warn("Ce dossier n'est pas un repo git \u2014 lancez git init si n\xE9cessaire");
822
+ }
823
+ const label = FRAMEWORK_LABELS[stack.framework];
824
+ logger.info(`Stack d\xE9tect\xE9e : ${label} (${stack.language})`);
825
+ const { confirmed } = await inquirer.prompt([
826
+ {
827
+ type: "confirm",
828
+ name: "confirmed",
829
+ message: `G\xE9n\xE9rer les fichiers pour ${label} ?`,
830
+ default: true
831
+ }
832
+ ]);
833
+ if (!confirmed) {
834
+ logger.warn("Annul\xE9.");
835
+ return;
836
+ }
837
+ const claudeMdPath = join4(cwd, "CLAUDE.md");
838
+ const workflowPath = join4(cwd, "AGENT_WORKFLOW.md");
839
+ const playbookPath = join4(cwd, "PLAYBOOK.md");
840
+ let projectName = basename(cwd);
841
+ try {
842
+ const pkg = JSON.parse(await readFile2(join4(cwd, "package.json"), "utf-8"));
843
+ if (pkg.name) projectName = pkg.name;
844
+ } catch {
845
+ }
846
+ if (!options.force) {
847
+ const existing = [];
848
+ if (await fileExists(claudeMdPath)) existing.push("CLAUDE.md");
849
+ if (await fileExists(workflowPath)) existing.push("AGENT_WORKFLOW.md");
850
+ if (await fileExists(playbookPath)) existing.push("PLAYBOOK.md");
851
+ if (existing.length > 0) {
852
+ const { overwrite } = await inquirer.prompt([
853
+ {
854
+ type: "confirm",
855
+ name: "overwrite",
856
+ message: `${existing.join(" et ")} existe d\xE9j\xE0. \xC9craser ?`,
857
+ default: false
858
+ }
859
+ ]);
860
+ if (!overwrite) {
861
+ logger.warn("Annul\xE9.");
862
+ return;
863
+ }
864
+ }
865
+ }
866
+ let blueprintContent;
867
+ if (options.blueprint) {
868
+ try {
869
+ blueprintContent = await readFile2(options.blueprint, "utf-8");
870
+ } catch {
871
+ logger.error(`Blueprint introuvable : ${options.blueprint}`);
872
+ process.exit(1);
873
+ }
874
+ }
875
+ const genSpinner = ora("G\xE9n\xE9ration des fichiers\u2026").start();
876
+ const claudeMdContent = generateClaudeMd(stack, blueprintContent);
877
+ const workflowContent = generateWorkflow(stack, blueprintContent);
878
+ const agents = extractAgentsFromWorkflow(workflowContent);
879
+ const playbookContent = generatePlaybook({ agents, projectName });
880
+ await writeFile2(claudeMdPath, claudeMdContent, "utf-8");
881
+ await writeFile2(workflowPath, workflowContent, "utf-8");
882
+ await writeFile2(playbookPath, playbookContent, "utf-8");
883
+ await generateSkills(agents, cwd);
884
+ genSpinner.succeed("Fichiers g\xE9n\xE9r\xE9s");
885
+ logger.success("CLAUDE.md \u2192 cr\xE9\xE9");
886
+ logger.success("AGENT_WORKFLOW.md \u2192 cr\xE9\xE9");
887
+ logger.success("PLAYBOOK.md \u2192 cr\xE9\xE9");
888
+ logger.success(`agents/ \u2192 ${agents.length} dossier(s) cr\xE9\xE9(s)`);
889
+ });
890
+ }
891
+
892
+ // src/commands/add.ts
893
+ import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
894
+ import { join as join5, basename as basename2 } from "path";
895
+ import inquirer2 from "inquirer";
896
+ function featureToAgentName(description) {
897
+ const clean = description.replace(/^(add|implement|create|build|integrate|setup|configure|refactor|improve)\s+/i, "").trim();
898
+ return clean.replace(/\b\w/g, (c) => c.toUpperCase());
899
+ }
900
+ async function addFeatureToProject(description, projectDir) {
901
+ const workflowPath = join5(projectDir, "AGENT_WORKFLOW.md");
902
+ const playbookPath = join5(projectDir, "PLAYBOOK.md");
903
+ let workflowContent = "";
904
+ try {
905
+ workflowContent = await readFile3(workflowPath, "utf-8");
906
+ } catch {
907
+ throw new Error(`AGENT_WORKFLOW.md introuvable dans ${projectDir} \u2014 lancez agentkit init`);
908
+ }
909
+ const existingAgents = extractAgentsFromWorkflow(workflowContent);
910
+ const nextNumber = existingAgents.length + 1;
911
+ const name = featureToAgentName(description);
912
+ const slug = toSlug(name);
913
+ const fullName = `Agent ${nextNumber} \xB7 ${name}`;
914
+ const newAgent = {
915
+ number: nextNumber,
916
+ name,
917
+ fullName,
918
+ slug,
919
+ scope: description,
920
+ outputs: [`agents/agent-${nextNumber}-${slug}/`],
921
+ criterion: "npm run build && npm test"
922
+ };
923
+ const agentBlock2 = `
924
+ ### ${fullName}
925
+ P\xE9rim\xE8tre : ${description}
926
+ Produit :
927
+ - agents/agent-${nextNumber}-${slug}/
928
+ Crit\xE8re : npm run build && npm test
929
+ `;
930
+ await writeFile3(workflowPath, workflowContent + agentBlock2, "utf-8");
931
+ await generateSkills([newAgent], projectDir);
932
+ let projectName = basename2(projectDir);
933
+ try {
934
+ const pkg = JSON.parse(
935
+ await readFile3(join5(projectDir, "package.json"), "utf-8")
936
+ );
937
+ if (pkg.name) projectName = pkg.name;
938
+ } catch {
939
+ }
940
+ const allAgents = [...existingAgents, newAgent];
941
+ const playbookContent = generatePlaybook({ agents: allAgents, projectName });
942
+ await writeFile3(playbookPath, playbookContent, "utf-8");
943
+ return {
944
+ agent: newAgent,
945
+ agentDirPath: join5(projectDir, "agents", `agent-${nextNumber}-${slug}`)
946
+ };
947
+ }
948
+ function registerAdd(program2) {
949
+ const addCmd = program2.command("add").description("Ajoute des ressources au projet agentkit").option("--feature <description>", "Ajoute un agent depuis une description de feature et r\xE9g\xE9n\xE8re PLAYBOOK.md").action(async (options) => {
950
+ if (options.feature) {
951
+ try {
952
+ const result = await addFeatureToProject(options.feature, process.cwd());
953
+ logger.success(`Agent ajout\xE9 : ${result.agent.fullName}`);
954
+ logger.success(`Dossier cr\xE9\xE9 : agents/agent-${result.agent.number}-${result.agent.slug}/`);
955
+ logger.success("PLAYBOOK.md : r\xE9g\xE9n\xE9r\xE9");
956
+ } catch (err) {
957
+ logger.error(err instanceof Error ? err.message : String(err));
958
+ process.exit(1);
959
+ }
960
+ } else {
961
+ addCmd.help();
962
+ }
963
+ });
964
+ addCmd.command("agent").description("Ajoute un nouvel agent dans AGENT_WORKFLOW.md (interactif)").action(async () => {
965
+ const cwd = process.cwd();
966
+ const workflowPath = join5(cwd, "AGENT_WORKFLOW.md");
967
+ let existing = "";
968
+ try {
969
+ existing = await readFile3(workflowPath, "utf-8");
970
+ } catch {
971
+ logger.error("AGENT_WORKFLOW.md introuvable \u2014 lancez d'abord : agentkit init");
972
+ process.exit(1);
973
+ }
974
+ const agentCount = (existing.match(/^### Agent \d+/gm) ?? []).length;
975
+ const nextNumber = agentCount + 1;
976
+ const answers = await inquirer2.prompt([
977
+ {
978
+ type: "input",
979
+ name: "name",
980
+ message: `Nom de l'agent (ex: "Agent ${nextNumber} \xB7 Feature X") :`,
981
+ default: `Agent ${nextNumber}`
982
+ },
983
+ {
984
+ type: "input",
985
+ name: "scope",
986
+ message: "P\xE9rim\xE8tre (une phrase) :"
987
+ },
988
+ {
989
+ type: "input",
990
+ name: "outputs",
991
+ message: "Fichiers produits (s\xE9par\xE9s par des virgules) :"
992
+ },
993
+ {
994
+ type: "input",
995
+ name: "criterion",
996
+ message: "Crit\xE8re de succ\xE8s :"
997
+ }
998
+ ]);
999
+ const outputLines = answers.outputs.split(",").map((o) => ` - ${o.trim()}`).join("\n");
1000
+ const agentSection = `
1001
+ ### ${answers.name}
1002
+ P\xE9rim\xE8tre : ${answers.scope}
1003
+ Produit :
1004
+ ${outputLines}
1005
+ Crit\xE8re : ${answers.criterion}
1006
+ `;
1007
+ await writeFile3(workflowPath, existing + agentSection, "utf-8");
1008
+ logger.success(`Agent "${answers.name}" ajout\xE9 dans AGENT_WORKFLOW.md`);
1009
+ });
1010
+ }
1011
+
1012
+ // src/commands/status.ts
1013
+ import { readFile as readFile4 } from "fs/promises";
1014
+ import { join as join6 } from "path";
1015
+ import chalk2 from "chalk";
1016
+ function registerStatus(program2) {
1017
+ program2.command("status").description("Affiche l'\xE9tat du workflow agentkit dans le dossier courant").action(async () => {
1018
+ const cwd = process.cwd();
1019
+ const [stack, isGit, claudeMd8, workflow8] = await Promise.all([
1020
+ detectStack(cwd),
1021
+ isGitRepo(cwd),
1022
+ readFile4(join6(cwd, "CLAUDE.md"), "utf-8").catch(() => null),
1023
+ readFile4(join6(cwd, "AGENT_WORKFLOW.md"), "utf-8").catch(() => null)
1024
+ ]);
1025
+ process.stdout.write("\n" + chalk2.bold("AgentKit Status") + "\n");
1026
+ process.stdout.write("\u2500".repeat(40) + "\n");
1027
+ process.stdout.write(
1028
+ chalk2.bold("Git repo : ") + (isGit ? chalk2.green("\u2714 oui") : chalk2.red("\u2716 non")) + "\n"
1029
+ );
1030
+ process.stdout.write(
1031
+ chalk2.bold("Stack : ") + chalk2.cyan(stack.framework) + " (" + stack.language + ")\n"
1032
+ );
1033
+ process.stdout.write(
1034
+ chalk2.bold("CLAUDE.md : ") + (claudeMd8 !== null ? chalk2.green("\u2714 pr\xE9sent") : chalk2.yellow("\u2716 absent \u2014 lancez agentkit init")) + "\n"
1035
+ );
1036
+ process.stdout.write(
1037
+ chalk2.bold("AGENT_WORKFLOW.md : ") + (workflow8 !== null ? chalk2.green("\u2714 pr\xE9sent") : chalk2.yellow("\u2716 absent \u2014 lancez agentkit init")) + "\n"
1038
+ );
1039
+ if (workflow8 !== null) {
1040
+ const agentMatches = workflow8.match(/^### Agent \d+/gm) ?? [];
1041
+ process.stdout.write(
1042
+ chalk2.bold("Agents d\xE9finis : ") + chalk2.cyan(String(agentMatches.length)) + "\n"
1043
+ );
1044
+ }
1045
+ process.stdout.write("\u2500".repeat(40) + "\n\n");
1046
+ });
1047
+ }
1048
+
1049
+ // src/cli.ts
1050
+ var program = new Command();
1051
+ program.name("agentkit").description("Scaffolder des workflows multi-agents Claude Code").version("0.1.0");
1052
+ registerInit(program);
1053
+ registerAdd(program);
1054
+ registerStatus(program);
1055
+ program.parse();
1056
+ //# sourceMappingURL=cli.js.map