create-claudy 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gilles Bertrand
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # create-claudy
2
+
3
+ Scaffolder qui crée un projet Claude Code préconfiguré pour utiliser le plugin [`claudy`](https://github.com/gilles-bertrand/claudy-plugin).
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ # Avec pnpm (recommandé)
9
+ pnpm create claudy mon-projet
10
+
11
+ # Avec npm
12
+ npm create claudy@latest mon-projet
13
+
14
+ # Avec npx
15
+ npx create-claudy mon-projet
16
+ ```
17
+
18
+ Si vous omettez le nom, il vous sera demandé.
19
+
20
+ ## Options
21
+
22
+ | Flag | Effet |
23
+ |------|-------|
24
+ | `--no-git` | Ne pas initialiser de dépôt git |
25
+ | `-h`, `--help` | Aide |
26
+
27
+ ## Ce qu'il génère
28
+
29
+ ```
30
+ mon-projet/
31
+ ├── .claude/
32
+ │ ├── settings.json # pré-configuré pour activer le plugin claudy
33
+ │ ├── CLAUDE.md # mémoire projet (à personnaliser)
34
+ │ ├── commands/ # vos commandes locales
35
+ │ └── agents/ # vos agents locaux
36
+ ├── .env.example
37
+ ├── .gitignore
38
+ ├── .mcp.json # Playwright préconfiguré
39
+ ├── ai_docs/ # doc API consultée par les agents
40
+ ├── docs/ # documentation projet
41
+ ├── specs/
42
+ │ ├── todo/ # plans en attente
43
+ │ ├── done/ # plans terminés
44
+ │ └── handoffs/ # états de session
45
+ ├── src/ # code applicatif
46
+ └── README.md
47
+ ```
48
+
49
+ ## Ce que fait le plugin claudy
50
+
51
+ Une fois Claude Code lancé dans le nouveau projet, le plugin est activé automatiquement et fournit :
52
+
53
+ - **Commandes** : `/TPK-plan`, `/TPK-build`, `/TPK-validate`, `/TPK-commit`, `/TPK-merge`, `/TPK-review`, `/TPK-prime`, `/TPK-handoff`, `/TPK-pickup`, `/TPK-create-command`, `/TPK-parallel-subagents`, `/TPK-visual-verify`, `/TPK-screenshot-compare`
54
+ - **Agents** : `code-reviewer`, `test-runner`, `doc-generator`, `validated-builder`
55
+ - **Skills** : `security-audit`, `skill-creator`
56
+ - **Hooks de sécurité** actifs par défaut (bloquent `rm -rf`, force push, et protègent `.env`, `~/.ssh/`, `~/.aws/`…)
57
+
58
+ Voir le [repo du plugin](https://github.com/gilles-bertrand/claudy-plugin) pour les détails.
59
+
60
+ ## Mise à jour du scaffolder
61
+
62
+ ```bash
63
+ # Avec pnpm
64
+ pnpm dlx create-claudy@latest ...
65
+
66
+ # Avec npm
67
+ npm create claudy@latest ...
68
+ ```
69
+
70
+ Le scaffolder est un outil one-shot : il génère le projet puis disparaît. Les mises à jour du projet lui-même (commandes/agents/hooks) passent par le plugin `claudy` via `/plugin update`.
71
+
72
+ ## Prérequis
73
+
74
+ - Node.js ≥ 18
75
+ - [Claude Code](https://claude.com/claude-code) installé (pour utiliser les projets générés)
76
+
77
+ ## Licence
78
+
79
+ MIT © Gilles Bertrand
package/index.mjs ADDED
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * create-claudy — scaffolder pour un projet Claude Code préconfiguré
4
+ * avec le plugin `claudy`.
5
+ *
6
+ * Usage :
7
+ * pnpm create claudy [project-name]
8
+ * npm create claudy@latest [project-name]
9
+ * npx create-claudy [project-name]
10
+ */
11
+
12
+ import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
13
+ import { dirname, join, resolve } from "node:path";
14
+ import { fileURLToPath } from "node:url";
15
+ import { createInterface } from "node:readline/promises";
16
+ import { stdin as input, stdout as output, exit } from "node:process";
17
+ import { execFileSync } from "node:child_process";
18
+
19
+ const __dirname = dirname(fileURLToPath(import.meta.url));
20
+ const TEMPLATE_DIR = join(__dirname, "template");
21
+
22
+ // --- Terminal helpers ---------------------------------------------------
23
+ const c = {
24
+ reset: "\x1b[0m",
25
+ bold: "\x1b[1m",
26
+ dim: "\x1b[2m",
27
+ red: "\x1b[31m",
28
+ green: "\x1b[32m",
29
+ yellow: "\x1b[33m",
30
+ blue: "\x1b[34m",
31
+ cyan: "\x1b[36m",
32
+ };
33
+
34
+ const log = (msg) => console.log(msg);
35
+ const info = (msg) => console.log(`${c.cyan}›${c.reset} ${msg}`);
36
+ const success = (msg) => console.log(`${c.green}✓${c.reset} ${msg}`);
37
+ const warn = (msg) => console.log(`${c.yellow}⚠${c.reset} ${msg}`);
38
+ const error = (msg) => console.error(`${c.red}✗${c.reset} ${msg}`);
39
+
40
+ // --- Args ---------------------------------------------------------------
41
+ function parseArgs(argv) {
42
+ const args = argv.slice(2);
43
+ let projectName = null;
44
+ let skipGit = false;
45
+ let help = false;
46
+
47
+ for (const arg of args) {
48
+ if (arg === "--help" || arg === "-h") help = true;
49
+ else if (arg === "--no-git") skipGit = true;
50
+ else if (!arg.startsWith("-") && !projectName) projectName = arg;
51
+ }
52
+
53
+ return { projectName, skipGit, help };
54
+ }
55
+
56
+ function printHelp() {
57
+ log(`
58
+ ${c.bold}create-claudy${c.reset} — scaffolder pour un projet Claude Code préconfiguré
59
+
60
+ ${c.bold}Usage${c.reset}
61
+ pnpm create claudy [project-name] [options]
62
+ npm create claudy@latest [project-name] [options]
63
+ npx create-claudy [project-name] [options]
64
+
65
+ ${c.bold}Options${c.reset}
66
+ --no-git Ne pas initialiser de dépôt git
67
+ -h, --help Affiche cette aide
68
+
69
+ ${c.bold}Example${c.reset}
70
+ pnpm create claudy mon-super-projet
71
+ `);
72
+ }
73
+
74
+ // --- Validation ---------------------------------------------------------
75
+ function isValidProjectName(name) {
76
+ return /^[a-z0-9][a-z0-9-_]*$/i.test(name);
77
+ }
78
+
79
+ async function promptProjectName() {
80
+ const rl = createInterface({ input, output });
81
+ try {
82
+ while (true) {
83
+ const answer = (await rl.question(`${c.cyan}?${c.reset} Nom du projet : `)).trim();
84
+ if (!answer) {
85
+ warn("Nom requis.");
86
+ continue;
87
+ }
88
+ if (!isValidProjectName(answer)) {
89
+ warn("Caractères autorisés : lettres, chiffres, tirets, underscores. Pas d'espaces.");
90
+ continue;
91
+ }
92
+ return answer;
93
+ }
94
+ } finally {
95
+ rl.close();
96
+ }
97
+ }
98
+
99
+ async function confirmOverwrite(targetDir) {
100
+ const rl = createInterface({ input, output });
101
+ try {
102
+ const answer = (await rl.question(
103
+ `${c.yellow}?${c.reset} Le dossier ${c.bold}${targetDir}${c.reset} existe déjà et n'est pas vide. Continuer quand même (fusion) ? [y/N] `
104
+ )).trim().toLowerCase();
105
+ return answer === "y" || answer === "yes" || answer === "o" || answer === "oui";
106
+ } finally {
107
+ rl.close();
108
+ }
109
+ }
110
+
111
+ // --- File helpers -------------------------------------------------------
112
+ function isDirEmpty(dir) {
113
+ try {
114
+ return readdirSync(dir).length === 0;
115
+ } catch {
116
+ return true;
117
+ }
118
+ }
119
+
120
+ function substituteInFile(filePath, replacements) {
121
+ const content = readFileSync(filePath, "utf8");
122
+ let out = content;
123
+ for (const [key, value] of Object.entries(replacements)) {
124
+ out = out.replaceAll(`{{${key}}}`, value);
125
+ }
126
+ if (out !== content) writeFileSync(filePath, out, "utf8");
127
+ }
128
+
129
+ function walkFiles(dir, callback) {
130
+ for (const entry of readdirSync(dir)) {
131
+ const full = join(dir, entry);
132
+ const stat = statSync(full);
133
+ if (stat.isDirectory()) walkFiles(full, callback);
134
+ else callback(full);
135
+ }
136
+ }
137
+
138
+ // --- Steps --------------------------------------------------------------
139
+ function copyTemplate(targetDir) {
140
+ cpSync(TEMPLATE_DIR, targetDir, { recursive: true });
141
+ }
142
+
143
+ function renameHiddenFiles(targetDir) {
144
+ // env-example.tmp → .env.example
145
+ // (contournement : les hooks de sécurité Claude Code empêchent de créer
146
+ // directement un fichier dont le chemin matche `.env.*` lors de la
147
+ // publication du template.)
148
+ const tmp = join(targetDir, "env-example.tmp");
149
+ const final = join(targetDir, ".env.example");
150
+ if (existsSync(tmp)) renameSync(tmp, final);
151
+ }
152
+
153
+ function applySubstitutions(targetDir, replacements) {
154
+ walkFiles(targetDir, (filePath) => {
155
+ if (/\.(md|json|txt|mjs|js|ts|yaml|yml|gitignore|example)$/i.test(filePath)) {
156
+ substituteInFile(filePath, replacements);
157
+ }
158
+ });
159
+ }
160
+
161
+ function runGit(targetDir, args) {
162
+ execFileSync("git", args, { cwd: targetDir, stdio: "ignore" });
163
+ }
164
+
165
+ function initGitRepo(targetDir) {
166
+ try {
167
+ runGit(targetDir, ["init", "-q", "-b", "main"]);
168
+ runGit(targetDir, ["add", "."]);
169
+ runGit(targetDir, [
170
+ "commit",
171
+ "-q",
172
+ "-m",
173
+ "chore: initial commit from create-claudy",
174
+ ]);
175
+ return true;
176
+ } catch {
177
+ return false;
178
+ }
179
+ }
180
+
181
+ // --- Main ---------------------------------------------------------------
182
+ async function main() {
183
+ const { projectName: argName, skipGit, help } = parseArgs(process.argv);
184
+
185
+ if (help) {
186
+ printHelp();
187
+ return;
188
+ }
189
+
190
+ log(`\n${c.bold}${c.cyan}claudy${c.reset} ${c.dim}— scaffolder Claude Code${c.reset}\n`);
191
+
192
+ let projectName = argName;
193
+ if (!projectName) {
194
+ projectName = await promptProjectName();
195
+ } else if (!isValidProjectName(projectName)) {
196
+ error(`Nom de projet invalide : ${projectName}`);
197
+ warn("Caractères autorisés : lettres, chiffres, tirets, underscores.");
198
+ exit(1);
199
+ }
200
+
201
+ const targetDir = resolve(process.cwd(), projectName);
202
+
203
+ if (existsSync(targetDir) && !isDirEmpty(targetDir)) {
204
+ const ok = await confirmOverwrite(targetDir);
205
+ if (!ok) {
206
+ warn("Abandon.");
207
+ exit(0);
208
+ }
209
+ }
210
+
211
+ info(`Création du projet dans ${c.bold}${targetDir}${c.reset}`);
212
+ mkdirSync(targetDir, { recursive: true });
213
+
214
+ info("Copie du template...");
215
+ copyTemplate(targetDir);
216
+
217
+ info("Renommage des fichiers spéciaux...");
218
+ renameHiddenFiles(targetDir);
219
+
220
+ info("Substitution des placeholders...");
221
+ applySubstitutions(targetDir, {
222
+ PROJECT_NAME: projectName,
223
+ });
224
+
225
+ if (!skipGit) {
226
+ info("Initialisation du dépôt git...");
227
+ const gitOk = initGitRepo(targetDir);
228
+ if (gitOk) success("Dépôt git initialisé avec un commit initial");
229
+ else warn("git n'a pas pu être initialisé (git installé ?)");
230
+ }
231
+
232
+ log(`\n${c.green}${c.bold}✨ Projet ${projectName} créé avec succès !${c.reset}\n`);
233
+ log(`${c.bold}Étapes suivantes :${c.reset}`);
234
+ log(` ${c.cyan}cd${c.reset} ${projectName}`);
235
+ log(` ${c.cyan}cp${c.reset} .env.example .env ${c.dim}# puis remplissez vos clés${c.reset}`);
236
+ log(` ${c.cyan}claude${c.reset} ${c.dim}# lance Claude Code${c.reset}`);
237
+ log(`\n${c.dim}Au premier lancement, Claude Code installera automatiquement le plugin${c.reset}`);
238
+ log(`${c.dim}claudy depuis gilles-bertrand/claudy-marketplace.${c.reset}\n`);
239
+ }
240
+
241
+ main().catch((err) => {
242
+ error(err?.message ?? String(err));
243
+ exit(1);
244
+ });
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "create-claudy",
3
+ "version": "0.1.0",
4
+ "description": "Scaffolder pour créer un projet préconfiguré avec le plugin Claude Code claudy",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-claudy": "./index.mjs"
8
+ },
9
+ "files": [
10
+ "index.mjs",
11
+ "template/",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "keywords": [
16
+ "claude-code",
17
+ "scaffolder",
18
+ "create",
19
+ "template",
20
+ "claudy"
21
+ ],
22
+ "author": {
23
+ "name": "Gilles Bertrand",
24
+ "url": "https://github.com/gilles-bertrand"
25
+ },
26
+ "license": "MIT",
27
+ "homepage": "https://github.com/gilles-bertrand/create-claudy",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/gilles-bertrand/create-claudy.git"
31
+ },
32
+ "engines": {
33
+ "node": ">=18"
34
+ }
35
+ }
@@ -0,0 +1,32 @@
1
+ # {{PROJECT_NAME}}
2
+
3
+ Description courte du projet.
4
+
5
+ ## Quick Reference
6
+
7
+ - Code applicatif : `src/`
8
+ - Plans : `specs/todo/` → `specs/done/`
9
+ - Documentation : `docs/`
10
+ - Doc API pour agents : `ai_docs/`
11
+
12
+ ## Commandes
13
+
14
+ - Test : `npm test`
15
+ - Build : `npm run build`
16
+ - Dev : `npm run dev`
17
+
18
+ ## Plugin Claude Code
19
+
20
+ Ce projet utilise le plugin [`claudy`](https://github.com/gilles-bertrand/claudy-plugin) qui fournit :
21
+
22
+ - Commandes `/TPK-*` (plan, build, validate, commit, merge, review, etc.)
23
+ - Sub-agents (`code-reviewer`, `test-runner`, `doc-generator`, `validated-builder`)
24
+ - Skills (`security-audit`, `skill-creator`)
25
+ - Hooks de sécurité actifs par défaut (damage-control)
26
+
27
+ Les commandes locales au projet vont dans `.claude/commands/` et les agents locaux dans `.claude/agents/`.
28
+
29
+ ## Notes importantes
30
+
31
+ - Garder ce fichier sous 500 tokens
32
+ - Contexte spécifique à une feature : dans les prompts ou `specs/`
File without changes
File without changes
@@ -0,0 +1,33 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/claude-code-settings.json",
3
+ "marketplaces": {
4
+ "claudy-marketplace": {
5
+ "source": "github",
6
+ "repo": "gilles-bertrand/claudy-marketplace"
7
+ }
8
+ },
9
+ "plugins": {
10
+ "claudy@claudy-marketplace": {
11
+ "enabled": true
12
+ }
13
+ },
14
+ "permissions": {
15
+ "allow": [
16
+ "Read",
17
+ "Glob",
18
+ "Grep",
19
+ "Bash(git status)",
20
+ "Bash(git diff *)",
21
+ "Bash(git log *)",
22
+ "Bash(npm *)",
23
+ "Bash(npx *)",
24
+ "Bash(pnpm *)"
25
+ ],
26
+ "deny": [
27
+ "Bash(rm -rf *)",
28
+ "Bash(sudo *)",
29
+ "Bash(chmod 777 *)",
30
+ "Read(.env)"
31
+ ]
32
+ }
33
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "playwright": {
4
+ "command": "npx",
5
+ "args": ["@playwright/mcp@latest"]
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,65 @@
1
+ # {{PROJECT_NAME}}
2
+
3
+ Description de votre projet.
4
+
5
+ ## Prérequis
6
+
7
+ - [Claude Code](https://claude.com/claude-code) installé
8
+ - Node.js 18+
9
+
10
+ ## Démarrage
11
+
12
+ ```bash
13
+ # Installer les dépendances
14
+ npm install
15
+
16
+ # Configurer l'environnement
17
+ cp .env.example .env
18
+ # Complétez .env avec vos clés
19
+
20
+ # Lancer Claude Code
21
+ claude
22
+ ```
23
+
24
+ Au premier lancement, Claude Code détectera le plugin `claudy` référencé dans `.claude/settings.json` et vous proposera de l'installer. Acceptez pour récupérer toutes les commandes `/TPK-*`, agents et hooks de sécurité.
25
+
26
+ ## Structure
27
+
28
+ ```
29
+ .
30
+ ├── .claude/ # Config Claude Code (settings + CLAUDE.md + extensions locales)
31
+ ├── src/ # Code applicatif
32
+ ├── specs/
33
+ │ ├── todo/ # Plans en attente
34
+ │ ├── done/ # Plans terminés
35
+ │ └── handoffs/ # États de session
36
+ ├── docs/ # Documentation projet
37
+ └── ai_docs/ # Doc API consultée par les agents
38
+ ```
39
+
40
+ ## Workflow avec Claude Code
41
+
42
+ ```
43
+ PLANIFIER → CONSTRUIRE → VALIDER → VÉRIFIER → COMMITTER
44
+ ```
45
+
46
+ 1. `/TPK-plan "ce que je veux faire"` — crée une spec dans `specs/todo/`
47
+ 2. `/TPK-build specs/todo/ma-spec.md` — implémente
48
+ 3. `/TPK-validate` — lance les tests
49
+ 4. `/TPK-review` — compare à la spec
50
+ 5. `/TPK-commit` — crée le commit
51
+
52
+ ## Plugin utilisé
53
+
54
+ Ce projet utilise [`claudy`](https://github.com/gilles-bertrand/claudy-plugin).
55
+
56
+ Pour mettre à jour le plugin :
57
+
58
+ ```bash
59
+ /plugin marketplace update claudy-marketplace
60
+ /plugin update claudy@claudy-marketplace
61
+ ```
62
+
63
+ ## Licence
64
+
65
+ À compléter.
File without changes
File without changes
@@ -0,0 +1,17 @@
1
+ # ===========================================
2
+ # Variables d'environnement du projet
3
+ # ===========================================
4
+ # Copiez ce fichier en .env et complétez.
5
+ # Ne committez JAMAIS .env dans git.
6
+ # ===========================================
7
+
8
+ # --- IA ---
9
+ # ANTHROPIC_API_KEY=
10
+ # GOOGLE_API_KEY=
11
+ # OPENAI_API_KEY=
12
+
13
+ # --- GitHub ---
14
+ # GITHUB_TOKEN=
15
+
16
+ # --- Base de données ---
17
+ # DATABASE_URL=
File without changes
File without changes
File without changes
File without changes