@iconsulting-dev/forgekit 1.6.2 → 1.7.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 (27) hide show
  1. package/README.md +33 -6
  2. package/dist/generators/claude-code/__tests__/claude-code.test.d.ts +2 -0
  3. package/dist/generators/claude-code/__tests__/claude-code.test.d.ts.map +1 -0
  4. package/dist/generators/claude-code/__tests__/claude-code.test.js +116 -0
  5. package/dist/generators/claude-code/__tests__/claude-code.test.js.map +1 -0
  6. package/dist/generators/claude-code/index.d.ts +1 -1
  7. package/dist/generators/claude-code/index.d.ts.map +1 -1
  8. package/dist/generators/claude-code/index.js +57 -4
  9. package/dist/generators/claude-code/index.js.map +1 -1
  10. package/dist/templates/claude-code/CLAUDE.md.hbs +14 -9
  11. package/dist/templates/claude-code/hookify/block-dangerous-rm.local.md +11 -0
  12. package/dist/templates/claude-code/hookify/block-force-push.local.md +11 -0
  13. package/dist/templates/claude-code/hookify/block-no-verify.local.md +11 -0
  14. package/dist/templates/claude-code/hookify/stop-verify-tests.local.md.hbs +21 -0
  15. package/dist/templates/claude-code/hookify/warn-console-log.local.md +11 -0
  16. package/dist/templates/claude-code/hookify/warn-env-edit.local.md +11 -0
  17. package/dist/templates/claude-code/hookify/warn-no-test-before-commit.local.md.hbs +18 -0
  18. package/dist/templates/claude-code/hookify/warn-todo-fixme.local.md +11 -0
  19. package/dist/templates/claude-code/hooks/pre-bash.sh.hbs +36 -0
  20. package/dist/templates/claude-code/hooks/session-start.sh.hbs +15 -0
  21. package/dist/templates/claude-code/settings.json.hbs +45 -2
  22. package/dist/templates/claude-code/specify/constitution.md.hbs +31 -0
  23. package/dist/utils/template-engine.d.ts +1 -0
  24. package/dist/utils/template-engine.d.ts.map +1 -1
  25. package/dist/utils/template-engine.js +1 -1
  26. package/dist/utils/template-engine.js.map +1 -1
  27. package/package.json +1 -1
package/README.md CHANGED
@@ -90,8 +90,9 @@ mon-projet/
90
90
  ├── frontend/ # Angular 21 / PrimeNG 21
91
91
  ├── docker-compose.yml # PostgreSQL 17 + pgAdmin (+ service api si FastAPI)
92
92
  ├── .github/workflows/ # CI GitHub Actions
93
- ├── CLAUDE.md # Conventions Claude Code
94
- ├── .claude/settings.json # Permissions Claude Code
93
+ ├── CLAUDE.md # Conventions, workflow routing, constitution ref
94
+ ├── .claude/ # Hooks, hookify guards, skills, settings
95
+ ├── .specify/memory/ # Constitution architecturale
95
96
  ├── .gitignore
96
97
  └── README.md
