@alxyrgin/agent-forge 1.0.0 → 3.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 (64) hide show
  1. package/README.md +384 -96
  2. package/dist/index.js +355 -58
  3. package/dist/index.js.map +1 -1
  4. package/package.json +12 -2
  5. package/templates/agents/documentation/gatekeeper.md.ejs +83 -0
  6. package/templates/agents/documentation/librarian.md.ejs +80 -0
  7. package/templates/agents/documentation/verifier.md.ejs +92 -0
  8. package/templates/agents/documentation/writer.md.ejs +189 -0
  9. package/templates/agents/pipeline/analyst.md.ejs +65 -0
  10. package/templates/agents/{core → pipeline}/architect.md.ejs +38 -1
  11. package/templates/agents/pipeline/developer.md.ejs +75 -0
  12. package/templates/agents/pipeline/inspector.md.ejs +123 -0
  13. package/templates/agents/pipeline/planner.md.ejs +211 -0
  14. package/templates/agents/pipeline/reviewer.md.ejs +158 -0
  15. package/templates/agents/pipeline/skeptic.md.ejs +105 -0
  16. package/templates/agents/pipeline/tester.md.ejs +134 -0
  17. package/templates/agents/planning/decomposer.md.ejs +103 -0
  18. package/templates/agents/planning/interviewer.md.ejs +104 -0
  19. package/templates/agents/planning/researcher.md.ejs +96 -0
  20. package/templates/agents/planning/validator.md.ejs +97 -0
  21. package/templates/agents/security/auditor.md.ejs +105 -0
  22. package/templates/agents/security/deployer.md.ejs +81 -0
  23. package/templates/agents/security/prompter.md.ejs +87 -0
  24. package/templates/agents/security/scaffolder.md.ejs +75 -0
  25. package/templates/hooks/protect-docs.sh.ejs +25 -0
  26. package/templates/memory/checkpoint.yml.ejs +21 -0
  27. package/templates/memory/tech-debt.md.ejs +9 -1
  28. package/templates/root/CLAUDE.md.ejs +228 -30
  29. package/templates/root/settings.json.ejs +15 -1
  30. package/templates/rules/agent-output-format.md.ejs +80 -0
  31. package/templates/rules/context-loading.md.ejs +70 -0
  32. package/templates/rules/development-cycle.md.ejs +163 -29
  33. package/templates/rules/quality-gates.md.ejs +80 -0
  34. package/templates/rules/rollback-protocol.md.ejs +60 -0
  35. package/templates/rules/shared-resources.md.ejs +73 -0
  36. package/templates/skills/core/code/SKILL.md.ejs +85 -0
  37. package/templates/skills/core/complete-task/SKILL.md.ejs +22 -9
  38. package/templates/skills/core/done/SKILL.md.ejs +66 -0
  39. package/templates/skills/core/end-session/SKILL.md.ejs +14 -6
  40. package/templates/skills/core/review/SKILL.md.ejs +1 -1
  41. package/templates/skills/core/start-session/SKILL.md.ejs +73 -10
  42. package/templates/skills/core/take-task/SKILL.md.ejs +279 -30
  43. package/templates/skills/core/test/SKILL.md.ejs +200 -0
  44. package/templates/skills/extra/audit-wave/SKILL.md.ejs +58 -0
  45. package/templates/skills/extra/dashboard/SKILL.md.ejs +64 -0
  46. package/templates/skills/extra/decompose/SKILL.md.ejs +72 -0
  47. package/templates/skills/extra/feature/SKILL.md.ejs +83 -0
  48. package/templates/skills/extra/interview/SKILL.md.ejs +66 -0
  49. package/templates/skills/extra/prompts/SKILL.md.ejs +65 -0
  50. package/templates/skills/extra/security/SKILL.md.ejs +77 -0
  51. package/templates/skills/extra/skill-master/SKILL.md.ejs +51 -0
  52. package/templates/skills/extra/spec/SKILL.md.ejs +111 -0
  53. package/templates/skills/extra/techspec/SKILL.md.ejs +97 -0
  54. package/templates/skills/extra/write-report/SKILL.md.ejs +26 -0
  55. package/templates/agents/core/analyst.md.ejs +0 -56
  56. package/templates/agents/core/developer.md.ejs +0 -54
  57. package/templates/agents/core/doc-writer.md.ejs +0 -50
  58. package/templates/agents/core/progress-tracker.md.ejs +0 -56
  59. package/templates/agents/core/reviewer.md.ejs +0 -52
  60. package/templates/agents/core/security-auditor.md.ejs +0 -51
  61. package/templates/agents/core/unit-tester.md.ejs +0 -56
  62. package/templates/agents/extra/acceptance-tester.md.ejs +0 -48
  63. package/templates/agents/extra/integration-tester.md.ejs +0 -49
  64. package/templates/agents/extra/planner.md.ejs +0 -89
