safeword 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/{check-KTLIM6UR.js → check-INXMFCL5.js} +7 -5
  2. package/dist/{check-KTLIM6UR.js.map → check-INXMFCL5.js.map} +1 -1
  3. package/dist/chunk-6CVTH67L.js +43 -0
  4. package/dist/chunk-6CVTH67L.js.map +1 -0
  5. package/dist/{chunk-KEWQQP4C.js → chunk-75FKNZUM.js} +2 -2
  6. package/dist/{chunk-NI3Z5XHH.js → chunk-ARIAOK2F.js} +2 -34
  7. package/dist/chunk-ARIAOK2F.js.map +1 -0
  8. package/dist/chunk-FRPJITGG.js +35 -0
  9. package/dist/chunk-FRPJITGG.js.map +1 -0
  10. package/dist/chunk-IWWBZVHT.js +274 -0
  11. package/dist/chunk-IWWBZVHT.js.map +1 -0
  12. package/dist/cli.js +9 -5
  13. package/dist/cli.js.map +1 -1
  14. package/dist/{diff-TV24EW3X.js → diff-L7G22MG7.js} +7 -5
  15. package/dist/{diff-TV24EW3X.js.map → diff-L7G22MG7.js.map} +1 -1
  16. package/dist/index.d.ts +4 -0
  17. package/dist/{reset-WJEQTYCX.js → reset-5SRM3P6J.js} +9 -7
  18. package/dist/reset-5SRM3P6J.js.map +1 -0
  19. package/dist/{setup-UYCYH5SE.js → setup-65EVU5OT.js} +179 -75
  20. package/dist/setup-65EVU5OT.js.map +1 -0
  21. package/dist/sync-4XBMKLXS.js +116 -0
  22. package/dist/sync-4XBMKLXS.js.map +1 -0
  23. package/dist/{upgrade-TJZYMNP2.js → upgrade-P3WX3ODU.js} +11 -9
  24. package/dist/{upgrade-TJZYMNP2.js.map → upgrade-P3WX3ODU.js.map} +1 -1
  25. package/package.json +2 -1
  26. package/templates/SAFEWORD.md +4 -4
  27. package/templates/commands/architecture.md +27 -0
  28. package/templates/commands/lint.md +15 -54
  29. package/templates/commands/quality-review.md +16 -13
  30. package/templates/hooks/post-tool-lint.sh +14 -53
  31. package/dist/chunk-74FG33MU.js +0 -211
  32. package/dist/chunk-74FG33MU.js.map +0 -1
  33. package/dist/chunk-NI3Z5XHH.js.map +0 -1
  34. package/dist/reset-WJEQTYCX.js.map +0 -1
  35. package/dist/setup-UYCYH5SE.js.map +0 -1
  36. package/templates/commands/arch-review.md +0 -28
  37. package/templates/hooks/git-pre-commit.sh +0 -18
  38. /package/dist/{chunk-KEWQQP4C.js.map → chunk-75FKNZUM.js.map} +0 -0
  39. /package/templates/prompts/{arch-review.md → architecture.md} +0 -0
  40. /package/templates/prompts/{quality-review.md → review.md} +0 -0
@@ -5,15 +5,17 @@ import {
5
5
  VERSION
6
6
  } from "./chunk-ORQHKDT2.js";
7
7
  import {
8
- exists,
9
8
  header,
10
9
  info,
11
10
  keyValue,
12
- readFile,
13
- readFileSafe,
14
11
  success,
15
12
  warn
16
- } from "./chunk-NI3Z5XHH.js";
13
+ } from "./chunk-FRPJITGG.js";
14
+ import {
15
+ exists,
16
+ readFile,
17
+ readFileSafe
18
+ } from "./chunk-ARIAOK2F.js";
17
19
 
18
20
  // src/commands/check.ts
19
21
  import { join } from "path";