97
98
  ```
@@ -196,9 +197,35 @@ frontend/src/app/
196
197
 
197
198
  ### Claude Code
198
199
 
199
- Génère automatiquement :
200
- - **`CLAUDE.md`** — Conventions du projet, commandes, structure, workflow speckit
201
- - **`.claude/settings.json`** — Permissions préconfigurées selon le backend choisi
200
+ Génère automatiquement une configuration complète et prête à l'emploi :
201
+
202
+ ```
203
+ mon-projet/
204
+ ├── CLAUDE.md # Workflow routing, TDD rules, constitution ref
205
+ ├── .claudeignore # Fichiers exclus du contexte Claude
206
+ ├── .claude/
207
+ │ ├── settings.json # Permissions + hooks (SessionStart, PreToolUse, PreCompact)
208
+ │ ├── hooks/
209
+ │ │ ├── pre-bash.sh # Guard bash (ex: bloque npm install hors frontend/)
210
+ │ │ └── session-start.sh # Auto-charge la constitution au démarrage
211
+ │ ├── hookify.block-dangerous-rm.local.md # Bloque rm -rf
212
+ │ ├── hookify.block-force-push.local.md # Bloque git push --force
213
+ │ ├── hookify.block-no-verify.local.md # Bloque --no-verify
214
+ │ ├── hookify.stop-verify-tests.local.md # Rappel TDD à la fin de session
215
+ │ ├── hookify.warn-console-log.local.md # Avertit sur console.log
216
+ │ ├── hookify.warn-env-edit.local.md # Avertit sur édition .env
217
+ │ ├── hookify.warn-no-test-before-commit.local.md # Rappel tests avant commit
218
+ │ ├── hookify.warn-todo-fixme.local.md # Avertit sur TODO/FIXME
219
+ │ └── skills/ # Skills copiés selon le stack
220
+ │ ├── applying-angular-conventions/SKILL.md # si frontend Angular
221
+ │ ├── applying-python-conventions/SKILL.md # si backend FastAPI
222
+ │ └── applying-java-conventions/SKILL.md # si backend Spring Boot
223
+ └── .specify/
224
+ └── memory/
225
+ └── constitution.md # Constitution architecturale (auto-chargée)
226
+ ```
227
+
228
+ Les skills sont copiés depuis `~/.claude/skills/` selon le stack sélectionné — chaque dev qui clone le projet dispose des mêmes conventions.
202
229
 
203
230
  ## Versions dynamiques
204
231
 
@@ -232,7 +259,7 @@ src/
232
259
  │ ├── fastapi/ # FastAPI (8 templates)
233
260
  │ ├── frontend/ # Angular (21 templates)
234
261
  │ ├── docker/ # Docker Compose
235
- │ ├── claude-code/ # CLAUDE.md + settings.json
262
+ │ ├── claude-code/ # CLAUDE.md, settings.json, hooks, hookify, specify
236
263
  │ ├── ci/ # GitHub Actions
237
264
  │ └── root/ # README + .gitignore
238
265
  ├── utils/
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=claude-code.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.test.d.ts","sourceRoot":"","sources":["../../../../src/generators/claude-code/__tests__/claude-code.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,116 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import fs from "fs-extra";
3
+ import path from "node:path";
4
+ import os from "node:os";
5
+ import { generateClaudeCode } from "../index.js";
6
+ // Fake global skills dir — seeded in beforeEach, used in skill tests
7
+ let fakeSkillsDir;
8
+ const baseConfig = {
9
+ name: "test-project",
10
+ groupId: "com.example",
11
+ description: "Test",
12
+ backendType: null,
13
+ frontend: false,
14
+ flyway: false,
15
+ openapi: false,
16
+ auth: false,
17
+ mapstruct: false,
18
+ uiFramework: "none",
19
+ primeNGPreset: "Aura",
20
+ ngrx: false,
21
+ docker: false,
22
+ ci: false,
23
+ claudeCode: true,
24
+ gitInit: false,
25
+ };
26
+ const baseVersions = {
27
+ springBoot: "3.4.0",
28
+ springDoc: "2.8.0",
29
+ mapstruct: "1.6.3",
30
+ angular: "19.0.0",
31
+ primeng: "19.0.0",
32
+ primeuixThemes: "2.0.3",
33
+ primeicons: "7.0.0",
34
+ primeflex: "3.3.1",
35
+ ngrxSignals: "19.0.0",
36
+ rxjs: "7.8.0",
37
+ zoneJs: "0.15.0",
38
+ typescript: "5.6.0",
39
+ tailwind: "4.0.0",
40
+ };
41
+ describe("ClaudeCodeGenerator", () => {
42
+ let tmpDir;
43
+ beforeEach(async () => {
44
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "forgekit-test-"));
45
+ fakeSkillsDir = path.join(tmpDir, "fake-skills");
46
+ for (const skill of [
47
+ "applying-angular-conventions",
48
+ "applying-python-conventions",
49
+ "applying-java-conventions",
50
+ ]) {
51
+ await fs.ensureDir(path.join(fakeSkillsDir, skill));
52
+ await fs.writeFile(path.join(fakeSkillsDir, skill, "SKILL.md"), `# ${skill}`);
53
+ }
54
+ });
55
+ afterEach(async () => {
56
+ await fs.remove(tmpDir);
57
+ });
58
+ it("generates hooks directory with scripts", async () => {
59
+ await generateClaudeCode(tmpDir, baseConfig, baseVersions);
60
+ expect(await fs.pathExists(path.join(tmpDir, ".claude", "hooks", "pre-bash.sh"))).toBe(true);
61
+ expect(await fs.pathExists(path.join(tmpDir, ".claude", "hooks", "session-start.sh"))).toBe(true);
62
+ });
63
+ it("makes hook scripts executable", async () => {
64
+ await generateClaudeCode(tmpDir, baseConfig, baseVersions);
65
+ const stat = await fs.stat(path.join(tmpDir, ".claude", "hooks", "pre-bash.sh"));
66
+ expect(stat.mode & 0o100).toBeTruthy();
67
+ });
68
+ it("generates hookify guard files", async () => {
69
+ await generateClaudeCode(tmpDir, baseConfig, baseVersions);
70
+ const hookifyFiles = [
71
+ "block-dangerous-rm.local.md",
72
+ "block-force-push.local.md",
73
+ "block-no-verify.local.md",
74
+ "stop-verify-tests.local.md",
75
+ "warn-console-log.local.md",
76
+ "warn-env-edit.local.md",
77
+ "warn-no-test-before-commit.local.md",
78
+ "warn-todo-fixme.local.md",
79
+ ];
80
+ for (const f of hookifyFiles) {
81
+ expect(await fs.pathExists(path.join(tmpDir, ".claude", `hookify.${f}`))).toBe(true);
82
+ }
83
+ });
84
+ it("generates .specify/memory/constitution.md", async () => {
85
+ await generateClaudeCode(tmpDir, baseConfig, baseVersions);
86
+ expect(await fs.pathExists(path.join(tmpDir, ".specify", "memory", "constitution.md"))).toBe(true);
87
+ });
88
+ it("settings.json contains hooks configuration", async () => {
89
+ await generateClaudeCode(tmpDir, baseConfig, baseVersions);
90
+ const settings = await fs.readJson(path.join(tmpDir, ".claude", "settings.json"));
91
+ expect(settings.hooks).toBeDefined();
92
+ expect(settings.hooks.SessionStart).toBeDefined();
93
+ expect(settings.hooks.PreToolUse).toBeDefined();
94
+ expect(settings.hooks.PreCompact).toBeDefined();
95
+ });
96
+ it("generates angular skill when frontend is enabled", async () => {
97
+ const config = { ...baseConfig, frontend: true };
98
+ await generateClaudeCode(tmpDir, config, baseVersions, fakeSkillsDir);
99
+ expect(await fs.pathExists(path.join(tmpDir, ".claude", "skills", "applying-angular-conventions", "SKILL.md"))).toBe(true);
100
+ });
101
+ it("generates python skill when fastapi backend", async () => {
102
+ const config = { ...baseConfig, backendType: "fastapi" };
103
+ await generateClaudeCode(tmpDir, config, baseVersions, fakeSkillsDir);
104
+ expect(await fs.pathExists(path.join(tmpDir, ".claude", "skills", "applying-python-conventions", "SKILL.md"))).toBe(true);
105
+ });
106
+ it("generates java skill when spring-boot backend", async () => {
107
+ const config = { ...baseConfig, backendType: "spring-boot" };
108
+ await generateClaudeCode(tmpDir, config, baseVersions, fakeSkillsDir);
109
+ expect(await fs.pathExists(path.join(tmpDir, ".claude", "skills", "applying-java-conventions", "SKILL.md"))).toBe(true);
110
+ });
111
+ it("generates no stack skills when claude-only (no backend, no frontend)", async () => {
112
+ await generateClaudeCode(tmpDir, baseConfig, baseVersions, fakeSkillsDir);
113
+ expect(await fs.pathExists(path.join(tmpDir, ".claude", "skills"))).toBe(false);
114
+ });
115
+ });
116
+ //# sourceMappingURL=claude-code.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.test.js","sourceRoot":"","sources":["../../../../src/generators/claude-code/__tests__/claude-code.test.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  import type { ProjectConfig } from "../../types.js";
2
2
  import type { ResolvedVersions } from "../../versions.js";
