joycraft 0.6.10 → 0.6.12

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,21 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/package-version.ts
4
+ import { readFileSync } from "fs";
5
+ import { fileURLToPath } from "url";
6
+ import { dirname, join } from "path";
7
+ var __dirname = dirname(fileURLToPath(import.meta.url));
8
+ function getPackageVersion() {
9
+ const pkgPath = join(__dirname, "..", "package.json");
10
+ const raw = readFileSync(pkgPath, "utf-8");
11
+ const pkg = JSON.parse(raw);
12
+ if (typeof pkg.version !== "string" || pkg.version.length === 0) {
13
+ throw new Error(`Joycraft package.json at ${pkgPath} is missing a version field`);
14
+ }
15
+ return pkg.version;
16
+ }
17
+
18
+ export {
19
+ getPackageVersion
20
+ };
21
+ //# sourceMappingURL=chunk-IELXGWSH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/package-version.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport function getPackageVersion(): string {\n const pkgPath = join(__dirname, '..', 'package.json');\n const raw = readFileSync(pkgPath, 'utf-8');\n const pkg = JSON.parse(raw) as { version?: unknown };\n if (typeof pkg.version !== 'string' || pkg.version.length === 0) {\n throw new Error(`Joycraft package.json at ${pkgPath} is missing a version field`);\n }\n return pkg.version;\n}\n"],"mappings":";;;AAAA,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,SAAS,YAAY;AAE9B,IAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAEjD,SAAS,oBAA4B;AAC1C,QAAM,UAAU,KAAK,WAAW,MAAM,cAAc;AACpD,QAAM,MAAM,aAAa,SAAS,OAAO;AACzC,QAAM,MAAM,KAAK,MAAM,GAAG;AAC1B,MAAI,OAAO,IAAI,YAAY,YAAY,IAAI,QAAQ,WAAW,GAAG;AAC/D,UAAM,IAAI,MAAM,4BAA4B,OAAO,6BAA6B;AAAA,EAClF;AACA,SAAO,IAAI;AACb;","names":[]}
@@ -9,7 +9,8 @@ var LEGACY_VERSION_FILE = ".joycraft-version";
9
9
  var HASH_LENGTH = 16;
10
10
  var DEFAULT_GITIGNORE_PROFILE = "shared";
11
11
  function parseGitignoreProfile(value) {
12
- return value === "shared" || value === "private" ? value : null;
12
+ const v = typeof value === "string" ? value.trim().toLowerCase() : value;
13
+ return v === "shared" || v === "private" ? v : null;
13
14
  }