package/dist/index.js CHANGED
@@ -181,9 +181,9 @@ async function promptProjectSetup(targetDir) {
181
181
  name: "agentPreset",
182
182
  message: "Agent preset:",
183
183
  choices: [
184
- { name: "Core (8 agents \u2014 recommended)", value: "core" },
185
- { name: "Full (11 agents)", value: "full" },
186
- { name: "Minimal (4 agents)", value: "minimal" }
184
+ { name: "Core (8 agents \u2014 development pipeline)", value: "core" },
185
+ { name: "Full (20 agents \u2014 all categories + extra skills)", value: "full" },
186
+ { name: "Minimal (5 agents \u2014 essentials + inspector)", value: "minimal" }
187
187
  ]
188
188
  },
189
189
  {
@@ -276,6 +276,9 @@ async function fileExists(filePath) {
276
276
  async function readFile(filePath) {
277
277
  return fs.readFile(filePath, "utf-8");
278
278
  }
279
+ async function makeExecutable(filePath) {
280
+ await fs.chmod(filePath, 493);
281
+ }
279
282
 
280
283
  // src/utils/template.ts
281
284
  import fs2 from "fs";
@@ -302,7 +305,8 @@ var MEMORY_FILES = [
302
305
  "tech-stack.md",
303
306
  "tech-debt.md",
304
307
  "patterns.md",
305
- "troubleshooting.md"
308
+ "troubleshooting.md",
309
+ "checkpoint.yml"
306
310
  ];
307
311
  async function generateMemoryBank(ctx, overwrite) {
308
312
  const result = {
@@ -333,39 +337,82 @@ async function generateMemoryBank(ctx, overwrite) {
333
337
 
334
338
  // src/generators/agents.ts
335
339
  import path4 from "path";
336
- var CORE_AGENTS = [
340
+ var PIPELINE_AGENTS = [
337
341
  "analyst",
338
342
  "architect",
343
+ "skeptic",
339
344
  "developer",
340
- "unit-tester",
345
+ "tester",
346
+ "inspector",
341
347
  "reviewer",
342
- "security-auditor",
343
- "doc-writer",
344
- "progress-tracker"
348
+ "planner"
349
+ ];
350
+ var PLANNING_AGENTS = [
351
+ "researcher",
352
+ "validator",
353
+ "interviewer",
354
+ "decomposer"
345
355
  ];
346
- var EXTRA_AGENTS = [
347
- "planner",
348
- "integration-tester",
349
- "acceptance-tester"
356
+ var SECURITY_AGENTS = [
357
+ "auditor",
358
+ "prompter",
359
+ "deployer",
360
+ "scaffolder"
361
+ ];
362
+ var DOCUMENTATION_AGENTS = [
363
+ "librarian",
364
+ "writer",
365
+ "gatekeeper",
366
+ "verifier"
350
367
  ];
351
368
  var MINIMAL_AGENTS = [
352
369
  "analyst",
353
370
  "developer",
354
- "unit-tester",
355
- "reviewer"
371
+ "tester",
372
+ "reviewer",
373
+ "inspector"
356
374
  ];
375
+ var CORE_AGENTS = [...PIPELINE_AGENTS];
376
+ var FULL_AGENTS = [
377
+ ...PIPELINE_AGENTS,
378
+ ...PLANNING_AGENTS,
379
+ ...SECURITY_AGENTS,
380
+ ...DOCUMENTATION_AGENTS
381
+ ];
382
+ var CATEGORY_MAP = {};
383
+ for (const name of PIPELINE_AGENTS) {
384
+ CATEGORY_MAP[name] = "pipeline";
385
+ }
386
+ for (const name of PLANNING_AGENTS) {
387
+ CATEGORY_MAP[name] = "planning";
388
+ }
389
+ for (const name of SECURITY_AGENTS) {
390
+ CATEGORY_MAP[name] = "security";
391
+ }
392
+ for (const name of DOCUMENTATION_AGENTS) {
393
+ CATEGORY_MAP[name] = "documentation";
394
+ }
395
+ function getAgentCategory(name) {
396
+ return CATEGORY_MAP[name] || "pipeline";
397
+ }
357
398
  function getAgentList(preset) {
358
- const agents = [];
359
- const coreList = preset === "minimal" ? MINIMAL_AGENTS : CORE_AGENTS;
360
- for (const name of coreList) {
361
- agents.push({ name, dir: "core" });
399
+ let names;
400
+ switch (preset) {
401
+ case "minimal":
402
+ names = MINIMAL_AGENTS;
403
+ break;
404
+ case "full":
405
+ names = FULL_AGENTS;
406
+ break;
407
+ case "core":
408
+ default:
409
+ names = CORE_AGENTS;
410
+ break;
362
411
  }
363
- if (preset === "full") {
364
- for (const name of EXTRA_AGENTS) {
365
- agents.push({ name, dir: "extra" });
366
- }
367
- }
368
- return agents;
412
+ return names.map((name) => ({
413
+ name,
414
+ category: getAgentCategory(name)
415
+ }));
369
416
  }
370
417
  async function generateAgents(ctx, overwrite) {
371
418
  const result = {
@@ -381,7 +428,7 @@ async function generateAgents(ctx, overwrite) {
381
428
  for (const agent of agents) {
382
429
  try {
383
430
  const content = await renderTemplate(
384
- `agents/${agent.dir}/${agent.name}.md.ejs`,
431
+ `agents/${agent.category}/${agent.name}.md.ejs`,
385
432
  templateData
386
433
  );
387
434
  const outputPath = path4.join(ctx.targetDir, ".claude/agents", `${agent.name}.md`);
@@ -400,15 +447,43 @@ async function generateAgents(ctx, overwrite) {
400
447
 
401
448
  // src/generators/skills.ts
402
449
  import path5 from "path";
403
- var SKILLS = [
450
+ var CORE_SKILLS = [
404
451
  "start-session",
405
452
  "end-session",
406
453
  "take-task",
407
454
  "complete-task",
408
455
  "status",
409
456
  "plan",
410
- "review"
457
+ "review",
458
+ "code",
459
+ "test",
460
+ "done"
461
+ ];
462
+ var EXTRA_SKILLS = [
463
+ "interview",
464
+ "audit-wave",
465
+ "write-report",
466
+ "dashboard",
467
+ "skill-master",
468
+ "decompose",
469
+ "feature",
470
+ "security",
471
+ "spec",
472
+ "techspec",
473
+ "prompts"
411
474
  ];
475
+ function getSkillList(preset) {
476
+ const skills = [];
477
+ for (const name of CORE_SKILLS) {
478
+ skills.push({ name, dir: "core" });
479
+ }
480
+ if (preset === "full") {
481
+ for (const name of EXTRA_SKILLS) {
482
+ skills.push({ name, dir: "extra" });
483
+ }
484
+ }
485
+ return skills;
486
+ }
412
487
  async function generateSkills(ctx, overwrite) {
413
488
  const result = {
414
489
  filesCreated: [],
@@ -419,13 +494,14 @@ async function generateSkills(ctx, overwrite) {
419
494
  ...ctx,
420
495
  defaultBranch: "main"
421
496
  };
422
- for (const skill of SKILLS) {
497
+ const skills = getSkillList(ctx.agentPreset);
498
+ for (const skill of skills) {
423
499
  try {
424
500
  const content = await renderTemplate(
425
- `skills/core/${skill}/SKILL.md.ejs`,
501
+ `skills/${skill.dir}/${skill.name}/SKILL.md.ejs`,
426
502
  templateData
427
503
  );
428
- const outputPath = path5.join(ctx.targetDir, `.claude/skills/${skill}`, "SKILL.md");
504
+ const outputPath = path5.join(ctx.targetDir, `.claude/skills/${skill.name}`, "SKILL.md");
429
505
  const status = await writeFileSafe(outputPath, content, overwrite);
430
506
  if (status === "skipped") {
431
507
  result.filesSkipped.push(outputPath);
@@ -433,7 +509,7 @@ async function generateSkills(ctx, overwrite) {
433
509
  result.filesCreated.push(outputPath);
434
510
  }
435
511
  } catch (err) {
436
- result.errors.push(`Skill ${skill}: ${err}`);
512
+ result.errors.push(`Skill ${skill.name}: ${err}`);
437
513
  }
438
514
  }
439
515
  return result;
@@ -444,7 +520,12 @@ import path6 from "path";
444
520
  var RULES = [
445
521
  "commit-conventions",
446
522
  "development-cycle",
447
- "testing-standards"
523
+ "testing-standards",
524
+ "shared-resources",
525
+ "context-loading",
526
+ "agent-output-format",
527
+ "quality-gates",
528
+ "rollback-protocol"
448
529
  ];
449
530
  async function generateRules(ctx, overwrite) {
450
531
  const result = {
@@ -558,14 +639,7 @@ async function generateInfra(ctx, overwrite) {
558
639
  }
559
640
  }
560
641
  try {
561
- const manifest = {
562
- version: "1.0.0",
563
- createdAt: ctx.today,
564
- projectName: ctx.projectName,
565
- agentPreset: ctx.agentPreset,
566
- language: ctx.language,
567
- expectedFiles: getExpectedFiles(ctx)
568
- };
642
+ const manifest = buildManifest(ctx);
569
643
  const outputPath = path8.join(ctx.targetDir, ".claude-forge.json");
570
644
  const status = await writeFileSafe(
571
645
  outputPath,
@@ -582,6 +656,25 @@ async function generateInfra(ctx, overwrite) {
582
656
  }
583
657
  return result;
584
658
  }
659
+ function buildManifest(ctx) {
660
+ return {
661
+ version: "3.0.0",
662
+ createdAt: ctx.today,
663
+ updatedAt: ctx.today,
664
+ projectName: ctx.projectName,
665
+ projectDescription: ctx.projectDescription,
666
+ language: ctx.language,
667
+ agentPreset: ctx.agentPreset,
668
+ stack: ctx.stack,
669
+ framework: ctx.framework,
670
+ testFramework: ctx.testFramework,
671
+ testCommand: ctx.testCommand,
672
+ srcDir: ctx.srcDir,
673
+ testDir: ctx.testDir,
674
+ commitStyle: ctx.commitStyle,
675
+ expectedFiles: getExpectedFiles(ctx)
676
+ };
677
+ }
585
678
  function getExpectedFiles(ctx) {
586
679
  const files = [
587
680
  ".claude/CLAUDE.md",
@@ -595,44 +688,105 @@ function getExpectedFiles(ctx) {
595
688
  "dev-infra/memory/tech-stack.md",
596
689
  "dev-infra/memory/tech-debt.md",
597
690
  "dev-infra/memory/patterns.md",
598
- "dev-infra/memory/troubleshooting.md"
691
+ "dev-infra/memory/troubleshooting.md",
692
+ "dev-infra/memory/checkpoint.yml"
599
693
  ];
694
+ files.push(".claude/hooks/protect-docs.sh");
600
695
  files.push(
601
696
  ".claude/rules/commit-conventions.md",
602
697
  ".claude/rules/development-cycle.md",
603
- ".claude/rules/testing-standards.md"
698
+ ".claude/rules/testing-standards.md",
699
+ ".claude/rules/shared-resources.md",
700
+ ".claude/rules/context-loading.md",
701
+ ".claude/rules/agent-output-format.md",
702
+ ".claude/rules/quality-gates.md",
703
+ ".claude/rules/rollback-protocol.md"
604
704
  );
605
- const skills = [
705
+ const coreSkills = [
606
706
  "start-session",
607
707
  "end-session",
608
708
  "take-task",
609
709
  "complete-task",
610
710
  "status",
611
711
  "plan",
612
- "review"
712
+ "review",
713
+ "code",
714
+ "test",
715
+ "done"
613
716
  ];
717
+ const extraSkills = [
718
+ "interview",
719
+ "audit-wave",
720
+ "write-report",
721
+ "dashboard",
722
+ "skill-master",
723
+ "decompose",
724
+ "feature",
725
+ "security",
726
+ "spec",
727
+ "techspec",
728
+ "prompts"
729
+ ];
730
+ const skills = ctx.agentPreset === "full" ? [...coreSkills, ...extraSkills] : coreSkills;
614
731
  for (const skill of skills) {
615
732
  files.push(`.claude/skills/${skill}/SKILL.md`);
616
733
  }
617
- const coreAgents = [
734
+ const pipelineAgents = [
618
735
  "analyst",
619
736
  "architect",
737
+ "skeptic",
620
738
  "developer",
621
- "unit-tester",
739
+ "tester",
740
+ "inspector",
622
741
  "reviewer",
623
- "security-auditor",
624
- "doc-writer",
625
- "progress-tracker"
742
+ "planner"
743
+ ];
744
+ const planningAgents = ["researcher", "validator", "interviewer", "decomposer"];
745
+ const securityAgents = ["auditor", "prompter", "deployer", "scaffolder"];
746
+ const documentationAgents = ["librarian", "writer", "gatekeeper", "verifier"];
747
+ const minimalAgents = ["analyst", "developer", "tester", "reviewer", "inspector"];
748
+ const coreAgents = [...pipelineAgents];
749
+ const fullAgents = [
750
+ ...pipelineAgents,
751
+ ...planningAgents,
752
+ ...securityAgents,
753
+ ...documentationAgents
626
754
  ];
627
- const minimalAgents = ["analyst", "developer", "unit-tester", "reviewer"];
628
- const extraAgents = ["planner", "integration-tester", "acceptance-tester"];
629
- const agents = ctx.agentPreset === "minimal" ? minimalAgents : ctx.agentPreset === "full" ? [...coreAgents, ...extraAgents] : coreAgents;
755
+ const agents = ctx.agentPreset === "minimal" ? minimalAgents : ctx.agentPreset === "full" ? fullAgents : coreAgents;
630
756
  for (const agent of agents) {
631
757
  files.push(`.claude/agents/${agent}.md`);
632
758
  }
633
759
  return files;
634
760
  }
635
761
 
762
+ // src/generators/hooks.ts
763
+ import path9 from "path";
764
+ async function generateHooks(ctx, overwrite) {
765
+ const result = {
766
+ filesCreated: [],
767
+ filesSkipped: [],
768
+ errors: []
769
+ };
770
+ const templateData = {
771
+ ...ctx,
772
+ defaultBranch: "main"
773
+ };
774
+ try {
775
+ const content = await renderTemplate("hooks/protect-docs.sh.ejs", templateData);
776
+ const outputPath = path9.join(ctx.targetDir, ".claude/hooks/protect-docs.sh");
777
+ const status = await writeFileSafe(outputPath, content, overwrite);
778
+ if (status === "skipped") {
779
+ result.filesSkipped.push(outputPath);
780
+ } else {
781
+ result.filesCreated.push(outputPath);
782
+ await makeExecutable(outputPath);
783
+ }
784
+ } catch (err) {
785
+ result.errors.push(`Hook protect-docs.sh: ${err}`);
786
+ }
787
+ return result;
788
+ }
789
+
636
790
  // src/generators/index.ts
637
791
  async function generateAll(ctx, overwrite = false) {
638
792
  const result = {
@@ -646,6 +800,7 @@ async function generateAll(ctx, overwrite = false) {
646
800
  generateSkills,
647
801
  generateRules,
648
802
  generateMemoryBank,
803
+ generateHooks,
649
804
  generateInfra
650
805
  ];
651
806
  for (const generator of generators) {
@@ -665,7 +820,7 @@ async function generateAll(ctx, overwrite = false) {
665
820
  async function initCommand(options) {
666
821
  const targetDir = process.cwd();
667
822
  console.log();
668
- console.log(chalk.bold(" agent-forge v1.0.0"));
823
+ console.log(chalk.bold(" agent-forge v3.0.0"));
669
824
  console.log(chalk.dim(" AI-driven Development Framework for Claude Code"));
670
825
  console.log();
671
826
  let ctx;
@@ -708,7 +863,7 @@ async function initCommand(options) {
708
863
  }
709
864
 
710
865
  // src/commands/doctor.ts
711
- import path9 from "path";
866
+ import path10 from "path";
712
867
  import chalk2 from "chalk";
713
868
  async function doctorCommand() {
714
869
  const targetDir = process.cwd();
@@ -716,7 +871,7 @@ async function doctorCommand() {
716
871
  console.log(chalk2.bold(" agent-forge doctor"));
717
872
  console.log(chalk2.dim(" Checking project structure integrity..."));
718
873
  console.log();
719
- const manifestPath = path9.join(targetDir, ".claude-forge.json");
874
+ const manifestPath = path10.join(targetDir, ".claude-forge.json");
720
875
  const manifestExists = await fileExists(manifestPath);
721
876
  if (!manifestExists) {
722
877
  console.log(chalk2.red(" .claude-forge.json not found"));
@@ -739,7 +894,7 @@ async function doctorCommand() {
739
894
  let okCount = 0;
740
895
  let failCount = 0;
741
896
  for (const file of manifest.expectedFiles) {
742
- const filePath = path9.join(targetDir, file);
897
+ const filePath = path10.join(targetDir, file);
743
898
  const exists = await fileExists(filePath);
744
899
  const check = {
745
900
  name: file,
@@ -799,10 +954,152 @@ async function doctorCommand() {
799
954
  }
800
955
  }
801
956
 
957
+ // src/commands/update.ts
958
+ import path11 from "path";
959
+ import chalk3 from "chalk";
960
+ import ora2 from "ora";
961
+ function today2() {
962
+ return (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
963
+ }
964
+ function contextFromManifest(manifest, targetDir) {
965
+ return {
966
+ projectName: manifest.projectName || targetDir.split("/").pop() || "my-project",
967
+ projectDescription: manifest.projectDescription || "AI-driven project",
968
+ stack: manifest.stack || "typescript",
969
+ framework: manifest.framework || "None",
970
+ testFramework: manifest.testFramework || "vitest",
971
+ testCommand: manifest.testCommand || "npx vitest run",
972
+ srcDir: manifest.srcDir || "src/",
973
+ testDir: manifest.testDir || "tests/",
974
+ team: [],
975
+ milestones: [],
976
+ agentPreset: manifest.agentPreset || "core",
977
+ language: manifest.language || "ru",
978
+ commitStyle: manifest.commitStyle || "standard",
979
+ today: today2(),
980
+ targetDir
981
+ };
982
+ }
983
+ async function updateCommand() {
984
+ const targetDir = process.cwd();
985
+ console.log();
986
+ console.log(chalk3.bold(" agent-forge update v3.0.0"));
987
+ console.log(chalk3.dim(" Updating framework files..."));
988
+ console.log();
989
+ const manifestPath = path11.join(targetDir, ".claude-forge.json");
990
+ const manifestExists = await fileExists(manifestPath);
991
+ if (!manifestExists) {
992
+ console.log(chalk3.red(" .claude-forge.json not found"));
993
+ console.log(
994
+ chalk3.dim(" This project is not initialized. Run `agent-forge init` first.")
995
+ );
996
+ console.log();
997
+ process.exit(1);
998
+ }
999
+ const manifestRaw = await readFile(manifestPath);
1000
+ let existingManifest;
1001
+ try {
1002
+ existingManifest = JSON.parse(manifestRaw);
1003
+ } catch {
1004
+ console.log(chalk3.red(" .claude-forge.json is corrupted. Cannot update."));
1005
+ console.log(
1006
+ chalk3.dim(" Run `agent-forge init --overwrite` to reinitialize.")
1007
+ );
1008
+ console.log();
1009
+ process.exit(1);
1010
+ }
1011
+ const previousVersion = existingManifest.version || "unknown";
1012
+ const ctx = contextFromManifest(existingManifest, targetDir);
1013
+ const spinner = ora2("Updating framework files...").start();
1014
+ try {
1015
+ const result = {
1016
+ filesCreated: [],
1017
+ filesSkipped: [],
1018
+ errors: []
1019
+ };
1020
+ const frameworkGenerators = [
1021
+ generateClaudeMd,
1022
+ generateAgents,
1023
+ generateSkills,
1024
+ generateRules,
1025
+ generateHooks
1026
+ ];
1027
+ for (const generator of frameworkGenerators) {
1028
+ try {
1029
+ const partial = await generator(ctx, true);
1030
+ result.filesCreated.push(...partial.filesCreated);
1031
+ result.filesSkipped.push(...partial.filesSkipped);
1032
+ result.errors.push(...partial.errors);
1033
+ } catch (err) {
1034
+ result.errors.push(`Generator error: ${err}`);
1035
+ }
1036
+ }
1037
+ const userDataGenerators = [
1038
+ generateMemoryBank,
1039
+ generateInfra
1040
+ ];
1041
+ for (const generator of userDataGenerators) {
1042
+ try {
1043
+ const partial = await generator(ctx, false);
1044
+ result.filesCreated.push(...partial.filesCreated);
1045
+ result.filesSkipped.push(...partial.filesSkipped);
1046
+ result.errors.push(...partial.errors);
1047
+ } catch (err) {
1048
+ result.errors.push(`Generator error: ${err}`);
1049
+ }
1050
+ }
1051
+ const updatedManifest = buildManifest(ctx);
1052
+ updatedManifest.createdAt = existingManifest.createdAt || updatedManifest.createdAt;
1053
+ updatedManifest.updatedAt = today2();
1054
+ await writeFileSafe(
1055
+ manifestPath,
1056
+ JSON.stringify(updatedManifest, null, 2) + "\n",
1057
+ true
1058
+ );
1059
+ spinner.succeed(chalk3.green("Framework files updated"));
1060
+ const newFiles = result.filesCreated.filter((f) => !result.filesSkipped.includes(f));
1061
+ const updatedCount = newFiles.length;
1062
+ const skippedCount = result.filesSkipped.length;
1063
+ console.log();
1064
+ if (updatedCount > 0) {
1065
+ console.log(
1066
+ chalk3.green(` + ${updatedCount} files updated/added`)
1067
+ );
1068
+ }
1069
+ if (skippedCount > 0) {
1070
+ console.log(
1071
+ chalk3.yellow(` ~ ${skippedCount} files skipped (user data preserved)`)
1072
+ );
1073
+ }
1074
+ if (result.errors.length > 0) {
1075
+ console.log(chalk3.red(` ! ${result.errors.length} errors:`));
1076
+ for (const err of result.errors) {
1077
+ console.log(chalk3.red(` - ${err}`));
1078
+ }
1079
+ }
1080
+ console.log();
1081
+ if (previousVersion !== updatedManifest.version) {
1082
+ console.log(
1083
+ chalk3.dim(` .claude-forge.json updated: ${previousVersion} -> v${updatedManifest.version}`)
1084
+ );
1085
+ } else {
1086
+ console.log(
1087
+ chalk3.dim(` .claude-forge.json updated (v${updatedManifest.version})`)
1088
+ );
1089
+ }
1090
+ console.log();
1091
+ } catch (err) {
1092
+ spinner.fail(chalk3.red("Failed to update framework files"));
1093
+ console.error(err);
1094
+ process.exit(1);
1095
+ }
1096
+ }
1097
+
802
1098
  // src/index.ts
803
1099
  var program = new Command();
804
- program.name("agent-forge").description("AI-driven Development Framework for Claude Code").version("1.0.0");
1100
+ program.name("agent-forge").description("AI-driven Development Framework for Claude Code").version("3.0.0");
805
1101
  program.command("init").description("Initialize AI-driven development infrastructure in the current project").option("-y, --yes", "Skip prompts and use defaults").option("--overwrite", "Overwrite existing files").action(initCommand);
806
1102
  program.command("doctor").description("Check integrity of the generated structure").action(doctorCommand);
1103
+ program.command("update").description("Update framework files to the latest version (preserves user data)").action(updateCommand);
807
1104
  program.parse();
808
1105
  //# sourceMappingURL=index.js.map