@@ -126,4 +128,4 @@ Upgrade available for project config`);
126
128
  export {
127
129
  check
128
130
  };
129
- //# sourceMappingURL=check-KTLIM6UR.js.map
131
+ //# sourceMappingURL=check-INXMFCL5.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/check.ts"],"sourcesContent":["/**\n * Check command - Verify project health and configuration\n */\n\nimport { join } from 'node:path';\nimport { VERSION } from '../version.js';\nimport { exists, readFile, readFileSafe } from '../utils/fs.js';\nimport { info, success, warn, header, keyValue } from '../utils/output.js';\nimport { isNewerVersion } from '../utils/version.js';\n\nexport interface CheckOptions {\n offline?: boolean;\n}\n\ninterface HealthStatus {\n configured: boolean;\n projectVersion: string | null;\n cliVersion: string;\n updateAvailable: boolean;\n latestVersion: string | null;\n issues: string[];\n}\n\n/**\n * Check for latest version from npm (with timeout)\n */\nasync function checkLatestVersion(timeout = 3000): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch('https://registry.npmjs.org/safeword/latest', {\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) return null;\n\n const data = (await response.json()) as { version?: string };\n return data.version ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Check project configuration health\n */\nfunction checkHealth(cwd: string): HealthStatus {\n const safewordDir = join(cwd, '.safeword');\n const issues: string[] = [];\n\n // Check if configured\n if (!exists(safewordDir)) {\n return {\n configured: false,\n projectVersion: null,\n cliVersion: VERSION,\n updateAvailable: false,\n latestVersion: null,\n issues: [],\n };\n }\n\n // Read project version\n const versionPath = join(safewordDir, 'version');\n const projectVersion = readFileSafe(versionPath)?.trim() ?? null;\n\n // Check for required files\n const requiredFiles = ['SAFEWORD.md', 'version', 'hooks/agents-md-check.sh'];\n\n for (const file of requiredFiles) {\n if (!exists(join(safewordDir, file))) {\n issues.push(`Missing: .safeword/${file}`);\n }\n }\n\n // Check AGENTS.md link\n const agentsMdPath = join(cwd, 'AGENTS.md');\n if (exists(agentsMdPath)) {\n const content = readFile(agentsMdPath);\n if (!content.includes('@./.safeword/SAFEWORD.md')) {\n issues.push('AGENTS.md missing safeword link');\n }\n } else {\n issues.push('AGENTS.md file missing');\n }\n\n // Check .claude/settings.json\n const settingsPath = join(cwd, '.claude', 'settings.json');\n if (!exists(settingsPath)) {\n issues.push('Missing: .claude/settings.json');\n }\n\n return {\n configured: true,\n projectVersion,\n cliVersion: VERSION,\n updateAvailable: false,\n latestVersion: null,\n issues,\n };\n}\n\nexport async function check(options: CheckOptions): Promise<void> {\n const cwd = process.cwd();\n\n header('Safeword Health Check');\n\n const health = checkHealth(cwd);\n\n // Not configured\n if (!health.configured) {\n info('Not configured. Run `safeword setup` to initialize.');\n return;\n }\n\n // Show versions\n keyValue('Safeword CLI', `v${health.cliVersion}`);\n keyValue('Project config', health.projectVersion ? `v${health.projectVersion}` : 'unknown');\n\n // Check for updates (unless offline)\n if (!options.offline) {\n info('\\nChecking for updates...');\n const latestVersion = await checkLatestVersion();\n\n if (latestVersion) {\n health.latestVersion = latestVersion;\n health.updateAvailable = isNewerVersion(health.cliVersion, latestVersion);\n\n if (health.updateAvailable) {\n warn(`Update available: v${latestVersion}`);\n info('Run `npm install -g safeword` to upgrade');\n } else {\n success('CLI is up to date');\n }\n } else {\n warn(\"Couldn't check for updates (offline?)\");\n }\n } else {\n info('\\nSkipped update check (offline mode)');\n }\n\n // Check project version vs CLI version\n if (health.projectVersion && isNewerVersion(health.cliVersion, health.projectVersion)) {\n warn(`Project config (v${health.projectVersion}) is newer than CLI (v${health.cliVersion})`);\n info('Consider upgrading the CLI');\n } else if (health.projectVersion && isNewerVersion(health.projectVersion, health.cliVersion)) {\n info(`\\nUpgrade available for project config`);\n info(\n `Run \\`safeword upgrade\\` to update from v${health.projectVersion} to v${health.cliVersion}`,\n );\n }\n\n // Show issues\n if (health.issues.length > 0) {\n header('Issues Found');\n for (const issue of health.issues) {\n warn(issue);\n }\n info('\\nRun `safeword upgrade` to repair configuration');\n } else {\n success('\\nConfiguration is healthy');\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/commands/check.ts"],"sourcesContent":["/**\n * Check command - Verify project health and configuration\n */\n\nimport { join } from 'node:path';\nimport { VERSION } from '../version.js';\nimport { exists, readFile, readFileSafe } from '../utils/fs.js';\nimport { info, success, warn, header, keyValue } from '../utils/output.js';\nimport { isNewerVersion } from '../utils/version.js';\n\nexport interface CheckOptions {\n offline?: boolean;\n}\n\ninterface HealthStatus {\n configured: boolean;\n projectVersion: string | null;\n cliVersion: string;\n updateAvailable: boolean;\n latestVersion: string | null;\n issues: string[];\n}\n\n/**\n * Check for latest version from npm (with timeout)\n */\nasync function checkLatestVersion(timeout = 3000): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const response = await fetch('https://registry.npmjs.org/safeword/latest', {\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) return null;\n\n const data = (await response.json()) as { version?: string };\n return data.version ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Check project configuration health\n */\nfunction checkHealth(cwd: string): HealthStatus {\n const safewordDir = join(cwd, '.safeword');\n const issues: string[] = [];\n\n // Check if configured\n if (!exists(safewordDir)) {\n return {\n configured: false,\n projectVersion: null,\n cliVersion: VERSION,\n updateAvailable: false,\n latestVersion: null,\n issues: [],\n };\n }\n\n // Read project version\n const versionPath = join(safewordDir, 'version');\n const projectVersion = readFileSafe(versionPath)?.trim() ?? null;\n\n // Check for required files\n const requiredFiles = ['SAFEWORD.md', 'version', 'hooks/agents-md-check.sh'];\n\n for (const file of requiredFiles) {\n if (!exists(join(safewordDir, file))) {\n issues.push(`Missing: .safeword/${file}`);\n }\n }\n\n // Check AGENTS.md link\n const agentsMdPath = join(cwd, 'AGENTS.md');\n if (exists(agentsMdPath)) {\n const content = readFile(agentsMdPath);\n if (!content.includes('@./.safeword/SAFEWORD.md')) {\n issues.push('AGENTS.md missing safeword link');\n }\n } else {\n issues.push('AGENTS.md file missing');\n }\n\n // Check .claude/settings.json\n const settingsPath = join(cwd, '.claude', 'settings.json');\n if (!exists(settingsPath)) {\n issues.push('Missing: .claude/settings.json');\n }\n\n return {\n configured: true,\n projectVersion,\n cliVersion: VERSION,\n updateAvailable: false,\n latestVersion: null,\n issues,\n };\n}\n\nexport async function check(options: CheckOptions): Promise<void> {\n const cwd = process.cwd();\n\n header('Safeword Health Check');\n\n const health = checkHealth(cwd);\n\n // Not configured\n if (!health.configured) {\n info('Not configured. Run `safeword setup` to initialize.');\n return;\n }\n\n // Show versions\n keyValue('Safeword CLI', `v${health.cliVersion}`);\n keyValue('Project config', health.projectVersion ? `v${health.projectVersion}` : 'unknown');\n\n // Check for updates (unless offline)\n if (!options.offline) {\n info('\\nChecking for updates...');\n const latestVersion = await checkLatestVersion();\n\n if (latestVersion) {\n health.latestVersion = latestVersion;\n health.updateAvailable = isNewerVersion(health.cliVersion, latestVersion);\n\n if (health.updateAvailable) {\n warn(`Update available: v${latestVersion}`);\n info('Run `npm install -g safeword` to upgrade');\n } else {\n success('CLI is up to date');\n }\n } else {\n warn(\"Couldn't check for updates (offline?)\");\n }\n } else {\n info('\\nSkipped update check (offline mode)');\n }\n\n // Check project version vs CLI version\n if (health.projectVersion && isNewerVersion(health.cliVersion, health.projectVersion)) {\n warn(`Project config (v${health.projectVersion}) is newer than CLI (v${health.cliVersion})`);\n info('Consider upgrading the CLI');\n } else if (health.projectVersion && isNewerVersion(health.projectVersion, health.cliVersion)) {\n info(`\\nUpgrade available for project config`);\n info(\n `Run \\`safeword upgrade\\` to update from v${health.projectVersion} to v${health.cliVersion}`,\n );\n }\n\n // Show issues\n if (health.issues.length > 0) {\n header('Issues Found');\n for (const issue of health.issues) {\n warn(issue);\n }\n info('\\nRun `safeword upgrade` to repair configuration');\n } else {\n success('\\nConfiguration is healthy');\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,43 @@
1
+ // src/utils/project-detector.ts
2
+ function detectProjectType(packageJson) {
3
+ const deps = packageJson.dependencies || {};
4
+ const devDeps = packageJson.devDependencies || {};
5
+ const allDeps = { ...deps, ...devDeps };
6
+ const hasTypescript = "typescript" in allDeps;
7
+ const hasReact = "react" in deps || "react" in devDeps;
8
+ const hasNextJs = "next" in deps;
9
+ const hasAstro = "astro" in deps || "astro" in devDeps;
10
+ const hasVue = "vue" in deps || "vue" in devDeps;
11
+ const hasNuxt = "nuxt" in deps;
12
+ const hasSvelte = "svelte" in deps || "svelte" in devDeps;
13
+ const hasSvelteKit = "@sveltejs/kit" in deps || "@sveltejs/kit" in devDeps;
14
+ const hasElectron = "electron" in deps || "electron" in devDeps;
15
+ const hasVitest = "vitest" in devDeps;
16
+ const hasPlaywright = "@playwright/test" in devDeps;
17
+ const hasTailwind = "tailwindcss" in allDeps;
18
+ const hasEntryPoints = !!(packageJson.main || packageJson.module || packageJson.exports);
19
+ const isPublishable = hasEntryPoints && packageJson.private !== true;
20
+ return {
21
+ typescript: hasTypescript,
22
+ react: hasReact || hasNextJs,
23
+ // Next.js implies React
24
+ nextjs: hasNextJs,
25
+ astro: hasAstro,
26
+ vue: hasVue || hasNuxt,
27
+ // Nuxt implies Vue
28
+ nuxt: hasNuxt,
29
+ svelte: hasSvelte || hasSvelteKit,
30
+ // SvelteKit implies Svelte
31
+ sveltekit: hasSvelteKit,
32
+ electron: hasElectron,
33
+ vitest: hasVitest,
34
+ playwright: hasPlaywright,
35
+ tailwind: hasTailwind,
36
+ publishableLibrary: isPublishable
37
+ };
38
+ }
39
+
40
+ export {
41
+ detectProjectType
42
+ };
43
+ //# sourceMappingURL=chunk-6CVTH67L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/project-detector.ts"],"sourcesContent":["/**\n * Project type detection from package.json\n *\n * Detects frameworks and tools used in the project to configure\n * appropriate linting rules.\n */\n\nexport interface PackageJson {\n name?: string;\n version?: string;\n private?: boolean;\n main?: string;\n module?: string;\n exports?: unknown;\n types?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport interface ProjectType {\n typescript: boolean;\n react: boolean;\n nextjs: boolean;\n astro: boolean;\n vue: boolean;\n nuxt: boolean;\n svelte: boolean;\n sveltekit: boolean;\n electron: boolean;\n vitest: boolean;\n playwright: boolean;\n tailwind: boolean;\n publishableLibrary: boolean;\n}\n\n/**\n * Detects project type from package.json contents\n */\nexport function detectProjectType(packageJson: PackageJson): ProjectType {\n const deps = packageJson.dependencies || {};\n const devDeps = packageJson.devDependencies || {};\n const allDeps = { ...deps, ...devDeps };\n\n const hasTypescript = 'typescript' in allDeps;\n const hasReact = 'react' in deps || 'react' in devDeps;\n const hasNextJs = 'next' in deps;\n const hasAstro = 'astro' in deps || 'astro' in devDeps;\n const hasVue = 'vue' in deps || 'vue' in devDeps;\n const hasNuxt = 'nuxt' in deps;\n const hasSvelte = 'svelte' in deps || 'svelte' in devDeps;\n const hasSvelteKit = '@sveltejs/kit' in deps || '@sveltejs/kit' in devDeps;\n const hasElectron = 'electron' in deps || 'electron' in devDeps;\n const hasVitest = 'vitest' in devDeps;\n const hasPlaywright = '@playwright/test' in devDeps;\n const hasTailwind = 'tailwindcss' in allDeps;\n\n // Publishable library: has entry points and is not marked private\n const hasEntryPoints = !!(packageJson.main || packageJson.module || packageJson.exports);\n const isPublishable = hasEntryPoints && packageJson.private !== true;\n\n return {\n typescript: hasTypescript,\n react: hasReact || hasNextJs, // Next.js implies React\n nextjs: hasNextJs,\n astro: hasAstro,\n vue: hasVue || hasNuxt, // Nuxt implies Vue\n nuxt: hasNuxt,\n svelte: hasSvelte || hasSvelteKit, // SvelteKit implies Svelte\n sveltekit: hasSvelteKit,\n electron: hasElectron,\n vitest: hasVitest,\n playwright: hasPlaywright,\n tailwind: hasTailwind,\n publishableLibrary: isPublishable,\n };\n}\n"],"mappings":";AAsCO,SAAS,kBAAkB,aAAuC;AACvE,QAAM,OAAO,YAAY,gBAAgB,CAAC;AAC1C,QAAM,UAAU,YAAY,mBAAmB,CAAC;AAChD,QAAM,UAAU,EAAE,GAAG,MAAM,GAAG,QAAQ;AAEtC,QAAM,gBAAgB,gBAAgB;AACtC,QAAM,WAAW,WAAW,QAAQ,WAAW;AAC/C,QAAM,YAAY,UAAU;AAC5B,QAAM,WAAW,WAAW,QAAQ,WAAW;AAC/C,QAAM,SAAS,SAAS,QAAQ,SAAS;AACzC,QAAM,UAAU,UAAU;AAC1B,QAAM,YAAY,YAAY,QAAQ,YAAY;AAClD,QAAM,eAAe,mBAAmB,QAAQ,mBAAmB;AACnE,QAAM,cAAc,cAAc,QAAQ,cAAc;AACxD,QAAM,YAAY,YAAY;AAC9B,QAAM,gBAAgB,sBAAsB;AAC5C,QAAM,cAAc,iBAAiB;AAGrC,QAAM,iBAAiB,CAAC,EAAE,YAAY,QAAQ,YAAY,UAAU,YAAY;AAChF,QAAM,gBAAgB,kBAAkB,YAAY,YAAY;AAEhE,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,OAAO,YAAY;AAAA;AAAA,IACnB,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,KAAK,UAAU;AAAA;AAAA,IACf,MAAM;AAAA,IACN,QAAQ,aAAa;AAAA;AAAA,IACrB,WAAW;AAAA,IACX,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,oBAAoB;AAAA,EACtB;AACF;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  exists
3
- } from "./chunk-NI3Z5XHH.js";
3
+ } from "./chunk-ARIAOK2F.js";
4
4
 
5
5
  // src/utils/git.ts
6
6
  import { execSync } from "child_process";
@@ -12,4 +12,4 @@ function isGitRepo(cwd) {
12
12
  export {
13
13
  isGitRepo
14
14
  };
15
- //# sourceMappingURL=chunk-KEWQQP4C.js.map
15
+ //# sourceMappingURL=chunk-75FKNZUM.js.map
@@ -91,31 +91,6 @@ function updateJson(path, updater) {
91
91
  writeJson(path, updated);
92
92
  }
93
93
 
94
- // src/utils/output.ts
95
- function info(message) {
96
- console.log(message);
97
- }
98
- function success(message) {
99
- console.log(`\u2713 ${message}`);
100
- }
101
- function warn(message) {
102
- console.warn(`\u26A0 ${message}`);
103
- }
104
- function error(message) {
105
- console.error(`\u2717 ${message}`);
106
- }
107
- function header(title) {
108
- console.log(`
109
- ${title}`);
110
- console.log("\u2500".repeat(title.length));
111
- }
112
- function listItem(item, indent = 2) {
113
- console.log(`${" ".repeat(indent)}\u2022 ${item}`);
114
- }
115
- function keyValue(key, value) {
116
- console.log(` ${key}: ${value}`);
117
- }
118
-
119
94
  export {
120
95
  getTemplatesDir,
121
96
  exists,
@@ -130,13 +105,6 @@ export {
130
105
  makeScriptsExecutable,
131
106
  readJson,
132
107
  writeJson,
133
- updateJson,
134
- info,
135
- success,
136
- warn,
137
- error,
138
- header,
139
- listItem,
140
- keyValue
108
+ updateJson
141
109
  };
142
- //# sourceMappingURL=chunk-NI3Z5XHH.js.map
110
+ //# sourceMappingURL=chunk-ARIAOK2F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/fs.ts"],"sourcesContent":["/**\n * File system utilities for CLI operations\n */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n rmSync,\n readdirSync,\n statSync,\n chmodSync,\n copyFileSync,\n} from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n// Get the directory of this module (for locating templates)\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Get path to bundled templates directory.\n * Works in both development (src/) and production (dist/) contexts.\n */\nexport function getTemplatesDir(): string {\n // When running from dist/, __dirname is packages/cli/dist/\n // Templates are at packages/cli/templates/ (one level up)\n const fromDist = join(__dirname, '..', 'templates');\n\n // Fallback path for edge cases\n const fallback = join(__dirname, '..', '..', 'templates');\n\n if (existsSync(fromDist)) return fromDist;\n if (existsSync(fallback)) return fallback;\n\n throw new Error('Templates directory not found');\n}\n\n/**\n * Check if a path exists\n */\nexport function exists(path: string): boolean {\n return existsSync(path);\n}\n\n/**\n * Check if path is a directory\n */\nexport function isDirectory(path: string): boolean {\n return existsSync(path) && statSync(path).isDirectory();\n}\n\n/**\n * Create directory recursively\n */\nexport function ensureDir(path: string): void {\n if (!existsSync(path)) {\n mkdirSync(path, { recursive: true });\n }\n}\n\n/**\n * Read file as string\n */\nexport function readFile(path: string): string {\n return readFileSync(path, 'utf-8');\n}\n\n/**\n * Read file as string, return null if not exists\n */\nexport function readFileSafe(path: string): string | null {\n if (!existsSync(path)) return null;\n return readFileSync(path, 'utf-8');\n}\n\n/**\n * Write file, creating parent directories if needed\n */\nexport function writeFile(path: string, content: string): void {\n ensureDir(dirname(path));\n writeFileSync(path, content);\n}\n\n/**\n * Remove file or directory recursively\n */\nexport function remove(path: string): void {\n if (existsSync(path)) {\n rmSync(path, { recursive: true, force: true });\n }\n}\n\n/**\n * List files in directory\n */\nexport function listDir(path: string): string[] {\n if (!existsSync(path)) return [];\n return readdirSync(path);\n}\n\n/**\n * Copy a single file\n */\nexport function copyFile(src: string, dest: string): void {\n ensureDir(dirname(dest));\n copyFileSync(src, dest);\n}\n\n/**\n * Copy directory recursively\n */\nexport function copyDir(src: string, dest: string): void {\n ensureDir(dest);\n const entries = readdirSync(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(src, entry.name);\n const destPath = join(dest, entry.name);\n\n if (entry.isDirectory()) {\n copyDir(srcPath, destPath);\n } else {\n copyFileSync(srcPath, destPath);\n }\n }\n}\n\n/**\n * Make file executable\n */\nexport function makeExecutable(path: string): void {\n chmodSync(path, 0o755);\n}\n\n/**\n * Make all shell scripts in a directory executable\n */\nexport function makeScriptsExecutable(dirPath: string): void {\n if (!existsSync(dirPath)) return;\n for (const file of readdirSync(dirPath)) {\n if (file.endsWith('.sh')) {\n chmodSync(join(dirPath, file), 0o755);\n }\n }\n}\n\n/**\n * Read JSON file\n */\nexport function readJson<T = unknown>(path: string): T | null {\n const content = readFileSafe(path);\n if (!content) return null;\n try {\n return JSON.parse(content) as T;\n } catch {\n return null;\n }\n}\n\n/**\n * Write JSON file with formatting\n */\nexport function writeJson(path: string, data: unknown): void {\n writeFile(path, JSON.stringify(data, null, 2) + '\\n');\n}\n\n/**\n * Update JSON file, merging with existing content\n */\nexport function updateJson<T extends Record<string, unknown>>(\n path: string,\n updater: (existing: T | null) => T,\n): void {\n const existing = readJson<T>(path);\n const updated = updater(existing);\n writeJson(path, updated);\n}\n"],"mappings":";AAIA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,MAAM,eAAe;AAC9B,SAAS,qBAAqB;AAG9B,IAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAMjD,SAAS,kBAA0B;AAGxC,QAAM,WAAW,KAAK,WAAW,MAAM,WAAW;AAGlD,QAAM,WAAW,KAAK,WAAW,MAAM,MAAM,WAAW;AAExD,MAAI,WAAW,QAAQ,EAAG,QAAO;AACjC,MAAI,WAAW,QAAQ,EAAG,QAAO;AAEjC,QAAM,IAAI,MAAM,+BAA+B;AACjD;AAKO,SAAS,OAAO,MAAuB;AAC5C,SAAO,WAAW,IAAI;AACxB;AAYO,SAAS,UAAU,MAAoB;AAC5C,MAAI,CAAC,WAAW,IAAI,GAAG;AACrB,cAAU,MAAM,EAAE,WAAW,KAAK,CAAC;AAAA,EACrC;AACF;AAKO,SAAS,SAAS,MAAsB;AAC7C,SAAO,aAAa,MAAM,OAAO;AACnC;AAKO,SAAS,aAAa,MAA6B;AACxD,MAAI,CAAC,WAAW,IAAI,EAAG,QAAO;AAC9B,SAAO,aAAa,MAAM,OAAO;AACnC;AAKO,SAAS,UAAU,MAAc,SAAuB;AAC7D,YAAU,QAAQ,IAAI,CAAC;AACvB,gBAAc,MAAM,OAAO;AAC7B;AAKO,SAAS,OAAO,MAAoB;AACzC,MAAI,WAAW,IAAI,GAAG;AACpB,WAAO,MAAM,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EAC/C;AACF;AAKO,SAAS,QAAQ,MAAwB;AAC9C,MAAI,CAAC,WAAW,IAAI,EAAG,QAAO,CAAC;AAC/B,SAAO,YAAY,IAAI;AACzB;AAKO,SAAS,SAAS,KAAa,MAAoB;AACxD,YAAU,QAAQ,IAAI,CAAC;AACvB,eAAa,KAAK,IAAI;AACxB;AAKO,SAAS,QAAQ,KAAa,MAAoB;AACvD,YAAU,IAAI;AACd,QAAM,UAAU,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAExD,aAAW,SAAS,SAAS;AAC3B,UAAM,UAAU,KAAK,KAAK,MAAM,IAAI;AACpC,UAAM,WAAW,KAAK,MAAM,MAAM,IAAI;AAEtC,QAAI,MAAM,YAAY,GAAG;AACvB,cAAQ,SAAS,QAAQ;AAAA,IAC3B,OAAO;AACL,mBAAa,SAAS,QAAQ;AAAA,IAChC;AAAA,EACF;AACF;AAYO,SAAS,sBAAsB,SAAuB;AAC3D,MAAI,CAAC,WAAW,OAAO,EAAG;AAC1B,aAAW,QAAQ,YAAY,OAAO,GAAG;AACvC,QAAI,KAAK,SAAS,KAAK,GAAG;AACxB,gBAAU,KAAK,SAAS,IAAI,GAAG,GAAK;AAAA,IACtC;AAAA,EACF;AACF;AAKO,SAAS,SAAsB,MAAwB;AAC5D,QAAM,UAAU,aAAa,IAAI;AACjC,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI;AACF,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,UAAU,MAAc,MAAqB;AAC3D,YAAU,MAAM,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,IAAI;AACtD;AAKO,SAAS,WACd,MACA,SACM;AACN,QAAM,WAAW,SAAY,IAAI;AACjC,QAAM,UAAU,QAAQ,QAAQ;AAChC,YAAU,MAAM,OAAO;AACzB;","names":[]}
@@ -0,0 +1,35 @@
1
+ // src/utils/output.ts
2
+ function info(message) {
3
+ console.log(message);
4
+ }
5
+ function success(message) {
6
+ console.log(`\u2713 ${message}`);
7
+ }
8
+ function warn(message) {
9
+ console.warn(`\u26A0 ${message}`);
10
+ }
11
+ function error(message) {
12
+ console.error(`\u2717 ${message}`);
13
+ }
14
+ function header(title) {
15
+ console.log(`
16
+ ${title}`);
17
+ console.log("\u2500".repeat(title.length));
18
+ }
19
+ function listItem(item, indent = 2) {
20
+ console.log(`${" ".repeat(indent)}\u2022 ${item}`);
21
+ }
22
+ function keyValue(key, value) {
23
+ console.log(` ${key}: ${value}`);
24
+ }
25
+
26
+ export {
27
+ info,
28
+ success,
29
+ warn,
30
+ error,
31
+ header,
32
+ listItem,
33
+ keyValue
34
+ };
35
+ //# sourceMappingURL=chunk-FRPJITGG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/output.ts"],"sourcesContent":["/**\n * Console output utilities for consistent CLI messaging\n */\n\n/**\n * Print info message\n */\nexport function info(message: string): void {\n console.log(message);\n}\n\n/**\n * Print success message\n */\nexport function success(message: string): void {\n console.log(`✓ ${message}`);\n}\n\n/**\n * Print warning message\n */\nexport function warn(message: string): void {\n console.warn(`⚠ ${message}`);\n}\n\n/**\n * Print error message to stderr\n */\nexport function error(message: string): void {\n console.error(`✗ ${message}`);\n}\n\n/**\n * Print a blank line\n */\nexport function blank(): void {\n console.log('');\n}\n\n/**\n * Print a section header\n */\nexport function header(title: string): void {\n console.log(`\\n${title}`);\n console.log('─'.repeat(title.length));\n}\n\n/**\n * Print a list item\n */\nexport function listItem(item: string, indent = 2): void {\n console.log(`${' '.repeat(indent)}• ${item}`);\n}\n\n/**\n * Print key-value pair\n */\nexport function keyValue(key: string, value: string): void {\n console.log(` ${key}: ${value}`);\n}\n"],"mappings":";AAOO,SAAS,KAAK,SAAuB;AAC1C,UAAQ,IAAI,OAAO;AACrB;AAKO,SAAS,QAAQ,SAAuB;AAC7C,UAAQ,IAAI,UAAK,OAAO,EAAE;AAC5B;AAKO,SAAS,KAAK,SAAuB;AAC1C,UAAQ,KAAK,UAAK,OAAO,EAAE;AAC7B;AAKO,SAAS,MAAM,SAAuB;AAC3C,UAAQ,MAAM,UAAK,OAAO,EAAE;AAC9B;AAYO,SAAS,OAAO,OAAqB;AAC1C,UAAQ,IAAI;AAAA,EAAK,KAAK,EAAE;AACxB,UAAQ,IAAI,SAAI,OAAO,MAAM,MAAM,CAAC;AACtC;AAKO,SAAS,SAAS,MAAc,SAAS,GAAS;AACvD,UAAQ,IAAI,GAAG,IAAI,OAAO,MAAM,CAAC,UAAK,IAAI,EAAE;AAC9C;AAKO,SAAS,SAAS,KAAa,OAAqB;AACzD,UAAQ,IAAI,KAAK,GAAG,KAAK,KAAK,EAAE;AAClC;","names":[]}
@@ -0,0 +1,274 @@
1
+ import {
2
+ exists,
3
+ readFile,
4
+ writeFile
5
+ } from "./chunk-ARIAOK2F.js";
6
+
7
+ // src/utils/hooks.ts
8
+ function isHookEntry(h) {
9
+ return typeof h === "object" && h !== null && "hooks" in h && Array.isArray(h.hooks);
10
+ }
11
+ function isSafewordHook(h) {
12
+ if (!isHookEntry(h)) return false;
13
+ return h.hooks.some(
14
+ (cmd) => typeof cmd.command === "string" && cmd.command.includes(".safeword")
15
+ );
16
+ }
17
+ function filterOutSafewordHooks(hooks) {
18
+ return hooks.filter((h) => !isSafewordHook(h));
19
+ }
20
+
21
+ // src/templates/content.ts
22
+ var AGENTS_MD_LINK = `**\u26A0\uFE0F ALWAYS READ FIRST: @./.safeword/SAFEWORD.md**
23
+
24
+ The SAFEWORD.md file contains core development patterns, workflows, and conventions.
25
+ Read it BEFORE working on any task in this project.
26
+
27
+ ---`;
28
+ var PRETTIERRC = `{
29
+ "semi": true,
30
+ "singleQuote": true,
31
+ "tabWidth": 2,
32
+ "trailingComma": "es5",
33
+ "printWidth": 100,
34
+ "endOfLine": "lf"
35
+ }
36
+ `;
37
+ var LINT_STAGED_CONFIG = {
38
+ "*.{js,jsx,ts,tsx,mjs,mts,cjs,cts}": ["eslint --fix", "prettier --write"],
39
+ "*.{vue,svelte,astro}": ["eslint --fix", "prettier --write"],
40
+ "*.{json,css,scss,html,yaml,yml,graphql}": ["prettier --write"],
41
+ "*.md": ["markdownlint-cli2 --fix", "prettier --write"]
42
+ };
43
+
44
+ // src/templates/config.ts
45
+ function getEslintConfig(options) {
46
+ return `import { readFileSync } from "fs";
47
+ import { defineConfig } from "eslint/config";
48
+ import js from "@eslint/js";
49
+ import { importX } from "eslint-plugin-import-x";
50
+ import sonarjs from "eslint-plugin-sonarjs";
51
+ import sdl from "@microsoft/eslint-plugin-sdl";
52
+ import playwright from "eslint-plugin-playwright";
53
+ import eslintConfigPrettier from "eslint-config-prettier";
54
+ ${options.boundaries ? 'import boundariesConfig from "./.safeword/eslint-boundaries.config.mjs";' : ""}
55
+
56
+ // Read package.json to detect frameworks at runtime
57
+ const pkg = JSON.parse(readFileSync("./package.json", "utf8"));
58
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
59
+
60
+ // Build dynamic ignores based on detected frameworks
61
+ const ignores = ["node_modules/", "dist/", "build/", "coverage/"];
62
+ if (deps["next"]) ignores.push(".next/");
63
+ if (deps["astro"]) ignores.push(".astro/");
64
+ if (deps["vue"] || deps["nuxt"]) ignores.push(".nuxt/");
65
+ if (deps["svelte"] || deps["@sveltejs/kit"]) ignores.push(".svelte-kit/");
66
+
67
+ // Start with base configs (always loaded)
68
+ const configs = [
69
+ { ignores },
70
+ js.configs.recommended,
71
+ importX.flatConfigs.recommended,
72
+ sonarjs.configs.recommended,
73
+ ...sdl.configs.recommended,
74
+ ];
75
+
76
+ // TypeScript support (detected from package.json)
77
+ if (deps["typescript"]) {
78
+ const tseslint = await import("typescript-eslint");
79
+ configs.push(importX.flatConfigs.typescript);
80
+ configs.push(...tseslint.default.configs.recommended);
81
+ }
82
+
83
+ // React/Next.js support
84
+ if (deps["react"] || deps["next"]) {
85
+ const react = await import("eslint-plugin-react");
86
+ const reactHooks = await import("eslint-plugin-react-hooks");
87
+ const jsxA11y = await import("eslint-plugin-jsx-a11y");
88
+ configs.push(react.default.configs.flat.recommended);
89
+ configs.push(react.default.configs.flat["jsx-runtime"]);
90
+ configs.push({
91
+ name: "react-hooks",
92
+ plugins: { "react-hooks": reactHooks.default },
93
+ rules: reactHooks.default.configs.recommended.rules,
94
+ });
95
+ configs.push(jsxA11y.default.flatConfigs.recommended);
96
+ }
97
+
98
+ // Next.js plugin
99
+ if (deps["next"]) {
100
+ const nextPlugin = await import("@next/eslint-plugin-next");
101
+ configs.push({
102
+ name: "nextjs",
103
+ plugins: { "@next/next": nextPlugin.default },
104
+ rules: nextPlugin.default.configs.recommended.rules,
105
+ });
106
+ }
107
+
108
+ // Astro support
109
+ if (deps["astro"]) {
110
+ const astro = await import("eslint-plugin-astro");
111
+ configs.push(...astro.default.configs.recommended);
112
+ }
113
+
114
+ // Vue support
115
+ if (deps["vue"] || deps["nuxt"]) {
116
+ const vue = await import("eslint-plugin-vue");
117
+ configs.push(...vue.default.configs["flat/recommended"]);
118
+ }
119
+
120
+ // Svelte support
121
+ if (deps["svelte"] || deps["@sveltejs/kit"]) {
122
+ const svelte = await import("eslint-plugin-svelte");
123
+ configs.push(...svelte.default.configs.recommended);
124
+ }
125
+
126
+ // Electron support
127
+ if (deps["electron"]) {
128
+ const electron = await import("@electron-toolkit/eslint-config");
129
+ configs.push(electron.default);
130
+ }
131
+
132
+ // Vitest support (scoped to test files)
133
+ if (deps["vitest"]) {
134
+ const vitest = await import("@vitest/eslint-plugin");
135
+ configs.push({
136
+ name: "vitest",
137
+ files: ["**/*.test.{js,ts,jsx,tsx}", "**/*.spec.{js,ts,jsx,tsx}", "**/tests/**"],
138
+ plugins: { vitest: vitest.default },
139
+ languageOptions: {
140
+ globals: { ...vitest.default.environments.env.globals },
141
+ },
142
+ rules: { ...vitest.default.configs.recommended.rules },
143
+ });
144
+ }
145
+
146
+ // Playwright for e2e tests (always included - safeword sets up Playwright)
147
+ configs.push({
148
+ name: "playwright",
149
+ files: ["**/e2e/**", "**/*.e2e.{js,ts,jsx,tsx}", "**/playwright/**"],
150
+ ...playwright.configs["flat/recommended"],
151
+ });
152
+
153
+ // Architecture boundaries${options.boundaries ? "\nconfigs.push(boundariesConfig);" : ""}
154
+
155
+ // eslint-config-prettier must be last to disable conflicting rules
156
+ configs.push(eslintConfigPrettier);
157
+
158
+ export default defineConfig(configs);
159
+ `;
160
+ }
161
+ var SETTINGS_HOOKS = {
162
+ SessionStart: [
163
+ {
164
+ hooks: [
165
+ {
166
+ type: "command",
167
+ command: "bash .safeword/hooks/session-verify-agents.sh"
168
+ }
169
+ ]
170
+ },
171
+ {
172
+ hooks: [
173
+ {
174
+ type: "command",
175
+ command: "bash .safeword/hooks/session-version.sh"
176
+ }
177
+ ]
178
+ },
179
+ {
180
+ hooks: [
181
+ {
182
+ type: "command",
183
+ command: "bash .safeword/hooks/session-lint-check.sh"
184
+ }
185
+ ]
186
+ }
187
+ ],
188
+ UserPromptSubmit: [
189
+ {
190
+ hooks: [
191
+ {
192
+ type: "command",
193
+ command: "bash .safeword/hooks/prompt-timestamp.sh"
194
+ }
195
+ ]
196
+ },
197
+ {
198
+ hooks: [
199
+ {
200
+ type: "command",
201
+ command: "bash .safeword/hooks/prompt-questions.sh"
202
+ }
203
+ ]
204
+ }
205
+ ],
206
+ Stop: [
207
+ {
208
+ hooks: [
209
+ {
210
+ type: "command",
211
+ command: "bash .safeword/hooks/stop-quality.sh"
212
+ }
213
+ ]
214
+ }
215
+ ],
216
+ PostToolUse: [
217
+ {
218
+ matcher: "Write|Edit|MultiEdit|NotebookEdit",
219
+ hooks: [
220
+ {
221
+ type: "command",
222
+ command: "bash .safeword/hooks/post-tool-lint.sh"
223
+ }
224
+ ]
225
+ }
226
+ ]
227
+ };
228
+
229
+ // src/utils/agents-md.ts
230
+ import { join } from "path";
231
+ var SAFEWORD_LINK_MARKER = "@./.safeword/SAFEWORD.md";
232
+ function ensureAgentsMdLink(cwd) {
233
+ const agentsMdPath = join(cwd, "AGENTS.md");
234
+ if (!exists(agentsMdPath)) {
235
+ writeFile(agentsMdPath, `${AGENTS_MD_LINK}
236
+ `);
237
+ return "created";
238
+ }
239
+ const content = readFile(agentsMdPath);
240
+ if (!content.includes(SAFEWORD_LINK_MARKER)) {
241
+ writeFile(agentsMdPath, `${AGENTS_MD_LINK}
242
+
243
+ ${content}`);
244
+ return "modified";
245
+ }
246
+ return "unchanged";
247
+ }
248
+ function removeAgentsMdLink(cwd) {
249
+ const agentsMdPath = join(cwd, "AGENTS.md");
250
+ if (!exists(agentsMdPath)) return false;
251
+ const content = readFile(agentsMdPath);
252
+ let newContent = content.replace(AGENTS_MD_LINK, "");
253
+ const lines = newContent.split("\n").filter((line) => !line.includes(SAFEWORD_LINK_MARKER));
254
+ while (lines.length > 0 && (lines[0].trim() === "" || lines[0].trim() === "---")) {
255
+ lines.shift();
256
+ }
257
+ newContent = lines.join("\n");
258
+ if (newContent !== content) {
259
+ writeFile(agentsMdPath, newContent);
260
+ return true;
261
+ }
262
+ return false;
263
+ }
264
+
265
+ export {
266
+ filterOutSafewordHooks,
267
+ PRETTIERRC,
268
+ LINT_STAGED_CONFIG,
269
+ getEslintConfig,
270
+ SETTINGS_HOOKS,
271
+ ensureAgentsMdLink,
272
+ removeAgentsMdLink
273
+ };
274
+ //# sourceMappingURL=chunk-IWWBZVHT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/hooks.ts","../src/templates/content.ts","../src/templates/config.ts","../src/utils/agents-md.ts"],"sourcesContent":["/**\n * Hook utilities for Claude Code settings\n */\n\ninterface HookCommand {\n type: string;\n command: string;\n}\n\ninterface HookEntry {\n matcher?: string;\n hooks: HookCommand[];\n}\n\n/**\n * Type guard to check if a value is a hook entry with hooks array\n */\nexport function isHookEntry(h: unknown): h is HookEntry {\n return (\n typeof h === 'object' &&\n h !== null &&\n 'hooks' in h &&\n Array.isArray((h as HookEntry).hooks)\n );\n}\n\n/**\n * Check if a hook entry contains a safeword hook (command contains '.safeword')\n */\nexport function isSafewordHook(h: unknown): boolean {\n if (!isHookEntry(h)) return false;\n return h.hooks.some(\n (cmd) => typeof cmd.command === 'string' && cmd.command.includes('.safeword'),\n );\n}\n\n/**\n * Filter out safeword hooks from an array of hook entries\n */\nexport function filterOutSafewordHooks(hooks: unknown[]): unknown[] {\n return hooks.filter((h) => !isSafewordHook(h));\n}\n","/**\n * Content templates - static string content\n *\n * Note: Most templates (SAFEWORD.md, hooks, skills, guides, etc.) are now\n * file-based in the templates/ directory. This file contains only small\n * string constants that are used inline.\n */\n\nexport const AGENTS_MD_LINK = `**⚠️ ALWAYS READ FIRST: @./.safeword/SAFEWORD.md**\n\nThe SAFEWORD.md file contains core development patterns, workflows, and conventions.\nRead it BEFORE working on any task in this project.\n\n---`;\n\nexport const PRETTIERRC = `{\n \"semi\": true,\n \"singleQuote\": true,\n \"tabWidth\": 2,\n \"trailingComma\": \"es5\",\n \"printWidth\": 100,\n \"endOfLine\": \"lf\"\n}\n`;\n\n/**\n * lint-staged configuration for pre-commit hooks\n * Runs linters only on staged files for fast commits\n *\n * SYNC: Keep file patterns in sync with post-tool-lint.sh in:\n * packages/cli/templates/hooks/post-tool-lint.sh\n */\nexport const LINT_STAGED_CONFIG = {\n '*.{js,jsx,ts,tsx,mjs,mts,cjs,cts}': ['eslint --fix', 'prettier --write'],\n '*.{vue,svelte,astro}': ['eslint --fix', 'prettier --write'],\n '*.{json,css,scss,html,yaml,yml,graphql}': ['prettier --write'],\n '*.md': ['markdownlint-cli2 --fix', 'prettier --write'],\n};\n","/**\n * Configuration templates - ESLint config generation and hook settings\n *\n * ESLint flat config (v9+) with:\n * - Dynamic framework detection from package.json at runtime\n * - Static imports for base plugins (always installed by safeword)\n * - Dynamic imports for framework plugins (loaded only if framework detected)\n * - defineConfig helper for validation and type checking\n * - eslint-config-prettier last to avoid conflicts\n *\n * See: https://eslint.org/docs/latest/use/configure/configuration-files\n */\n\n/**\n * Generates a dynamic ESLint config that adapts to project frameworks at runtime.\n *\n * The generated config reads package.json to detect frameworks and dynamically\n * imports the corresponding ESLint plugins. This allows the config to be generated\n * once at setup and automatically adapt when frameworks are added or removed.\n *\n * @param options.boundaries - Whether to include architecture boundaries config\n * @returns ESLint config file content as a string\n */\nexport function getEslintConfig(options: { boundaries?: boolean }): string {\n return `import { readFileSync } from \"fs\";\nimport { defineConfig } from \"eslint/config\";\nimport js from \"@eslint/js\";\nimport { importX } from \"eslint-plugin-import-x\";\nimport sonarjs from \"eslint-plugin-sonarjs\";\nimport sdl from \"@microsoft/eslint-plugin-sdl\";\nimport playwright from \"eslint-plugin-playwright\";\nimport eslintConfigPrettier from \"eslint-config-prettier\";\n${options.boundaries ? 'import boundariesConfig from \"./.safeword/eslint-boundaries.config.mjs\";' : ''}\n\n// Read package.json to detect frameworks at runtime\nconst pkg = JSON.parse(readFileSync(\"./package.json\", \"utf8\"));\nconst deps = { ...pkg.dependencies, ...pkg.devDependencies };\n\n// Build dynamic ignores based on detected frameworks\nconst ignores = [\"node_modules/\", \"dist/\", \"build/\", \"coverage/\"];\nif (deps[\"next\"]) ignores.push(\".next/\");\nif (deps[\"astro\"]) ignores.push(\".astro/\");\nif (deps[\"vue\"] || deps[\"nuxt\"]) ignores.push(\".nuxt/\");\nif (deps[\"svelte\"] || deps[\"@sveltejs/kit\"]) ignores.push(\".svelte-kit/\");\n\n// Start with base configs (always loaded)\nconst configs = [\n { ignores },\n js.configs.recommended,\n importX.flatConfigs.recommended,\n sonarjs.configs.recommended,\n ...sdl.configs.recommended,\n];\n\n// TypeScript support (detected from package.json)\nif (deps[\"typescript\"]) {\n const tseslint = await import(\"typescript-eslint\");\n configs.push(importX.flatConfigs.typescript);\n configs.push(...tseslint.default.configs.recommended);\n}\n\n// React/Next.js support\nif (deps[\"react\"] || deps[\"next\"]) {\n const react = await import(\"eslint-plugin-react\");\n const reactHooks = await import(\"eslint-plugin-react-hooks\");\n const jsxA11y = await import(\"eslint-plugin-jsx-a11y\");\n configs.push(react.default.configs.flat.recommended);\n configs.push(react.default.configs.flat[\"jsx-runtime\"]);\n configs.push({\n name: \"react-hooks\",\n plugins: { \"react-hooks\": reactHooks.default },\n rules: reactHooks.default.configs.recommended.rules,\n });\n configs.push(jsxA11y.default.flatConfigs.recommended);\n}\n\n// Next.js plugin\nif (deps[\"next\"]) {\n const nextPlugin = await import(\"@next/eslint-plugin-next\");\n configs.push({\n name: \"nextjs\",\n plugins: { \"@next/next\": nextPlugin.default },\n rules: nextPlugin.default.configs.recommended.rules,\n });\n}\n\n// Astro support\nif (deps[\"astro\"]) {\n const astro = await import(\"eslint-plugin-astro\");\n configs.push(...astro.default.configs.recommended);\n}\n\n// Vue support\nif (deps[\"vue\"] || deps[\"nuxt\"]) {\n const vue = await import(\"eslint-plugin-vue\");\n configs.push(...vue.default.configs[\"flat/recommended\"]);\n}\n\n// Svelte support\nif (deps[\"svelte\"] || deps[\"@sveltejs/kit\"]) {\n const svelte = await import(\"eslint-plugin-svelte\");\n configs.push(...svelte.default.configs.recommended);\n}\n\n// Electron support\nif (deps[\"electron\"]) {\n const electron = await import(\"@electron-toolkit/eslint-config\");\n configs.push(electron.default);\n}\n\n// Vitest support (scoped to test files)\nif (deps[\"vitest\"]) {\n const vitest = await import(\"@vitest/eslint-plugin\");\n configs.push({\n name: \"vitest\",\n files: [\"**/*.test.{js,ts,jsx,tsx}\", \"**/*.spec.{js,ts,jsx,tsx}\", \"**/tests/**\"],\n plugins: { vitest: vitest.default },\n languageOptions: {\n globals: { ...vitest.default.environments.env.globals },\n },\n rules: { ...vitest.default.configs.recommended.rules },\n });\n}\n\n// Playwright for e2e tests (always included - safeword sets up Playwright)\nconfigs.push({\n name: \"playwright\",\n files: [\"**/e2e/**\", \"**/*.e2e.{js,ts,jsx,tsx}\", \"**/playwright/**\"],\n ...playwright.configs[\"flat/recommended\"],\n});\n\n// Architecture boundaries${options.boundaries ? '\\nconfigs.push(boundariesConfig);' : ''}\n\n// eslint-config-prettier must be last to disable conflicting rules\nconfigs.push(eslintConfigPrettier);\n\nexport default defineConfig(configs);\n`;\n}\n\nexport const SETTINGS_HOOKS = {\n SessionStart: [\n {\n hooks: [\n {\n type: 'command',\n command: 'bash .safeword/hooks/session-verify-agents.sh',\n },\n ],\n },\n {\n hooks: [\n {\n type: 'command',\n command: 'bash .safeword/hooks/session-version.sh',\n },\n ],\n },\n {\n hooks: [\n {\n type: 'command',\n command: 'bash .safeword/hooks/session-lint-check.sh',\n },\n ],\n },\n ],\n UserPromptSubmit: [\n {\n hooks: [\n {\n type: 'command',\n command: 'bash .safeword/hooks/prompt-timestamp.sh',\n },\n ],\n },\n {\n hooks: [\n {\n type: 'command',\n command: 'bash .safeword/hooks/prompt-questions.sh',\n },\n ],\n },\n ],\n Stop: [\n {\n hooks: [\n {\n type: 'command',\n command: 'bash .safeword/hooks/stop-quality.sh',\n },\n ],\n },\n ],\n PostToolUse: [\n {\n matcher: 'Write|Edit|MultiEdit|NotebookEdit',\n hooks: [\n {\n type: 'command',\n command: 'bash .safeword/hooks/post-tool-lint.sh',\n },\n ],\n },\n ],\n};\n","/**\n * AGENTS.md file utilities\n */\n\nimport { join } from 'node:path';\nimport { exists, readFile, writeFile } from './fs.js';\nimport { AGENTS_MD_LINK } from '../templates/index.js';\n\nconst SAFEWORD_LINK_MARKER = '@./.safeword/SAFEWORD.md';\n\n/**\n * Check if AGENTS.md has the safeword link\n */\nexport function hasAgentsMdLink(cwd: string): boolean {\n const agentsMdPath = join(cwd, 'AGENTS.md');\n if (!exists(agentsMdPath)) return false;\n const content = readFile(agentsMdPath);\n return content.includes(SAFEWORD_LINK_MARKER);\n}\n\n/**\n * Ensure AGENTS.md exists and has the safeword link.\n * Returns 'created' | 'modified' | 'unchanged'\n */\nexport function ensureAgentsMdLink(cwd: string): 'created' | 'modified' | 'unchanged' {\n const agentsMdPath = join(cwd, 'AGENTS.md');\n\n if (!exists(agentsMdPath)) {\n writeFile(agentsMdPath, `${AGENTS_MD_LINK}\\n`);\n return 'created';\n }\n\n const content = readFile(agentsMdPath);\n if (!content.includes(SAFEWORD_LINK_MARKER)) {\n writeFile(agentsMdPath, `${AGENTS_MD_LINK}\\n\\n${content}`);\n return 'modified';\n }\n\n return 'unchanged';\n}\n\n/**\n * Remove safeword link block from AGENTS.md.\n * Returns true if link was removed.\n */\nexport function removeAgentsMdLink(cwd: string): boolean {\n const agentsMdPath = join(cwd, 'AGENTS.md');\n if (!exists(agentsMdPath)) return false;\n\n const content = readFile(agentsMdPath);\n\n // Remove the entire AGENTS_MD_LINK block if present\n let newContent = content.replace(AGENTS_MD_LINK, '');\n\n // Also handle legacy single-line format (filter any remaining lines with marker)\n const lines = newContent.split('\\n').filter((line) => !line.includes(SAFEWORD_LINK_MARKER));\n\n // Remove extra blank lines and separators at the start\n while (lines.length > 0 && (lines[0].trim() === '' || lines[0].trim() === '---')) {\n lines.shift();\n }\n\n newContent = lines.join('\\n');\n\n if (newContent !== content) {\n writeFile(agentsMdPath, newContent);\n return true;\n }\n\n return false;\n}\n"],"mappings":";;;;;;;AAiBO,SAAS,YAAY,GAA4B;AACtD,SACE,OAAO,MAAM,YACb,MAAM,QACN,WAAW,KACX,MAAM,QAAS,EAAgB,KAAK;AAExC;AAKO,SAAS,eAAe,GAAqB;AAClD,MAAI,CAAC,YAAY,CAAC,EAAG,QAAO;AAC5B,SAAO,EAAE,MAAM;AAAA,IACb,CAAC,QAAQ,OAAO,IAAI,YAAY,YAAY,IAAI,QAAQ,SAAS,WAAW;AAAA,EAC9E;AACF;AAKO,SAAS,uBAAuB,OAA6B;AAClE,SAAO,MAAM,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;AAC/C;;;ACjCO,IAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAOvB,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBnB,IAAM,qBAAqB;AAAA,EAChC,qCAAqC,CAAC,gBAAgB,kBAAkB;AAAA,EACxE,wBAAwB,CAAC,gBAAgB,kBAAkB;AAAA,EAC3D,2CAA2C,CAAC,kBAAkB;AAAA,EAC9D,QAAQ,CAAC,2BAA2B,kBAAkB;AACxD;;;ACdO,SAAS,gBAAgB,SAA2C;AACzE,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQP,QAAQ,aAAa,6EAA6E,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAmG1E,QAAQ,aAAa,sCAAsC,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOzF;AAEO,IAAM,iBAAiB;AAAA,EAC5B,cAAc;AAAA,IACZ;AAAA,MACE,OAAO;AAAA,QACL;AAAA,UACE,MAAM;AAAA,UACN,SAAS;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,OAAO;AAAA,QACL;AAAA,UACE,MAAM;AAAA,UACN,SAAS;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,OAAO;AAAA,QACL;AAAA,UACE,MAAM;AAAA,UACN,SAAS;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,kBAAkB;AAAA,IAChB;AAAA,MACE,OAAO;AAAA,QACL;AAAA,UACE,MAAM;AAAA,UACN,SAAS;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,OAAO;AAAA,QACL;AAAA,UACE,MAAM;AAAA,UACN,SAAS;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,MACE,OAAO;AAAA,QACL;AAAA,UACE,MAAM;AAAA,UACN,SAAS;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,MACE,SAAS;AAAA,MACT,OAAO;AAAA,QACL;AAAA,UACE,MAAM;AAAA,UACN,SAAS;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AC1MA,SAAS,YAAY;AAIrB,IAAM,uBAAuB;AAgBtB,SAAS,mBAAmB,KAAmD;AACpF,QAAM,eAAe,KAAK,KAAK,WAAW;AAE1C,MAAI,CAAC,OAAO,YAAY,GAAG;AACzB,cAAU,cAAc,GAAG,cAAc;AAAA,CAAI;AAC7C,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,SAAS,YAAY;AACrC,MAAI,CAAC,QAAQ,SAAS,oBAAoB,GAAG;AAC3C,cAAU,cAAc,GAAG,cAAc;AAAA;AAAA,EAAO,OAAO,EAAE;AACzD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAMO,SAAS,mBAAmB,KAAsB;AACvD,QAAM,eAAe,KAAK,KAAK,WAAW;AAC1C,MAAI,CAAC,OAAO,YAAY,EAAG,QAAO;AAElC,QAAM,UAAU,SAAS,YAAY;AAGrC,MAAI,aAAa,QAAQ,QAAQ,gBAAgB,EAAE;AAGnD,QAAM,QAAQ,WAAW,MAAM,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,KAAK,SAAS,oBAAoB,CAAC;AAG1F,SAAO,MAAM,SAAS,MAAM,MAAM,CAAC,EAAE,KAAK,MAAM,MAAM,MAAM,CAAC,EAAE,KAAK,MAAM,QAAQ;AAChF,UAAM,MAAM;AAAA,EACd;AAEA,eAAa,MAAM,KAAK,IAAI;AAE5B,MAAI,eAAe,SAAS;AAC1B,cAAU,cAAc,UAAU;AAClC,WAAO;AAAA,EACT;AAEA,SAAO;AACT;","names":[]}
package/dist/cli.js CHANGED
@@ -8,25 +8,29 @@ import { Command } from "commander";
8
8
  var program = new Command();