3
- export declare function generateClaudeCode(projectDir: string, config: ProjectConfig, versions: ResolvedVersions): Promise<void>;
3
+ export declare function generateClaudeCode(projectDir: string, config: ProjectConfig, versions: ResolvedVersions, globalSkillsBase?: string): Promise<void>;
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/generators/claude-code/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAwG1D,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,gBAAgB,GACzB,OAAO,CAAC,IAAI,CAAC,CAGf"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/generators/claude-code/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAkM1D,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,gBAAgB,EAC1B,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC,CAQf"}
@@ -1,12 +1,16 @@
1
1
  import path from "node:path";
2
+ import os from "node:os";
2
3
  import fs from "fs-extra";
3
- import { renderAndWrite } from "../../utils/template-engine.js";
4
+ import { renderAndWrite, TEMPLATES_DIR } from "../../utils/template-engine.js";
4
5
  import { BaseGenerator } from "../base-generator.js";
5
6
  class ClaudeCodeGenerator extends BaseGenerator {
6
7
  versions;
7
- constructor(projectDir, config, versions) {
8
+ globalSkillsBase;
9
+ constructor(projectDir, config, versions, globalSkillsBase) {
8
10
  super(projectDir, config);
9
11
  this.versions = versions;
12
+ this.globalSkillsBase =
13
+ globalSkillsBase ?? path.join(os.homedir(), ".claude", "skills");
10
14
  }
11
15
  async generate() {
12
16
  const claudeDir = path.join(this.projectDir, ".claude");
@@ -15,6 +19,9 @@ class ClaudeCodeGenerator extends BaseGenerator {
15
19
  const springBoot = this.config.backendType === "spring-boot";
16
20
  const fastapi = this.config.backendType === "fastapi";
17
21
  const backend = this.config.backendType !== null;
22
+ const hooksDir = path.join(claudeDir, "hooks");
23
+ await fs.ensureDir(hooksDir);
24
+ await fs.ensureDir(path.join(this.projectDir, ".specify", "memory"));
18
25
  const data = {
19
26
  name: this.config.name,
20
27
  description: this.config.description,
@@ -28,12 +35,58 @@ class ClaudeCodeGenerator extends BaseGenerator {
28
35
  auth: this.config.auth,
29
36
  versions: this.versions,
30
37
  allowedCommands,
38
+ claudeDir: ".claude",
31
39
  };
40
+ // Static hookify files (no templating needed)
41
+ const staticHookifyFiles = [
42
+ "block-dangerous-rm.local.md",
43
+ "block-force-push.local.md",
44
+ "block-no-verify.local.md",
45
+ "warn-console-log.local.md",
46
+ "warn-env-edit.local.md",
47
+ "warn-todo-fixme.local.md",
48
+ ];
32
49
  await Promise.all([
50
+ // Existing files
33
51
  renderAndWrite("claude-code/CLAUDE.md.hbs", path.join(this.projectDir, "CLAUDE.md"), data),
34
52
  renderAndWrite("claude-code/settings.json.hbs", path.join(claudeDir, "settings.json"), data),
35
53
  renderAndWrite("claude-code/claudeignore.hbs", path.join(this.projectDir, ".claudeignore"), data),
54
+ // Hook scripts (templated, then chmod)
55
+ renderAndWrite("claude-code/hooks/pre-bash.sh.hbs", path.join(hooksDir, "pre-bash.sh"), data, { mode: 0o755 }),
56
+ renderAndWrite("claude-code/hooks/session-start.sh.hbs", path.join(hooksDir, "session-start.sh"), data, { mode: 0o755 }),
57
+ // Templated hookify files
58
+ renderAndWrite("claude-code/hookify/stop-verify-tests.local.md.hbs", path.join(claudeDir, "hookify.stop-verify-tests.local.md"), data),
59
+ renderAndWrite("claude-code/hookify/warn-no-test-before-commit.local.md.hbs", path.join(claudeDir, "hookify.warn-no-test-before-commit.local.md"), data),
60
+ // .specify constitution
61
+ renderAndWrite("claude-code/specify/constitution.md.hbs", path.join(this.projectDir, ".specify", "memory", "constitution.md"), data),
62
+ // Static hookify files
63
+ ...staticHookifyFiles.map((f) => fs.copy(path.join(TEMPLATES_DIR, "claude-code", "hookify", f), path.join(claudeDir, `hookify.${f}`))),
36
64
  ]);
65
+ await this.generateSkills();
66
+ }
67
+ async generateSkills() {
68
+ const globalSkillsBase = this.globalSkillsBase;
69
+ const skillsToGenerate = [
70
+ { name: "applying-angular-conventions", condition: this.config.frontend },
71
+ {
72
+ name: "applying-python-conventions",
73
+ condition: this.config.backendType === "fastapi",
74
+ },
75
+ {
76
+ name: "applying-java-conventions",
77
+ condition: this.config.backendType === "spring-boot",
78
+ },
79
+ ];
80
+ for (const { name, condition } of skillsToGenerate) {
81
+ if (!condition)
82
+ continue;
83
+ const src = path.join(globalSkillsBase, name, "SKILL.md");
84
+ const dest = path.join(this.projectDir, ".claude", "skills", name, "SKILL.md");
85
+ if (await fs.pathExists(src)) {
86
+ await fs.ensureDir(path.dirname(dest));
87
+ await fs.copy(src, dest);
88
+ }
89
+ }
37
90
  }
38
91
  buildAllowedCommands() {
39
92
  const commands = [];
@@ -54,8 +107,8 @@ class ClaudeCodeGenerator extends BaseGenerator {
54
107
  return commands;
55
108
  }
56
109
  }
57
- export async function generateClaudeCode(projectDir, config, versions) {
58
- const generator = new ClaudeCodeGenerator(projectDir, config, versions);
110
+ export async function generateClaudeCode(projectDir, config, versions, globalSkillsBase) {
111
+ const generator = new ClaudeCodeGenerator(projectDir, config, versions, globalSkillsBase);
59
112
  await generator.generate();
60
113
  }
61
114
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/generators/claude-code/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD,MAAM,mBAAoB,SAAQ,aAAa;IAC5B,QAAQ,CAAmB;IAE5C,YACE,UAAkB,EAClB,MAAqB,EACrB,QAA0B;QAE1B,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QACxD,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAE9B,MAAM,eAAe,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAEpD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,KAAK,aAAa,CAAC;QAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS,CAAC;QACtD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,KAAK,IAAI,CAAC;QAEjD,MAAM,IAAI,GAAG;YACX,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;YACtB,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;YACpC,OAAO;YACP,UAAU;YACV,OAAO;YACP,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;YAC9B,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;YAC1B,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;YAC1B,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;YACtB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;YACtB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,eAAe;SAChB,CAAC;QAEF,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,cAAc,CACZ,2BAA2B,EAC3B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,EACvC,IAAI,CACL;YACD,cAAc,CACZ,+BAA+B,EAC/B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,EACrC,IAAI,CACL;YACD,cAAc,CACZ,8BAA8B,EAC9B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,EAC3C,IAAI,CACL;SACF,CAAC,CAAC;IACL,CAAC;IAEO,oBAAoB;QAC1B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,KAAK,aAAa,CAAC;QAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS,CAAC;QAEtD,IAAI,UAAU,EAAE,CAAC;YACf,QAAQ,CAAC,IAAI,CACX,8BAA8B,EAC9B,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,CACrB,CAAC;QACJ,CAAC;QAED,IAAI,OAAO,EAAE,CAAC;YACZ,QAAQ,CAAC,IAAI,CACX,qCAAqC,EACrC,cAAc,EACd,mBAAmB,EACnB,kBAAkB,CACnB,CAAC;QACJ,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACzB,QAAQ,CAAC,IAAI,CACX,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,CAChB,CAAC;QACJ,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACvB,QAAQ,CAAC,IAAI,CACX,yBAAyB,EACzB,2BAA2B,EAC3B,yBAAyB,CAC1B,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,UAAkB,EAClB,MAAqB,EACrB,QAA0B;IAE1B,MAAM,SAAS,GAAG,IAAI,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACxE,MAAM,SAAS,CAAC,QAAQ,EAAE,CAAC;AAC7B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/generators/claude-code/index.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,20 @@
18
18
  └── README.md
19
19
  ```
20
20
 
21
+ ## Workflow Routing (mandatory)
22
+
23
+ | Scenario | Action |
24
+ |---|---|
25
+ | New feature / non-trivial change | `/speckit.workflow` |
26
+ | Small fix (1-2 lines, docs-only) | Direct edit, no spec |
27
+ | Bug | Apply `superpowers:systematic-debugging` |
28
+ | UI component | Apply `frontend-design:frontend-design` skill |
29
+ | Commit / PR | Use `commit-commands:commit-push-pr` skill |
30
+
31
+ ## Architecture Constitution
32
+
33
+ Read `.specify/memory/constitution.md` before any architectural decision. It is auto-loaded at session start.
34
+
21
35
  {{#if springBoot}}
22
36
  ## Backend — Spring Boot {{versions.springBoot}}
23
37
 
@@ -90,15 +104,6 @@ docker compose down # Stop services
90
104
  - **pgAdmin:** localhost:5050 (admin@admin.com / admin)
91
105
 
92
106
  {{/if}}
93
- ## Workflow
94
-
95
- | Scenario | Action |
96
- |---|---|
97
- | New feature | `/speckit.workflow` — routes automatiquement (fast track ou full workflow spec→PR) |
98
- | Bug | Describe to Claude → apply `superpowers:systematic-debugging` |
99
- | UI component | Apply `frontend-design:frontend-design` skill |
100
- | Commit / PR | Use `commit-commands:commit-push-pr` skill |
101
-
102
107
  ## TDD
103
108
 
104
109
  Write the failing test first — no implementation code before a red test.
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: block-dangerous-rm
3
+ enabled: true
4
+ event: bash
5
+ pattern: rm\s+(-rf|-fr)
6
+ action: block
7
+ ---
8
+
9
+ ⚠️ **Commande rm -rf détectée**
10
+
11
+ Cette commande peut supprimer des fichiers de façon irréversible. Vérifie bien le chemin avant de continuer.
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: block-force-push
3
+ enabled: true
4
+ event: bash
5
+ pattern: git\s+push\s+.*--force(?!-with-lease)|git\s+push\s+.*\s-f\b
6
+ action: block
7
+ ---
8
+
9
+ 🚫 **git push --force bloqué**
10
+
11
+ Le force push est interdit sur ce projet. Utilise `--force-with-lease` si tu sais ce que tu fais, ou ouvre une PR à la place.
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: block-no-verify
3
+ enabled: true
4
+ event: bash
5
+ pattern: --no-verify
6
+ action: block
7
+ ---
8
+
9
+ 🚫 **--no-verify bloqué**
10
+
11
+ Le bypass des hooks de commit est interdit. Les tests et le lint doivent passer avant tout commit.
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: stop-verify-tests
3
+ enabled: true
4
+ event: stop
5
+ pattern: .*
6
+ action: warn
7
+ ---
8
+
9
+ ⚠️ **Avant de terminer — TDD check**
10
+
11
+ As-tu :
12
+ - [ ] Lancé les tests et vérifié qu'ils passent ?
13
+ {{#if fastapi}} - `cd backend && .venv/bin/pytest tests/ -v`
14
+ {{/if}}{{#if springBoot}} - `cd backend && ./mvnw test`
15
+ {{/if}}{{#if frontend}} - `cd frontend && npm test -- --watch=false`
16
+ {{/if}}- [ ] Lancé le lint ?
17
+ {{#if fastapi}} - `cd backend && .venv/bin/ruff check .`
18
+ {{/if}}{{#if springBoot}} - `cd backend && ./mvnw checkstyle:check` (if configured)
19
+ {{/if}}{{#if frontend}} - `cd frontend && npm run lint`
20
+ {{/if}}
21
+ Iron law : aucun commit sans tests verts.
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: warn-console-log
3
+ enabled: true
4
+ event: file
5
+ pattern: console\.log\(
6
+ action: warn
7
+ ---
8
+
9
+ ⚠️ **console.log detected**
10
+
11
+ You're about to add a `console.log` statement. Make sure this is intentional and not a debug leftover.
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: warn-env-edit
3
+ enabled: true
4
+ event: file
5
+ pattern: (^|/)\.env(\.|$)
6
+ action: warn
7
+ ---
8
+
9
+ ⚠️ **Fichier .env détecté**
10
+
11
+ Tu es sur le point de modifier un fichier d'environnement. Assure-toi de ne pas committer de secrets — utilise `.env.example` pour les valeurs de référence.
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: warn-no-test-before-commit
3
+ enabled: true
4
+ event: bash
5
+ pattern: git\s+commit
6
+ action: warn
7
+ ---
8
+
9
+ ⚠️ **Commit détecté — tests lancés ?**
10
+
11
+ Avant de committer, confirme :
12
+ {{#if fastapi}}- [ ] `cd backend && .venv/bin/pytest tests/ -v` → vert
13
+ {{/if}}{{#if springBoot}}- [ ] `cd backend && ./mvnw test` → vert
14
+ {{/if}}{{#if frontend}}- [ ] `cd frontend && npm test -- --watch=false` → vert
15
+ {{/if}}{{#if fastapi}}- [ ] `cd backend && .venv/bin/ruff check .` → propre
16
+ {{/if}}{{#if frontend}}- [ ] `cd frontend && npm run lint` → propre
17
+ {{/if}}
18
+ Iron law : aucun commit sans tests verts.
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: warn-todo-fixme
3
+ enabled: true
4
+ event: file
5
+ pattern: TODO|FIXME
6
+ action: warn
7
+ ---
8
+
9
+ ⚠️ **TODO / FIXME détecté**
10
+
11
+ Tu ajoutes un marqueur TODO ou FIXME. Assure-toi qu'il ne sera pas oublié avant de committer.
@@ -0,0 +1,36 @@
1
+ #!/bin/bash
2
+ # Hook: PreToolUse (Bash) — {{name}} project guards.
3
+ # Exit 2 = block | Exit 0 = allow
4
+
5
+ COMMAND=$(jq -r '.tool_input.command // ""')
6
+
7
+ # Strip heredoc bodies so patterns don't match inside commit messages.
8
+ COMMAND_STRIPPED=$(echo "$COMMAND" | awk '
9
+ /<</ {
10
+ tmp = $0
11
+ gsub(/^.*<<'"'"'?/, "", tmp)
12
+ gsub(/[^A-Za-z_0-9].*$/, "", tmp)
13
+ delim = tmp
14
+ in_hd = 1; print; next
15
+ }
16
+ in_hd { if ($0 == delim) in_hd = 0; next }
17
+ { print }
18
+ ')
19
+ {{#if frontend}}
20
+
21
+ # Block: npm install / uninstall outside frontend/
22
+ if echo "$COMMAND_STRIPPED" | grep -qE '(^|[;&|[:space:]])npm[[:space:]]+(install|i|uninstall|un)(\s|$)'; then
23
+ current_dir=$(pwd)
24
+ in_frontend=0
25
+ if echo "$current_dir" | grep -qE '/frontend(/|$)'; then
26
+ in_frontend=1
27
+ fi
28
+ if echo "$COMMAND_STRIPPED" | grep -qE '(^|[;&|[:space:]])cd[[:space:]]+([^;&|]*\/)?frontend([[:space:]]|$|/)'; then
29
+ in_frontend=1
30
+ fi
31
+ if [ "$in_frontend" -eq 0 ]; then
32
+ echo "BLOCKED: 'npm install' is only allowed inside frontend/. Run: cd frontend && npm install" >&2
33
+ exit 2
34
+ fi
35
+ fi
36
+ {{/if}}
@@ -0,0 +1,15 @@
1
+ #!/bin/bash
2
+ # Hook: SessionStart (once: true) — loads project constitution into context once per session.
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
+ REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null)"
6
+ if [ -z "$REPO_ROOT" ]; then
7
+ exit 0
8
+ fi
9
+ CONSTITUTION="$REPO_ROOT/.specify/memory/constitution.md"
10
+
11
+ if [ -f "$CONSTITUTION" ]; then
12
+ echo "=== {{name}} Architecture Constitution (auto-loaded) ==="
13
+ cat "$CONSTITUTION"
14
+ echo "=== End Constitution ==="
15
+ fi
@@ -2,9 +2,52 @@
2
2
  "permissions": {
3
3
  "allow": [
4
4
  {{#each allowedCommands}}
5
- "{{this}}"{{#unless @last}},{{/unless}}
5
+ "{{this}}",
6
6
  {{/each}}
7
+ "Bash(.specify/scripts/bash/*)",
8
+ "Bash(git commit*)",
9
+ "Bash(gh *)",
10
+ "Skill(commit-commands:commit)",
11
+ "Skill(commit-commands:commit:*)",
12
+ "Skill(commit-commands:commit-push-pr)",
13
+ "WebFetch(domain:github.com)",
14
+ "WebFetch(domain:resources.anthropic.com)"
15
+ ]
16
+ },
17
+ "hooks": {
18
+ "SessionStart": [
19
+ {
20
+ "matcher": "",
21
+ "hooks": [
22
+ {
23
+ "type": "command",
24
+ "command": "{{claudeDir}}/hooks/session-start.sh",
25
+ "once": true
26
+ }
27
+ ]
28
+ }
7
29
  ],
8
- "defaultMode": "dontAsk"
30
+ "PreToolUse": [
31
+ {
32
+ "matcher": "Bash",
33
+ "hooks": [
34
+ {
35
+ "type": "command",
36
+ "command": "{{claudeDir}}/hooks/pre-bash.sh"
37
+ }
38
+ ]
39
+ }
40
+ ],
41
+ "PreCompact": [
42
+ {
43
+ "matcher": "",
44
+ "hooks": [
45
+ {
46
+ "type": "command",
47
+ "command": "echo 'Compaction: KEEP: file diffs, failing test errors, architecture decisions from constitution.md. DROP: passing test output, startup logs, install output, resolved discussions.'"
48
+ }
49
+ ]
50
+ }
51
+ ]
9
52
  }
10
53
  }
@@ -0,0 +1,31 @@
1
+ # {{name}} — Architecture Constitution
2
+
3
+ > Auto-loaded at session start via `.claude/hooks/session-start.sh`.
4
+ > Edit this file to document hard architectural constraints for your project.
5
+
6
+ ## Core Principles
7
+
8
+ ### I. [Your first principle]
9
+
10
+ Describe a non-negotiable architectural rule here. Example: "All data access MUST go through the repository layer. Direct DB queries in controllers are forbidden."
11
+
12
+ ### II. [Your second principle]
13
+
14
+ ...
15
+
16
+ ## Scope
17
+
18
+ ### In Scope
19
+ - [Feature A]
20
+ - [Feature B]
21
+
22
+ ### Out of Scope
23
+ - [Feature C — why excluded]
24
+
25
+ ## Key Decisions
26
+
27
+ Document architectural decisions here as they are made (or link to DECISIONS.md).
28
+
29
+ | # | Decision | Rationale |
30
+ |---|----------|-----------|
31
+ | 1 | Example: PostgreSQL over SQLite | Production-grade from day 1 |
@@ -1,3 +1,4 @@
1
+ export declare const TEMPLATES_DIR: string;
1
2
  export declare function renderTemplate(templatePath: string, data: Record<string, unknown>): string;
2
3
  export declare function renderAndWrite(templatePath: string, outputPath: string, data: Record<string, unknown>, options?: {
3
4
  mode?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"template-engine.d.ts","sourceRoot":"","sources":["../../src/utils/template-engine.ts"],"names":[],"mappings":"AAWA,wBAAgB,cAAc,CAC5B,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,CAKR;AAED,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1B,OAAO,CAAC,IAAI,CAAC,CAOf"}
1
+ {"version":3,"file":"template-engine.d.ts","sourceRoot":"","sources":["../../src/utils/template-engine.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,aAAa,QAA0C,CAAC;AAIrE,wBAAgB,cAAc,CAC5B,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,CAKR;AAED,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1B,OAAO,CAAC,IAAI,CAAC,CAOf"}
@@ -4,7 +4,7 @@ import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
7
- const TEMPLATES_DIR = path.join(__dirname, "..", "templates");
7
+ export const TEMPLATES_DIR = path.join(__dirname, "..", "templates");
8
8
  Handlebars.registerHelper("lowerCase", (str) => str.toLowerCase());
9
9
  export function renderTemplate(templatePath, data) {
10
10
  const fullPath = path.join(TEMPLATES_DIR, templatePath);
@@ -1 +1 @@
1
- {"version":3,"file":"template-engine.js","sourceRoot":"","sources":["../../src/utils/template-engine.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAC3C,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;AAE9D,UAAU,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;AAE3E,MAAM,UAAU,cAAc,CAC5B,YAAoB,EACpB,IAA6B;IAE7B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,YAAoB,EACpB,UAAkB,EAClB,IAA6B,EAC7B,OAA2B;IAE3B,MAAM,OAAO,GAAG,cAAc,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IACnD,IAAI,OAAO,EAAE,IAAI,EAAE,CAAC;QAClB,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;SAAM,CAAC;QACN,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"template-engine.js","sourceRoot":"","sources":["../../src/utils/template-engine.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAC3C,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;AAErE,UAAU,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;AAE3E,MAAM,UAAU,cAAc,CAC5B,YAAoB,EACpB,IAA6B;IAE7B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,YAAoB,EACpB,UAAkB,EAClB,IAA6B,EAC7B,OAA2B;IAE3B,MAAM,OAAO,GAAG,cAAc,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IACnD,IAAI,OAAO,EAAE,IAAI,EAAE,CAAC;QAClB,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;SAAM,CAAC;QACN,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iconsulting-dev/forgekit",
3
- "version": "1.6.2",
3
+ "version": "1.7.0",
4
4
  "description": "CLI de scaffolding full-stack pour projets Spring Boot + Angular",
5
5
  "type": "module",
6
6
  "bin": {