joycraft 0.3.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.
@@ -0,0 +1,552 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ SKILLS,
4
+ TEMPLATES,
5
+ hashContent,
6
+ writeVersion
7
+ } from "./chunk-IJ7SLXOI.js";
8
+
9
+ // src/init.ts
10
+ import { mkdirSync, existsSync as existsSync2, writeFileSync, readFileSync as readFileSync2 } from "fs";
11
+ import { join as join2, basename, resolve, dirname } from "path";
12
+
13
+ // src/detect.ts
14
+ import { readFileSync, existsSync } from "fs";
15
+ import { join } from "path";
16
+ function readFile(path) {
17
+ try {
18
+ return readFileSync(path, "utf-8");
19
+ } catch {
20
+ return null;
21
+ }
22
+ }
23
+ function detectNodeFramework(pkg) {
24
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
25
+ if (allDeps["next"]) return "Next.js";
26
+ if (allDeps["nuxt"]) return "Nuxt";
27
+ if (allDeps["@remix-run/node"] || allDeps["@remix-run/react"]) return "Remix";
28
+ if (allDeps["express"]) return "Express";
29
+ if (allDeps["fastify"]) return "Fastify";
30
+ if (allDeps["react"]) return "React";
31
+ if (allDeps["vue"]) return "Vue";
32
+ if (allDeps["svelte"]) return "Svelte";
33
+ return void 0;
34
+ }
35
+ function detectNodeTestFramework(pkg) {
36
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
37
+ if (allDeps["vitest"]) return "vitest";
38
+ if (allDeps["jest"]) return "jest";
39
+ if (allDeps["mocha"]) return "mocha";
40
+ return void 0;
41
+ }
42
+ function detectNodePackageManager(dir) {
43
+ if (existsSync(join(dir, "pnpm-lock.yaml"))) return "pnpm";
44
+ if (existsSync(join(dir, "yarn.lock"))) return "yarn";
45
+ if (existsSync(join(dir, "bun.lockb")) || existsSync(join(dir, "bun.lock"))) return "bun";
46
+ return "npm";
47
+ }
48
+ function detectNode(dir) {
49
+ const raw = readFile(join(dir, "package.json"));
50
+ if (raw === null) return null;
51
+ let pkg;
52
+ try {
53
+ pkg = JSON.parse(raw);
54
+ } catch {
55
+ return null;
56
+ }
57
+ const pm = detectNodePackageManager(dir);
58
+ const run = pm === "npm" ? "npm run" : pm;
59
+ const scripts = pkg.scripts ?? {};
60
+ const framework = detectNodeFramework(pkg);
61
+ const testFramework = detectNodeTestFramework(pkg);
62
+ const commands = {};
63
+ if (scripts.build) commands.build = `${run} build`;
64
+ else commands.build = `${run} build`;
65
+ if (scripts.test) commands.test = `${run} test`;
66
+ else if (testFramework) commands.test = `${run} test`;
67
+ else commands.test = `${pm === "npm" ? "npm" : pm} test`;
68
+ if (scripts.lint) commands.lint = `${run} lint`;
69
+ if (scripts.typecheck) commands.typecheck = `${run} typecheck`;
70
+ else if (pkg.devDependencies?.["typescript"]) {
71
+ commands.typecheck = "tsc --noEmit";
72
+ }
73
+ return {
74
+ language: "node",
75
+ packageManager: pm,
76
+ commands,
77
+ framework
78
+ };
79
+ }
80
+ function detectPythonFramework(content) {
81
+ if (/fastapi/i.test(content)) return "FastAPI";
82
+ if (/django/i.test(content)) return "Django";
83
+ if (/flask/i.test(content)) return "Flask";
84
+ return void 0;
85
+ }
86
+ function detectPython(dir) {
87
+ const pyproject = readFile(join(dir, "pyproject.toml"));
88
+ if (pyproject !== null) {
89
+ const isPoetry = /\[tool\.poetry\]/.test(pyproject);
90
+ const isUv = existsSync(join(dir, "uv.lock"));
91
+ let pm;
92
+ let run;
93
+ if (isUv) {
94
+ pm = "uv";
95
+ run = "uv run";
96
+ } else if (isPoetry) {
97
+ pm = "poetry";
98
+ run = "poetry run";
99
+ } else {
100
+ pm = "pip";
101
+ run = "python -m";
102
+ }
103
+ const framework = detectPythonFramework(pyproject);
104
+ const hasPytest = /pytest/i.test(pyproject);
105
+ return {
106
+ language: "python",
107
+ packageManager: pm,
108
+ commands: {
109
+ build: `${pm === "poetry" ? "poetry" : pm} build`,
110
+ test: hasPytest ? `${run} pytest` : `${run} pytest`,
111
+ lint: `${run} ruff check .`
112
+ },
113
+ framework
114
+ };
115
+ }
116
+ const requirements = readFile(join(dir, "requirements.txt"));
117
+ if (requirements !== null) {
118
+ const framework = detectPythonFramework(requirements);
119
+ return {
120
+ language: "python",
121
+ packageManager: "pip",
122
+ commands: {
123
+ build: "pip install -e .",
124
+ test: "python -m pytest",
125
+ lint: "python -m ruff check ."
126
+ },
127
+ framework
128
+ };
129
+ }
130
+ return null;
131
+ }
132
+ function detectRust(dir) {
133
+ const cargo = readFile(join(dir, "Cargo.toml"));
134
+ if (cargo === null) return null;
135
+ let framework;
136
+ if (/actix-web/.test(cargo)) framework = "Actix";
137
+ else if (/axum/.test(cargo)) framework = "Axum";
138
+ else if (/rocket/.test(cargo)) framework = "Rocket";
139
+ return {
140
+ language: "rust",
141
+ packageManager: "cargo",
142
+ commands: {
143
+ build: "cargo build",
144
+ test: "cargo test",
145
+ lint: "cargo clippy"
146
+ },
147
+ framework
148
+ };
149
+ }
150
+ function detectGo(dir) {
151
+ const gomod = readFile(join(dir, "go.mod"));
152
+ if (gomod === null) return null;
153
+ let framework;
154
+ if (/github\.com\/gin-gonic\/gin/.test(gomod)) framework = "Gin";
155
+ else if (/github\.com\/gofiber\/fiber/.test(gomod)) framework = "Fiber";
156
+ else if (/github\.com\/labstack\/echo/.test(gomod)) framework = "Echo";
157
+ return {
158
+ language: "go",
159
+ packageManager: "go",
160
+ commands: {
161
+ build: "go build ./...",
162
+ test: "go test ./...",
163
+ lint: "golangci-lint run"
164
+ },
165
+ framework
166
+ };
167
+ }
168
+ function detectSwift(dir) {
169
+ const pkg = readFile(join(dir, "Package.swift"));
170
+ if (pkg === null) return null;
171
+ return {
172
+ language: "swift",
173
+ packageManager: "swift",
174
+ commands: {
175
+ build: "swift build",
176
+ test: "swift test"
177
+ }
178
+ };
179
+ }
180
+ function detectMakefile(dir) {
181
+ const makefile = readFile(join(dir, "Makefile"));
182
+ if (makefile === null) return null;
183
+ const commands = {};
184
+ commands.build = "make build";
185
+ if (/^test:/m.test(makefile)) commands.test = "make test";
186
+ if (/^lint:/m.test(makefile)) commands.lint = "make lint";
187
+ return {
188
+ language: "unknown",
189
+ packageManager: "make",
190
+ commands
191
+ };
192
+ }
193
+ function detectDockerfile(dir) {
194
+ if (!existsSync(join(dir, "Dockerfile"))) return null;
195
+ return {
196
+ language: "unknown",
197
+ packageManager: "docker",
198
+ commands: {
199
+ build: "docker build ."
200
+ }
201
+ };
202
+ }
203
+ async function detectStack(dir) {
204
+ const detectors = [
205
+ detectNode,
206
+ detectPython,
207
+ detectRust,
208
+ detectGo,
209
+ detectSwift,
210
+ detectMakefile,
211
+ detectDockerfile
212
+ ];
213
+ for (const detect of detectors) {
214
+ const result = detect(dir);
215
+ if (result) return result;
216
+ }
217
+ return { language: "unknown", packageManager: "", commands: {} };
218
+ }
219
+
220
+ // src/improve-claude-md.ts
221
+ function generateCommandsBlock(stack) {
222
+ const lines = ["```bash"];
223
+ if (stack.commands.build) lines.push(`# Build
224
+ ${stack.commands.build}`);
225
+ if (stack.commands.test) lines.push(`# Test
226
+ ${stack.commands.test}`);
227
+ if (stack.commands.lint) lines.push(`# Lint
228
+ ${stack.commands.lint}`);
229
+ if (stack.commands.typecheck) lines.push(`# Type check
230
+ ${stack.commands.typecheck}`);
231
+ if (stack.commands.deploy) lines.push(`# Deploy
232
+ ${stack.commands.deploy}`);
233
+ lines.push("```");
234
+ return lines.join("\n");
235
+ }
236
+ function generateBoundariesSection() {
237
+ return `## Behavioral Boundaries
238
+
239
+ ### ALWAYS
240
+ - Run tests and type-check before committing
241
+ - Commit after completing each discrete task
242
+ - Follow existing code patterns and style
243
+
244
+ ### ASK FIRST
245
+ - Adding new dependencies
246
+ - Modifying database schema or data models
247
+ - Changing authentication or authorization flows
248
+ - Any destructive operation (deleting files, force-pushing)
249
+
250
+ ### NEVER
251
+ - Push to main branch without explicit approval
252
+ - Skip type-checking or linting
253
+ - Commit code that doesn't build
254
+ - Hardcode secrets, API keys, or credentials`;
255
+ }
256
+ function generateWorkflowSection(stack) {
257
+ return `## Development Workflow
258
+
259
+ ${generateCommandsBlock(stack)}`;
260
+ }
261
+ function generateArchitectureSection() {
262
+ return `## Architecture
263
+
264
+ _TODO: Add a brief description of your project's architecture and key directories._`;
265
+ }
266
+ function generateKeyFilesSection() {
267
+ return `## Key Files
268
+
269
+ | File | Purpose |
270
+ |------|---------|
271
+ | _TODO_ | _Add key files and their purposes_ |`;
272
+ }
273
+ function generateGotchasSection() {
274
+ return `## Common Gotchas
275
+
276
+ _TODO: Add any gotchas, quirks, or non-obvious behaviors that developers should know about._`;
277
+ }
278
+ function generateGettingStartedSection() {
279
+ return `## Getting Started with Joycraft
280
+
281
+ This project uses [Joycraft](https://github.com/maksutovic/joycraft) for AI development workflow. Available skills:
282
+
283
+ | Skill | Purpose |
284
+ |-------|---------|
285
+ | \`/tune\` | Assess your harness, apply upgrades, see path to Level 5 |
286
+ | \`/new-feature\` | Interview -> Feature Brief -> Atomic Specs |
287
+ | \`/interview\` | Lightweight brainstorm \u2014 yap about ideas, get a structured summary |
288
+ | \`/decompose\` | Break a brief into small, testable specs |
289
+ | \`/session-end\` | Capture discoveries, verify, commit |
290
+
291
+ Run \`/tune\` to see where your project stands and what to improve next.`;
292
+ }
293
+ function generateCLAUDEMd(projectName, stack) {
294
+ const frameworkNote = stack.framework ? ` (${stack.framework})` : "";
295
+ const langLabel = stack.language === "unknown" ? "" : ` | **Stack:** ${stack.language}${frameworkNote}`;
296
+ const lines = [
297
+ `# ${projectName}`,
298
+ "",
299
+ `**Component:** _TODO: describe what this project is_${langLabel}`,
300
+ "",
301
+ "---",
302
+ "",
303
+ generateBoundariesSection(),
304
+ "",
305
+ generateWorkflowSection(stack),
306
+ "",
307
+ generateArchitectureSection(),
308
+ "",
309
+ generateKeyFilesSection(),
310
+ "",
311
+ generateGotchasSection(),
312
+ "",
313
+ generateGettingStartedSection(),
314
+ ""
315
+ ];
316
+ return lines.join("\n");
317
+ }
318
+
319
+ // src/agents-md.ts
320
+ function generateCommandsBlock2(stack) {
321
+ const lines = ["```bash"];
322
+ if (stack.commands.build) lines.push(stack.commands.build);
323
+ if (stack.commands.test) lines.push(stack.commands.test);
324
+ if (stack.commands.lint) lines.push(stack.commands.lint);
325
+ if (stack.commands.typecheck) lines.push(stack.commands.typecheck);
326
+ if (stack.commands.deploy) lines.push(stack.commands.deploy);
327
+ lines.push("```");
328
+ return lines.join("\n");
329
+ }
330
+ function generateBoundariesSection2() {
331
+ return `## Behavioral Boundaries
332
+
333
+ ### ALWAYS
334
+ - Run tests and type-check before committing
335
+ - Follow existing code patterns and style
336
+
337
+ ### ASK FIRST
338
+ - Adding new dependencies
339
+ - Changing auth or data models
340
+ - Any destructive operation
341
+
342
+ ### NEVER
343
+ - Push to main without approval
344
+ - Skip tests or type-checking
345
+ - Hardcode secrets or credentials`;
346
+ }
347
+ function generateDevelopmentSection(stack) {
348
+ return `## Development
349
+
350
+ ${generateCommandsBlock2(stack)}`;
351
+ }
352
+ function generateArchitectureSection2() {
353
+ return `## Architecture
354
+
355
+ _TODO: Add a compact directory tree and one-paragraph summary._`;
356
+ }
357
+ function generateKeyFilesSection2() {
358
+ return `## Key Files
359
+
360
+ | File | Purpose |
361
+ |------|---------|
362
+ | _TODO_ | _Add key files_ |`;
363
+ }
364
+ function generateAgentsMd(projectName, stack) {
365
+ const frameworkNote = stack.framework ? ` (${stack.framework})` : "";
366
+ const langLabel = stack.language === "unknown" ? "" : ` | **Stack:** ${stack.language}${frameworkNote}`;
367
+ const lines = [
368
+ `# ${projectName}`,
369
+ "",
370
+ `**Component:** _TODO: describe what this project is_${langLabel}`,
371
+ "",
372
+ "> Auto-generated by Joycraft. See CLAUDE.md for detailed instructions.",
373
+ "",
374
+ "---",
375
+ "",
376
+ generateBoundariesSection2(),
377
+ "",
378
+ generateArchitectureSection2(),
379
+ "",
380
+ generateKeyFilesSection2(),
381
+ "",
382
+ generateDevelopmentSection(stack),
383
+ ""
384
+ ];
385
+ return lines.join("\n");
386
+ }
387
+
388
+ // src/init.ts
389
+ function ensureDir(dir) {
390
+ if (!existsSync2(dir)) {
391
+ mkdirSync(dir, { recursive: true });
392
+ }
393
+ }
394
+ function writeFile(path, content, force, result) {
395
+ if (existsSync2(path) && !force) {
396
+ result.skipped.push(path);
397
+ return;
398
+ }
399
+ writeFileSync(path, content, "utf-8");
400
+ result.created.push(path);
401
+ }
402
+ async function init(dir, opts) {
403
+ const targetDir = resolve(dir);
404
+ const result = { created: [], skipped: [], modified: [], warnings: [] };
405
+ const stack = await detectStack(targetDir);
406
+ const docsDirs = ["briefs", "specs", "discoveries", "contracts", "decisions"];
407
+ for (const sub of docsDirs) {
408
+ ensureDir(join2(targetDir, "docs", sub));
409
+ }
410
+ const skillsDir = join2(targetDir, ".claude", "skills");
411
+ for (const [filename, content] of Object.entries(SKILLS)) {
412
+ const skillName = filename.replace(/\.md$/, "");
413
+ const skillDir = join2(skillsDir, skillName);
414
+ ensureDir(skillDir);
415
+ writeFile(join2(skillDir, "SKILL.md"), content, opts.force, result);
416
+ }
417
+ const templatesDir = join2(targetDir, "docs", "templates");
418
+ ensureDir(templatesDir);
419
+ for (const [filename, content] of Object.entries(TEMPLATES)) {
420
+ ensureDir(dirname(join2(templatesDir, filename)));
421
+ writeFile(join2(templatesDir, filename), content, opts.force, result);
422
+ }
423
+ const claudeMdPath = join2(targetDir, "CLAUDE.md");
424
+ if (existsSync2(claudeMdPath) && !opts.force) {
425
+ result.skipped.push(claudeMdPath);
426
+ } else {
427
+ const projectName = basename(targetDir);
428
+ const content = generateCLAUDEMd(projectName, stack);
429
+ writeFileSync(claudeMdPath, content, "utf-8");
430
+ result.created.push(claudeMdPath);
431
+ }
432
+ const agentsMdPath = join2(targetDir, "AGENTS.md");
433
+ if (existsSync2(agentsMdPath) && !opts.force) {
434
+ result.skipped.push(agentsMdPath);
435
+ } else {
436
+ const projectName = basename(targetDir);
437
+ const content = generateAgentsMd(projectName, stack);
438
+ writeFileSync(agentsMdPath, content, "utf-8");
439
+ result.created.push(agentsMdPath);
440
+ }
441
+ const fileHashes = {};
442
+ for (const [filename, content] of Object.entries(SKILLS)) {
443
+ const skillName = filename.replace(/\.md$/, "");
444
+ fileHashes[join2(".claude", "skills", skillName, "SKILL.md")] = hashContent(content);
445
+ }
446
+ for (const [filename, content] of Object.entries(TEMPLATES)) {
447
+ fileHashes[join2("docs", "templates", filename)] = hashContent(content);
448
+ }
449
+ writeVersion(targetDir, "0.1.0", fileHashes);
450
+ const hooksDir = join2(targetDir, ".claude", "hooks");
451
+ ensureDir(hooksDir);
452
+ const hookScript = `// Joycraft version check \u2014 runs on Claude Code session start
453
+ import { readFileSync } from 'node:fs';
454
+ import { join } from 'node:path';
455
+ try {
456
+ const data = JSON.parse(readFileSync(join(process.cwd(), '.joycraft-version'), 'utf-8'));
457
+ const res = await fetch('https://registry.npmjs.org/joycraft/latest', { signal: AbortSignal.timeout(3000) });
458
+ if (res.ok) {
459
+ const latest = (await res.json()).version;
460
+ if (data.version !== latest) console.log('Joycraft ' + latest + ' available (you have ' + data.version + '). Run: npx joycraft upgrade');
461
+ }
462
+ } catch {}
463
+ `;
464
+ writeFile(join2(hooksDir, "joycraft-version-check.mjs"), hookScript, opts.force, result);
465
+ const settingsPath = join2(targetDir, ".claude", "settings.json");
466
+ let settings = {};
467
+ if (existsSync2(settingsPath)) {
468
+ try {
469
+ settings = JSON.parse(readFileSync2(settingsPath, "utf-8"));
470
+ } catch {
471
+ }
472
+ }
473
+ if (!settings.hooks) settings.hooks = {};
474
+ const hooksConfig = settings.hooks;
475
+ if (!hooksConfig.SessionStart) hooksConfig.SessionStart = [];
476
+ const sessionStartHooks = hooksConfig.SessionStart;
477
+ const hasJoycraftHook = sessionStartHooks.some((h) => {
478
+ const innerHooks = h.hooks;
479
+ return innerHooks?.some((ih) => typeof ih.command === "string" && ih.command.includes("joycraft"));
480
+ });
481
+ if (!hasJoycraftHook) {
482
+ sessionStartHooks.push({
483
+ matcher: "",
484
+ hooks: [{
485
+ type: "command",
486
+ command: "node .claude/hooks/joycraft-version-check.mjs"
487
+ }]
488
+ });
489
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
490
+ result.created.push(settingsPath);
491
+ }
492
+ const gitignorePath = join2(targetDir, ".gitignore");
493
+ if (existsSync2(gitignorePath)) {
494
+ const gitignore = readFileSync2(gitignorePath, "utf-8");
495
+ if (/^\.claude\/?$/m.test(gitignore) || /^\.claude\/\*$/m.test(gitignore)) {
496
+ result.warnings.push(
497
+ ".claude/ is in your .gitignore \u2014 teammates won't get Joycraft skills.\n Add this line to .gitignore to fix: !.claude/skills/"
498
+ );
499
+ }
500
+ }
501
+ printSummary(result, stack);
502
+ }
503
+ function printSummary(result, stack) {
504
+ console.log("\nJoycraft initialized!\n");
505
+ if (stack.language !== "unknown") {
506
+ const fw = stack.framework ? ` + ${stack.framework}` : "";
507
+ console.log(` Detected stack: ${stack.language}${fw} (${stack.packageManager})`);
508
+ } else {
509
+ console.log(" Detected stack: unknown (no recognized manifest found)");
510
+ }
511
+ if (result.created.length > 0) {
512
+ console.log(`
513
+ Created ${result.created.length} file(s):`);
514
+ for (const f of result.created) {
515
+ console.log(` + ${f}`);
516
+ }
517
+ }
518
+ if (result.modified.length > 0) {
519
+ console.log(`
520
+ Modified ${result.modified.length} file(s):`);
521
+ for (const f of result.modified) {
522
+ console.log(` ~ ${f}`);
523
+ }
524
+ }
525
+ if (result.skipped.length > 0) {
526
+ console.log(`
527
+ Skipped ${result.skipped.length} file(s) (already exist, use --force to overwrite):`);
528
+ for (const f of result.skipped) {
529
+ console.log(` - ${f}`);
530
+ }
531
+ }
532
+ if (result.warnings.length > 0) {
533
+ console.log("\n Warnings:");
534
+ for (const w of result.warnings) {
535
+ console.log(` \u26A0 ${w}`);
536
+ }
537
+ }
538
+ const hasExistingClaude = result.skipped.some((f) => f.endsWith("CLAUDE.md"));
539
+ console.log("\n Next steps:");
540
+ if (hasExistingClaude) {
541
+ console.log(" 1. Run Claude Code and try /tune to assess and improve your existing CLAUDE.md");
542
+ } else {
543
+ console.log(" 1. Review and customize the generated CLAUDE.md for your project");
544
+ }
545
+ console.log(" 2. Try /new-feature to start building with the spec-driven workflow");
546
+ console.log(" 3. Commit .claude/skills/ and docs/ so your team gets the same workflow");
547
+ console.log("");
548
+ }
549
+ export {
550
+ init
551
+ };
552
+ //# sourceMappingURL=init-ZFFV4NO3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/init.ts","../src/detect.ts","../src/improve-claude-md.ts","../src/agents-md.ts"],"sourcesContent":["import { mkdirSync, existsSync, writeFileSync, readFileSync } from 'node:fs';\nimport { join, basename, resolve, dirname } from 'node:path';\nimport { detectStack } from './detect.js';\nimport { generateCLAUDEMd } from './improve-claude-md.js';\nimport { generateAgentsMd } from './agents-md.js';\nimport { SKILLS, TEMPLATES } from './bundled-files.js';\nimport { writeVersion, hashContent } from './version.js';\n\nexport interface InitOptions {\n force: boolean;\n}\n\ninterface InitResult {\n created: string[];\n skipped: string[];\n modified: string[];\n warnings: string[];\n}\n\nfunction ensureDir(dir: string): void {\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n}\n\nfunction writeFile(path: string, content: string, force: boolean, result: InitResult): void {\n if (existsSync(path) && !force) {\n result.skipped.push(path);\n return;\n }\n writeFileSync(path, content, 'utf-8');\n result.created.push(path);\n}\n\nexport async function init(dir: string, opts: InitOptions): Promise<void> {\n const targetDir = resolve(dir);\n const result: InitResult = { created: [], skipped: [], modified: [], warnings: [] };\n\n // Detect stack\n const stack = await detectStack(targetDir);\n\n // 1. Create docs/ subdirectories\n const docsDirs = ['briefs', 'specs', 'discoveries', 'contracts', 'decisions'];\n for (const sub of docsDirs) {\n ensureDir(join(targetDir, 'docs', sub));\n }\n\n // 2. Copy skill files to .claude/skills/<name>/SKILL.md\n const skillsDir = join(targetDir, '.claude', 'skills');\n for (const [filename, content] of Object.entries(SKILLS)) {\n const skillName = filename.replace(/\\.md$/, '');\n const skillDir = join(skillsDir, skillName);\n ensureDir(skillDir);\n writeFile(join(skillDir, 'SKILL.md'), content, opts.force, result);\n }\n\n // 3. Copy template files to docs/templates/\n const templatesDir = join(targetDir, 'docs', 'templates');\n ensureDir(templatesDir);\n for (const [filename, content] of Object.entries(TEMPLATES)) {\n ensureDir(dirname(join(templatesDir, filename)));\n writeFile(join(templatesDir, filename), content, opts.force, result);\n }\n\n // 4. Handle CLAUDE.md — only create if missing, never modify existing (unless --force)\n const claudeMdPath = join(targetDir, 'CLAUDE.md');\n if (existsSync(claudeMdPath) && !opts.force) {\n result.skipped.push(claudeMdPath);\n } else {\n const projectName = basename(targetDir);\n const content = generateCLAUDEMd(projectName, stack);\n writeFileSync(claudeMdPath, content, 'utf-8');\n result.created.push(claudeMdPath);\n }\n\n // 5. Handle AGENTS.md — only create if missing, never modify existing (unless --force)\n const agentsMdPath = join(targetDir, 'AGENTS.md');\n if (existsSync(agentsMdPath) && !opts.force) {\n result.skipped.push(agentsMdPath);\n } else {\n const projectName = basename(targetDir);\n const content = generateAgentsMd(projectName, stack);\n writeFileSync(agentsMdPath, content, 'utf-8');\n result.created.push(agentsMdPath);\n }\n\n // 6. Write .joycraft-version with hashes of all managed files\n const fileHashes: Record<string, string> = {};\n for (const [filename, content] of Object.entries(SKILLS)) {\n const skillName = filename.replace(/\\.md$/, '');\n fileHashes[join('.claude', 'skills', skillName, 'SKILL.md')] = hashContent(content);\n }\n for (const [filename, content] of Object.entries(TEMPLATES)) {\n fileHashes[join('docs', 'templates', filename)] = hashContent(content);\n }\n writeVersion(targetDir, '0.1.0', fileHashes);\n\n // 7. Install version check hook\n const hooksDir = join(targetDir, '.claude', 'hooks');\n ensureDir(hooksDir);\n const hookScript = `// Joycraft version check — runs on Claude Code session start\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\ntry {\n const data = JSON.parse(readFileSync(join(process.cwd(), '.joycraft-version'), 'utf-8'));\n const res = await fetch('https://registry.npmjs.org/joycraft/latest', { signal: AbortSignal.timeout(3000) });\n if (res.ok) {\n const latest = (await res.json()).version;\n if (data.version !== latest) console.log('Joycraft ' + latest + ' available (you have ' + data.version + '). Run: npx joycraft upgrade');\n }\n} catch {}\n`;\n writeFile(join(hooksDir, 'joycraft-version-check.mjs'), hookScript, opts.force, result);\n\n // Update .claude/settings.json with SessionStart hook\n const settingsPath = join(targetDir, '.claude', 'settings.json');\n let settings: Record<string, unknown> = {};\n if (existsSync(settingsPath)) {\n try {\n settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));\n } catch {\n // If settings.json is malformed, start fresh\n }\n }\n if (!settings.hooks) settings.hooks = {};\n const hooksConfig = settings.hooks as Record<string, unknown>;\n if (!hooksConfig.SessionStart) hooksConfig.SessionStart = [];\n const sessionStartHooks = hooksConfig.SessionStart as Array<Record<string, unknown>>;\n const hasJoycraftHook = sessionStartHooks.some(h => {\n const innerHooks = h.hooks as Array<Record<string, unknown>> | undefined;\n return innerHooks?.some(ih => typeof ih.command === 'string' && ih.command.includes('joycraft'));\n });\n if (!hasJoycraftHook) {\n sessionStartHooks.push({\n matcher: '',\n hooks: [{\n type: 'command',\n command: 'node .claude/hooks/joycraft-version-check.mjs',\n }],\n });\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n', 'utf-8');\n result.created.push(settingsPath);\n }\n\n // 8. Check .gitignore for .claude/ exclusion\n const gitignorePath = join(targetDir, '.gitignore');\n if (existsSync(gitignorePath)) {\n const gitignore = readFileSync(gitignorePath, 'utf-8');\n if (/^\\.claude\\/?$/m.test(gitignore) || /^\\.claude\\/\\*$/m.test(gitignore)) {\n result.warnings.push(\n '.claude/ is in your .gitignore — teammates won\\'t get Joycraft skills.\\n' +\n ' Add this line to .gitignore to fix: !.claude/skills/'\n );\n }\n }\n\n // 9. Print summary\n printSummary(result, stack);\n}\n\nfunction printSummary(result: InitResult, stack: import('./detect.js').StackInfo): void {\n console.log('\\nJoycraft initialized!\\n');\n\n if (stack.language !== 'unknown') {\n const fw = stack.framework ? ` + ${stack.framework}` : '';\n console.log(` Detected stack: ${stack.language}${fw} (${stack.packageManager})`);\n } else {\n console.log(' Detected stack: unknown (no recognized manifest found)');\n }\n\n if (result.created.length > 0) {\n console.log(`\\n Created ${result.created.length} file(s):`);\n for (const f of result.created) {\n console.log(` + ${f}`);\n }\n }\n\n if (result.modified.length > 0) {\n console.log(`\\n Modified ${result.modified.length} file(s):`);\n for (const f of result.modified) {\n console.log(` ~ ${f}`);\n }\n }\n\n if (result.skipped.length > 0) {\n console.log(`\\n Skipped ${result.skipped.length} file(s) (already exist, use --force to overwrite):`);\n for (const f of result.skipped) {\n console.log(` - ${f}`);\n }\n }\n\n if (result.warnings.length > 0) {\n console.log('\\n Warnings:');\n for (const w of result.warnings) {\n console.log(` ⚠ ${w}`);\n }\n }\n\n const hasExistingClaude = result.skipped.some(f => f.endsWith('CLAUDE.md'));\n\n console.log('\\n Next steps:');\n if (hasExistingClaude) {\n console.log(' 1. Run Claude Code and try /tune to assess and improve your existing CLAUDE.md');\n } else {\n console.log(' 1. Review and customize the generated CLAUDE.md for your project');\n }\n console.log(' 2. Try /new-feature to start building with the spec-driven workflow');\n console.log(' 3. Commit .claude/skills/ and docs/ so your team gets the same workflow');\n console.log('');\n}\n","import { readFileSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport interface StackInfo {\n language: string;\n packageManager: string;\n commands: {\n build?: string;\n test?: string;\n lint?: string;\n typecheck?: string;\n deploy?: string;\n };\n framework?: string;\n}\n\nfunction readFile(path: string): string | null {\n try {\n return readFileSync(path, 'utf-8');\n } catch {\n return null;\n }\n}\n\nfunction detectNodeFramework(pkg: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> }): string | undefined {\n const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (allDeps['next']) return 'Next.js';\n if (allDeps['nuxt']) return 'Nuxt';\n if (allDeps['@remix-run/node'] || allDeps['@remix-run/react']) return 'Remix';\n if (allDeps['express']) return 'Express';\n if (allDeps['fastify']) return 'Fastify';\n if (allDeps['react']) return 'React';\n if (allDeps['vue']) return 'Vue';\n if (allDeps['svelte']) return 'Svelte';\n return undefined;\n}\n\nfunction detectNodeTestFramework(pkg: { devDependencies?: Record<string, string>; dependencies?: Record<string, string> }): string | undefined {\n const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (allDeps['vitest']) return 'vitest';\n if (allDeps['jest']) return 'jest';\n if (allDeps['mocha']) return 'mocha';\n return undefined;\n}\n\nfunction detectNodePackageManager(dir: string): string {\n if (existsSync(join(dir, 'pnpm-lock.yaml'))) return 'pnpm';\n if (existsSync(join(dir, 'yarn.lock'))) return 'yarn';\n if (existsSync(join(dir, 'bun.lockb')) || existsSync(join(dir, 'bun.lock'))) return 'bun';\n return 'npm';\n}\n\nfunction detectNode(dir: string): StackInfo | null {\n const raw = readFile(join(dir, 'package.json'));\n if (raw === null) return null;\n\n let pkg: Record<string, unknown>;\n try {\n pkg = JSON.parse(raw);\n } catch {\n return null;\n }\n\n const pm = detectNodePackageManager(dir);\n const run = pm === 'npm' ? 'npm run' : pm;\n const scripts = (pkg.scripts ?? {}) as Record<string, string>;\n const framework = detectNodeFramework(pkg as { dependencies?: Record<string, string>; devDependencies?: Record<string, string> });\n const testFramework = detectNodeTestFramework(pkg as { devDependencies?: Record<string, string>; dependencies?: Record<string, string> });\n\n const commands: StackInfo['commands'] = {};\n if (scripts.build) commands.build = `${run} build`;\n else commands.build = `${run} build`;\n if (scripts.test) commands.test = `${run} test`;\n else if (testFramework) commands.test = `${run} test`;\n else commands.test = `${pm === 'npm' ? 'npm' : pm} test`;\n if (scripts.lint) commands.lint = `${run} lint`;\n if (scripts.typecheck) commands.typecheck = `${run} typecheck`;\n else if ((pkg.devDependencies as Record<string, string> | undefined)?.['typescript']) {\n commands.typecheck = 'tsc --noEmit';\n }\n\n return {\n language: 'node',\n packageManager: pm,\n commands,\n framework,\n };\n}\n\nfunction detectPythonFramework(content: string): string | undefined {\n if (/fastapi/i.test(content)) return 'FastAPI';\n if (/django/i.test(content)) return 'Django';\n if (/flask/i.test(content)) return 'Flask';\n return undefined;\n}\n\nfunction detectPython(dir: string): StackInfo | null {\n const pyproject = readFile(join(dir, 'pyproject.toml'));\n if (pyproject !== null) {\n const isPoetry = /\\[tool\\.poetry\\]/.test(pyproject);\n const isUv = existsSync(join(dir, 'uv.lock'));\n\n let pm: string;\n let run: string;\n if (isUv) {\n pm = 'uv';\n run = 'uv run';\n } else if (isPoetry) {\n pm = 'poetry';\n run = 'poetry run';\n } else {\n pm = 'pip';\n run = 'python -m';\n }\n\n const framework = detectPythonFramework(pyproject);\n const hasPytest = /pytest/i.test(pyproject);\n\n return {\n language: 'python',\n packageManager: pm,\n commands: {\n build: `${pm === 'poetry' ? 'poetry' : pm} build`,\n test: hasPytest ? `${run} pytest` : `${run} pytest`,\n lint: `${run} ruff check .`,\n },\n framework,\n };\n }\n\n const requirements = readFile(join(dir, 'requirements.txt'));\n if (requirements !== null) {\n const framework = detectPythonFramework(requirements);\n return {\n language: 'python',\n packageManager: 'pip',\n commands: {\n build: 'pip install -e .',\n test: 'python -m pytest',\n lint: 'python -m ruff check .',\n },\n framework,\n };\n }\n\n return null;\n}\n\nfunction detectRust(dir: string): StackInfo | null {\n const cargo = readFile(join(dir, 'Cargo.toml'));\n if (cargo === null) return null;\n\n let framework: string | undefined;\n if (/actix-web/.test(cargo)) framework = 'Actix';\n else if (/axum/.test(cargo)) framework = 'Axum';\n else if (/rocket/.test(cargo)) framework = 'Rocket';\n\n return {\n language: 'rust',\n packageManager: 'cargo',\n commands: {\n build: 'cargo build',\n test: 'cargo test',\n lint: 'cargo clippy',\n },\n framework,\n };\n}\n\nfunction detectGo(dir: string): StackInfo | null {\n const gomod = readFile(join(dir, 'go.mod'));\n if (gomod === null) return null;\n\n let framework: string | undefined;\n if (/github\\.com\\/gin-gonic\\/gin/.test(gomod)) framework = 'Gin';\n else if (/github\\.com\\/gofiber\\/fiber/.test(gomod)) framework = 'Fiber';\n else if (/github\\.com\\/labstack\\/echo/.test(gomod)) framework = 'Echo';\n\n return {\n language: 'go',\n packageManager: 'go',\n commands: {\n build: 'go build ./...',\n test: 'go test ./...',\n lint: 'golangci-lint run',\n },\n framework,\n };\n}\n\nfunction detectSwift(dir: string): StackInfo | null {\n const pkg = readFile(join(dir, 'Package.swift'));\n if (pkg === null) return null;\n\n return {\n language: 'swift',\n packageManager: 'swift',\n commands: {\n build: 'swift build',\n test: 'swift test',\n },\n };\n}\n\nfunction detectMakefile(dir: string): StackInfo | null {\n const makefile = readFile(join(dir, 'Makefile'));\n if (makefile === null) return null;\n\n const commands: StackInfo['commands'] = {};\n commands.build = 'make build';\n if (/^test:/m.test(makefile)) commands.test = 'make test';\n if (/^lint:/m.test(makefile)) commands.lint = 'make lint';\n\n return {\n language: 'unknown',\n packageManager: 'make',\n commands,\n };\n}\n\nfunction detectDockerfile(dir: string): StackInfo | null {\n if (!existsSync(join(dir, 'Dockerfile'))) return null;\n\n return {\n language: 'unknown',\n packageManager: 'docker',\n commands: {\n build: 'docker build .',\n },\n };\n}\n\nexport async function detectStack(dir: string): Promise<StackInfo> {\n const detectors = [\n detectNode,\n detectPython,\n detectRust,\n detectGo,\n detectSwift,\n detectMakefile,\n detectDockerfile,\n ];\n\n for (const detect of detectors) {\n const result = detect(dir);\n if (result) return result;\n }\n\n return { language: 'unknown', packageManager: '', commands: {} };\n}\n","import type { StackInfo } from './detect.js';\n\ninterface Section {\n header: string;\n content: string;\n}\n\nfunction parseSections(markdown: string): Section[] {\n const lines = markdown.split('\\n');\n const sections: Section[] = [];\n let currentHeader = '';\n let currentLines: string[] = [];\n\n for (const line of lines) {\n if (line.startsWith('## ')) {\n if (currentHeader || currentLines.length > 0) {\n sections.push({ header: currentHeader, content: currentLines.join('\\n') });\n }\n currentHeader = line;\n currentLines = [];\n } else {\n currentLines.push(line);\n }\n }\n\n // Push the last section\n if (currentHeader || currentLines.length > 0) {\n sections.push({ header: currentHeader, content: currentLines.join('\\n') });\n }\n\n return sections;\n}\n\nfunction hasSection(sections: Section[], pattern: RegExp): boolean {\n return sections.some(s => pattern.test(s.header));\n}\n\nfunction generateCommandsBlock(stack: StackInfo): string {\n const lines: string[] = ['```bash'];\n if (stack.commands.build) lines.push(`# Build\\n${stack.commands.build}`);\n if (stack.commands.test) lines.push(`# Test\\n${stack.commands.test}`);\n if (stack.commands.lint) lines.push(`# Lint\\n${stack.commands.lint}`);\n if (stack.commands.typecheck) lines.push(`# Type check\\n${stack.commands.typecheck}`);\n if (stack.commands.deploy) lines.push(`# Deploy\\n${stack.commands.deploy}`);\n lines.push('```');\n return lines.join('\\n');\n}\n\nfunction generateBoundariesSection(): string {\n return `## Behavioral Boundaries\n\n### ALWAYS\n- Run tests and type-check before committing\n- Commit after completing each discrete task\n- Follow existing code patterns and style\n\n### ASK FIRST\n- Adding new dependencies\n- Modifying database schema or data models\n- Changing authentication or authorization flows\n- Any destructive operation (deleting files, force-pushing)\n\n### NEVER\n- Push to main branch without explicit approval\n- Skip type-checking or linting\n- Commit code that doesn't build\n- Hardcode secrets, API keys, or credentials`;\n}\n\nfunction generateWorkflowSection(stack: StackInfo): string {\n return `## Development Workflow\n\n${generateCommandsBlock(stack)}`;\n}\n\nfunction generateArchitectureSection(): string {\n return `## Architecture\n\n_TODO: Add a brief description of your project's architecture and key directories._`;\n}\n\nfunction generateKeyFilesSection(): string {\n return `## Key Files\n\n| File | Purpose |\n|------|---------|\n| _TODO_ | _Add key files and their purposes_ |`;\n}\n\nfunction generateGotchasSection(): string {\n return `## Common Gotchas\n\n_TODO: Add any gotchas, quirks, or non-obvious behaviors that developers should know about._`;\n}\n\nfunction generateGettingStartedSection(): string {\n return `## Getting Started with Joycraft\n\nThis project uses [Joycraft](https://github.com/maksutovic/joycraft) for AI development workflow. Available skills:\n\n| Skill | Purpose |\n|-------|---------|\n| \\`/tune\\` | Assess your harness, apply upgrades, see path to Level 5 |\n| \\`/new-feature\\` | Interview -> Feature Brief -> Atomic Specs |\n| \\`/interview\\` | Lightweight brainstorm — yap about ideas, get a structured summary |\n| \\`/decompose\\` | Break a brief into small, testable specs |\n| \\`/session-end\\` | Capture discoveries, verify, commit |\n\nRun \\`/tune\\` to see where your project stands and what to improve next.`;\n}\n\nexport function improveCLAUDEMd(existing: string, stack: StackInfo): string {\n const sections = parseSections(existing);\n const additions: string[] = [];\n\n if (!hasSection(sections, /behavioral\\s*boundar/i)) {\n additions.push(generateBoundariesSection());\n }\n\n if (!hasSection(sections, /development\\s*workflow/i) && !hasSection(sections, /workflow/i)) {\n additions.push(generateWorkflowSection(stack));\n }\n\n if (!hasSection(sections, /architecture/i)) {\n additions.push(generateArchitectureSection());\n }\n\n if (!hasSection(sections, /key\\s*files/i)) {\n additions.push(generateKeyFilesSection());\n }\n\n if (!hasSection(sections, /common\\s*gotchas/i) && !hasSection(sections, /gotchas/i)) {\n additions.push(generateGotchasSection());\n }\n\n if (!hasSection(sections, /getting\\s*started.*joycraft/i) && !hasSection(sections, /joycraft.*skills/i)) {\n additions.push(generateGettingStartedSection());\n }\n\n if (additions.length === 0) {\n return existing;\n }\n\n // Append missing sections\n const trimmed = existing.trimEnd();\n return trimmed + '\\n\\n' + additions.join('\\n\\n') + '\\n';\n}\n\nexport function generateCLAUDEMd(projectName: string, stack: StackInfo): string {\n const frameworkNote = stack.framework ? ` (${stack.framework})` : '';\n const langLabel = stack.language === 'unknown' ? '' : ` | **Stack:** ${stack.language}${frameworkNote}`;\n\n const lines: string[] = [\n `# ${projectName}`,\n '',\n `**Component:** _TODO: describe what this project is_${langLabel}`,\n '',\n '---',\n '',\n generateBoundariesSection(),\n '',\n generateWorkflowSection(stack),\n '',\n generateArchitectureSection(),\n '',\n generateKeyFilesSection(),\n '',\n generateGotchasSection(),\n '',\n generateGettingStartedSection(),\n '',\n ];\n\n return lines.join('\\n');\n}\n","import type { StackInfo } from './detect.js';\n\ninterface Section {\n header: string;\n content: string;\n}\n\nfunction parseSections(markdown: string): Section[] {\n const lines = markdown.split('\\n');\n const sections: Section[] = [];\n let currentHeader = '';\n let currentLines: string[] = [];\n\n for (const line of lines) {\n if (line.startsWith('## ')) {\n if (currentHeader || currentLines.length > 0) {\n sections.push({ header: currentHeader, content: currentLines.join('\\n') });\n }\n currentHeader = line;\n currentLines = [];\n } else {\n currentLines.push(line);\n }\n }\n\n if (currentHeader || currentLines.length > 0) {\n sections.push({ header: currentHeader, content: currentLines.join('\\n') });\n }\n\n return sections;\n}\n\nfunction hasSection(sections: Section[], pattern: RegExp): boolean {\n return sections.some(s => pattern.test(s.header));\n}\n\nfunction generateCommandsBlock(stack: StackInfo): string {\n const lines: string[] = ['```bash'];\n if (stack.commands.build) lines.push(stack.commands.build);\n if (stack.commands.test) lines.push(stack.commands.test);\n if (stack.commands.lint) lines.push(stack.commands.lint);\n if (stack.commands.typecheck) lines.push(stack.commands.typecheck);\n if (stack.commands.deploy) lines.push(stack.commands.deploy);\n lines.push('```');\n return lines.join('\\n');\n}\n\nfunction generateBoundariesSection(): string {\n return `## Behavioral Boundaries\n\n### ALWAYS\n- Run tests and type-check before committing\n- Follow existing code patterns and style\n\n### ASK FIRST\n- Adding new dependencies\n- Changing auth or data models\n- Any destructive operation\n\n### NEVER\n- Push to main without approval\n- Skip tests or type-checking\n- Hardcode secrets or credentials`;\n}\n\nfunction generateDevelopmentSection(stack: StackInfo): string {\n return `## Development\n\n${generateCommandsBlock(stack)}`;\n}\n\nfunction generateArchitectureSection(): string {\n return `## Architecture\n\n_TODO: Add a compact directory tree and one-paragraph summary._`;\n}\n\nfunction generateKeyFilesSection(): string {\n return `## Key Files\n\n| File | Purpose |\n|------|---------|\n| _TODO_ | _Add key files_ |`;\n}\n\nexport function generateAgentsMd(projectName: string, stack: StackInfo): string {\n const frameworkNote = stack.framework ? ` (${stack.framework})` : '';\n const langLabel = stack.language === 'unknown' ? '' : ` | **Stack:** ${stack.language}${frameworkNote}`;\n\n const lines: string[] = [\n `# ${projectName}`,\n '',\n `**Component:** _TODO: describe what this project is_${langLabel}`,\n '',\n '> Auto-generated by Joycraft. See CLAUDE.md for detailed instructions.',\n '',\n '---',\n '',\n generateBoundariesSection(),\n '',\n generateArchitectureSection(),\n '',\n generateKeyFilesSection(),\n '',\n generateDevelopmentSection(stack),\n '',\n ];\n\n return lines.join('\\n');\n}\n\nexport function improveAgentsMd(existing: string, stack: StackInfo): string {\n const sections = parseSections(existing);\n const additions: string[] = [];\n\n if (!hasSection(sections, /behavioral\\s*boundar/i)) {\n additions.push(generateBoundariesSection());\n }\n\n if (!hasSection(sections, /architecture/i)) {\n additions.push(generateArchitectureSection());\n }\n\n if (!hasSection(sections, /key\\s*files/i)) {\n additions.push(generateKeyFilesSection());\n }\n\n if (!hasSection(sections, /development/i)) {\n additions.push(generateDevelopmentSection(stack));\n }\n\n if (additions.length === 0) {\n return existing;\n }\n\n const trimmed = existing.trimEnd();\n return trimmed + '\\n\\n' + additions.join('\\n\\n') + '\\n';\n}\n"],"mappings":"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","names":["existsSync","readFileSync","join","generateCommandsBlock","generateBoundariesSection","generateArchitectureSection","generateKeyFilesSection","existsSync","join","readFileSync"]}