14
15
  function hashContent(content) {
15
16
  return createHash("sha256").update(content).digest("hex");
@@ -38,6 +39,7 @@ function readVersion(dir) {
38
39
  }
39
40
  function writeVersion(dir, version, files, gitignoreProfile) {
40
41
  const filePath = join(dir, STATE_PATH);
42
+ const profile = gitignoreProfile ?? readVersion(dir)?.gitignoreProfile;
41
43
  const truncated = {};
42
44
  for (const [path, hash] of Object.entries(files)) {
43
45
  truncated[path] = truncateHash(hash);
@@ -45,7 +47,7 @@ function writeVersion(dir, version, files, gitignoreProfile) {
45
47
  const data = {
46
48
  version,
47
49
  files: truncated,
48
- ...gitignoreProfile ? { gitignoreProfile } : {}
50
+ ...profile ? { gitignoreProfile: profile } : {}
49
51
  };
50
52
  mkdirSync(dirname(filePath), { recursive: true });
51
53
  writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
@@ -70,4 +72,4 @@ export {
70
72
  writeVersion,
71
73
  getLevel
72
74
  };
73
- //# sourceMappingURL=chunk-PUYGEBLA.js.map
75
+ //# sourceMappingURL=chunk-TD65VH2W.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/version.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { createHash } from 'node:crypto';\n\n/**\n * Project-relative path to Joycraft's upgrade-state file.\n *\n * Hidden inside `.claude/` — the dir `init` always creates for every harness —\n * directly analogous to npm's own hidden lockfile at\n * `node_modules/.package-lock.json`. Never at the repo root, never committed\n * (init/upgrade gitignore it). The old root location was `.joycraft-version`\n * (see LEGACY_VERSION_FILE); `upgrade` migrates it on first run.\n */\nexport const STATE_PATH = join('.claude', '.joycraft', 'state.json');\n\n/** The pre-relocation root path. Kept only so `upgrade` can migrate it. */\nexport const LEGACY_VERSION_FILE = '.joycraft-version';\n\n/**\n * Length we truncate stored hashes to. Full SHA-256 is 64 hex chars; 16 hex\n * (64 bits) is ample to detect customization across ~100 managed files and\n * shrinks the state ~4×. Compare truncated-on-both-sides (see upgrade.ts).\n */\nconst HASH_LENGTH = 16;\n\n/**\n * How much of the Joycraft harness is tracked in git.\n * - `shared` — commit skills/agents/pi so teammates get the workflow (default).\n * - `private` — gitignore .claude/, .agents/, .pi/; track only CLAUDE.md,\n * AGENTS.md, and docs/.\n */\nexport type GitignoreProfile = 'shared' | 'private';\n\nexport const DEFAULT_GITIGNORE_PROFILE: GitignoreProfile = 'shared';\n\n/**\n * Narrow an arbitrary value to a GitignoreProfile, or null if unrecognized.\n * Strings are normalized (trim + lowercase) here so every call site — flag,\n * prompt, persisted state — gets the same case-insensitivity for free.\n */\nexport function parseGitignoreProfile(value: unknown): GitignoreProfile | null {\n const v = typeof value === 'string' ? value.trim().toLowerCase() : value;\n return v === 'shared' || v === 'private' ? v : null;\n}\n\nexport interface VersionInfo {\n version: string;\n files: Record<string, string>;\n /**\n * The gitignore profile chosen at init/upgrade. Absent on state written by\n * Joycraft versions before this field existed — treat absent as `shared`.\n */\n gitignoreProfile?: GitignoreProfile;\n}\n\nexport function hashContent(content: string): string {\n return createHash('sha256').update(content).digest('hex');\n}\n\n/** Truncate a (full) content hash to the stored length. Idempotent for already-short input. */\nexport function truncateHash(hash: string): string {\n return hash.slice(0, HASH_LENGTH);\n}\n\nexport function readVersion(dir: string): VersionInfo | null {\n const filePath = join(dir, STATE_PATH);\n if (!existsSync(filePath)) return null;\n try {\n const raw = readFileSync(filePath, 'utf-8');\n const parsed = JSON.parse(raw);\n if (typeof parsed.version === 'string' && typeof parsed.files === 'object') {\n // Sanitize the profile: ignore unknown/legacy values rather than\n // returning them (absent or bogus → undefined, callers default to shared).\n const profile = parseGitignoreProfile(parsed.gitignoreProfile);\n return {\n version: parsed.version,\n files: parsed.files,\n ...(profile ? { gitignoreProfile: profile } : {}),\n };\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport function writeVersion(\n dir: string,\n version: string,\n files: Record<string, string>,\n gitignoreProfile?: GitignoreProfile\n): void {\n const filePath = join(dir, STATE_PATH);\n // An omitted profile means \"no new decision\", not \"clear it\": preserve\n // whatever is already persisted so call sites that only refresh\n // version/hashes can never silently strip a saved choice.\n const profile = gitignoreProfile ?? readVersion(dir)?.gitignoreProfile;\n // Store truncated hashes — single source of truth for the on-disk shape.\n const truncated: Record<string, string> = {};\n for (const [path, hash] of Object.entries(files)) {\n truncated[path] = truncateHash(hash);\n }\n const data: VersionInfo = {\n version,\n files: truncated,\n ...(profile ? { gitignoreProfile: profile } : {}),\n };\n mkdirSync(dirname(filePath), { recursive: true });\n writeFileSync(filePath, JSON.stringify(data, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Detect the current Joycraft harness level for a project directory.\n * Returns 5 if Level 5 artifacts (autofix workflow + External Validation) are present, 4 otherwise.\n */\nexport function getLevel(dir: string): number {\n const hasAutofix = existsSync(join(dir, '.github', 'workflows', 'autofix.yml'));\n if (!hasAutofix) return 4;\n const claudeMdPath = join(dir, 'CLAUDE.md');\n if (!existsSync(claudeMdPath)) return 4;\n const content = readFileSync(claudeMdPath, 'utf-8');\n return content.includes('## External Validation') ? 5 : 4;\n}\n"],"mappings":";;;AAAA,SAAS,cAAc,eAAe,YAAY,iBAAiB;AACnE,SAAS,MAAM,eAAe;AAC9B,SAAS,kBAAkB;AAWpB,IAAM,aAAa,KAAK,WAAW,aAAa,YAAY;AAG5D,IAAM,sBAAsB;AAOnC,IAAM,cAAc;AAUb,IAAM,4BAA8C;AAOpD,SAAS,sBAAsB,OAAyC;AAC7E,QAAM,IAAI,OAAO,UAAU,WAAW,MAAM,KAAK,EAAE,YAAY,IAAI;AACnE,SAAO,MAAM,YAAY,MAAM,YAAY,IAAI;AACjD;AAYO,SAAS,YAAY,SAAyB;AACnD,SAAO,WAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAC1D;AAGO,SAAS,aAAa,MAAsB;AACjD,SAAO,KAAK,MAAM,GAAG,WAAW;AAClC;AAEO,SAAS,YAAY,KAAiC;AAC3D,QAAM,WAAW,KAAK,KAAK,UAAU;AACrC,MAAI,CAAC,WAAW,QAAQ,EAAG,QAAO;AAClC,MAAI;AACF,UAAM,MAAM,aAAa,UAAU,OAAO;AAC1C,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,OAAO,OAAO,YAAY,YAAY,OAAO,OAAO,UAAU,UAAU;AAG1E,YAAM,UAAU,sBAAsB,OAAO,gBAAgB;AAC7D,aAAO;AAAA,QACL,SAAS,OAAO;AAAA,QAChB,OAAO,OAAO;AAAA,QACd,GAAI,UAAU,EAAE,kBAAkB,QAAQ,IAAI,CAAC;AAAA,MACjD;AAAA,IACF;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,aACd,KACA,SACA,OACA,kBACM;AACN,QAAM,WAAW,KAAK,KAAK,UAAU;AAIrC,QAAM,UAAU,oBAAoB,YAAY,GAAG,GAAG;AAEtD,QAAM,YAAoC,CAAC;AAC3C,aAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,cAAU,IAAI,IAAI,aAAa,IAAI;AAAA,EACrC;AACA,QAAM,OAAoB;AAAA,IACxB;AAAA,IACA,OAAO;AAAA,IACP,GAAI,UAAU,EAAE,kBAAkB,QAAQ,IAAI,CAAC;AAAA,EACjD;AACA,YAAU,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAChD,gBAAc,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,MAAM,OAAO;AACvE;AAMO,SAAS,SAAS,KAAqB;AAC5C,QAAM,aAAa,WAAW,KAAK,KAAK,WAAW,aAAa,aAAa,CAAC;AAC9E,MAAI,CAAC,WAAY,QAAO;AACxB,QAAM,eAAe,KAAK,KAAK,WAAW;AAC1C,MAAI,CAAC,WAAW,YAAY,EAAG,QAAO;AACtC,QAAM,UAAU,aAAa,cAAc,OAAO;AAClD,SAAO,QAAQ,SAAS,wBAAwB,IAAI,IAAI;AAC1D;","names":[]}
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ DEFAULT_GITIGNORE_PROFILE,
4
+ STATE_PATH,
5
+ parseGitignoreProfile
6
+ } from "./chunk-TD65VH2W.js";
7
+
8
+ // src/gitignore.ts
9
+ import { existsSync, readFileSync, writeFileSync } from "fs";
10
+ import { join } from "path";
11
+ import { createInterface } from "readline";
12
+ var PRIVATE_PROFILE_IGNORES = [".claude/", ".agents/", ".pi/"];
13
+ var PRIVATE_DIRS_DISPLAY = PRIVATE_PROFILE_IGNORES.join(", ");
14
+ var PRIVATE_UNTRACK_COMMAND = `git rm -r --cached ${PRIVATE_PROFILE_IGNORES.map((d) => d.replace(/\/$/, "")).join(" ")}`;
15
+ function ensureGitignoreEntries(targetDir, entries) {
16
+ const gitignorePath = join(targetDir, ".gitignore");
17
+ const current = existsSync(gitignorePath) ? readFileSync(gitignorePath, "utf-8") : "";
18
+ const present = new Set(current.split("\n").map((l) => l.trim()));
19
+ const missing = entries.filter((e) => !present.has(e.trim()));
20
+ if (missing.length === 0) return [];
21
+ const sep = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
22
+ writeFileSync(gitignorePath, current + sep + missing.join("\n") + "\n", "utf-8");
23
+ return missing;
24
+ }
25
+ function applyGitignoreProfile(targetDir, profile) {
26
+ if (profile === "private") {
27
+ return ensureGitignoreEntries(targetDir, PRIVATE_PROFILE_IGNORES);
28
+ }
29
+ return ensureGitignoreEntries(targetDir, [STATE_PATH]);
30
+ }
31
+ function validateGitignoreFlag(flag) {
32
+ const parsed = parseGitignoreProfile(flag);
33
+ if (!parsed) {
34
+ throw new Error(`Unknown gitignore profile '${flag}'. Use 'shared' or 'private'.`);
35
+ }
36
+ return parsed;
37
+ }
38
+ async function promptGitignoreProfile(intro) {
39
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
40
+ console.log(intro);
41
+ console.log(" shared \u2014 commit skills so your team gets the same workflow (default)");
42
+ console.log(` private \u2014 gitignore ${PRIVATE_DIRS_DISPLAY}; track only CLAUDE.md, AGENTS.md, docs/`);
43
+ return new Promise((resolve) => {
44
+ const ask = () => {
45
+ rl.question(`Profile [shared/private] (${DEFAULT_GITIGNORE_PROFILE}): `, (answer) => {
46
+ if (answer.trim() === "") {
47
+ rl.close();
48
+ resolve(DEFAULT_GITIGNORE_PROFILE);
49
+ return;
50
+ }
51
+ const parsed = parseGitignoreProfile(answer);
52
+ if (parsed) {
53
+ rl.close();
54
+ resolve(parsed);
55
+ return;
56
+ }
57
+ console.log(
58
+ `Unrecognized answer '${answer.trim()}' \u2014 type 'shared' or 'private', or press Enter for ${DEFAULT_GITIGNORE_PROFILE}.`
59
+ );
60
+ ask();
61
+ });
62
+ };
63
+ ask();
64
+ });
65
+ }
66
+ async function resolveGitignoreProfile(opts) {
67
+ if (opts.flag !== void 0) {
68
+ return { profile: validateGitignoreFlag(opts.flag), decided: true };
69
+ }
70
+ if (opts.persisted) {
71
+ return { profile: opts.persisted, decided: true };
72
+ }
73
+ if (opts.interactive) {
74
+ return { profile: await promptGitignoreProfile(opts.promptIntro), decided: true };
75
+ }
76
+ return { profile: DEFAULT_GITIGNORE_PROFILE, decided: false };
77
+ }
78
+
79
+ export {
80
+ PRIVATE_DIRS_DISPLAY,
81
+ PRIVATE_UNTRACK_COMMAND,
82
+ applyGitignoreProfile,
83
+ validateGitignoreFlag,
84
+ resolveGitignoreProfile
85
+ };
86
+ //# sourceMappingURL=chunk-VIVJUY6J.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/gitignore.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createInterface } from 'node:readline';\nimport {\n STATE_PATH,\n parseGitignoreProfile,\n DEFAULT_GITIGNORE_PROFILE,\n type GitignoreProfile,\n} from './version.js';\n\n/**\n * The harness directories the `private` profile gitignores. Tracking only\n * CLAUDE.md, AGENTS.md, and docs/ means everything under these three dirs\n * stays local. `.claude/` already covers the hidden state file.\n *\n * Single source of truth: every user-facing string that names these dirs\n * (prompts, summaries, the untrack hint, CLI help) derives from this list via\n * the constants below, so adding a harness dir can't leave stale messages.\n */\nexport const PRIVATE_PROFILE_IGNORES = ['.claude/', '.agents/', '.pi/'];\n\n/** Human-readable list of the private-profile dirs, for prompts and summaries. */\nexport const PRIVATE_DIRS_DISPLAY = PRIVATE_PROFILE_IGNORES.join(', ');\n\n/** Copy-pasteable command to untrack already-committed harness files. */\nexport const PRIVATE_UNTRACK_COMMAND = `git rm -r --cached ${PRIVATE_PROFILE_IGNORES.map((d) => d.replace(/\\/$/, '')).join(' ')}`;\n\n/**\n * Append-only, create-if-absent, idempotent .gitignore writer.\n *\n * Mirrors the \"append over modify when touching user files\" principle: it never\n * rewrites, reorders, or removes existing lines — it only appends the entries\n * not already present (matched exactly, after trimming). One read + at most one\n * write per call. Returns the entries actually added (empty when everything was\n * already present).\n */\nexport function ensureGitignoreEntries(targetDir: string, entries: string[]): string[] {\n const gitignorePath = join(targetDir, '.gitignore');\n const current = existsSync(gitignorePath) ? readFileSync(gitignorePath, 'utf-8') : '';\n const present = new Set(current.split('\\n').map((l) => l.trim()));\n const missing = entries.filter((e) => !present.has(e.trim()));\n if (missing.length === 0) return [];\n\n // Append on their own lines, tolerating a file that may or may not end in \\n.\n const sep = current.length > 0 && !current.endsWith('\\n') ? '\\n' : '';\n writeFileSync(gitignorePath, current + sep + missing.join('\\n') + '\\n', 'utf-8');\n return missing;\n}\n\n/** Single-entry convenience wrapper around ensureGitignoreEntries. */\nexport function ensureGitignoreEntry(targetDir: string, line: string): boolean {\n return ensureGitignoreEntries(targetDir, [line]).length > 0;\n}\n\n/**\n * Apply a gitignore profile's entries to the project's .gitignore.\n *\n * - `shared` — ignore only the hidden upgrade-state file (current default).\n * - `private` — ignore the whole .claude/, .agents/, .pi/ trees. Since\n * .claude/ already covers the state file, the writer skips the redundant\n * state entry to avoid a dead line.\n *\n * Append-only and idempotent (via ensureGitignoreEntries), so re-running\n * init/upgrade never duplicates entries. Returns the list of lines actually\n * added this call.\n */\nexport function applyGitignoreProfile(targetDir: string, profile: GitignoreProfile): string[] {\n if (profile === 'private') {\n return ensureGitignoreEntries(targetDir, PRIVATE_PROFILE_IGNORES);\n }\n // `shared`: only the hidden state file, matching long-standing behavior.\n return ensureGitignoreEntries(targetDir, [STATE_PATH]);\n}\n\n/** A resolved profile plus how it was arrived at. */\nexport interface ResolvedGitignoreProfile {\n profile: GitignoreProfile;\n /**\n * True when the profile is an actual decision: a --gitignore flag, a\n * persisted choice, or an interactive answer. False when it is the\n * non-interactive fallback default — callers must NOT persist a fallback,\n * or the one-time prompt would be permanently suppressed for the project.\n */\n decided: boolean;\n}\n\n/** Validate a raw --gitignore flag value. Throws the user-facing error on unknown values. */\nexport function validateGitignoreFlag(flag: string): GitignoreProfile {\n const parsed = parseGitignoreProfile(flag);\n if (!parsed) {\n throw new Error(`Unknown gitignore profile '${flag}'. Use 'shared' or 'private'.`);\n }\n return parsed;\n}\n\n/**\n * Prompt for a gitignore profile. An empty answer takes the default; an\n * unrecognized answer re-asks instead of being silently coerced — a typo must\n * not get persisted as a permanent choice.\n */\nasync function promptGitignoreProfile(intro: string): Promise<GitignoreProfile> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n console.log(intro);\n console.log(' shared — commit skills so your team gets the same workflow (default)');\n console.log(` private — gitignore ${PRIVATE_DIRS_DISPLAY}; track only CLAUDE.md, AGENTS.md, docs/`);\n return new Promise((resolve) => {\n const ask = (): void => {\n rl.question(`Profile [shared/private] (${DEFAULT_GITIGNORE_PROFILE}): `, (answer) => {\n if (answer.trim() === '') {\n rl.close();\n resolve(DEFAULT_GITIGNORE_PROFILE);\n return;\n }\n const parsed = parseGitignoreProfile(answer);\n if (parsed) {\n rl.close();\n resolve(parsed);\n return;\n }\n console.log(\n `Unrecognized answer '${answer.trim()}' — type 'shared' or 'private', or press Enter for ${DEFAULT_GITIGNORE_PROFILE}.`\n );\n ask();\n });\n };\n ask();\n });\n}\n\n/**\n * Resolve the gitignore profile by precedence — the single resolver shared by\n * init and upgrade so the two commands can never drift:\n * 1. --gitignore flag (validated; throws on unknown value)\n * 2. profile persisted in state.json (re-init / upgrade keep the prior choice)\n * 3. interactive prompt (the caller decides when prompting is allowed)\n * 4. fallback default `shared`, reported with decided=false\n */\nexport async function resolveGitignoreProfile(opts: {\n /** Raw --gitignore value from the CLI, if provided. */\n flag?: string;\n /** Profile previously persisted in state.json, if any. */\n persisted?: GitignoreProfile;\n /** Whether prompting is allowed (TTY, and the command permits interaction). */\n interactive: boolean;\n /** First line printed above the prompt; init and upgrade word it differently. */\n promptIntro: string;\n}): Promise<ResolvedGitignoreProfile> {\n if (opts.flag !== undefined) {\n return { profile: validateGitignoreFlag(opts.flag), decided: true };\n }\n if (opts.persisted) {\n return { profile: opts.persisted, decided: true };\n }\n if (opts.interactive) {\n return { profile: await promptGitignoreProfile(opts.promptIntro), decided: true };\n }\n return { profile: DEFAULT_GITIGNORE_PROFILE, decided: false };\n}\n"],"mappings":";;;;;;;;AAAA,SAAS,YAAY,cAAc,qBAAqB;AACxD,SAAS,YAAY;AACrB,SAAS,uBAAuB;AAiBzB,IAAM,0BAA0B,CAAC,YAAY,YAAY,MAAM;AAG/D,IAAM,uBAAuB,wBAAwB,KAAK,IAAI;AAG9D,IAAM,0BAA0B,sBAAsB,wBAAwB,IAAI,CAAC,MAAM,EAAE,QAAQ,OAAO,EAAE,CAAC,EAAE,KAAK,GAAG,CAAC;AAWxH,SAAS,uBAAuB,WAAmB,SAA6B;AACrF,QAAM,gBAAgB,KAAK,WAAW,YAAY;AAClD,QAAM,UAAU,WAAW,aAAa,IAAI,aAAa,eAAe,OAAO,IAAI;AACnF,QAAM,UAAU,IAAI,IAAI,QAAQ,MAAM,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAChE,QAAM,UAAU,QAAQ,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,KAAK,CAAC,CAAC;AAC5D,MAAI,QAAQ,WAAW,EAAG,QAAO,CAAC;AAGlC,QAAM,MAAM,QAAQ,SAAS,KAAK,CAAC,QAAQ,SAAS,IAAI,IAAI,OAAO;AACnE,gBAAc,eAAe,UAAU,MAAM,QAAQ,KAAK,IAAI,IAAI,MAAM,OAAO;AAC/E,SAAO;AACT;AAmBO,SAAS,sBAAsB,WAAmB,SAAqC;AAC5F,MAAI,YAAY,WAAW;AACzB,WAAO,uBAAuB,WAAW,uBAAuB;AAAA,EAClE;AAEA,SAAO,uBAAuB,WAAW,CAAC,UAAU,CAAC;AACvD;AAeO,SAAS,sBAAsB,MAAgC;AACpE,QAAM,SAAS,sBAAsB,IAAI;AACzC,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,8BAA8B,IAAI,+BAA+B;AAAA,EACnF;AACA,SAAO;AACT;AAOA,eAAe,uBAAuB,OAA0C;AAC9E,QAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAC3E,UAAQ,IAAI,KAAK;AACjB,UAAQ,IAAI,8EAAyE;AACrF,UAAQ,IAAI,8BAAyB,oBAAoB,0CAA0C;AACnG,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,MAAM,MAAY;AACtB,SAAG,SAAS,6BAA6B,yBAAyB,OAAO,CAAC,WAAW;AACnF,YAAI,OAAO,KAAK,MAAM,IAAI;AACxB,aAAG,MAAM;AACT,kBAAQ,yBAAyB;AACjC;AAAA,QACF;AACA,cAAM,SAAS,sBAAsB,MAAM;AAC3C,YAAI,QAAQ;AACV,aAAG,MAAM;AACT,kBAAQ,MAAM;AACd;AAAA,QACF;AACA,gBAAQ;AAAA,UACN,wBAAwB,OAAO,KAAK,CAAC,2DAAsD,yBAAyB;AAAA,QACtH;AACA,YAAI;AAAA,MACN,CAAC;AAAA,IACH;AACA,QAAI;AAAA,EACN,CAAC;AACH;AAUA,eAAsB,wBAAwB,MASR;AACpC,MAAI,KAAK,SAAS,QAAW;AAC3B,WAAO,EAAE,SAAS,sBAAsB,KAAK,IAAI,GAAG,SAAS,KAAK;AAAA,EACpE;AACA,MAAI,KAAK,WAAW;AAClB,WAAO,EAAE,SAAS,KAAK,WAAW,SAAS,KAAK;AAAA,EAClD;AACA,MAAI,KAAK,aAAa;AACpB,WAAO,EAAE,SAAS,MAAM,uBAAuB,KAAK,WAAW,GAAG,SAAS,KAAK;AAAA,EAClF;AACA,SAAO,EAAE,SAAS,2BAA2B,SAAS,MAAM;AAC9D;","names":[]}
package/dist/cli.js CHANGED
@@ -1,4 +1,8 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ PRIVATE_DIRS_DISPLAY
4
+ } from "./chunk-VIVJUY6J.js";
5
+ import "./chunk-TD65VH2W.js";
2
6
 
3
7
  // src/cli.ts
4
8
  import { Command } from "commander";
@@ -7,10 +11,11 @@ import { fileURLToPath } from "url";
7
11
  import { dirname, join } from "path";
8
12
  var __dirname = dirname(fileURLToPath(import.meta.url));
9
13
  var pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
14
+ var GITIGNORE_OPTION_DESC = `Gitignore profile: 'shared' (commit skills) or 'private' (gitignore ${PRIVATE_DIRS_DISPLAY})`;
10
15
  var program = new Command();
11
16
  program.name("joycraft").description("Scaffold and upgrade AI development harnesses").version(pkg.version, "-v, --version");
12
- program.command("init").description("Scaffold the Joycraft harness into the current project").argument("[dir]", "Target directory", ".").option("--force", "Overwrite existing files").option("--gitignore <profile>", "Gitignore profile: 'shared' (commit skills) or 'private' (gitignore .claude/.agents/.pi)").action(async (dir, opts) => {
13
- const { init } = await import("./init-PS57M5XM.js");
17
+ program.command("init").description("Scaffold the Joycraft harness into the current project").argument("[dir]", "Target directory", ".").option("--force", "Overwrite existing files").option("--gitignore <profile>", GITIGNORE_OPTION_DESC).action(async (dir, opts) => {
18
+ const { init } = await import("./init-YJYJZUZU.js");
14
19
  try {
15
20
  await init(dir, { force: opts.force ?? false, gitignore: opts.gitignore });
16
21
  } catch (err) {
@@ -18,19 +23,24 @@ program.command("init").description("Scaffold the Joycraft harness into the curr
18
23
  process.exit(1);
19
24
  }
20
25
  });
21
- program.command("upgrade").description("Upgrade installed Joycraft templates and skills to latest").argument("[dir]", "Target directory", ".").option("--yes", "Auto-accept all updates").action(async (dir, opts) => {
22
- const { upgrade } = await import("./upgrade-7E5ZGYHP.js");
23
- await upgrade(dir, { yes: opts.yes ?? false });
26
+ program.command("upgrade").description("Upgrade installed Joycraft templates and skills to latest").argument("[dir]", "Target directory", ".").option("--yes", "Auto-accept all updates").option("--gitignore <profile>", GITIGNORE_OPTION_DESC).action(async (dir, opts) => {
27
+ const { upgrade } = await import("./upgrade-33NLD24D.js");
28
+ try {
29
+ await upgrade(dir, { yes: opts.yes ?? false, gitignore: opts.gitignore });
30
+ } catch (err) {
31
+ console.error(err instanceof Error ? err.message : String(err));
32
+ process.exit(1);
33
+ }
24
34
  });
25
35
  program.command("init-autofix").description("Set up the Level 5 auto-fix loop with holdout scenarios").argument("[dir]", "Target directory", ".").option("--scenarios-repo <name>", "Name for scenarios repo").option("--app-id <id>", "GitHub App ID for Joycraft Autofix").option("--force", "Overwrite existing workflow files").option("--dry-run", "Show what would be created without creating it").action(async (dir, opts) => {
26
- const { initAutofix } = await import("./init-autofix-MQL74RF7.js");
36
+ const { initAutofix } = await import("./init-autofix-4GUVGDXT.js");
27
37
  await initAutofix(dir, opts);
28
38
  });
29
39
  program.command("check-version").description("Check if a newer version of Joycraft is available").action(async () => {
30
40
  try {
31
41
  const { readFileSync: readFileSync2, existsSync } = await import("fs");
32
42
  const { join: join2 } = await import("path");
33
- const { STATE_PATH, LEGACY_VERSION_FILE } = await import("./version-TG3D7QLM.js");
43
+ const { STATE_PATH, LEGACY_VERSION_FILE } = await import("./version-2FGZETKD.js");
34
44
  const statePath = existsSync(join2(process.cwd(), STATE_PATH)) ? join2(process.cwd(), STATE_PATH) : join2(process.cwd(), LEGACY_VERSION_FILE);
35
45
  const data = JSON.parse(readFileSync2(statePath, "utf-8"));
36
46
  const res = await fetch("https://registry.npmjs.org/joycraft/latest", { signal: AbortSignal.timeout(3e3) });
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));\n\nconst program = new Command();\n\nprogram\n .name('joycraft')\n .description('Scaffold and upgrade AI development harnesses')\n .version(pkg.version, '-v, --version');\n\nprogram\n .command('init')\n .description('Scaffold the Joycraft harness into the current project')\n .argument('[dir]', 'Target directory', '.')\n .option('--force', 'Overwrite existing files')\n .option('--gitignore <profile>', \"Gitignore profile: 'shared' (commit skills) or 'private' (gitignore .claude/.agents/.pi)\")\n .action(async (dir: string, opts: { force?: boolean; gitignore?: string }) => {\n const { init } = await import('./init.js');\n try {\n await init(dir, { force: opts.force ?? false, gitignore: opts.gitignore });\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\nprogram\n .command('upgrade')\n .description('Upgrade installed Joycraft templates and skills to latest')\n .argument('[dir]', 'Target directory', '.')\n .option('--yes', 'Auto-accept all updates')\n .action(async (dir: string, opts: { yes?: boolean }) => {\n const { upgrade } = await import('./upgrade.js');\n await upgrade(dir, { yes: opts.yes ?? false });\n });\n\nprogram\n .command('init-autofix')\n .description('Set up the Level 5 auto-fix loop with holdout scenarios')\n .argument('[dir]', 'Target directory', '.')\n .option('--scenarios-repo <name>', 'Name for scenarios repo')\n .option('--app-id <id>', 'GitHub App ID for Joycraft Autofix')\n .option('--force', 'Overwrite existing workflow files')\n .option('--dry-run', 'Show what would be created without creating it')\n .action(async (dir: string, opts: { scenariosRepo?: string; appId?: string; force?: boolean; dryRun?: boolean }) => {\n const { initAutofix } = await import('./init-autofix.js');\n await initAutofix(dir, opts);\n });\n\nprogram\n .command('check-version')\n .description('Check if a newer version of Joycraft is available')\n .action(async () => {\n try {\n const { readFileSync, existsSync } = await import('node:fs');\n const { join } = await import('node:path');\n const { STATE_PATH, LEGACY_VERSION_FILE } = await import('./version.js');\n // Prefer the hidden state; fall back to the legacy root file for projects\n // that have not been upgraded (which relocates it) yet.\n const statePath = existsSync(join(process.cwd(), STATE_PATH))\n ? join(process.cwd(), STATE_PATH)\n : join(process.cwd(), LEGACY_VERSION_FILE);\n const data = JSON.parse(readFileSync(statePath, '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()) as { version: string }).version;\n if (data.version !== latest) {\n console.log(`Joycraft ${latest} available (you have ${data.version}). Run: npm install -g joycraft`);\n }\n }\n } catch {\n // Silent — don't block session start\n }\n });\n\n// Start update check immediately so it runs in parallel with the command\nconst updateCheckPromise = (async (): Promise<string | null> => {\n try {\n const res = await fetch('https://registry.npmjs.org/joycraft/latest', {\n signal: AbortSignal.timeout(3000)\n });\n if (res.ok) {\n const latest = ((await res.json()) as { version: string }).version;\n if (latest !== pkg.version) {\n return `\\nJoycraft ${latest} available (you have ${pkg.version}). Run: npm install -g joycraft`;\n }\n }\n } catch {\n // Silent — don't block or error on network issues\n }\n return null;\n})();\n\n// Print update nudge after every command\nprogram.hook('postAction', async () => {\n const message = await updateCheckPromise;\n if (message) {\n console.log(message);\n }\n});\n\n// Show help when no arguments provided\nif (process.argv.length <= 2) {\n program.outputHelp();\n process.exit(0);\n}\n\nprogram.parse();\n"],"mappings":"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","names":["readFileSync","join"]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\nimport { PRIVATE_DIRS_DISPLAY } from './gitignore.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));\n\nconst GITIGNORE_OPTION_DESC = `Gitignore profile: 'shared' (commit skills) or 'private' (gitignore ${PRIVATE_DIRS_DISPLAY})`;\n\nconst program = new Command();\n\nprogram\n .name('joycraft')\n .description('Scaffold and upgrade AI development harnesses')\n .version(pkg.version, '-v, --version');\n\nprogram\n .command('init')\n .description('Scaffold the Joycraft harness into the current project')\n .argument('[dir]', 'Target directory', '.')\n .option('--force', 'Overwrite existing files')\n .option('--gitignore <profile>', GITIGNORE_OPTION_DESC)\n .action(async (dir: string, opts: { force?: boolean; gitignore?: string }) => {\n const { init } = await import('./init.js');\n try {\n await init(dir, { force: opts.force ?? false, gitignore: opts.gitignore });\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\nprogram\n .command('upgrade')\n .description('Upgrade installed Joycraft templates and skills to latest')\n .argument('[dir]', 'Target directory', '.')\n .option('--yes', 'Auto-accept all updates')\n .option('--gitignore <profile>', GITIGNORE_OPTION_DESC)\n .action(async (dir: string, opts: { yes?: boolean; gitignore?: string }) => {\n const { upgrade } = await import('./upgrade.js');\n try {\n await upgrade(dir, { yes: opts.yes ?? false, gitignore: opts.gitignore });\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\nprogram\n .command('init-autofix')\n .description('Set up the Level 5 auto-fix loop with holdout scenarios')\n .argument('[dir]', 'Target directory', '.')\n .option('--scenarios-repo <name>', 'Name for scenarios repo')\n .option('--app-id <id>', 'GitHub App ID for Joycraft Autofix')\n .option('--force', 'Overwrite existing workflow files')\n .option('--dry-run', 'Show what would be created without creating it')\n .action(async (dir: string, opts: { scenariosRepo?: string; appId?: string; force?: boolean; dryRun?: boolean }) => {\n const { initAutofix } = await import('./init-autofix.js');\n await initAutofix(dir, opts);\n });\n\nprogram\n .command('check-version')\n .description('Check if a newer version of Joycraft is available')\n .action(async () => {\n try {\n const { readFileSync, existsSync } = await import('node:fs');\n const { join } = await import('node:path');\n const { STATE_PATH, LEGACY_VERSION_FILE } = await import('./version.js');\n // Prefer the hidden state; fall back to the legacy root file for projects\n // that have not been upgraded (which relocates it) yet.\n const statePath = existsSync(join(process.cwd(), STATE_PATH))\n ? join(process.cwd(), STATE_PATH)\n : join(process.cwd(), LEGACY_VERSION_FILE);\n const data = JSON.parse(readFileSync(statePath, '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()) as { version: string }).version;\n if (data.version !== latest) {\n console.log(`Joycraft ${latest} available (you have ${data.version}). Run: npm install -g joycraft`);\n }\n }\n } catch {\n // Silent — don't block session start\n }\n });\n\n// Start update check immediately so it runs in parallel with the command\nconst updateCheckPromise = (async (): Promise<string | null> => {\n try {\n const res = await fetch('https://registry.npmjs.org/joycraft/latest', {\n signal: AbortSignal.timeout(3000)\n });\n if (res.ok) {\n const latest = ((await res.json()) as { version: string }).version;\n if (latest !== pkg.version) {\n return `\\nJoycraft ${latest} available (you have ${pkg.version}). Run: npm install -g joycraft`;\n }\n }\n } catch {\n // Silent — don't block or error on network issues\n }\n return null;\n})();\n\n// Print update nudge after every command\nprogram.hook('postAction', async () => {\n const message = await updateCheckPromise;\n if (message) {\n console.log(message);\n }\n});\n\n// Show help when no arguments provided\nif (process.argv.length <= 2) {\n program.outputHelp();\n process.exit(0);\n}\n\nprogram.parse();\n"],"mappings":"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","names":["readFileSync","join"]}
@@ -1,8 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- applyGitignoreProfile,
4
3
  getPackageVersion
5
- } from "./chunk-P45XNSGK.js";
4
+ } from "./chunk-IELXGWSH.js";
5
+ import {
6
+ PRIVATE_DIRS_DISPLAY,
7
+ PRIVATE_UNTRACK_COMMAND,
8
+ applyGitignoreProfile,
9
+ resolveGitignoreProfile
10
+ } from "./chunk-VIVJUY6J.js";
6
11
  import {
7
12
  CODEX_SKILLS,
8
13
  PI_AGENTS,
@@ -11,15 +16,14 @@ import {
11
16
  PI_SKILLS,
12
17
  SKILLS,
13
18
  TEMPLATES
14
- } from "./chunk-W6AHAE7X.js";
19
+ } from "./chunk-GM2T44P6.js";
15
20
  import {
16
21
  DEFAULT_GITIGNORE_PROFILE,
17
22
  STATE_PATH,
18
23
  hashContent,
19
- parseGitignoreProfile,
20
24
  readVersion,
21
25
  writeVersion
22
- } from "./chunk-PUYGEBLA.js";
26
+ } from "./chunk-TD65VH2W.js";
23
27
 
24
28
  // src/init.ts
25
29
  import { mkdirSync as mkdirSync2, existsSync as existsSync4, writeFileSync as writeFileSync2, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync, chmodSync } from "fs";
@@ -699,37 +703,6 @@ function installSafeguardHooks(targetDir, customPatterns = [], force = false, sk
699
703
  }
700
704
 
701
705
  // src/init.ts
702
- import { createInterface } from "readline";
703
- async function promptGitignoreProfile() {
704
- const rl = createInterface({ input: process.stdin, output: process.stdout });
705
- console.log("\nHow should Joycraft files be tracked in git?");
706
- console.log(" shared \u2014 commit skills so your team gets the same workflow (default)");
707
- console.log(" private \u2014 gitignore .claude/, .agents/, .pi/; track only CLAUDE.md, AGENTS.md, docs/");
708
- return new Promise((resolve2) => {
709
- rl.question("Profile [shared/private] (shared): ", (answer) => {
710
- rl.close();
711
- const parsed = parseGitignoreProfile(answer.trim().toLowerCase());
712
- resolve2(parsed ?? DEFAULT_GITIGNORE_PROFILE);
713
- });
714
- });
715
- }
716
- async function resolveGitignoreProfile(targetDir, opts) {
717
- if (opts.gitignore !== void 0) {
718
- const parsed = parseGitignoreProfile(opts.gitignore.trim().toLowerCase());
719
- if (!parsed) {
720
- throw new Error(
721
- `Unknown gitignore profile '${opts.gitignore}'. Use 'shared' or 'private'.`
722
- );
723
- }
724
- return parsed;
725
- }
726
- const persisted = readVersion(targetDir)?.gitignoreProfile;
727
- if (persisted) return persisted;
728
- if (process.stdin.isTTY) {
729
- return promptGitignoreProfile();
730
- }
731
- return DEFAULT_GITIGNORE_PROFILE;
732
- }
733
706
  function ensureDir(dir) {
734
707
  if (!existsSync4(dir)) {
735
708
  mkdirSync2(dir, { recursive: true });
@@ -748,7 +721,12 @@ async function init(dir, opts) {
748
721
  const result = { created: [], skipped: [], modified: [], warnings: [] };
749
722
  const stack = await detectStack(targetDir);
750
723
  const isPi = existsSync4(join4(targetDir, ".pi"));
751
- const gitignoreProfile = await resolveGitignoreProfile(targetDir, opts);
724
+ const { profile: gitignoreProfile } = await resolveGitignoreProfile({
725
+ flag: opts.gitignore,
726
+ persisted: readVersion(targetDir)?.gitignoreProfile,
727
+ interactive: process.stdin.isTTY === true,
728
+ promptIntro: "\nHow should Joycraft files be tracked in git?"
729
+ });
752
730
  ensureDir(join4(targetDir, "docs", "context"));
753
731
  const skillsDir = join4(targetDir, ".claude", "skills");
754
732
  let existingSkills = [];
@@ -971,7 +949,7 @@ function printSummary(result, stack, existingSkills = [], isPi = false, gitignor
971
949
  console.log(" Detected agent: Pi");
972
950
  }
973
951
  if (gitignoreProfile === "private") {
974
- console.log(" Gitignore profile: private (.claude/, .agents/, .pi/ are gitignored \u2014 only CLAUDE.md, AGENTS.md, docs/ are tracked)");
952
+ console.log(` Gitignore profile: private (${PRIVATE_DIRS_DISPLAY} are gitignored \u2014 only CLAUDE.md, AGENTS.md, docs/ are tracked)`);
975
953
  } else {
976
954
  console.log(" Gitignore profile: shared (skills and docs are tracked for your team)");
977
955
  }
@@ -1017,8 +995,8 @@ function printSummary(result, stack, existingSkills = [], isPi = false, gitignor
1017
995
  console.log(" 2. Try /joycraft-new-feature to start building with the spec-driven workflow");
1018
996
  console.log(" (feature artifacts are written to docs/features/<slug>/ as you go)");
1019
997
  if (gitignoreProfile === "private") {
1020
- console.log(" 3. Commit CLAUDE.md, AGENTS.md, and docs/ \u2014 .claude/, .agents/, .pi/ stay local (gitignored)");
1021
- console.log(" (if any harness files were already committed, run: git rm -r --cached .claude .agents .pi)");
998
+ console.log(` 3. Commit CLAUDE.md, AGENTS.md, and docs/ \u2014 ${PRIVATE_DIRS_DISPLAY} stay local (gitignored)`);
999
+ console.log(` (if any harness files were already committed, run: ${PRIVATE_UNTRACK_COMMAND})`);
1022
1000
  } else {
1023
1001
  console.log(" 3. Commit .claude/skills/ and docs/ so your team gets the same workflow");
1024
1002
  }
@@ -1030,4 +1008,4 @@ function printSummary(result, stack, existingSkills = [], isPi = false, gitignor
1030
1008
  export {
1031
1009
  init
1032
1010
  };
1033
- //# sourceMappingURL=init-PS57M5XM.js.map
1011
+ //# sourceMappingURL=init-YJYJZUZU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/init.ts","../src/detect.ts","../src/improve-claude-md.ts","../src/agents-md.ts","../src/permissions.ts","../src/safeguard.ts"],"sourcesContent":["import { mkdirSync, existsSync, writeFileSync, readFileSync, readdirSync, statSync, chmodSync } 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 { generatePermissions } from './permissions.js';\nimport { installSafeguardHooks } from './safeguard.js';\nimport { SKILLS, TEMPLATES, CODEX_SKILLS, PI_SKILLS, PI_SCRIPTS, PI_EXTENSIONS, PI_AGENTS } from './bundled-files.js';\nimport {\n writeVersion,\n readVersion,\n hashContent,\n STATE_PATH,\n DEFAULT_GITIGNORE_PROFILE,\n type GitignoreProfile,\n} from './version.js';\nimport {\n applyGitignoreProfile,\n resolveGitignoreProfile,\n PRIVATE_DIRS_DISPLAY,\n PRIVATE_UNTRACK_COMMAND,\n} from './gitignore.js';\nimport { getPackageVersion } from './package-version.js';\n\nexport interface InitOptions {\n force: boolean;\n /** Raw --gitignore value from the CLI, if provided. Validated in init(). */\n gitignore?: string;\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 // Pi detection — check if project uses Pi coding agent\n const isPi = existsSync(join(targetDir, '.pi'));\n\n // Resolve the gitignore profile up front (flag → persisted → prompt → default)\n // so it governs both the .gitignore writes and the \"teammates won't get skills\"\n // warning below. Unlike upgrade, init persists even the non-interactive\n // default: init creates the state fresh, and `shared` is the documented\n // default for a first run.\n const { profile: gitignoreProfile } = await resolveGitignoreProfile({\n flag: opts.gitignore,\n persisted: readVersion(targetDir)?.gitignoreProfile,\n interactive: process.stdin.isTTY === true,\n promptIntro: '\\nHow should Joycraft files be tracked in git?',\n });\n\n // 1. Create the only Joycraft-managed docs/ subdirectory: context/.\n // All other folders (briefs/specs/discoveries/decisions/contracts/features/backlog/...) are\n // lazy-created by the skills that write to them. Solo-first: no preemptive ceremony.\n ensureDir(join(targetDir, 'docs', 'context'));\n\n // 1b. Scan for existing non-Joycraft skills before copying ours\n const skillsDir = join(targetDir, '.claude', 'skills');\n let existingSkills: string[] = [];\n if (existsSync(skillsDir)) {\n existingSkills = readdirSync(skillsDir)\n .filter(name => {\n if (name.startsWith('joycraft-')) return false;\n if (name.startsWith('.')) return false;\n const fullPath = join(skillsDir, name);\n try {\n return statSync(fullPath).isDirectory();\n } catch {\n return false;\n }\n });\n }\n\n // 2. Copy skill files to .claude/skills/<name>/SKILL.md\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 // 2b. Copy Codex skill files to .agents/skills/<name>/SKILL.md\n const codexSkillsDir = join(targetDir, '.agents', 'skills');\n let existingCodexSkills: string[] = [];\n if (existsSync(codexSkillsDir)) {\n existingCodexSkills = readdirSync(codexSkillsDir)\n .filter(name => {\n if (name.startsWith('joycraft-')) return false;\n if (name.startsWith('.')) return false;\n const fullPath = join(codexSkillsDir, name);\n try {\n return statSync(fullPath).isDirectory();\n } catch {\n return false;\n }\n });\n }\n for (const [filename, content] of Object.entries(CODEX_SKILLS)) {\n const skillName = filename.replace(/\\.md$/, '');\n const skillDir = join(codexSkillsDir, skillName);\n ensureDir(skillDir);\n writeFile(join(skillDir, 'SKILL.md'), content, opts.force, result);\n }\n\n // 2c. Copy Pi skill files to .pi/skills/<name>/SKILL.md\n const piSkillsDir = join(targetDir, '.pi', 'skills');\n for (const [filename, content] of Object.entries(PI_SKILLS)) {\n const skillName = filename.replace(/\\.md$/, '');\n const skillDir = join(piSkillsDir, skillName);\n ensureDir(skillDir);\n writeFile(join(skillDir, 'SKILL.md'), content, opts.force, result);\n }\n\n // 2d. Install Pi pipeline runtime scripts to .pi/scripts/joycraft/\n const piScriptsDir = join(targetDir, '.pi', 'scripts', 'joycraft');\n ensureDir(piScriptsDir);\n for (const [name, content] of Object.entries(PI_SCRIPTS)) {\n const scriptPath = join(piScriptsDir, name);\n writeFile(scriptPath, content, opts.force, result);\n if (name !== 'README.md') {\n try { chmodSync(scriptPath, 0o755); } catch { /* non-fatal */ }\n }\n }\n\n // 2e. Install Pi extension to .pi/extensions/\n const piExtDir = join(targetDir, '.pi', 'extensions');\n ensureDir(piExtDir);\n for (const [name, content] of Object.entries(PI_EXTENSIONS)) {\n writeFile(join(piExtDir, name), content, opts.force, result);\n }\n\n // 2f. Install Pi subagent definitions to .pi/agents/\n const piAgentsDir = join(targetDir, '.pi', 'agents');\n ensureDir(piAgentsDir);\n for (const [name, content] of Object.entries(PI_AGENTS)) {\n writeFile(join(piAgentsDir, name), 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, existingSkills);\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 the hidden state (.claude/.joycraft/state.json) 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(CODEX_SKILLS)) {\n const skillName = filename.replace(/\\.md$/, '');\n fileHashes[join('.agents', '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 for (const [filename, content] of Object.entries(PI_SKILLS)) {\n const skillName = filename.replace(/\\.md$/, '');\n fileHashes[join('.pi', 'skills', skillName, 'SKILL.md')] = hashContent(content);\n }\n for (const [name, content] of Object.entries(PI_SCRIPTS)) {\n fileHashes[join('.pi', 'scripts', 'joycraft', name)] = hashContent(content);\n }\n for (const [name, content] of Object.entries(PI_EXTENSIONS)) {\n fileHashes[join('.pi', 'extensions', name)] = hashContent(content);\n }\n for (const [name, content] of Object.entries(PI_AGENTS)) {\n fileHashes[join('.pi', 'agents', name)] = hashContent(content);\n }\n writeVersion(targetDir, getPackageVersion(), fileHashes, gitignoreProfile);\n\n // 6b. Apply the chosen gitignore profile.\n // - shared: ignore only the hidden upgrade-state file (npm-lockfile-style;\n // tool-managed state that should never land in commits).\n // - private: ignore .claude/, .agents/, .pi/ — track only CLAUDE.md,\n // AGENTS.md, docs/.\n // Append-only + create-if-absent + idempotent (never clobbers existing entries).\n applyGitignoreProfile(targetDir, gitignoreProfile);\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(), '${STATE_PATH.split(/[\\\\/]/).join(\"', '\")}'), '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: npm install -g joycraft');\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 let settingsMalformed = false;\n if (existsSync(settingsPath)) {\n try {\n settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));\n } catch {\n settingsMalformed = true;\n result.warnings.push(\n 'settings.json exists but is malformed — skipping settings merge to protect your config.\\n' +\n ' Fix the JSON in .claude/settings.json and re-run init.'\n );\n }\n }\n if (!settingsMalformed) {\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. Generate and merge permission rules into settings.json\n const permissions = generatePermissions(stack);\n // Re-read settings in case it was just created by hook step\n if (existsSync(settingsPath)) {\n try {\n settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));\n } catch {\n result.warnings.push(\n 'settings.json became unreadable after hook merge — skipping permissions merge.\\n' +\n ' Fix the JSON in .claude/settings.json and re-run init.'\n );\n settingsMalformed = true;\n }\n }\n if (!settingsMalformed) {\n if (!settings.permissions) settings.permissions = {};\n const perms = settings.permissions as Record<string, string[]>;\n if (!perms.allow) perms.allow = [];\n if (!perms.deny) perms.deny = [];\n for (const rule of permissions.allow) {\n if (!perms.allow.includes(rule)) perms.allow.push(rule);\n }\n for (const rule of permissions.deny) {\n if (!perms.deny.includes(rule)) perms.deny.push(rule);\n }\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n', 'utf-8');\n }\n }\n\n // 9. Install safeguard hooks (PreToolUse deny-pattern blocking)\n const hookResult = installSafeguardHooks(targetDir, [], opts.force, settingsMalformed);\n result.created.push(...hookResult.created);\n result.skipped.push(...hookResult.skipped);\n\n // 10. Check .gitignore for .claude/ exclusion.\n // Only a concern under the `shared` profile, where the intent is to commit\n // skills so teammates get them. Under `private`, ignoring .claude/ is the\n // user's deliberate choice — surfacing a warning there would be wrong.\n if (gitignoreProfile === 'shared') {\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\n // 11. Print summary\n printSummary(result, stack, existingSkills, isPi, gitignoreProfile);\n}\n\nfunction printSummary(result: InitResult, stack: import('./detect.js').StackInfo, existingSkills: string[] = [], isPi: boolean = false, gitignoreProfile: GitignoreProfile = DEFAULT_GITIGNORE_PROFILE): 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 (isPi) {\n console.log(' Detected agent: Pi');\n }\n\n if (gitignoreProfile === 'private') {\n console.log(` Gitignore profile: private (${PRIVATE_DIRS_DISPLAY} are gitignored — only CLAUDE.md, AGENTS.md, docs/ are tracked)`);\n } else {\n console.log(' Gitignore profile: shared (skills and docs are tracked for your team)');\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 if (existingSkills.length > 0) {\n console.log(`\\n Found existing skills: ${existingSkills.join(', ')}. These are preserved — Joycraft is additive.`);\n }\n\n const hasExistingClaude = result.skipped.some(f => f.endsWith('CLAUDE.md'));\n\n console.log('\\n Next steps:');\n console.log(' 1. Run Claude Code and try /joycraft-setup — the first-run door that sets up and assesses your project');\n if (hasExistingClaude) {\n console.log(' (it routes to /joycraft-tune to assess and improve your existing CLAUDE.md)');\n } else {\n console.log(' (then review and customize the generated CLAUDE.md for your project)');\n }\n console.log(' 2. Try /joycraft-new-feature to start building with the spec-driven workflow');\n console.log(' (feature artifacts are written to docs/features/<slug>/ as you go)');\n if (gitignoreProfile === 'private') {\n console.log(` 3. Commit CLAUDE.md, AGENTS.md, and docs/ — ${PRIVATE_DIRS_DISPLAY} stay local (gitignored)`);\n console.log(` (if any harness files were already committed, run: ${PRIVATE_UNTRACK_COMMAND})`);\n } else {\n console.log(' 3. Commit .claude/skills/ and docs/ so your team gets the same workflow');\n }\n if (!isPi) {\n console.log(' Pi: Skills installed to .pi/skills/. Use /skill:joycraft-* to invoke.');\n }\n console.log('');\n}\n","import { readFileSync, existsSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport interface TestingStrategy {\n backbone: 'playwright' | 'maestro' | 'api' | 'native';\n testFormat: string;\n layers: ('ui' | 'api' | 'logic' | 'static')[];\n}\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 testingStrategy?: TestingStrategy;\n}\n\nconst WEB_FRAMEWORKS = new Set(['Next.js', 'Nuxt', 'Remix', 'React', 'Vue', 'Svelte']);\nconst API_FRAMEWORKS = new Set(['Express', 'Fastify', 'FastAPI', 'Django', 'Flask', 'Gin', 'Fiber', 'Echo', 'Actix', 'Axum', 'Rocket']);\n\nfunction buildTestingStrategy(backbone: TestingStrategy['backbone']): TestingStrategy {\n switch (backbone) {\n case 'playwright':\n return { backbone, testFormat: '.spec.ts', layers: ['ui', 'api', 'logic', 'static'] };\n case 'maestro':\n return { backbone, testFormat: '.yaml', layers: ['ui', 'api', 'logic', 'static'] };\n case 'api':\n return { backbone, testFormat: '.test.ts', layers: ['api', 'logic', 'static'] };\n case 'native':\n return { backbone, testFormat: '.test.ts', layers: ['logic', 'static'] };\n }\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 const allDeps = { ...(pkg.dependencies as Record<string, string> | undefined), ...(pkg.devDependencies as Record<string, string> | undefined) };\n let testingStrategy: TestingStrategy;\n if (allDeps['react-native']) {\n testingStrategy = buildTestingStrategy('maestro');\n } else if (framework && WEB_FRAMEWORKS.has(framework)) {\n testingStrategy = buildTestingStrategy('playwright');\n } else if (framework && API_FRAMEWORKS.has(framework)) {\n testingStrategy = buildTestingStrategy('api');\n } else {\n testingStrategy = buildTestingStrategy('native');\n }\n\n return {\n language: 'node',\n packageManager: pm,\n commands,\n framework,\n testingStrategy,\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 const testingStrategy = framework && API_FRAMEWORKS.has(framework)\n ? buildTestingStrategy('api')\n : buildTestingStrategy('native');\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 testingStrategy,\n };\n }\n\n const requirements = readFile(join(dir, 'requirements.txt'));\n if (requirements !== null) {\n const framework = detectPythonFramework(requirements);\n const testingStrategy = framework && API_FRAMEWORKS.has(framework)\n ? buildTestingStrategy('api')\n : buildTestingStrategy('native');\n\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 testingStrategy,\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 const testingStrategy = framework && API_FRAMEWORKS.has(framework)\n ? buildTestingStrategy('api')\n : buildTestingStrategy('native');\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 testingStrategy,\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 const testingStrategy = framework && API_FRAMEWORKS.has(framework)\n ? buildTestingStrategy('api')\n : buildTestingStrategy('native');\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 testingStrategy,\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 testingStrategy: buildTestingStrategy('native'),\n };\n}\n\nfunction detectFlutter(dir: string): StackInfo | null {\n const pubspec = readFile(join(dir, 'pubspec.yaml'));\n if (pubspec === null) return null;\n if (!/flutter/i.test(pubspec)) return null;\n\n return {\n language: 'dart',\n packageManager: 'flutter',\n commands: {\n build: 'flutter build',\n test: 'flutter test',\n lint: 'flutter analyze',\n },\n framework: 'Flutter',\n testingStrategy: buildTestingStrategy('maestro'),\n };\n}\n\nfunction detectXcode(dir: string): StackInfo | null {\n // Check for .xcodeproj or .xcworkspace directories\n try {\n const entries = readdirSync(dir);\n const hasXcode = entries.some(e => e.endsWith('.xcodeproj') || e.endsWith('.xcworkspace'));\n if (!hasXcode) return null;\n } catch {\n return null;\n }\n\n return {\n language: 'swift',\n packageManager: 'xcode',\n commands: {\n build: 'xcodebuild build',\n test: 'xcodebuild test',\n },\n testingStrategy: buildTestingStrategy('maestro'),\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 detectFlutter,\n detectSwift,\n detectXcode,\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 { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { StackInfo } from './detect.js';\n\nexport interface ImproveOptions {\n projectDir?: string;\n}\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\nexport function generateBoundariesSection(): string {\n return `## Behavioral Boundaries\n\n### ALWAYS\n- Run tests and type-check before committing\n- Run tests before implementing new features -- confirm they fail first, then implement until they pass\n- Use \\`verb: concise message\\` format for commits\n- Commit after completing each discrete task (atomic commits)\n- Stage specific files by name (not \\`git add -A\\` or \\`git add .\\`)\n- Read \\`docs/context/\\` before making infrastructure or config changes\n- Follow existing code patterns and style\n\n### ASK FIRST\n- Pushing to remote\n- Creating or merging pull requests\n- Adding new dependencies\n- Modifying database schema or data models\n- Changing authentication or authorization flows\n- Any destructive git operation (force-push, reset --hard, branch deletion)\n\n### NEVER\n- Push directly to main/master without approval\n- Commit .env files, secrets, or credentials\n- Use --no-verify to skip hooks\n- Amend commits that have been pushed\n- Skip type-checking or linting\n- Commit code that doesn't build`;\n}\n\nfunction generateWorkflowSection(stack: StackInfo): string {\n return `## Development Workflow\n\n${generateCommandsBlock(stack)}\n\n**Default execution mode:** batch\n\n_How \\`/joycraft-implement\\` wraps up after each spec. \\`joycraft-decompose\\` reads this line (absent ⇒ \\`batch\\`) and recommends a per-spec mode you approve. Modes: \\`batch\\` (implement a cluster, wrap once at the end), \\`checkpoint\\` (commit + status bump after each spec), \\`isolated\\` (fresh context per spec — on Pi, the \\`joycraft-implement-loop\\` driver). Change the value above to set your project default._`;\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| \\`/joycraft-setup\\` | Start here — the first-run door; sets up and assesses your project |\n| \\`/joycraft-tune\\` | Assess your harness, apply upgrades, see path to Level 5 |\n| \\`/joycraft-new-feature\\` | Interview -> Feature Brief -> Atomic Specs |\n| \\`/joycraft-interview\\` | Lightweight brainstorm — yap about ideas, get a structured summary |\n| \\`/joycraft-decompose\\` | Break a brief into small, testable specs |\n| \\`/joycraft-session-end\\` | Capture discoveries, verify, commit |\n| \\`/joycraft-implement-level5\\` | Set up Level 5 — autofix loop, holdout scenarios, scenario evolution |\n\nRun \\`/joycraft-tune\\` to see where your project stands and what to improve next.`;\n}\n\nexport function generateContextMapSection(): string {\n return `## Context Map\n\nKeep this file lean — link out, don't inline. Long-form reference docs live in \\`docs/context/reference/\\`; this table points to what to read on demand.\n\n| Document | Read it when… |\n|----------|---------------|`;\n}\n\nfunction generateExternalValidationSection(): string {\n return `## External Validation\n\nThis project uses holdout scenario tests in a separate private repo.\n\n### NEVER\n- Access, read, or reference the scenarios repo\n- Mention scenario test names or contents\n- Modify the scenarios dispatch workflow to leak test information\n\nThe scenarios repo is deliberately invisible to you. This is the holdout guarantee — like a validation set in ML.`;\n}\n\nfunction generateAreasSection(): string {\n return `## Areas\n\nThis project organizes some work by area. When working on a specific area, read its README first; check for area-specific boundaries.\n\n- For each area: see \\`docs/areas/<area-name>/README.md\\`\n- Area-level boundaries (when present): \\`docs/areas/<area-name>/boundaries.md\\``;\n}\n\nfunction projectHasAreas(opts?: ImproveOptions): boolean {\n if (!opts?.projectDir) return false;\n return existsSync(join(opts.projectDir, 'docs', 'areas'));\n}\n\nfunction stripAreasSection(content: string): string {\n // Remove an existing \"## Areas\" section (header + body up to next \"## \" header or EOF).\n return content.replace(/\\n##\\s+Areas\\b[\\s\\S]*?(?=\\n##\\s|\\n*$)/, '').trimEnd() + '\\n';\n}\n\nfunction generateProjectToolsSection(existingSkills: string[]): string {\n const MAX_LISTED = 10;\n let skillList: string;\n if (existingSkills.length <= MAX_LISTED) {\n skillList = existingSkills.join(', ');\n } else {\n skillList = existingSkills.slice(0, MAX_LISTED).join(', ') +\n `, and ${existingSkills.length - MAX_LISTED} more — see .claude/skills/`;\n }\n return `## Project Tools\n\nThis project has additional tools beyond Joycraft. Always check \\`.claude/skills/\\` for available skills: ${skillList}`;\n}\n\nexport function improveCLAUDEMd(\n existing: string,\n stack: StackInfo,\n existingSkills: string[] = [],\n opts?: ImproveOptions,\n): string {\n // Areas pointer: idempotent in both directions.\n // Always strip an existing \"## Areas\" section first so we re-evaluate cleanly.\n let working = stripAreasSection(existing);\n const sections = parseSections(working);\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 (!hasSection(sections, /context\\s*map/i)) {\n additions.push(generateContextMapSection());\n }\n\n if (!hasSection(sections, /external\\s*validation/i)) {\n additions.push(generateExternalValidationSection());\n }\n\n if (existingSkills.length > 0 && !hasSection(sections, /project\\s*tools/i)) {\n additions.push(generateProjectToolsSection(existingSkills));\n }\n\n if (projectHasAreas(opts)) {\n additions.push(generateAreasSection());\n }\n\n if (additions.length === 0) {\n return working === existing ? existing : working;\n }\n\n const trimmed = working.trimEnd();\n return trimmed + '\\n\\n' + additions.join('\\n\\n') + '\\n';\n}\n\nexport function generateCLAUDEMd(\n projectName: string,\n stack: StackInfo,\n existingSkills: string[] = [],\n opts?: ImproveOptions,\n): 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 generateContextMapSection(),\n '',\n generateGettingStartedSection(),\n '',\n ];\n\n if (existingSkills.length > 0) {\n lines.push(generateProjectToolsSection(existingSkills), '');\n }\n\n if (projectHasAreas(opts)) {\n lines.push(generateAreasSection(), '');\n }\n\n return lines.join('\\n');\n}\n","import type { StackInfo } from './detect.js';\nimport { generateBoundariesSection } from './improve-claude-md.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 generateExternalApiSafetySection(): string {\n return '### External API Safety\\n- Read official docs and type definitions before writing code against a third-party SDK\\n- Add third-party SDKs as devDependencies so typecheck runs against real types, not stubs\\n- Critical integration paths should have a smoke test that validates against the real runtime';\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.',\n '',\n '---',\n '',\n generateBoundariesSection(),\n generateExternalApiSafetySection(),\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 (!/external\\s*api\\s*safety/i.test(existing)) {\n additions.push('### External API Safety\\n- Read official docs and type definitions before writing code against a third-party SDK\\n- Add third-party SDKs as devDependencies so typecheck runs against real types, not stubs\\n- Critical integration paths should have a smoke test that validates against the real runtime');\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","import type { StackInfo } from './detect.js';\n\nexport interface PermissionRules {\n allow: string[];\n deny: string[];\n}\n\nexport function generatePermissions(stack: StackInfo): PermissionRules {\n // Default deny rules for ALL projects\n const deny: string[] = [\n 'Bash(rm -rf *)',\n 'Bash(git push --force *)',\n 'Bash(git push -f *)',\n 'Bash(git reset --hard *)',\n 'Edit(//.env*)',\n 'Edit(//*.pem)',\n 'Edit(//*.key)',\n 'Edit(//.git/**)',\n ];\n\n // Default allow rules\n const allow: string[] = [\n 'Bash(git status)',\n 'Bash(git diff *)',\n 'Bash(git log *)',\n 'Bash(git add *)',\n 'Bash(git commit *)',\n 'Bash(git checkout *)',\n 'Bash(git branch *)',\n ];\n\n // Stack-specific rules\n if (stack.language === 'node') {\n allow.push(`Bash(${stack.packageManager} *)`);\n if (stack.packageManager !== 'npm') deny.push('Bash(npm install *)');\n if (stack.packageManager !== 'yarn') deny.push('Bash(yarn add *)');\n if (stack.packageManager !== 'pnpm') deny.push('Bash(pnpm add *)');\n if (stack.packageManager !== 'bun') deny.push('Bash(bun add *)');\n if (stack.commands.test) allow.push(`Bash(${stack.commands.test})`);\n if (stack.commands.build) allow.push(`Bash(${stack.commands.build})`);\n if (stack.commands.lint) allow.push(`Bash(${stack.commands.lint})`);\n if (stack.commands.typecheck) allow.push(`Bash(${stack.commands.typecheck})`);\n }\n\n if (stack.language === 'python') {\n allow.push(`Bash(${stack.packageManager} *)`);\n if (stack.commands.test) allow.push(`Bash(${stack.commands.test})`);\n if (stack.commands.lint) allow.push(`Bash(${stack.commands.lint})`);\n if (stack.commands.build) allow.push(`Bash(${stack.commands.build})`);\n }\n\n if (stack.language === 'rust') {\n allow.push('Bash(cargo *)');\n }\n\n if (stack.language === 'go') {\n allow.push('Bash(go *)');\n }\n\n if (stack.language === 'swift') {\n allow.push('Bash(swift *)');\n allow.push('Bash(xcodebuild *)');\n }\n\n return { allow, deny };\n}\n","import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport interface SafeguardConfig {\n denyPatterns: string[];\n}\n\n/**\n * Generate default deny patterns from common dangerous operations.\n */\nexport function getDefaultDenyPatterns(): string[] {\n return [\n 'rm\\\\s+-rf\\\\s+/', // rm -rf with absolute path\n 'rm\\\\s+-rf\\\\s+\\\\.', // rm -rf . or ./\n 'git\\\\s+push\\\\s+--force', // force push\n 'git\\\\s+push\\\\s+-f\\\\b', // force push shorthand\n 'git\\\\s+reset\\\\s+--hard', // hard reset\n 'DROP\\\\s+TABLE', // SQL drop\n 'DROP\\\\s+DATABASE', // SQL drop\n 'TRUNCATE', // SQL truncate\n 'chmod\\\\s+777', // wide-open permissions\n 'curl.*\\\\|.*sh', // pipe curl to shell\n 'wget.*\\\\|.*sh', // pipe wget to shell\n ];\n}\n\n/**\n * Generate the hook script that blocks dangerous Bash commands.\n */\nexport function generateHookScript(): string {\n return `#!/bin/bash\n# Joycraft Safeguard — PreToolUse hook\n# Blocks dangerous Bash commands. Exit 2 = block the action.\n# Edit deny-patterns.txt to customize what's blocked.\n\nTOOL_NAME=\"$1\"\n# Read the full tool input from stdin\nINPUT=$(cat)\n\n# Only check Bash commands\nif [ \"$TOOL_NAME\" != \"Bash\" ]; then\n exit 0\nfi\n\n# Extract the command from the JSON input\nCOMMAND=$(echo \"$INPUT\" | grep -o '\"command\":\"[^\"]*\"' | head -1 | sed 's/\"command\":\"//;s/\"$//')\n\nif [ -z \"$COMMAND\" ]; then\n exit 0\nfi\n\nPATTERNS_FILE=\"$(dirname \"$0\")/deny-patterns.txt\"\n\nif [ ! -f \"$PATTERNS_FILE\" ]; then\n exit 0\nfi\n\nwhile IFS= read -r pattern || [ -n \"$pattern\" ]; do\n # Skip empty lines and comments\n [ -z \"$pattern\" ] && continue\n [[ \"$pattern\" == \\\\#* ]] && continue\n\n if echo \"$COMMAND\" | grep -qEi \"$pattern\"; then\n echo \"Blocked by Joycraft Safeguard: command matches deny pattern '$pattern'\"\n echo \"Edit .claude/hooks/joycraft/deny-patterns.txt to modify blocked patterns.\"\n exit 2\n fi\ndone < \"$PATTERNS_FILE\"\n\nexit 0\n`;\n}\n\n/**\n * Generate deny-patterns.txt content from default patterns + custom patterns.\n */\nexport function generateDenyPatternsFile(customPatterns: string[] = []): string {\n const lines = [\n '# Joycraft Safeguard — Deny Patterns',\n '# One regex pattern per line. Lines starting with # are comments.',\n '# Commands matching any pattern will be blocked (exit 2).',\n '# Edit this file to customize what\\'s blocked.',\n '',\n '# Destructive file operations',\n 'rm\\\\s+-rf\\\\s+/',\n 'rm\\\\s+-rf\\\\s+\\\\.',\n '',\n '# Dangerous git operations',\n 'git\\\\s+push\\\\s+--force',\n 'git\\\\s+push\\\\s+-f\\\\b',\n 'git\\\\s+reset\\\\s+--hard',\n '',\n '# SQL destruction',\n 'DROP\\\\s+TABLE',\n 'DROP\\\\s+DATABASE',\n 'TRUNCATE',\n '',\n '# System security',\n 'chmod\\\\s+777',\n 'curl.*\\\\|.*sh',\n 'wget.*\\\\|.*sh',\n ];\n\n if (customPatterns.length > 0) {\n lines.push('');\n lines.push('# Project-specific patterns (from risk interview)');\n for (const p of customPatterns) {\n lines.push(p);\n }\n }\n\n return lines.join('\\n') + '\\n';\n}\n\n/**\n * Install safeguard hooks into a project.\n */\nexport function installSafeguardHooks(\n targetDir: string,\n customPatterns: string[] = [],\n force: boolean = false,\n skipSettingsMerge: boolean = false\n): { created: string[]; skipped: string[] } {\n const result = { created: [] as string[], skipped: [] as string[] };\n const hooksDir = join(targetDir, '.claude', 'hooks', 'joycraft');\n\n if (!existsSync(hooksDir)) {\n mkdirSync(hooksDir, { recursive: true });\n }\n\n // Write hook script\n const hookPath = join(hooksDir, 'block-dangerous.sh');\n if (!existsSync(hookPath) || force) {\n writeFileSync(hookPath, generateHookScript(), { mode: 0o755 });\n result.created.push(hookPath);\n } else {\n result.skipped.push(hookPath);\n }\n\n // Write deny patterns\n const patternsPath = join(hooksDir, 'deny-patterns.txt');\n if (!existsSync(patternsPath) || force) {\n writeFileSync(patternsPath, generateDenyPatternsFile(customPatterns));\n result.created.push(patternsPath);\n } else {\n result.skipped.push(patternsPath);\n }\n\n // Register hook in settings.json (skip if caller detected malformed JSON)\n if (!skipSettingsMerge) {\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 // Don't overwrite — caller should handle the warning\n return result;\n }\n }\n\n if (!settings.hooks) settings.hooks = {};\n const hooks = settings.hooks as Record<string, unknown[]>;\n if (!hooks.PreToolUse) hooks.PreToolUse = [];\n\n const preToolUse = hooks.PreToolUse as Array<Record<string, unknown>>;\n const hasJoycraftHook = preToolUse.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\n if (!hasJoycraftHook) {\n preToolUse.push({\n matcher: 'Bash',\n hooks: [{\n type: 'command',\n command: '.claude/hooks/joycraft/block-dangerous.sh',\n }],\n });\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\\n', 'utf-8');\n }\n }\n\n return result;\n}\n"],"mappings":"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","names":["mkdirSync","existsSync","writeFileSync","readFileSync","readdirSync","join","existsSync","join","existsSync","join","generateCommandsBlock","generateArchitectureSection","generateKeyFilesSection","existsSync","readFileSync","join","join","existsSync","readFileSync","existsSync","mkdirSync","writeFileSync","join","readdirSync","readFileSync"]}
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEMPLATES
4
- } from "./chunk-W6AHAE7X.js";
4
+ } from "./chunk-GM2T44P6.js";
5
5
  import {
6
6
  LEGACY_VERSION_FILE,
7
7
  STATE_PATH
8
- } from "./chunk-PUYGEBLA.js";
8
+ } from "./chunk-TD65VH2W.js";
9
9
 
10
10
  // src/init-autofix.ts
11
11
  import { mkdirSync, existsSync, writeFileSync } from "fs";
@@ -116,4 +116,4 @@ function printSummary(result, dryRun, scenariosRepo) {
116
116
  export {
117
117
  initAutofix
118
118
  };
119
- //# sourceMappingURL=init-autofix-MQL74RF7.js.map
119
+ //# sourceMappingURL=init-autofix-4GUVGDXT.js.map