9
9
  program.name("safeword").description("CLI for setting up and managing safeword development environments").version(VERSION);
10
10
  program.command("setup").description("Set up safeword in the current project").option("-y, --yes", "Accept all defaults (non-interactive mode)").action(async (options) => {
11
- const { setup } = await import("./setup-UYCYH5SE.js");
11
+ const { setup } = await import("./setup-65EVU5OT.js");
12
12
  await setup(options);
13
13
  });
14
14
  program.command("check").description("Check project health and versions").option("--offline", "Skip remote version check").action(async (options) => {
15
- const { check } = await import("./check-KTLIM6UR.js");
15
+ const { check } = await import("./check-INXMFCL5.js");
16
16
  await check(options);
17
17
  });
18
18
  program.command("upgrade").description("Upgrade safeword configuration to latest version").action(async () => {
19
- const { upgrade } = await import("./upgrade-TJZYMNP2.js");
19
+ const { upgrade } = await import("./upgrade-P3WX3ODU.js");
20
20
  await upgrade();
21
21
  });
22
22
  program.command("diff").description("Preview changes that would be made by upgrade").option("-v, --verbose", "Show full diff output").action(async (options) => {
23
- const { diff } = await import("./diff-TV24EW3X.js");
23
+ const { diff } = await import("./diff-L7G22MG7.js");
24
24
  await diff(options);
25
25
  });
26
26
  program.command("reset").description("Remove safeword configuration from project").option("-y, --yes", "Skip confirmation prompt").action(async (options) => {
27
- const { reset } = await import("./reset-WJEQTYCX.js");
27
+ const { reset } = await import("./reset-5SRM3P6J.js");
28
28
  await reset(options);
29
29
  });
30
+ program.command("sync").description("Sync linting plugins with project dependencies").option("-q, --quiet", "Suppress output except errors").option("-s, --stage", "Stage modified files (for pre-commit hooks)").action(async (options) => {
31
+ const { sync } = await import("./sync-4XBMKLXS.js");
32
+ await sync(options);
33
+ });
30
34
  if (process.argv.length === 2) {
31
35
  program.help();
32
36
  }
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport { VERSION } from './version.js';\n\nconst program = new Command();\n\nprogram\n .name('safeword')\n .description('CLI for setting up and managing safeword development environments')\n .version(VERSION);\n\nprogram\n .command('setup')\n .description('Set up safeword in the current project')\n .option('-y, --yes', 'Accept all defaults (non-interactive mode)')\n .action(async options => {\n const { setup } = await import('./commands/setup.js');\n await setup(options);\n });\n\nprogram\n .command('check')\n .description('Check project health and versions')\n .option('--offline', 'Skip remote version check')\n .action(async options => {\n const { check } = await import('./commands/check.js');\n await check(options);\n });\n\nprogram\n .command('upgrade')\n .description('Upgrade safeword configuration to latest version')\n .action(async () => {\n const { upgrade } = await import('./commands/upgrade.js');\n await upgrade();\n });\n\nprogram\n .command('diff')\n .description('Preview changes that would be made by upgrade')\n .option('-v, --verbose', 'Show full diff output')\n .action(async options => {\n const { diff } = await import('./commands/diff.js');\n await diff(options);\n });\n\nprogram\n .command('reset')\n .description('Remove safeword configuration from project')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async options => {\n const { reset } = await import('./commands/reset.js');\n await reset(options);\n });\n\n// Show help if no arguments provided\nif (process.argv.length === 2) {\n program.help();\n}\n\n// Parse arguments\nprogram.parse();\n"],"mappings":";;;;;;AAEA,SAAS,eAAe;AAGxB,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,UAAU,EACf,YAAY,mEAAmE,EAC/E,QAAQ,OAAO;AAElB,QACG,QAAQ,OAAO,EACf,YAAY,wCAAwC,EACpD,OAAO,aAAa,4CAA4C,EAChE,OAAO,OAAM,YAAW;AACvB,QAAM,EAAE,MAAM,IAAI,MAAM,OAAO,qBAAqB;AACpD,QAAM,MAAM,OAAO;AACrB,CAAC;AAEH,QACG,QAAQ,OAAO,EACf,YAAY,mCAAmC,EAC/C,OAAO,aAAa,2BAA2B,EAC/C,OAAO,OAAM,YAAW;AACvB,QAAM,EAAE,MAAM,IAAI,MAAM,OAAO,qBAAqB;AACpD,QAAM,MAAM,OAAO;AACrB,CAAC;AAEH,QACG,QAAQ,SAAS,EACjB,YAAY,kDAAkD,EAC9D,OAAO,YAAY;AAClB,QAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,uBAAuB;AACxD,QAAM,QAAQ;AAChB,CAAC;AAEH,QACG,QAAQ,MAAM,EACd,YAAY,+CAA+C,EAC3D,OAAO,iBAAiB,uBAAuB,EAC/C,OAAO,OAAM,YAAW;AACvB,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,oBAAoB;AAClD,QAAM,KAAK,OAAO;AACpB,CAAC;AAEH,QACG,QAAQ,OAAO,EACf,YAAY,4CAA4C,EACxD,OAAO,aAAa,0BAA0B,EAC9C,OAAO,OAAM,YAAW;AACvB,QAAM,EAAE,MAAM,IAAI,MAAM,OAAO,qBAAqB;AACpD,QAAM,MAAM,OAAO;AACrB,CAAC;AAGH,IAAI,QAAQ,KAAK,WAAW,GAAG;AAC7B,UAAQ,KAAK;AACf;AAGA,QAAQ,MAAM;","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport { VERSION } from './version.js';\n\nconst program = new Command();\n\nprogram\n .name('safeword')\n .description('CLI for setting up and managing safeword development environments')\n .version(VERSION);\n\nprogram\n .command('setup')\n .description('Set up safeword in the current project')\n .option('-y, --yes', 'Accept all defaults (non-interactive mode)')\n .action(async options => {\n const { setup } = await import('./commands/setup.js');\n await setup(options);\n });\n\nprogram\n .command('check')\n .description('Check project health and versions')\n .option('--offline', 'Skip remote version check')\n .action(async options => {\n const { check } = await import('./commands/check.js');\n await check(options);\n });\n\nprogram\n .command('upgrade')\n .description('Upgrade safeword configuration to latest version')\n .action(async () => {\n const { upgrade } = await import('./commands/upgrade.js');\n await upgrade();\n });\n\nprogram\n .command('diff')\n .description('Preview changes that would be made by upgrade')\n .option('-v, --verbose', 'Show full diff output')\n .action(async options => {\n const { diff } = await import('./commands/diff.js');\n await diff(options);\n });\n\nprogram\n .command('reset')\n .description('Remove safeword configuration from project')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async options => {\n const { reset } = await import('./commands/reset.js');\n await reset(options);\n });\n\nprogram\n .command('sync')\n .description('Sync linting plugins with project dependencies')\n .option('-q, --quiet', 'Suppress output except errors')\n .option('-s, --stage', 'Stage modified files (for pre-commit hooks)')\n .action(async options => {\n const { sync } = await import('./commands/sync.js');\n await sync(options);\n });\n\n// Show help if no arguments provided\nif (process.argv.length === 2) {\n program.help();\n}\n\n// Parse arguments\nprogram.parse();\n"],"mappings":";;;;;;AAEA,SAAS,eAAe;AAGxB,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,UAAU,EACf,YAAY,mEAAmE,EAC/E,QAAQ,OAAO;AAElB,QACG,QAAQ,OAAO,EACf,YAAY,wCAAwC,EACpD,OAAO,aAAa,4CAA4C,EAChE,OAAO,OAAM,YAAW;AACvB,QAAM,EAAE,MAAM,IAAI,MAAM,OAAO,qBAAqB;AACpD,QAAM,MAAM,OAAO;AACrB,CAAC;AAEH,QACG,QAAQ,OAAO,EACf,YAAY,mCAAmC,EAC/C,OAAO,aAAa,2BAA2B,EAC/C,OAAO,OAAM,YAAW;AACvB,QAAM,EAAE,MAAM,IAAI,MAAM,OAAO,qBAAqB;AACpD,QAAM,MAAM,OAAO;AACrB,CAAC;AAEH,QACG,QAAQ,SAAS,EACjB,YAAY,kDAAkD,EAC9D,OAAO,YAAY;AAClB,QAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,uBAAuB;AACxD,QAAM,QAAQ;AAChB,CAAC;AAEH,QACG,QAAQ,MAAM,EACd,YAAY,+CAA+C,EAC3D,OAAO,iBAAiB,uBAAuB,EAC/C,OAAO,OAAM,YAAW;AACvB,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,oBAAoB;AAClD,QAAM,KAAK,OAAO;AACpB,CAAC;AAEH,QACG,QAAQ,OAAO,EACf,YAAY,4CAA4C,EACxD,OAAO,aAAa,0BAA0B,EAC9C,OAAO,OAAM,YAAW;AACvB,QAAM,EAAE,MAAM,IAAI,MAAM,OAAO,qBAAqB;AACpD,QAAM,MAAM,OAAO;AACrB,CAAC;AAEH,QACG,QAAQ,MAAM,EACd,YAAY,gDAAgD,EAC5D,OAAO,eAAe,+BAA+B,EACrD,OAAO,eAAe,6CAA6C,EACnE,OAAO,OAAM,YAAW;AACvB,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,oBAAoB;AAClD,QAAM,KAAK,OAAO;AACpB,CAAC;AAGH,IAAI,QAAQ,KAAK,WAAW,GAAG;AAC7B,UAAQ,KAAK;AACf;AAGA,QAAQ,MAAM;","names":[]}
@@ -3,14 +3,16 @@ import {
3
3
  } from "./chunk-ORQHKDT2.js";
4
4
  import {
5
5
  error,
6
- exists,
7
- getTemplatesDir,
8
6
  header,
9
7
  info,
10
8
  listItem,
11
- readFileSafe,
12
9
  success
13
- } from "./chunk-NI3Z5XHH.js";
10
+ } from "./chunk-FRPJITGG.js";
11
+ import {
12
+ exists,
13
+ getTemplatesDir,
14
+ readFileSafe
15
+ } from "./chunk-ARIAOK2F.js";
14
16
 
15
17
  // src/commands/diff.ts
16
18
  import { join } from "path";
@@ -163,4 +165,4 @@ ${file.path}: (new file)`);
163
165
  export {
164
166
  diff
165
167
  };
166
- //# sourceMappingURL=diff-TV24EW3X.js.map
168
+ //# sourceMappingURL=diff-L7G22MG7.js.map