safeword 0.8.5 → 0.8.7

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.
@@ -9,12 +9,12 @@ import {
9
9
  reconcile,
10
10
  success,
11
11
  warn
12
- } from "./chunk-SIEJPWQA.js";
12
+ } from "./chunk-3OK3NQEW.js";
13
13
  import {
14
14
  SAFEWORD_SCHEMA,
15
15
  exists,
16
16
  readFileSafe
17
- } from "./chunk-62YXVEKM.js";
17
+ } from "./chunk-34PU3QZI.js";
18
18
  import {
19
19
  VERSION
20
20
  } from "./chunk-ORQHKDT2.js";
@@ -162,4 +162,4 @@ async function check(options) {
162
162
  export {
163
163
  check
164
164
  };
165
- //# sourceMappingURL=check-QZ3ZAHZY.js.map
165
+ //# sourceMappingURL=check-PPVIEF3Q.js.map
@@ -270,10 +270,36 @@ const configs = [
270
270
  ];
271
271
 
272
272
  // TypeScript support (detected from package.json)
273
+ // Uses type-aware rules if tsconfig.json exists, otherwise falls back to basic rules
273
274
  if (deps["typescript"] || deps["typescript-eslint"]) {
274
275
  const tseslint = await tryImport("typescript-eslint", "TypeScript");
276
+ const { existsSync } = await import("fs");
277
+ const hasTsconfig = existsSync(join(__dirname, "tsconfig.json"));
278
+
275
279
  configs.push(importX.flatConfigs.typescript);
276
- configs.push(...tseslint.default.configs.recommended);
280
+
281
+ if (hasTsconfig) {
282
+ // Type-aware linting (recommended + stylistic)
283
+ configs.push(...tseslint.default.configs.recommendedTypeChecked);
284
+ configs.push(...tseslint.default.configs.stylisticTypeChecked);
285
+ configs.push({
286
+ languageOptions: {
287
+ parserOptions: {
288
+ projectService: true,
289
+ tsconfigRootDir: __dirname,
290
+ },
291
+ },
292
+ });
293
+ // Disable type-checked rules for JS files (no type info available)
294
+ configs.push({
295
+ files: ["**/*.js", "**/*.mjs", "**/*.cjs"],
296
+ extends: [tseslint.default.configs.disableTypeChecked],
297
+ });
298
+ } else {
299
+ // Fall back to non-type-aware rules when no tsconfig exists
300
+ configs.push(...tseslint.default.configs.recommended);
301
+ configs.push(...tseslint.default.configs.stylistic);
302
+ }
277
303
  }
278
304
 
279
305
  // React/Next.js support
@@ -636,6 +662,7 @@ var SAFEWORD_SCHEMA = {
636
662
  ".safeword/planning/test-definitions",
637
663
  ".safeword/planning/design",
638
664
  ".safeword/planning/issues",
665
+ ".safeword/planning/plans",
639
666
  ".safeword/scripts",
640
667
  ".husky",
641
668
  ".cursor",
@@ -720,7 +747,7 @@ var SAFEWORD_SCHEMA = {
720
747
  template: "scripts/bisect-zombie-processes.sh"
721
748
  },
722
749
  ".safeword/scripts/lint-md.sh": { template: "scripts/lint-md.sh" },
723
- // Claude skills and commands (8 files)
750
+ // Claude skills and commands (9 files)
724
751
  ".claude/skills/safeword-brainstorming/SKILL.md": {
725
752
  template: "skills/safeword-brainstorming/SKILL.md"
726
753
  },
@@ -736,12 +763,15 @@ var SAFEWORD_SCHEMA = {
736
763
  ".claude/skills/safeword-refactoring/SKILL.md": {
737
764
  template: "skills/safeword-refactoring/SKILL.md"
738
765
  },
766
+ ".claude/skills/safeword-writing-plans/SKILL.md": {
767
+ template: "skills/safeword-writing-plans/SKILL.md"
768
+ },
739
769
  ".claude/commands/architecture.md": { template: "commands/architecture.md" },
740
770
  ".claude/commands/lint.md": { template: "commands/lint.md" },
741
771
  ".claude/commands/quality-review.md": { template: "commands/quality-review.md" },
742
772
  // Husky (1 file)
743
773
  ".husky/pre-commit": { content: HUSKY_PRE_COMMIT_CONTENT },
744
- // Cursor rules (6 files)
774
+ // Cursor rules (7 files)
745
775
  ".cursor/rules/safeword-core.mdc": { template: "cursor/rules/safeword-core.mdc" },
746
776
  ".cursor/rules/safeword-brainstorming.mdc": {
747
777
  template: "cursor/rules/safeword-brainstorming.mdc"
@@ -758,6 +788,9 @@ var SAFEWORD_SCHEMA = {
758
788
  ".cursor/rules/safeword-refactoring.mdc": {
759
789
  template: "cursor/rules/safeword-refactoring.mdc"
760
790
  },
791
+ ".cursor/rules/safeword-writing-plans.mdc": {
792
+ template: "cursor/rules/safeword-writing-plans.mdc"
793
+ },
761
794
  // Cursor commands (3 files - same as Claude)
762
795
  ".cursor/commands/lint.md": { template: "commands/lint.md" },
763
796
  ".cursor/commands/quality-review.md": { template: "commands/quality-review.md" },
@@ -1011,4 +1044,4 @@ export {
1011
1044
  getConditionalEslintPackages,
1012
1045
  SAFEWORD_SCHEMA
1013
1046
  };
1014
- //# sourceMappingURL=chunk-62YXVEKM.js.map
1047
+ //# sourceMappingURL=chunk-34PU3QZI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/fs.ts","../src/utils/project-detector.ts","../src/templates/content.ts","../src/templates/config.ts","../src/utils/boundaries.ts","../src/utils/install.ts","../src/utils/hooks.ts","../src/schema.ts"],"sourcesContent":["/**\n * File system utilities for CLI operations\n */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n rmSync,\n rmdirSync,\n readdirSync,\n chmodSync,\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 *\n * Note: We check for SAFEWORD.md to distinguish from src/templates/ which\n * contains TypeScript source files (config.ts, content.ts).\n *\n * Path resolution (bundled with tsup):\n * - From dist/chunk-*.js: __dirname = packages/cli/dist/ → ../templates\n */\nexport function getTemplatesDir(): string {\n const knownTemplateFile = 'SAFEWORD.md';\n\n // Try different relative paths - the bundled code ends up in dist/ directly (flat)\n // while source is in src/utils/\n const candidates = [\n join(__dirname, '..', 'templates'), // From dist/ (flat bundled)\n join(__dirname, '..', '..', 'templates'), // From src/utils/ or dist/utils/\n join(__dirname, 'templates'), // Direct sibling (unlikely but safe)\n ];\n\n for (const candidate of candidates) {\n if (existsSync(join(candidate, knownTemplateFile))) {\n return candidate;\n }\n }\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 * 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 * Remove directory only if empty, returns true if removed\n */\nexport function removeIfEmpty(path: string): boolean {\n if (!existsSync(path)) return false;\n try {\n rmdirSync(path); // Non-recursive, throws if not empty\n return true;\n } catch {\n return false;\n }\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 * Project type detection from package.json\n *\n * Detects frameworks and tools used in the project to configure\n * appropriate linting rules.\n */\n\nimport { readdirSync } from 'node:fs';\nimport { join } from 'node:path';\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 shell: boolean;\n}\n\n/**\n * Checks if a directory contains any .sh files up to specified depth.\n * Excludes node_modules and .git directories.\n */\nexport function hasShellScripts(cwd: string, maxDepth = 4): boolean {\n const excludeDirs = new Set(['node_modules', '.git', '.safeword']);\n\n function scan(dir: string, depth: number): boolean {\n if (depth > maxDepth) return false;\n\n try {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isFile() && entry.name.endsWith('.sh')) {\n return true;\n }\n if (entry.isDirectory() && !excludeDirs.has(entry.name)) {\n if (scan(join(dir, entry.name), depth + 1)) {\n return true;\n }\n }\n }\n } catch {\n // Ignore permission errors\n }\n return false;\n }\n\n return scan(cwd, 0);\n}\n\n/**\n * Detects project type from package.json contents and optional file scanning\n */\nexport function detectProjectType(packageJson: PackageJson, cwd?: string): 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 // Shell scripts: detected by scanning for .sh files\n const hasShell = cwd ? hasShellScripts(cwd) : false;\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 shell: hasShell,\n };\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\nimport type { ProjectType } from '../utils/project-detector.js';\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\ninterface PrettierConfig {\n semi: boolean;\n singleQuote: boolean;\n tabWidth: number;\n trailingComma: string;\n printWidth: number;\n endOfLine: string;\n plugins?: string[];\n}\n\n/**\n * Generate .prettierrc content based on project type.\n * Explicitly lists plugins to ensure compatibility with pnpm/Yarn PnP.\n */\nexport function getPrettierConfig(projectType: ProjectType): string {\n const config: PrettierConfig = {\n semi: true,\n singleQuote: true,\n tabWidth: 2,\n trailingComma: 'es5',\n printWidth: 100,\n endOfLine: 'lf',\n };\n\n const plugins: string[] = [];\n\n if (projectType.astro) plugins.push('prettier-plugin-astro');\n if (projectType.svelte) plugins.push('prettier-plugin-svelte');\n if (projectType.shell) plugins.push('prettier-plugin-sh');\n // Tailwind must be last for proper class sorting\n if (projectType.tailwind) plugins.push('prettier-plugin-tailwindcss');\n\n if (plugins.length > 0) {\n config.plugins = plugins;\n }\n\n return JSON.stringify(config, null, 2) + '\\n';\n}\n\n/**\n * Generate lint-staged configuration based on project type.\n * Only includes shell patterns when shell scripts are detected.\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 function getLintStagedConfig(projectType: ProjectType): Record<string, string[]> {\n const config: Record<string, string[]> = {\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 if (projectType.shell) {\n config['*.sh'] = ['shellcheck', 'prettier --write'];\n }\n\n return config;\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 `/* eslint-disable import-x/no-unresolved, no-undef -- dynamic imports for optional framework plugins, console used in tryImport */\nimport { readFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { defineConfig } from \"eslint/config\";\nimport js from \"@eslint/js\";\nimport { importX } from \"eslint-plugin-import-x\";\nimport { createTypeScriptImportResolver } from \"eslint-import-resolver-typescript\";\nimport sonarjs from \"eslint-plugin-sonarjs\";\nimport sdl from \"@microsoft/eslint-plugin-sdl\";\nimport playwright from \"eslint-plugin-playwright\";\nimport unicorn from \"eslint-plugin-unicorn\";\nimport eslintConfigPrettier from \"eslint-config-prettier\";\n${options.boundaries ? 'import boundariesConfig from \"./.safeword/eslint-boundaries.config.mjs\";' : ''}\n\n// Read package.json relative to this config file (not CWD)\n// This ensures correct detection in monorepos where lint-staged may run from subdirectories\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, \"package.json\"), \"utf8\"));\nconst deps = { ...pkg.dependencies, ...pkg.devDependencies };\n\n// Helper for dynamic imports with actionable error messages\nasync function tryImport(pkgName, frameworkName) {\n try {\n return await import(pkgName);\n } catch (err) {\n if (err.code === \"ERR_MODULE_NOT_FOUND\") {\n console.error(\\`\\\\n✗ Missing ESLint plugin for \\${frameworkName}\\\\n\\`);\n console.error(\\`Your package.json has \\${frameworkName} but the ESLint plugin is not installed.\\`);\n console.error(\\`Run: npm install -D \\${pkgName}\\\\n\\`);\n console.error(\\`Or run: npx safeword sync\\\\n\\`);\n }\n throw err;\n }\n}\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 {\n settings: {\n \"import-x/resolver-next\": [createTypeScriptImportResolver()],\n },\n },\n sonarjs.configs.recommended,\n ...sdl.configs.recommended,\n unicorn.configs[\"flat/recommended\"],\n {\n // Unicorn overrides for LLM-generated code\n // Keep modern JS enforcement, disable overly pedantic rules\n rules: {\n \"unicorn/prevent-abbreviations\": \"off\", // ctx, dir, pkg, err are standard\n \"unicorn/no-null\": \"off\", // null is valid JS\n \"unicorn/no-process-exit\": \"off\", // CLI apps use process.exit\n \"unicorn/import-style\": \"off\", // Named imports are fine\n \"unicorn/numeric-separators-style\": \"off\", // Style preference\n \"unicorn/text-encoding-identifier-case\": \"off\", // utf-8 vs utf8\n \"unicorn/switch-case-braces\": \"warn\", // Good practice, not critical\n \"unicorn/catch-error-name\": \"warn\", // Reasonable, auto-fixable\n \"unicorn/no-negated-condition\": \"off\", // Sometimes clearer\n \"unicorn/no-array-reduce\": \"off\", // Reduce is fine when readable\n \"unicorn/no-array-for-each\": \"off\", // forEach is fine\n \"unicorn/prefer-module\": \"off\", // CJS still valid\n },\n },\n];\n\n// TypeScript support (detected from package.json)\n// Uses type-aware rules if tsconfig.json exists, otherwise falls back to basic rules\nif (deps[\"typescript\"] || deps[\"typescript-eslint\"]) {\n const tseslint = await tryImport(\"typescript-eslint\", \"TypeScript\");\n const { existsSync } = await import(\"fs\");\n const hasTsconfig = existsSync(join(__dirname, \"tsconfig.json\"));\n\n configs.push(importX.flatConfigs.typescript);\n\n if (hasTsconfig) {\n // Type-aware linting (recommended + stylistic)\n configs.push(...tseslint.default.configs.recommendedTypeChecked);\n configs.push(...tseslint.default.configs.stylisticTypeChecked);\n configs.push({\n languageOptions: {\n parserOptions: {\n projectService: true,\n tsconfigRootDir: __dirname,\n },\n },\n });\n // Disable type-checked rules for JS files (no type info available)\n configs.push({\n files: [\"**/*.js\", \"**/*.mjs\", \"**/*.cjs\"],\n extends: [tseslint.default.configs.disableTypeChecked],\n });\n } else {\n // Fall back to non-type-aware rules when no tsconfig exists\n configs.push(...tseslint.default.configs.recommended);\n configs.push(...tseslint.default.configs.stylistic);\n }\n}\n\n// React/Next.js support\nif (deps[\"react\"] || deps[\"next\"]) {\n const react = await tryImport(\"eslint-plugin-react\", \"React\");\n const reactHooks = await tryImport(\"eslint-plugin-react-hooks\", \"React\");\n const jsxA11y = await tryImport(\"eslint-plugin-jsx-a11y\", \"React\");\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 tryImport(\"@next/eslint-plugin-next\", \"Next.js\");\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 tryImport(\"eslint-plugin-astro\", \"Astro\");\n configs.push(...astro.default.configs.recommended);\n}\n\n// Vue support\nif (deps[\"vue\"] || deps[\"nuxt\"]) {\n const vue = await tryImport(\"eslint-plugin-vue\", \"Vue\");\n configs.push(...vue.default.configs[\"flat/recommended\"]);\n}\n\n// Svelte support\nif (deps[\"svelte\"] || deps[\"@sveltejs/kit\"]) {\n const svelte = await tryImport(\"eslint-plugin-svelte\", \"Svelte\");\n configs.push(...svelte.default.configs.recommended);\n}\n\n// Electron support\nif (deps[\"electron\"]) {\n const electron = await tryImport(\"@electron-toolkit/eslint-config\", \"Electron\");\n configs.push(electron.default);\n}\n\n// Vitest support (scoped to test files)\nif (deps[\"vitest\"]) {\n const vitest = await tryImport(\"@vitest/eslint-plugin\", \"Vitest\");\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\n// Cursor hooks configuration (.cursor/hooks.json format)\n// See: https://cursor.com/docs/agent/hooks\nexport const CURSOR_HOOKS = {\n afterFileEdit: [{ command: './.safeword/hooks/cursor/after-file-edit.sh' }],\n stop: [{ command: './.safeword/hooks/cursor/stop.sh' }],\n};\n\n// Claude Code hooks configuration (.claude/settings.json format)\nexport const SETTINGS_HOOKS = {\n SessionStart: [\n {\n hooks: [\n {\n type: 'command',\n command: '\"$CLAUDE_PROJECT_DIR\"/.safeword/hooks/session-verify-agents.sh',\n },\n ],\n },\n {\n hooks: [\n {\n type: 'command',\n command: '\"$CLAUDE_PROJECT_DIR\"/.safeword/hooks/session-version.sh',\n },\n ],\n },\n {\n hooks: [\n {\n type: 'command',\n command: '\"$CLAUDE_PROJECT_DIR\"/.safeword/hooks/session-lint-check.sh',\n },\n ],\n },\n ],\n UserPromptSubmit: [\n {\n hooks: [\n {\n type: 'command',\n command: '\"$CLAUDE_PROJECT_DIR\"/.safeword/hooks/prompt-timestamp.sh',\n },\n ],\n },\n {\n hooks: [\n {\n type: 'command',\n command: '\"$CLAUDE_PROJECT_DIR\"/.safeword/hooks/prompt-questions.sh',\n },\n ],\n },\n ],\n Stop: [\n {\n hooks: [\n {\n type: 'command',\n command: '\"$CLAUDE_PROJECT_DIR\"/.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: '\"$CLAUDE_PROJECT_DIR\"/.safeword/hooks/post-tool-lint.sh',\n },\n ],\n },\n ],\n};\n","/**\n * Architecture boundaries detection and config generation\n *\n * Auto-detects common architecture directories and generates\n * eslint-plugin-boundaries config with sensible hierarchy rules.\n *\n * Supports:\n * - Standard projects (src/utils, utils/)\n * - Monorepos (packages/*, apps/*)\n * - Various naming conventions (helpers, shared, core, etc.)\n */\n\nimport { join } from 'node:path';\nimport { readdirSync } from 'node:fs';\nimport { exists } from './fs.js';\n\n/**\n * Architecture layer definitions with alternative names.\n * Each layer maps to equivalent directory names.\n * Order defines hierarchy: earlier = lower layer.\n */\nconst ARCHITECTURE_LAYERS = [\n // Layer 0: Pure types (no imports)\n { layer: 'types', dirs: ['types', 'interfaces', 'schemas'] },\n // Layer 1: Utilities (only types)\n { layer: 'utils', dirs: ['utils', 'helpers', 'shared', 'common', 'core'] },\n // Layer 2: Libraries (types, utils)\n { layer: 'lib', dirs: ['lib', 'libraries'] },\n // Layer 3: State & logic (types, utils, lib)\n { layer: 'hooks', dirs: ['hooks', 'composables'] },\n { layer: 'services', dirs: ['services', 'api', 'stores', 'state'] },\n // Layer 4: UI components (all above)\n { layer: 'components', dirs: ['components', 'ui'] },\n // Layer 5: Features (all above)\n { layer: 'features', dirs: ['features', 'modules', 'domains'] },\n // Layer 6: Entry points (can import everything)\n { layer: 'app', dirs: ['app', 'pages', 'views', 'routes', 'commands'] },\n] as const;\n\ntype Layer = (typeof ARCHITECTURE_LAYERS)[number]['layer'];\n\n/**\n * Hierarchy rules: what each layer can import\n * Lower layers have fewer import permissions\n */\nconst HIERARCHY: Record<Layer, Layer[]> = {\n types: [],\n utils: ['types'],\n lib: ['utils', 'types'],\n hooks: ['lib', 'utils', 'types'],\n services: ['lib', 'utils', 'types'],\n components: ['hooks', 'services', 'lib', 'utils', 'types'],\n features: ['components', 'hooks', 'services', 'lib', 'utils', 'types'],\n app: ['features', 'components', 'hooks', 'services', 'lib', 'utils', 'types'],\n};\n\nexport interface DetectedElement {\n layer: Layer;\n pattern: string; // glob pattern for boundaries config\n location: string; // human-readable location\n}\n\nexport interface DetectedArchitecture {\n elements: DetectedElement[];\n isMonorepo: boolean;\n}\n\n/**\n * Find monorepo package directories\n */\nfunction findMonorepoPackages(projectDir: string): string[] {\n const packages: string[] = [];\n\n // Check common monorepo patterns\n const monorepoRoots = ['packages', 'apps', 'libs', 'modules'];\n\n for (const root of monorepoRoots) {\n const rootPath = join(projectDir, root);\n if (exists(rootPath)) {\n try {\n const entries = readdirSync(rootPath, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory() && !entry.name.startsWith('.')) {\n packages.push(join(root, entry.name));\n }\n }\n } catch {\n // Directory not readable, skip\n }\n }\n }\n\n return packages;\n}\n\n/**\n * Check if a layer already exists for this path prefix\n */\nfunction hasLayerForPrefix(elements: DetectedElement[], layer: Layer, pathPrefix: string): boolean {\n return elements.some(e => e.layer === layer && e.pattern.startsWith(pathPrefix));\n}\n\n/**\n * Scan a single search path for architecture layers\n */\nfunction scanSearchPath(\n projectDir: string,\n searchPath: string,\n pathPrefix: string,\n elements: DetectedElement[],\n): void {\n for (const layerDef of ARCHITECTURE_LAYERS) {\n for (const dirName of layerDef.dirs) {\n const fullPath = join(projectDir, searchPath, dirName);\n if (exists(fullPath) && !hasLayerForPrefix(elements, layerDef.layer, pathPrefix)) {\n elements.push({\n layer: layerDef.layer,\n pattern: `${pathPrefix}${dirName}/**`,\n location: `${pathPrefix}${dirName}`,\n });\n }\n }\n }\n}\n\n/**\n * Scan a directory for architecture layers\n */\nfunction scanForLayers(projectDir: string, basePath: string): DetectedElement[] {\n const elements: DetectedElement[] = [];\n const prefix = basePath ? `${basePath}/` : '';\n\n // Check src/ and root level\n scanSearchPath(projectDir, join(basePath, 'src'), `${prefix}src/`, elements);\n scanSearchPath(projectDir, basePath, prefix, elements);\n\n return elements;\n}\n\n/**\n * Detects architecture directories in the project\n * Handles both standard projects and monorepos\n */\nexport function detectArchitecture(projectDir: string): DetectedArchitecture {\n const elements: DetectedElement[] = [];\n\n // First, check for monorepo packages\n const packages = findMonorepoPackages(projectDir);\n const isMonorepo = packages.length > 0;\n\n if (isMonorepo) {\n // Scan each package\n for (const pkg of packages) {\n elements.push(...scanForLayers(projectDir, pkg));\n }\n }\n\n // Also scan root level (works for both monorepo root and standard projects)\n elements.push(...scanForLayers(projectDir, ''));\n\n // Deduplicate by pattern\n const seen = new Set<string>();\n const uniqueElements = elements.filter(e => {\n if (seen.has(e.pattern)) return false;\n seen.add(e.pattern);\n return true;\n });\n\n return { elements: uniqueElements, isMonorepo };\n}\n\n/**\n * Format a single element for the config\n */\nfunction formatElement(el: DetectedElement): string {\n return ` { type: '${el.layer}', pattern: '${el.pattern}', mode: 'full' }`;\n}\n\n/**\n * Format allowed imports for a rule\n */\nfunction formatAllowedImports(allowed: Layer[]): string {\n return allowed.map(d => `'${d}'`).join(', ');\n}\n\n/**\n * Generate a single rule for what a layer can import\n */\nfunction generateRule(layer: Layer, detectedLayers: Set<Layer>): string | null {\n const allowedLayers = HIERARCHY[layer];\n if (allowedLayers.length === 0) return null;\n\n const allowed = allowedLayers.filter(dep => detectedLayers.has(dep));\n if (allowed.length === 0) return null;\n\n return ` { from: ['${layer}'], allow: [${formatAllowedImports(allowed)}] }`;\n}\n\n/**\n * Build description of what was detected\n */\nfunction buildDetectedInfo(arch: DetectedArchitecture): string {\n if (arch.elements.length === 0) {\n return 'No architecture directories detected yet - add types/, utils/, components/, etc.';\n }\n const locations = arch.elements.map(e => e.location).join(', ');\n const monorepoNote = arch.isMonorepo ? ' (monorepo)' : '';\n return `Detected: ${locations}${monorepoNote}`;\n}\n\nexport function generateBoundariesConfig(arch: DetectedArchitecture): string {\n const hasElements = arch.elements.length > 0;\n\n // Generate element definitions\n const elementsContent = arch.elements.map(el => formatElement(el)).join(',\\n');\n\n // Generate rules (what each layer can import)\n const detectedLayers = new Set(arch.elements.map(e => e.layer));\n const rules = [...detectedLayers]\n .map(layer => generateRule(layer, detectedLayers))\n .filter((rule): rule is string => rule !== null);\n const rulesContent = rules.join(',\\n');\n\n const detectedInfo = buildDetectedInfo(arch);\n\n return `/**\n * Architecture Boundaries Configuration (AUTO-GENERATED)\n *\n * ${detectedInfo}\n *\n * This enforces import boundaries between architectural layers:\n * - Lower layers (types, utils) cannot import from higher layers (components, features)\n * - Uses 'warn' severity - informative, not blocking\n *\n * Recognized directories (in hierarchy order):\n * types → utils → lib → hooks/services → components → features/modules → app\n *\n * To customize, override in your eslint.config.mjs:\n * rules: { 'boundaries/element-types': ['error', { ... }] }\n */\n\nimport boundaries from 'eslint-plugin-boundaries';\n\nexport default {\n plugins: { boundaries },\n settings: {\n 'boundaries/elements': [\n${elementsContent}\n ],\n },\n rules: {${\n hasElements\n ? `\n 'boundaries/element-types': ['warn', {\n default: 'disallow',\n rules: [\n${rulesContent}\n ],\n }],`\n : ''\n }\n 'boundaries/no-unknown': 'off', // Allow files outside defined elements\n 'boundaries/no-unknown-files': 'off', // Allow non-matching files\n },\n};\n`;\n}\n","/**\n * Shared installation constants\n *\n * These constants are used by schema.ts to define the single source of truth.\n * All functions have been removed - reconcile.ts now handles all operations.\n */\n\n/**\n * Husky pre-commit hook content - includes safeword sync + lint-staged\n * The sync command keeps ESLint plugins aligned with detected frameworks\n */\nexport const HUSKY_PRE_COMMIT_CONTENT = 'npx safeword sync --quiet --stage\\nnpx lint-staged\\n';\n\n/**\n * MCP servers installed by safeword\n */\nexport const MCP_SERVERS = {\n context7: {\n command: 'npx',\n args: ['-y', '@upstash/context7-mcp@latest'],\n },\n playwright: {\n command: 'npx',\n args: ['@playwright/mcp@latest'],\n },\n} as const;\n\n// NOTE: All other constants and functions were removed in the declarative schema refactor.\n// The single source of truth is now SAFEWORD_SCHEMA in src/schema.ts.\n// Operations are handled by reconcile() in src/reconcile.ts.\n","/**\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' && h !== null && 'hooks' in h && 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(cmd => typeof cmd.command === 'string' && cmd.command.includes('.safeword'));\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 * SAFEWORD Schema - Single Source of Truth\n *\n * All files, directories, configurations, and packages managed by safeword\n * are defined here. Commands use this schema via the reconciliation engine.\n *\n * Adding a new file? Add it here and it will be handled by setup/upgrade/reset.\n */\n\nimport { VERSION } from './version.js';\nimport { type ProjectType } from './utils/project-detector.js';\nimport { AGENTS_MD_LINK, getPrettierConfig, getLintStagedConfig } from './templates/content.js';\nimport { getEslintConfig, SETTINGS_HOOKS, CURSOR_HOOKS } from './templates/config.js';\nimport { generateBoundariesConfig, detectArchitecture } from './utils/boundaries.js';\nimport { HUSKY_PRE_COMMIT_CONTENT, MCP_SERVERS } from './utils/install.js';\nimport { filterOutSafewordHooks } from './utils/hooks.js';\n\n// ============================================================================\n// Interfaces\n// ============================================================================\n\nexport interface ProjectContext {\n cwd: string;\n projectType: ProjectType;\n devDeps: Record<string, string>;\n isGitRepo: boolean;\n}\n\nexport interface FileDefinition {\n template?: string; // Path in templates/ dir\n content?: string | (() => string); // Static content or factory\n generator?: (ctx: ProjectContext) => string; // Dynamic generator needing context\n}\n\n// managedFiles: created if missing, updated only if content === current template output\nexport type ManagedFileDefinition = FileDefinition;\n\nexport interface JsonMergeDefinition {\n keys: string[]; // Dot-notation keys we manage\n conditionalKeys?: Record<string, string[]>; // Keys added based on project type\n merge: (existing: Record<string, unknown>, ctx: ProjectContext) => Record<string, unknown>;\n unmerge: (existing: Record<string, unknown>) => Record<string, unknown>;\n removeFileIfEmpty?: boolean; // Delete file if our keys were the only content\n}\n\nexport interface TextPatchDefinition {\n operation: 'prepend' | 'append';\n content: string;\n marker: string; // Used to detect if already applied & for removal\n createIfMissing: boolean;\n}\n\nexport interface SafewordSchema {\n version: string;\n ownedDirs: string[]; // Fully owned - create on setup, delete on reset\n sharedDirs: string[]; // We add to but don't own\n preservedDirs: string[]; // Created on setup, NOT deleted on reset (user data)\n deprecatedFiles: string[]; // Files to delete on upgrade (renamed or removed)\n ownedFiles: Record<string, FileDefinition>; // Overwrite on upgrade (if changed)\n managedFiles: Record<string, ManagedFileDefinition>; // Create if missing, update if safeword content\n jsonMerges: Record<string, JsonMergeDefinition>;\n textPatches: Record<string, TextPatchDefinition>;\n packages: {\n base: string[];\n conditional: Record<string, string[]>;\n };\n}\n\n// ============================================================================\n// SAFEWORD_SCHEMA - The Single Source of Truth\n// ============================================================================\n\n/**\n * Check if a package name is an ESLint-related package.\n * Used by sync command to filter packages for pre-commit installation.\n */\nfunction isEslintPackage(pkg: string): boolean {\n return (\n pkg.startsWith('eslint') ||\n pkg.startsWith('@eslint/') ||\n pkg.startsWith('@microsoft/eslint') ||\n pkg.startsWith('@next/eslint') ||\n pkg.startsWith('@vitest/eslint') ||\n pkg.startsWith('@electron-toolkit/eslint') ||\n pkg === 'typescript-eslint'\n );\n}\n\n/**\n * Get ESLint packages from schema base packages.\n * Single source of truth - no separate list to maintain.\n */\nexport function getBaseEslintPackages(): string[] {\n return SAFEWORD_SCHEMA.packages.base.filter(pkg => isEslintPackage(pkg));\n}\n\n/**\n * Get conditional ESLint packages for a specific project type key.\n */\nexport function getConditionalEslintPackages(key: string): string[] {\n const deps = SAFEWORD_SCHEMA.packages.conditional[key];\n return deps ? deps.filter(pkg => isEslintPackage(pkg)) : [];\n}\n\nexport const SAFEWORD_SCHEMA: SafewordSchema = {\n version: VERSION,\n\n // Directories fully owned by safeword (created on setup, deleted on reset)\n ownedDirs: [\n '.safeword',\n '.safeword/hooks',\n '.safeword/hooks/cursor',\n '.safeword/lib',\n '.safeword/guides',\n '.safeword/templates',\n '.safeword/prompts',\n '.safeword/planning',\n '.safeword/planning/specs',\n '.safeword/planning/test-definitions',\n '.safeword/planning/design',\n '.safeword/planning/issues',\n '.safeword/planning/plans',\n '.safeword/scripts',\n '.husky',\n '.cursor',\n '.cursor/rules',\n '.cursor/commands',\n ],\n\n // Directories we add to but don't own (not deleted on reset)\n sharedDirs: ['.claude', '.claude/skills', '.claude/commands'],\n\n // Created on setup but NOT deleted on reset (preserves user data)\n preservedDirs: [\n '.safeword/learnings',\n '.safeword/tickets',\n '.safeword/tickets/completed',\n '.safeword/logs',\n ],\n\n // Files to delete on upgrade (renamed or removed in newer versions)\n deprecatedFiles: [\n '.safeword/templates/user-stories-template.md',\n // Consolidated into planning-guide.md and testing-guide.md (v0.8.0)\n '.safeword/guides/development-workflow.md',\n '.safeword/guides/tdd-best-practices.md',\n '.safeword/guides/user-story-guide.md',\n '.safeword/guides/test-definitions-guide.md',\n ],\n\n // Files owned by safeword (overwritten on upgrade if content changed)\n ownedFiles: {\n // Core files\n '.safeword/SAFEWORD.md': { template: 'SAFEWORD.md' },\n '.safeword/version': { content: () => VERSION },\n '.safeword/eslint-boundaries.config.mjs': {\n generator: ctx => generateBoundariesConfig(detectArchitecture(ctx.cwd)),\n },\n\n // Hooks (7 files)\n '.safeword/hooks/session-verify-agents.sh': { template: 'hooks/session-verify-agents.sh' },\n '.safeword/hooks/session-version.sh': { template: 'hooks/session-version.sh' },\n '.safeword/hooks/session-lint-check.sh': { template: 'hooks/session-lint-check.sh' },\n '.safeword/hooks/prompt-timestamp.sh': { template: 'hooks/prompt-timestamp.sh' },\n '.safeword/hooks/prompt-questions.sh': { template: 'hooks/prompt-questions.sh' },\n '.safeword/hooks/post-tool-lint.sh': { template: 'hooks/post-tool-lint.sh' },\n '.safeword/hooks/stop-quality.sh': { template: 'hooks/stop-quality.sh' },\n\n // Lib (2 files)\n '.safeword/lib/common.sh': { template: 'lib/common.sh' },\n '.safeword/lib/jq-fallback.sh': { template: 'lib/jq-fallback.sh' },\n\n // Guides (11 files)\n '.safeword/guides/architecture-guide.md': { template: 'guides/architecture-guide.md' },\n '.safeword/guides/cli-reference.md': { template: 'guides/cli-reference.md' },\n '.safeword/guides/code-philosophy.md': { template: 'guides/code-philosophy.md' },\n '.safeword/guides/context-files-guide.md': { template: 'guides/context-files-guide.md' },\n '.safeword/guides/data-architecture-guide.md': {\n template: 'guides/data-architecture-guide.md',\n },\n '.safeword/guides/design-doc-guide.md': { template: 'guides/design-doc-guide.md' },\n '.safeword/guides/learning-extraction.md': { template: 'guides/learning-extraction.md' },\n '.safeword/guides/llm-guide.md': { template: 'guides/llm-guide.md' },\n '.safeword/guides/planning-guide.md': { template: 'guides/planning-guide.md' },\n '.safeword/guides/testing-guide.md': { template: 'guides/testing-guide.md' },\n '.safeword/guides/zombie-process-cleanup.md': { template: 'guides/zombie-process-cleanup.md' },\n\n // Templates (7 files)\n '.safeword/templates/architecture-template.md': {\n template: 'doc-templates/architecture-template.md',\n },\n '.safeword/templates/design-doc-template.md': {\n template: 'doc-templates/design-doc-template.md',\n },\n '.safeword/templates/task-spec-template.md': {\n template: 'doc-templates/task-spec-template.md',\n },\n '.safeword/templates/test-definitions-feature.md': {\n template: 'doc-templates/test-definitions-feature.md',\n },\n '.safeword/templates/ticket-template.md': { template: 'doc-templates/ticket-template.md' },\n '.safeword/templates/feature-spec-template.md': {\n template: 'doc-templates/feature-spec-template.md',\n },\n '.safeword/templates/work-log-template.md': { template: 'doc-templates/work-log-template.md' },\n\n // Prompts (2 files)\n '.safeword/prompts/architecture.md': { template: 'prompts/architecture.md' },\n '.safeword/prompts/quality-review.md': { template: 'prompts/quality-review.md' },\n\n // Scripts (3 files)\n '.safeword/scripts/bisect-test-pollution.sh': { template: 'scripts/bisect-test-pollution.sh' },\n '.safeword/scripts/bisect-zombie-processes.sh': {\n template: 'scripts/bisect-zombie-processes.sh',\n },\n '.safeword/scripts/lint-md.sh': { template: 'scripts/lint-md.sh' },\n\n // Claude skills and commands (9 files)\n '.claude/skills/safeword-brainstorming/SKILL.md': {\n template: 'skills/safeword-brainstorming/SKILL.md',\n },\n '.claude/skills/safeword-debugging/SKILL.md': {\n template: 'skills/safeword-debugging/SKILL.md',\n },\n '.claude/skills/safeword-enforcing-tdd/SKILL.md': {\n template: 'skills/safeword-enforcing-tdd/SKILL.md',\n },\n '.claude/skills/safeword-quality-reviewer/SKILL.md': {\n template: 'skills/safeword-quality-reviewer/SKILL.md',\n },\n '.claude/skills/safeword-refactoring/SKILL.md': {\n template: 'skills/safeword-refactoring/SKILL.md',\n },\n '.claude/skills/safeword-writing-plans/SKILL.md': {\n template: 'skills/safeword-writing-plans/SKILL.md',\n },\n '.claude/commands/architecture.md': { template: 'commands/architecture.md' },\n '.claude/commands/lint.md': { template: 'commands/lint.md' },\n '.claude/commands/quality-review.md': { template: 'commands/quality-review.md' },\n\n // Husky (1 file)\n '.husky/pre-commit': { content: HUSKY_PRE_COMMIT_CONTENT },\n\n // Cursor rules (7 files)\n '.cursor/rules/safeword-core.mdc': { template: 'cursor/rules/safeword-core.mdc' },\n '.cursor/rules/safeword-brainstorming.mdc': {\n template: 'cursor/rules/safeword-brainstorming.mdc',\n },\n '.cursor/rules/safeword-debugging.mdc': {\n template: 'cursor/rules/safeword-debugging.mdc',\n },\n '.cursor/rules/safeword-enforcing-tdd.mdc': {\n template: 'cursor/rules/safeword-enforcing-tdd.mdc',\n },\n '.cursor/rules/safeword-quality-reviewer.mdc': {\n template: 'cursor/rules/safeword-quality-reviewer.mdc',\n },\n '.cursor/rules/safeword-refactoring.mdc': {\n template: 'cursor/rules/safeword-refactoring.mdc',\n },\n '.cursor/rules/safeword-writing-plans.mdc': {\n template: 'cursor/rules/safeword-writing-plans.mdc',\n },\n\n // Cursor commands (3 files - same as Claude)\n '.cursor/commands/lint.md': { template: 'commands/lint.md' },\n '.cursor/commands/quality-review.md': { template: 'commands/quality-review.md' },\n '.cursor/commands/architecture.md': { template: 'commands/architecture.md' },\n\n // Cursor hooks adapters (2 files)\n '.safeword/hooks/cursor/after-file-edit.sh': { template: 'hooks/cursor/after-file-edit.sh' },\n '.safeword/hooks/cursor/stop.sh': { template: 'hooks/cursor/stop.sh' },\n },\n\n // Files created if missing, updated only if content matches current template\n managedFiles: {\n 'eslint.config.mjs': {\n generator: () => getEslintConfig({ boundaries: true }),\n },\n '.prettierrc': { generator: ctx => getPrettierConfig(ctx.projectType) },\n '.markdownlint-cli2.jsonc': { template: 'markdownlint-cli2.jsonc' },\n },\n\n // JSON files where we merge specific keys\n jsonMerges: {\n 'package.json': {\n keys: [\n 'scripts.lint',\n 'scripts.lint:md',\n 'scripts.format',\n 'scripts.format:check',\n 'scripts.knip',\n 'scripts.prepare',\n 'lint-staged',\n ],\n conditionalKeys: {\n publishableLibrary: ['scripts.publint'],\n shell: ['scripts.lint:sh'],\n },\n merge: (existing, ctx) => {\n const scripts = (existing.scripts as Record<string, string>) ?? {};\n const result = { ...existing };\n\n // Add scripts if not present\n if (!scripts.lint) scripts.lint = 'eslint .';\n if (!scripts['lint:md']) scripts['lint:md'] = 'markdownlint-cli2 \"**/*.md\" \"#node_modules\"';\n if (!scripts.format) scripts.format = 'prettier --write .';\n if (!scripts['format:check']) scripts['format:check'] = 'prettier --check .';\n if (!scripts.knip) scripts.knip = 'knip';\n if (!scripts.prepare) scripts.prepare = 'husky || true';\n\n // Conditional: publint for publishable libraries\n if (ctx.projectType.publishableLibrary && !scripts.publint) {\n scripts.publint = 'publint';\n }\n\n // Conditional: lint:sh for projects with shell scripts\n if (ctx.projectType.shell && !scripts['lint:sh']) {\n scripts['lint:sh'] = 'shellcheck **/*.sh';\n }\n\n result.scripts = scripts;\n\n // Add lint-staged config\n if (!existing['lint-staged']) {\n result['lint-staged'] = getLintStagedConfig(ctx.projectType);\n }\n\n return result;\n },\n unmerge: existing => {\n const result = { ...existing };\n const scripts = { ...(existing.scripts as Record<string, string>) };\n\n // Remove safeword-specific scripts but preserve lint/format (useful standalone)\n delete scripts['lint:md'];\n delete scripts['lint:sh'];\n delete scripts['format:check'];\n delete scripts.knip;\n delete scripts.prepare;\n delete scripts.publint;\n\n if (Object.keys(scripts).length > 0) {\n result.scripts = scripts;\n } else {\n delete result.scripts;\n }\n\n delete result['lint-staged'];\n\n return result;\n },\n },\n\n '.claude/settings.json': {\n keys: ['hooks'],\n merge: existing => {\n // Preserve non-safeword hooks while adding/updating safeword hooks\n const existingHooks = (existing.hooks as Record<string, unknown[]>) ?? {};\n const mergedHooks: Record<string, unknown[]> = { ...existingHooks };\n\n for (const [event, newHooks] of Object.entries(SETTINGS_HOOKS)) {\n const eventHooks = (mergedHooks[event] as unknown[]) ?? [];\n const nonSafewordHooks = filterOutSafewordHooks(eventHooks);\n mergedHooks[event] = [...nonSafewordHooks, ...newHooks];\n }\n\n return { ...existing, hooks: mergedHooks };\n },\n unmerge: existing => {\n // Remove only safeword hooks, preserve custom hooks\n const existingHooks = (existing.hooks as Record<string, unknown[]>) ?? {};\n const cleanedHooks: Record<string, unknown[]> = {};\n\n for (const [event, eventHooks] of Object.entries(existingHooks)) {\n const nonSafewordHooks = filterOutSafewordHooks(eventHooks as unknown[]);\n if (nonSafewordHooks.length > 0) {\n cleanedHooks[event] = nonSafewordHooks;\n }\n }\n\n const result = { ...existing };\n if (Object.keys(cleanedHooks).length > 0) {\n result.hooks = cleanedHooks;\n } else {\n delete result.hooks;\n }\n return result;\n },\n },\n\n '.mcp.json': {\n keys: ['mcpServers.context7', 'mcpServers.playwright'],\n removeFileIfEmpty: true,\n merge: existing => {\n const mcpServers = (existing.mcpServers as Record<string, unknown>) ?? {};\n return {\n ...existing,\n mcpServers: {\n ...mcpServers,\n context7: MCP_SERVERS.context7,\n playwright: MCP_SERVERS.playwright,\n },\n };\n },\n unmerge: existing => {\n const result = { ...existing };\n const mcpServers = { ...(existing.mcpServers as Record<string, unknown>) };\n\n delete mcpServers.context7;\n delete mcpServers.playwright;\n\n if (Object.keys(mcpServers).length > 0) {\n result.mcpServers = mcpServers;\n } else {\n delete result.mcpServers;\n }\n\n return result;\n },\n },\n\n '.cursor/mcp.json': {\n keys: ['mcpServers.context7', 'mcpServers.playwright'],\n removeFileIfEmpty: true,\n merge: existing => {\n const mcpServers = (existing.mcpServers as Record<string, unknown>) ?? {};\n return {\n ...existing,\n mcpServers: {\n ...mcpServers,\n context7: MCP_SERVERS.context7,\n playwright: MCP_SERVERS.playwright,\n },\n };\n },\n unmerge: existing => {\n const result = { ...existing };\n const mcpServers = { ...(existing.mcpServers as Record<string, unknown>) };\n\n delete mcpServers.context7;\n delete mcpServers.playwright;\n\n if (Object.keys(mcpServers).length > 0) {\n result.mcpServers = mcpServers;\n } else {\n delete result.mcpServers;\n }\n\n return result;\n },\n },\n\n '.cursor/hooks.json': {\n keys: ['version', 'hooks.afterFileEdit', 'hooks.stop'],\n removeFileIfEmpty: true,\n merge: existing => {\n const hooks = (existing.hooks as Record<string, unknown[]>) ?? {};\n return {\n ...existing,\n version: 1, // Required by Cursor\n hooks: {\n ...hooks,\n ...CURSOR_HOOKS,\n },\n };\n },\n unmerge: existing => {\n const result = { ...existing };\n const hooks = { ...(existing.hooks as Record<string, unknown[]>) };\n\n delete hooks.afterFileEdit;\n delete hooks.stop;\n\n if (Object.keys(hooks).length > 0) {\n result.hooks = hooks;\n } else {\n delete result.hooks;\n delete result.version;\n }\n\n return result;\n },\n },\n },\n\n // Text files where we patch specific content\n textPatches: {\n 'AGENTS.md': {\n operation: 'prepend',\n content: AGENTS_MD_LINK,\n marker: '.safeword/SAFEWORD.md',\n createIfMissing: true,\n },\n 'CLAUDE.md': {\n operation: 'prepend',\n content: AGENTS_MD_LINK,\n marker: '.safeword/SAFEWORD.md',\n createIfMissing: false, // Only patch if exists, don't create (AGENTS.md is primary)\n },\n },\n\n // NPM packages to install\n packages: {\n base: [\n 'eslint',\n 'prettier',\n '@eslint/js',\n 'eslint-plugin-import-x',\n 'eslint-import-resolver-typescript',\n 'eslint-plugin-sonarjs',\n 'eslint-plugin-unicorn',\n 'eslint-plugin-boundaries',\n 'eslint-plugin-playwright',\n '@microsoft/eslint-plugin-sdl',\n 'eslint-config-prettier',\n 'markdownlint-cli2',\n 'knip',\n 'husky',\n 'lint-staged',\n ],\n conditional: {\n typescript: ['typescript-eslint'],\n react: ['eslint-plugin-react', 'eslint-plugin-react-hooks', 'eslint-plugin-jsx-a11y'],\n nextjs: ['@next/eslint-plugin-next'],\n astro: ['eslint-plugin-astro', 'prettier-plugin-astro'],\n vue: ['eslint-plugin-vue'],\n svelte: ['eslint-plugin-svelte', 'prettier-plugin-svelte'],\n electron: ['@electron-toolkit/eslint-config'],\n vitest: ['@vitest/eslint-plugin'],\n tailwind: ['prettier-plugin-tailwindcss'],\n publishableLibrary: ['publint'],\n shell: ['shellcheck', 'prettier-plugin-sh'],\n },\n },\n};\n"],"mappings":"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","names":["readdirSync","join","join","readdirSync","join","readdirSync"]}
@@ -11,7 +11,7 @@ import {
11
11
  removeIfEmpty,
12
12
  writeFile,
13
13
  writeJson
14
- } from "./chunk-62YXVEKM.js";
14
+ } from "./chunk-34PU3QZI.js";
15
15
 
16
16
  // src/utils/output.ts
17
17
  function info(message) {
@@ -473,4 +473,4 @@ export {
473
473
  createProjectContext,
474
474
  reconcile
475
475
  };
476
- //# sourceMappingURL=chunk-SIEJPWQA.js.map
476
+ //# sourceMappingURL=chunk-3OK3NQEW.js.map
@@ -4,7 +4,7 @@ import {
4
4
  getBaseEslintPackages,
5
5
  getConditionalEslintPackages,
6
6
  readJson
7
- } from "./chunk-62YXVEKM.js";
7
+ } from "./chunk-34PU3QZI.js";
8
8
 
9
9
  // src/commands/sync.ts
10
10
  import { join } from "path";
@@ -85,4 +85,4 @@ Run manually when online:`);
85
85
  export {
86
86
  sync
87
87
  };
88
- //# sourceMappingURL=chunk-VZPFU4YI.js.map
88
+ //# sourceMappingURL=chunk-BFBUEJDH.js.map
package/dist/cli.js CHANGED
@@ -8,27 +8,27 @@ 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-JX476EH3.js");
11
+ const { setup } = await import("./setup-ANAIEP3D.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-QZ3ZAHZY.js");
15
+ const { check } = await import("./check-PPVIEF3Q.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-45E6255Q.js");
19
+ const { upgrade } = await import("./upgrade-QFIGWZ5I.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-YXUSIILN.js");
23
+ const { diff } = await import("./diff-S3ICSYQY.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").option("--full", "Also remove linting config and uninstall npm packages").action(async (options) => {
27
- const { reset } = await import("./reset-HQXT7SCI.js");
27
+ const { reset } = await import("./reset-ZST2SGZ2.js");
28
28
  await reset(options);
29
29
  });
30
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-A7VWZKQD.js");
31
+ const { sync } = await import("./sync-V6D7QTMO.js");
32
32
  await sync(options);
33
33
  });
34
34
  if (process.argv.length === 2) {
@@ -6,12 +6,12 @@ import {
6
6
  listItem,
7
7
  reconcile,
8
8
  success
9
- } from "./chunk-SIEJPWQA.js";
9
+ } from "./chunk-3OK3NQEW.js";
10
10
  import {
11
11
  SAFEWORD_SCHEMA,
12
12
  exists,
13
13
  readFileSafe
14
- } from "./chunk-62YXVEKM.js";
14
+ } from "./chunk-34PU3QZI.js";
15
15
  import {
16
16
  VERSION
17
17
  } from "./chunk-ORQHKDT2.js";
@@ -163,4 +163,4 @@ Packages to install: ${result.packagesToInstall.length}`);
163
163
  export {
164
164
  diff
165
165
  };
166
- //# sourceMappingURL=diff-YXUSIILN.js.map
166
+ //# sourceMappingURL=diff-S3ICSYQY.js.map
@@ -7,11 +7,11 @@ import {
7
7
  reconcile,
8
8
  success,
9
9
  warn
10
- } from "./chunk-SIEJPWQA.js";
10
+ } from "./chunk-3OK3NQEW.js";
11
11
  import {
12
12
  SAFEWORD_SCHEMA,
13
13
  exists
14
- } from "./chunk-62YXVEKM.js";
14
+ } from "./chunk-34PU3QZI.js";
15
15
  import "./chunk-ORQHKDT2.js";
16
16
 
17
17
  // src/commands/reset.ts
@@ -71,4 +71,4 @@ async function reset(options) {
71
71
  export {
72
72
  reset
73
73
  };
74
- //# sourceMappingURL=reset-HQXT7SCI.js.map
74
+ //# sourceMappingURL=reset-ZST2SGZ2.js.map
@@ -8,12 +8,12 @@ import {
8
8
  reconcile,
9
9
  success,
10
10
  warn
11
- } from "./chunk-SIEJPWQA.js";
11
+ } from "./chunk-3OK3NQEW.js";
12
12
  import {
13
13
  SAFEWORD_SCHEMA,
14
14
  exists,
15
15
  writeJson
16
- } from "./chunk-62YXVEKM.js";
16
+ } from "./chunk-34PU3QZI.js";
17
17
  import {
18
18
  VERSION
19
19
  } from "./chunk-ORQHKDT2.js";
@@ -97,4 +97,4 @@ Safeword ${VERSION} installed successfully!`);
97
97
  export {
98
98
  setup
99
99
  };
100
- //# sourceMappingURL=setup-JX476EH3.js.map
100
+ //# sourceMappingURL=setup-ANAIEP3D.js.map
@@ -0,0 +1,9 @@
1
+ import {
2
+ sync
3
+ } from "./chunk-BFBUEJDH.js";
4
+ import "./chunk-34PU3QZI.js";
5
+ import "./chunk-ORQHKDT2.js";
6
+ export {
7
+ sync
8
+ };
9
+ //# sourceMappingURL=sync-V6D7QTMO.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-W66Z3C5H.js";
4
4
  import {
5
5
  sync
6
- } from "./chunk-VZPFU4YI.js";
6
+ } from "./chunk-BFBUEJDH.js";
7
7
  import {
8
8
  createProjectContext,
9
9
  error,
@@ -12,12 +12,12 @@ import {
12
12
  listItem,
13
13
  reconcile,
14
14
  success
15
- } from "./chunk-SIEJPWQA.js";
15
+ } from "./chunk-3OK3NQEW.js";
16
16
  import {
17
17
  SAFEWORD_SCHEMA,
18
18
  exists,
19
19
  readFileSafe
20
- } from "./chunk-62YXVEKM.js";
20
+ } from "./chunk-34PU3QZI.js";
21
21
  import {
22
22
  VERSION
23
23
  } from "./chunk-ORQHKDT2.js";
@@ -73,4 +73,4 @@ Safeword upgraded to v${VERSION}`);
73
73
  export {
74
74
  upgrade
75
75
  };
76
- //# sourceMappingURL=upgrade-45E6255Q.js.map
76
+ //# sourceMappingURL=upgrade-QFIGWZ5I.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "safeword",
3
- "version": "0.8.5",
3
+ "version": "0.8.7",
4
4
  "description": "CLI for setting up and managing safeword development environments",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,218 @@
1
+ ---
2
+ description: Use when spec is complete and you need detailed implementation tasks for LLM agents. Creates execution plans with exact file paths, complete code examples, and verification steps. Triggers: 'write plan', 'execution plan', 'implementation plan', 'break down into tasks', 'detailed steps'.
3
+ alwaysApply: false
4
+ ---
5
+
6
+ # Writing Execution Plans
7
+
8
+ Convert specs into detailed implementation plans for LLM agents.
9
+
10
+ **Iron Law:** EXACT PATHS. COMPLETE CODE. VERIFICATION GATES.
11
+
12
+ ## When to Use
13
+
14
+ Answer IN ORDER. Stop at first match:
15
+
16
+ 1. Spec exists and is approved? → Use this skill
17
+ 2. No spec yet? → Use brainstorming skill first
18
+ 3. Simple task, obvious steps? → Skip (use enforcing-tdd directly)
19
+
20
+ ---
21
+
22
+ ## Phase 1: CONTEXT
23
+
24
+ **Purpose:** Understand the spec and identify all affected files.
25
+
26
+ **Protocol:**
27
+
28
+ 1. Read the spec from `.safeword/planning/specs/`
29
+ 2. Identify all files that will be created or modified
30
+ 3. Check existing patterns in the codebase
31
+ 4. Note test file locations and naming conventions
32
+
33
+ **Exit Criteria:**
34
+
35
+ - [ ] Spec read and understood
36
+ - [ ] All affected files identified
37
+ - [ ] Existing patterns noted
38
+
39
+ ---
40
+
41
+ ## Phase 2: DECOMPOSE
42
+
43
+ **Purpose:** Break the spec into atomic tasks.
44
+
45
+ **Protocol:**
46
+
47
+ 1. Each task = one logical unit (one component, one function, one integration point)
48
+ 2. Order tasks by dependency (foundations first)
49
+ 3. Each task must be independently verifiable
50
+
51
+ **Task sizing guide:**
52
+
53
+ | Too Big | Right Size | Too Small |
54
+ | ----------------- | ---------------------------------- | ---------------- |
55
+ | "Add auth system" | "Add password validation function" | "Import bcrypt" |
56
+ | "Build API" | "Add POST /users endpoint" | "Add route file" |
57
+
58
+ **Exit Criteria:**
59
+
60
+ - [ ] Tasks are atomic and ordered
61
+ - [ ] No task depends on uncommitted work from another
62
+ - [ ] Each task has clear boundaries
63
+
64
+ ---
65
+
66
+ ## Phase 3: DETAIL
67
+
68
+ **Purpose:** Write exact implementation details for each task.
69
+
70
+ **Protocol:**
71
+
72
+ For each task, provide:
73
+
74
+ 1. **Files** - Exact paths (create/modify/test)
75
+ 2. **Test code** - Complete, runnable test
76
+ 3. **Implementation code** - Complete, minimal code to pass
77
+ 4. **Verification command** - Exact command with expected output
78
+ 5. **Commit message** - Ready to use
79
+
80
+ **Task Format** (adapt syntax to project's language/test framework):
81
+
82
+ ````markdown
83
+ ### Task N: [Name]
84
+
85
+ **Files:**
86
+
87
+ - Create: `src/path/to/file.ext`
88
+ - Test: `src/path/to/file.test.ext`
89
+
90
+ **Step 1: Write failing test**
91
+
92
+ ```
93
+ [Complete test code using project's test framework]
94
+ ```
95
+
96
+ **Step 2: Verify test fails**
97
+
98
+ Run: `[exact test command]`
99
+ Expected: FAIL - "[specific error message]"
100
+
101
+ **Step 3: Implement**
102
+
103
+ ```
104
+ [Complete implementation code]
105
+ ```
106
+
107
+ **Step 4: Verify test passes**
108
+
109
+ Run: `[exact test command]`
110
+ Expected: PASS
111
+
112
+ **Step 5: Commit**
113
+
114
+ ```bash
115
+ git add [files]
116
+ git commit -m "[type]: [description]"
117
+ ```
118
+ ````
119
+
120
+ **Exit Criteria:**
121
+
122
+ - [ ] Every task has complete code (no "add validation here")
123
+ - [ ] Every task has exact verification command
124
+ - [ ] Every task has commit message
125
+
126
+ ---
127
+
128
+ ## Phase 4: SAVE
129
+
130
+ **Purpose:** Write the plan to disk.
131
+
132
+ **Protocol:**
133
+
134
+ 1. Create plan file at `.safeword/planning/plans/{slug}.md`
135
+ 2. Include header with metadata
136
+ 3. Include all tasks in order
137
+
138
+ **Plan Header:**
139
+
140
+ ```markdown
141
+ # [Feature Name] Execution Plan
142
+
143
+ **Source Spec:** `.safeword/planning/specs/{spec-file}.md`
144
+ **Created:** YYYY-MM-DD
145
+ **Status:** Ready
146
+
147
+ **Goal:** [One sentence]
148
+
149
+ **Tasks:** N tasks
150
+
151
+ ---
152
+ ```
153
+
154
+ **Exit Criteria:**
155
+
156
+ - [ ] Plan saved to `.safeword/planning/plans/`
157
+ - [ ] Header includes source spec reference
158
+ - [ ] All tasks included
159
+
160
+ ---
161
+
162
+ ## Phase 5: HANDOFF
163
+
164
+ **Purpose:** Transition to execution.
165
+
166
+ **Protocol:**
167
+
168
+ 1. Summarize the plan (task count, scope)
169
+ 2. Offer execution options:
170
+
171
+ ```text
172
+ Plan saved to `.safeword/planning/plans/{slug}.md`
173
+
174
+ **Execution options:**
175
+
176
+ 1. **Continue here** - I'll execute tasks one-by-one using enforcing-tdd
177
+ 2. **Fresh session** - Open new session, reference the plan file
178
+
179
+ Which approach?
180
+ ```
181
+
182
+ 3. If continuing: Start with Task 1, use enforcing-tdd skill
183
+
184
+ **Exit Criteria:**
185
+
186
+ - [ ] User chose execution approach
187
+ - [ ] Handed off appropriately
188
+
189
+ ---
190
+
191
+ ## Key Principles
192
+
193
+ | Principle | Why |
194
+ | ------------------ | -------------------------------------------------- |
195
+ | Exact file paths | LLMs hallucinate paths without specifics |
196
+ | Complete code | "Add X here" leads to inconsistent implementations |
197
+ | Verification gates | LLMs need explicit pass/fail criteria |
198
+ | Atomic tasks | Fresh context per task = less drift |
199
+ | TDD per task | Catches errors immediately |
200
+
201
+ ---
202
+
203
+ ## Anti-Patterns
204
+
205
+ | Don't | Do |
206
+ | ------------------------------ | ---------------------------------- |
207
+ | "Add error handling" | Show exact try/catch code |
208
+ | "Create test file" | Show complete test with assertions |
209
+ | "Run tests" | `npm test -- path/to/file.test.ts` |
210
+ | Combine 3 features in one task | One feature per task |
211
+ | Skip verification step | Always: Run X, expect Y |
212
+
213
+ ---
214
+
215
+ ## Related
216
+
217
+ - @./.safeword/guides/planning-guide.md
218
+ - @./.safeword/guides/testing-guide.md
@@ -0,0 +1,219 @@
1
+ ---
2
+ name: writing-plans
3
+ description: Use when spec is complete and you need detailed implementation tasks for LLM agents. Creates execution plans with exact file paths, complete code examples, and verification steps. Triggers: 'write plan', 'execution plan', 'implementation plan', 'break down into tasks', 'detailed steps'.
4
+ allowed-tools: '*'
5
+ ---
6
+
7
+ # Writing Execution Plans
8
+
9
+ Convert specs into detailed implementation plans for LLM agents.
10
+
11
+ **Iron Law:** EXACT PATHS. COMPLETE CODE. VERIFICATION GATES.
12
+
13
+ ## When to Use
14
+
15
+ Answer IN ORDER. Stop at first match:
16
+
17
+ 1. Spec exists and is approved? → Use this skill
18
+ 2. No spec yet? → Use brainstorming skill first
19
+ 3. Simple task, obvious steps? → Skip (use enforcing-tdd directly)
20
+
21
+ ---
22
+
23
+ ## Phase 1: CONTEXT
24
+
25
+ **Purpose:** Understand the spec and identify all affected files.
26
+
27
+ **Protocol:**
28
+
29
+ 1. Read the spec from `.safeword/planning/specs/`
30
+ 2. Identify all files that will be created or modified
31
+ 3. Check existing patterns in the codebase
32
+ 4. Note test file locations and naming conventions
33
+
34
+ **Exit Criteria:**
35
+
36
+ - [ ] Spec read and understood
37
+ - [ ] All affected files identified
38
+ - [ ] Existing patterns noted
39
+
40
+ ---
41
+
42
+ ## Phase 2: DECOMPOSE
43
+
44
+ **Purpose:** Break the spec into atomic tasks.
45
+
46
+ **Protocol:**
47
+
48
+ 1. Each task = one logical unit (one component, one function, one integration point)
49
+ 2. Order tasks by dependency (foundations first)
50
+ 3. Each task must be independently verifiable
51
+
52
+ **Task sizing guide:**
53
+
54
+ | Too Big | Right Size | Too Small |
55
+ | ----------------- | ---------------------------------- | ---------------- |
56
+ | "Add auth system" | "Add password validation function" | "Import bcrypt" |
57
+ | "Build API" | "Add POST /users endpoint" | "Add route file" |
58
+
59
+ **Exit Criteria:**
60
+
61
+ - [ ] Tasks are atomic and ordered
62
+ - [ ] No task depends on uncommitted work from another
63
+ - [ ] Each task has clear boundaries
64
+
65
+ ---
66
+
67
+ ## Phase 3: DETAIL
68
+
69
+ **Purpose:** Write exact implementation details for each task.
70
+
71
+ **Protocol:**
72
+
73
+ For each task, provide:
74
+
75
+ 1. **Files** - Exact paths (create/modify/test)
76
+ 2. **Test code** - Complete, runnable test
77
+ 3. **Implementation code** - Complete, minimal code to pass
78
+ 4. **Verification command** - Exact command with expected output
79
+ 5. **Commit message** - Ready to use
80
+
81
+ **Task Format** (adapt syntax to project's language/test framework):
82
+
83
+ ````markdown
84
+ ### Task N: [Name]
85
+
86
+ **Files:**
87
+
88
+ - Create: `src/path/to/file.ext`
89
+ - Test: `src/path/to/file.test.ext`
90
+
91
+ **Step 1: Write failing test**
92
+
93
+ ```
94
+ [Complete test code using project's test framework]
95
+ ```
96
+
97
+ **Step 2: Verify test fails**
98
+
99
+ Run: `[exact test command]`
100
+ Expected: FAIL - "[specific error message]"
101
+
102
+ **Step 3: Implement**
103
+
104
+ ```
105
+ [Complete implementation code]
106
+ ```
107
+
108
+ **Step 4: Verify test passes**
109
+
110
+ Run: `[exact test command]`
111
+ Expected: PASS
112
+
113
+ **Step 5: Commit**
114
+
115
+ ```bash
116
+ git add [files]
117
+ git commit -m "[type]: [description]"
118
+ ```
119
+ ````
120
+
121
+ **Exit Criteria:**
122
+
123
+ - [ ] Every task has complete code (no "add validation here")
124
+ - [ ] Every task has exact verification command
125
+ - [ ] Every task has commit message
126
+
127
+ ---
128
+
129
+ ## Phase 4: SAVE
130
+
131
+ **Purpose:** Write the plan to disk.
132
+
133
+ **Protocol:**
134
+
135
+ 1. Create plan file at `.safeword/planning/plans/{slug}.md`
136
+ 2. Include header with metadata
137
+ 3. Include all tasks in order
138
+
139
+ **Plan Header:**
140
+
141
+ ```markdown
142
+ # [Feature Name] Execution Plan
143
+
144
+ **Source Spec:** `.safeword/planning/specs/{spec-file}.md`
145
+ **Created:** YYYY-MM-DD
146
+ **Status:** Ready
147
+
148
+ **Goal:** [One sentence]
149
+
150
+ **Tasks:** N tasks
151
+
152
+ ---
153
+ ```
154
+
155
+ **Exit Criteria:**
156
+
157
+ - [ ] Plan saved to `.safeword/planning/plans/`
158
+ - [ ] Header includes source spec reference
159
+ - [ ] All tasks included
160
+
161
+ ---
162
+
163
+ ## Phase 5: HANDOFF
164
+
165
+ **Purpose:** Transition to execution.
166
+
167
+ **Protocol:**
168
+
169
+ 1. Summarize the plan (task count, scope)
170
+ 2. Offer execution options:
171
+
172
+ ```text
173
+ Plan saved to `.safeword/planning/plans/{slug}.md`
174
+
175
+ **Execution options:**
176
+
177
+ 1. **Continue here** - I'll execute tasks one-by-one using enforcing-tdd
178
+ 2. **Fresh session** - Open new session, reference the plan file
179
+
180
+ Which approach?
181
+ ```
182
+
183
+ 3. If continuing: Start with Task 1, use enforcing-tdd skill
184
+
185
+ **Exit Criteria:**
186
+
187
+ - [ ] User chose execution approach
188
+ - [ ] Handed off appropriately
189
+
190
+ ---
191
+
192
+ ## Key Principles
193
+
194
+ | Principle | Why |
195
+ | ------------------ | -------------------------------------------------- |
196
+ | Exact file paths | LLMs hallucinate paths without specifics |
197
+ | Complete code | "Add X here" leads to inconsistent implementations |
198
+ | Verification gates | LLMs need explicit pass/fail criteria |
199
+ | Atomic tasks | Fresh context per task = less drift |
200
+ | TDD per task | Catches errors immediately |
201
+
202
+ ---
203
+
204
+ ## Anti-Patterns
205
+
206
+ | Don't | Do |
207
+ | ------------------------------ | ---------------------------------- |
208
+ | "Add error handling" | Show exact try/catch code |
209
+ | "Create test file" | Show complete test with assertions |
210
+ | "Run tests" | `npm test -- path/to/file.test.ts` |
211
+ | Combine 3 features in one task | One feature per task |
212
+ | Skip verification step | Always: Run X, expect Y |
213
+
214
+ ---
215
+
216
+ ## Related
217
+
218
+ - @./.safeword/guides/planning-guide.md
219
+ - @./.safeword/guides/testing-guide.md
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/fs.ts","../src/utils/project-detector.ts","../src/templates/content.ts","../src/templates/config.ts","../src/utils/boundaries.ts","../src/utils/install.ts","../src/utils/hooks.ts","../src/schema.ts"],"sourcesContent":["/**\n * File system utilities for CLI operations\n */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n rmSync,\n rmdirSync,\n readdirSync,\n chmodSync,\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 *\n * Note: We check for SAFEWORD.md to distinguish from src/templates/ which\n * contains TypeScript source files (config.ts, content.ts).\n *\n * Path resolution (bundled with tsup):\n * - From dist/chunk-*.js: __dirname = packages/cli/dist/ → ../templates\n */\nexport function getTemplatesDir(): string {\n const knownTemplateFile = 'SAFEWORD.md';\n\n // Try different relative paths - the bundled code ends up in dist/ directly (flat)\n // while source is in src/utils/\n const candidates = [\n join(__dirname, '..', 'templates'), // From dist/ (flat bundled)\n join(__dirname, '..', '..', 'templates'), // From src/utils/ or dist/utils/\n join(__dirname, 'templates'), // Direct sibling (unlikely but safe)\n ];\n\n for (const candidate of candidates) {\n if (existsSync(join(candidate, knownTemplateFile))) {\n return candidate;\n }\n }\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 * 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 * Remove directory only if empty, returns true if removed\n */\nexport function removeIfEmpty(path: string): boolean {\n if (!existsSync(path)) return false;\n try {\n rmdirSync(path); // Non-recursive, throws if not empty\n return true;\n } catch {\n return false;\n }\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 * Project type detection from package.json\n *\n * Detects frameworks and tools used in the project to configure\n * appropriate linting rules.\n */\n\nimport { readdirSync } from 'node:fs';\nimport { join } from 'node:path';\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 shell: boolean;\n}\n\n/**\n * Checks if a directory contains any .sh files up to specified depth.\n * Excludes node_modules and .git directories.\n */\nexport function hasShellScripts(cwd: string, maxDepth = 4): boolean {\n const excludeDirs = new Set(['node_modules', '.git', '.safeword']);\n\n function scan(dir: string, depth: number): boolean {\n if (depth > maxDepth) return false;\n\n try {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isFile() && entry.name.endsWith('.sh')) {\n return true;\n }\n if (entry.isDirectory() && !excludeDirs.has(entry.name)) {\n if (scan(join(dir, entry.name), depth + 1)) {\n return true;\n }\n }\n }\n } catch {\n // Ignore permission errors\n }\n return false;\n }\n\n return scan(cwd, 0);\n}\n\n/**\n * Detects project type from package.json contents and optional file scanning\n */\nexport function detectProjectType(packageJson: PackageJson, cwd?: string): 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 // Shell scripts: detected by scanning for .sh files\n const hasShell = cwd ? hasShellScripts(cwd) : false;\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 shell: hasShell,\n };\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\nimport type { ProjectType } from '../utils/project-detector.js';\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\ninterface PrettierConfig {\n semi: boolean;\n singleQuote: boolean;\n tabWidth: number;\n trailingComma: string;\n printWidth: number;\n endOfLine: string;\n plugins?: string[];\n}\n\n/**\n * Generate .prettierrc content based on project type.\n * Explicitly lists plugins to ensure compatibility with pnpm/Yarn PnP.\n */\nexport function getPrettierConfig(projectType: ProjectType): string {\n const config: PrettierConfig = {\n semi: true,\n singleQuote: true,\n tabWidth: 2,\n trailingComma: 'es5',\n printWidth: 100,\n endOfLine: 'lf',\n };\n\n const plugins: string[] = [];\n\n if (projectType.astro) plugins.push('prettier-plugin-astro');\n if (projectType.svelte) plugins.push('prettier-plugin-svelte');\n if (projectType.shell) plugins.push('prettier-plugin-sh');\n // Tailwind must be last for proper class sorting\n if (projectType.tailwind) plugins.push('prettier-plugin-tailwindcss');\n\n if (plugins.length > 0) {\n config.plugins = plugins;\n }\n\n return JSON.stringify(config, null, 2) + '\\n';\n}\n\n/**\n * Generate lint-staged configuration based on project type.\n * Only includes shell patterns when shell scripts are detected.\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 function getLintStagedConfig(projectType: ProjectType): Record<string, string[]> {\n const config: Record<string, string[]> = {\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 if (projectType.shell) {\n config['*.sh'] = ['shellcheck', 'prettier --write'];\n }\n\n return config;\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 `/* eslint-disable import-x/no-unresolved, no-undef -- dynamic imports for optional framework plugins, console used in tryImport */\nimport { readFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { defineConfig } from \"eslint/config\";\nimport js from \"@eslint/js\";\nimport { importX } from \"eslint-plugin-import-x\";\nimport { createTypeScriptImportResolver } from \"eslint-import-resolver-typescript\";\nimport sonarjs from \"eslint-plugin-sonarjs\";\nimport sdl from \"@microsoft/eslint-plugin-sdl\";\nimport playwright from \"eslint-plugin-playwright\";\nimport unicorn from \"eslint-plugin-unicorn\";\nimport eslintConfigPrettier from \"eslint-config-prettier\";\n${options.boundaries ? 'import boundariesConfig from \"./.safeword/eslint-boundaries.config.mjs\";' : ''}\n\n// Read package.json relative to this config file (not CWD)\n// This ensures correct detection in monorepos where lint-staged may run from subdirectories\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, \"package.json\"), \"utf8\"));\nconst deps = { ...pkg.dependencies, ...pkg.devDependencies };\n\n// Helper for dynamic imports with actionable error messages\nasync function tryImport(pkgName, frameworkName) {\n try {\n return await import(pkgName);\n } catch (err) {\n if (err.code === \"ERR_MODULE_NOT_FOUND\") {\n console.error(\\`\\\\n✗ Missing ESLint plugin for \\${frameworkName}\\\\n\\`);\n console.error(\\`Your package.json has \\${frameworkName} but the ESLint plugin is not installed.\\`);\n console.error(\\`Run: npm install -D \\${pkgName}\\\\n\\`);\n console.error(\\`Or run: npx safeword sync\\\\n\\`);\n }\n throw err;\n }\n}\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 {\n settings: {\n \"import-x/resolver-next\": [createTypeScriptImportResolver()],\n },\n },\n sonarjs.configs.recommended,\n ...sdl.configs.recommended,\n unicorn.configs[\"flat/recommended\"],\n {\n // Unicorn overrides for LLM-generated code\n // Keep modern JS enforcement, disable overly pedantic rules\n rules: {\n \"unicorn/prevent-abbreviations\": \"off\", // ctx, dir, pkg, err are standard\n \"unicorn/no-null\": \"off\", // null is valid JS\n \"unicorn/no-process-exit\": \"off\", // CLI apps use process.exit\n \"unicorn/import-style\": \"off\", // Named imports are fine\n \"unicorn/numeric-separators-style\": \"off\", // Style preference\n \"unicorn/text-encoding-identifier-case\": \"off\", // utf-8 vs utf8\n \"unicorn/switch-case-braces\": \"warn\", // Good practice, not critical\n \"unicorn/catch-error-name\": \"warn\", // Reasonable, auto-fixable\n \"unicorn/no-negated-condition\": \"off\", // Sometimes clearer\n \"unicorn/no-array-reduce\": \"off\", // Reduce is fine when readable\n \"unicorn/no-array-for-each\": \"off\", // forEach is fine\n \"unicorn/prefer-module\": \"off\", // CJS still valid\n },\n },\n];\n\n// TypeScript support (detected from package.json)\nif (deps[\"typescript\"] || deps[\"typescript-eslint\"]) {\n const tseslint = await tryImport(\"typescript-eslint\", \"TypeScript\");\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 tryImport(\"eslint-plugin-react\", \"React\");\n const reactHooks = await tryImport(\"eslint-plugin-react-hooks\", \"React\");\n const jsxA11y = await tryImport(\"eslint-plugin-jsx-a11y\", \"React\");\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 tryImport(\"@next/eslint-plugin-next\", \"Next.js\");\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 tryImport(\"eslint-plugin-astro\", \"Astro\");\n configs.push(...astro.default.configs.recommended);\n}\n\n// Vue support\nif (deps[\"vue\"] || deps[\"nuxt\"]) {\n const vue = await tryImport(\"eslint-plugin-vue\", \"Vue\");\n configs.push(...vue.default.configs[\"flat/recommended\"]);\n}\n\n// Svelte support\nif (deps[\"svelte\"] || deps[\"@sveltejs/kit\"]) {\n const svelte = await tryImport(\"eslint-plugin-svelte\", \"Svelte\");\n configs.push(...svelte.default.configs.recommended);\n}\n\n// Electron support\nif (deps[\"electron\"]) {\n const electron = await tryImport(\"@electron-toolkit/eslint-config\", \"Electron\");\n configs.push(electron.default);\n}\n\n// Vitest support (scoped to test files)\nif (deps[\"vitest\"]) {\n const vitest = await tryImport(\"@vitest/eslint-plugin\", \"Vitest\");\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\n// Cursor hooks configuration (.cursor/hooks.json format)\n// See: https://cursor.com/docs/agent/hooks\nexport const CURSOR_HOOKS = {\n afterFileEdit: [{ command: './.safeword/hooks/cursor/after-file-edit.sh' }],\n stop: [{ command: './.safeword/hooks/cursor/stop.sh' }],\n};\n\n// Claude Code hooks configuration (.claude/settings.json format)\nexport const SETTINGS_HOOKS = {\n SessionStart: [\n {\n hooks: [\n {\n type: 'command',\n command: '\"$CLAUDE_PROJECT_DIR\"/.safeword/hooks/session-verify-agents.sh',\n },\n ],\n },\n {\n hooks: [\n {\n type: 'command',\n command: '\"$CLAUDE_PROJECT_DIR\"/.safeword/hooks/session-version.sh',\n },\n ],\n },\n {\n hooks: [\n {\n type: 'command',\n command: '\"$CLAUDE_PROJECT_DIR\"/.safeword/hooks/session-lint-check.sh',\n },\n ],\n },\n ],\n UserPromptSubmit: [\n {\n hooks: [\n {\n type: 'command',\n command: '\"$CLAUDE_PROJECT_DIR\"/.safeword/hooks/prompt-timestamp.sh',\n },\n ],\n },\n {\n hooks: [\n {\n type: 'command',\n command: '\"$CLAUDE_PROJECT_DIR\"/.safeword/hooks/prompt-questions.sh',\n },\n ],\n },\n ],\n Stop: [\n {\n hooks: [\n {\n type: 'command',\n command: '\"$CLAUDE_PROJECT_DIR\"/.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: '\"$CLAUDE_PROJECT_DIR\"/.safeword/hooks/post-tool-lint.sh',\n },\n ],\n },\n ],\n};\n","/**\n * Architecture boundaries detection and config generation\n *\n * Auto-detects common architecture directories and generates\n * eslint-plugin-boundaries config with sensible hierarchy rules.\n *\n * Supports:\n * - Standard projects (src/utils, utils/)\n * - Monorepos (packages/*, apps/*)\n * - Various naming conventions (helpers, shared, core, etc.)\n */\n\nimport { join } from 'node:path';\nimport { readdirSync } from 'node:fs';\nimport { exists } from './fs.js';\n\n/**\n * Architecture layer definitions with alternative names.\n * Each layer maps to equivalent directory names.\n * Order defines hierarchy: earlier = lower layer.\n */\nconst ARCHITECTURE_LAYERS = [\n // Layer 0: Pure types (no imports)\n { layer: 'types', dirs: ['types', 'interfaces', 'schemas'] },\n // Layer 1: Utilities (only types)\n { layer: 'utils', dirs: ['utils', 'helpers', 'shared', 'common', 'core'] },\n // Layer 2: Libraries (types, utils)\n { layer: 'lib', dirs: ['lib', 'libraries'] },\n // Layer 3: State & logic (types, utils, lib)\n { layer: 'hooks', dirs: ['hooks', 'composables'] },\n { layer: 'services', dirs: ['services', 'api', 'stores', 'state'] },\n // Layer 4: UI components (all above)\n { layer: 'components', dirs: ['components', 'ui'] },\n // Layer 5: Features (all above)\n { layer: 'features', dirs: ['features', 'modules', 'domains'] },\n // Layer 6: Entry points (can import everything)\n { layer: 'app', dirs: ['app', 'pages', 'views', 'routes', 'commands'] },\n] as const;\n\ntype Layer = (typeof ARCHITECTURE_LAYERS)[number]['layer'];\n\n/**\n * Hierarchy rules: what each layer can import\n * Lower layers have fewer import permissions\n */\nconst HIERARCHY: Record<Layer, Layer[]> = {\n types: [],\n utils: ['types'],\n lib: ['utils', 'types'],\n hooks: ['lib', 'utils', 'types'],\n services: ['lib', 'utils', 'types'],\n components: ['hooks', 'services', 'lib', 'utils', 'types'],\n features: ['components', 'hooks', 'services', 'lib', 'utils', 'types'],\n app: ['features', 'components', 'hooks', 'services', 'lib', 'utils', 'types'],\n};\n\nexport interface DetectedElement {\n layer: Layer;\n pattern: string; // glob pattern for boundaries config\n location: string; // human-readable location\n}\n\nexport interface DetectedArchitecture {\n elements: DetectedElement[];\n isMonorepo: boolean;\n}\n\n/**\n * Find monorepo package directories\n */\nfunction findMonorepoPackages(projectDir: string): string[] {\n const packages: string[] = [];\n\n // Check common monorepo patterns\n const monorepoRoots = ['packages', 'apps', 'libs', 'modules'];\n\n for (const root of monorepoRoots) {\n const rootPath = join(projectDir, root);\n if (exists(rootPath)) {\n try {\n const entries = readdirSync(rootPath, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory() && !entry.name.startsWith('.')) {\n packages.push(join(root, entry.name));\n }\n }\n } catch {\n // Directory not readable, skip\n }\n }\n }\n\n return packages;\n}\n\n/**\n * Check if a layer already exists for this path prefix\n */\nfunction hasLayerForPrefix(elements: DetectedElement[], layer: Layer, pathPrefix: string): boolean {\n return elements.some(e => e.layer === layer && e.pattern.startsWith(pathPrefix));\n}\n\n/**\n * Scan a single search path for architecture layers\n */\nfunction scanSearchPath(\n projectDir: string,\n searchPath: string,\n pathPrefix: string,\n elements: DetectedElement[],\n): void {\n for (const layerDef of ARCHITECTURE_LAYERS) {\n for (const dirName of layerDef.dirs) {\n const fullPath = join(projectDir, searchPath, dirName);\n if (exists(fullPath) && !hasLayerForPrefix(elements, layerDef.layer, pathPrefix)) {\n elements.push({\n layer: layerDef.layer,\n pattern: `${pathPrefix}${dirName}/**`,\n location: `${pathPrefix}${dirName}`,\n });\n }\n }\n }\n}\n\n/**\n * Scan a directory for architecture layers\n */\nfunction scanForLayers(projectDir: string, basePath: string): DetectedElement[] {\n const elements: DetectedElement[] = [];\n const prefix = basePath ? `${basePath}/` : '';\n\n // Check src/ and root level\n scanSearchPath(projectDir, join(basePath, 'src'), `${prefix}src/`, elements);\n scanSearchPath(projectDir, basePath, prefix, elements);\n\n return elements;\n}\n\n/**\n * Detects architecture directories in the project\n * Handles both standard projects and monorepos\n */\nexport function detectArchitecture(projectDir: string): DetectedArchitecture {\n const elements: DetectedElement[] = [];\n\n // First, check for monorepo packages\n const packages = findMonorepoPackages(projectDir);\n const isMonorepo = packages.length > 0;\n\n if (isMonorepo) {\n // Scan each package\n for (const pkg of packages) {\n elements.push(...scanForLayers(projectDir, pkg));\n }\n }\n\n // Also scan root level (works for both monorepo root and standard projects)\n elements.push(...scanForLayers(projectDir, ''));\n\n // Deduplicate by pattern\n const seen = new Set<string>();\n const uniqueElements = elements.filter(e => {\n if (seen.has(e.pattern)) return false;\n seen.add(e.pattern);\n return true;\n });\n\n return { elements: uniqueElements, isMonorepo };\n}\n\n/**\n * Format a single element for the config\n */\nfunction formatElement(el: DetectedElement): string {\n return ` { type: '${el.layer}', pattern: '${el.pattern}', mode: 'full' }`;\n}\n\n/**\n * Format allowed imports for a rule\n */\nfunction formatAllowedImports(allowed: Layer[]): string {\n return allowed.map(d => `'${d}'`).join(', ');\n}\n\n/**\n * Generate a single rule for what a layer can import\n */\nfunction generateRule(layer: Layer, detectedLayers: Set<Layer>): string | null {\n const allowedLayers = HIERARCHY[layer];\n if (allowedLayers.length === 0) return null;\n\n const allowed = allowedLayers.filter(dep => detectedLayers.has(dep));\n if (allowed.length === 0) return null;\n\n return ` { from: ['${layer}'], allow: [${formatAllowedImports(allowed)}] }`;\n}\n\n/**\n * Build description of what was detected\n */\nfunction buildDetectedInfo(arch: DetectedArchitecture): string {\n if (arch.elements.length === 0) {\n return 'No architecture directories detected yet - add types/, utils/, components/, etc.';\n }\n const locations = arch.elements.map(e => e.location).join(', ');\n const monorepoNote = arch.isMonorepo ? ' (monorepo)' : '';\n return `Detected: ${locations}${monorepoNote}`;\n}\n\nexport function generateBoundariesConfig(arch: DetectedArchitecture): string {\n const hasElements = arch.elements.length > 0;\n\n // Generate element definitions\n const elementsContent = arch.elements.map(el => formatElement(el)).join(',\\n');\n\n // Generate rules (what each layer can import)\n const detectedLayers = new Set(arch.elements.map(e => e.layer));\n const rules = [...detectedLayers]\n .map(layer => generateRule(layer, detectedLayers))\n .filter((rule): rule is string => rule !== null);\n const rulesContent = rules.join(',\\n');\n\n const detectedInfo = buildDetectedInfo(arch);\n\n return `/**\n * Architecture Boundaries Configuration (AUTO-GENERATED)\n *\n * ${detectedInfo}\n *\n * This enforces import boundaries between architectural layers:\n * - Lower layers (types, utils) cannot import from higher layers (components, features)\n * - Uses 'warn' severity - informative, not blocking\n *\n * Recognized directories (in hierarchy order):\n * types → utils → lib → hooks/services → components → features/modules → app\n *\n * To customize, override in your eslint.config.mjs:\n * rules: { 'boundaries/element-types': ['error', { ... }] }\n */\n\nimport boundaries from 'eslint-plugin-boundaries';\n\nexport default {\n plugins: { boundaries },\n settings: {\n 'boundaries/elements': [\n${elementsContent}\n ],\n },\n rules: {${\n hasElements\n ? `\n 'boundaries/element-types': ['warn', {\n default: 'disallow',\n rules: [\n${rulesContent}\n ],\n }],`\n : ''\n }\n 'boundaries/no-unknown': 'off', // Allow files outside defined elements\n 'boundaries/no-unknown-files': 'off', // Allow non-matching files\n },\n};\n`;\n}\n","/**\n * Shared installation constants\n *\n * These constants are used by schema.ts to define the single source of truth.\n * All functions have been removed - reconcile.ts now handles all operations.\n */\n\n/**\n * Husky pre-commit hook content - includes safeword sync + lint-staged\n * The sync command keeps ESLint plugins aligned with detected frameworks\n */\nexport const HUSKY_PRE_COMMIT_CONTENT = 'npx safeword sync --quiet --stage\\nnpx lint-staged\\n';\n\n/**\n * MCP servers installed by safeword\n */\nexport const MCP_SERVERS = {\n context7: {\n command: 'npx',\n args: ['-y', '@upstash/context7-mcp@latest'],\n },\n playwright: {\n command: 'npx',\n args: ['@playwright/mcp@latest'],\n },\n} as const;\n\n// NOTE: All other constants and functions were removed in the declarative schema refactor.\n// The single source of truth is now SAFEWORD_SCHEMA in src/schema.ts.\n// Operations are handled by reconcile() in src/reconcile.ts.\n","/**\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' && h !== null && 'hooks' in h && 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(cmd => typeof cmd.command === 'string' && cmd.command.includes('.safeword'));\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 * SAFEWORD Schema - Single Source of Truth\n *\n * All files, directories, configurations, and packages managed by safeword\n * are defined here. Commands use this schema via the reconciliation engine.\n *\n * Adding a new file? Add it here and it will be handled by setup/upgrade/reset.\n */\n\nimport { VERSION } from './version.js';\nimport { type ProjectType } from './utils/project-detector.js';\nimport { AGENTS_MD_LINK, getPrettierConfig, getLintStagedConfig } from './templates/content.js';\nimport { getEslintConfig, SETTINGS_HOOKS, CURSOR_HOOKS } from './templates/config.js';\nimport { generateBoundariesConfig, detectArchitecture } from './utils/boundaries.js';\nimport { HUSKY_PRE_COMMIT_CONTENT, MCP_SERVERS } from './utils/install.js';\nimport { filterOutSafewordHooks } from './utils/hooks.js';\n\n// ============================================================================\n// Interfaces\n// ============================================================================\n\nexport interface ProjectContext {\n cwd: string;\n projectType: ProjectType;\n devDeps: Record<string, string>;\n isGitRepo: boolean;\n}\n\nexport interface FileDefinition {\n template?: string; // Path in templates/ dir\n content?: string | (() => string); // Static content or factory\n generator?: (ctx: ProjectContext) => string; // Dynamic generator needing context\n}\n\n// managedFiles: created if missing, updated only if content === current template output\nexport type ManagedFileDefinition = FileDefinition;\n\nexport interface JsonMergeDefinition {\n keys: string[]; // Dot-notation keys we manage\n conditionalKeys?: Record<string, string[]>; // Keys added based on project type\n merge: (existing: Record<string, unknown>, ctx: ProjectContext) => Record<string, unknown>;\n unmerge: (existing: Record<string, unknown>) => Record<string, unknown>;\n removeFileIfEmpty?: boolean; // Delete file if our keys were the only content\n}\n\nexport interface TextPatchDefinition {\n operation: 'prepend' | 'append';\n content: string;\n marker: string; // Used to detect if already applied & for removal\n createIfMissing: boolean;\n}\n\nexport interface SafewordSchema {\n version: string;\n ownedDirs: string[]; // Fully owned - create on setup, delete on reset\n sharedDirs: string[]; // We add to but don't own\n preservedDirs: string[]; // Created on setup, NOT deleted on reset (user data)\n deprecatedFiles: string[]; // Files to delete on upgrade (renamed or removed)\n ownedFiles: Record<string, FileDefinition>; // Overwrite on upgrade (if changed)\n managedFiles: Record<string, ManagedFileDefinition>; // Create if missing, update if safeword content\n jsonMerges: Record<string, JsonMergeDefinition>;\n textPatches: Record<string, TextPatchDefinition>;\n packages: {\n base: string[];\n conditional: Record<string, string[]>;\n };\n}\n\n// ============================================================================\n// SAFEWORD_SCHEMA - The Single Source of Truth\n// ============================================================================\n\n/**\n * Check if a package name is an ESLint-related package.\n * Used by sync command to filter packages for pre-commit installation.\n */\nfunction isEslintPackage(pkg: string): boolean {\n return (\n pkg.startsWith('eslint') ||\n pkg.startsWith('@eslint/') ||\n pkg.startsWith('@microsoft/eslint') ||\n pkg.startsWith('@next/eslint') ||\n pkg.startsWith('@vitest/eslint') ||\n pkg.startsWith('@electron-toolkit/eslint') ||\n pkg === 'typescript-eslint'\n );\n}\n\n/**\n * Get ESLint packages from schema base packages.\n * Single source of truth - no separate list to maintain.\n */\nexport function getBaseEslintPackages(): string[] {\n return SAFEWORD_SCHEMA.packages.base.filter(pkg => isEslintPackage(pkg));\n}\n\n/**\n * Get conditional ESLint packages for a specific project type key.\n */\nexport function getConditionalEslintPackages(key: string): string[] {\n const deps = SAFEWORD_SCHEMA.packages.conditional[key];\n return deps ? deps.filter(pkg => isEslintPackage(pkg)) : [];\n}\n\nexport const SAFEWORD_SCHEMA: SafewordSchema = {\n version: VERSION,\n\n // Directories fully owned by safeword (created on setup, deleted on reset)\n ownedDirs: [\n '.safeword',\n '.safeword/hooks',\n '.safeword/hooks/cursor',\n '.safeword/lib',\n '.safeword/guides',\n '.safeword/templates',\n '.safeword/prompts',\n '.safeword/planning',\n '.safeword/planning/specs',\n '.safeword/planning/test-definitions',\n '.safeword/planning/design',\n '.safeword/planning/issues',\n '.safeword/scripts',\n '.husky',\n '.cursor',\n '.cursor/rules',\n '.cursor/commands',\n ],\n\n // Directories we add to but don't own (not deleted on reset)\n sharedDirs: ['.claude', '.claude/skills', '.claude/commands'],\n\n // Created on setup but NOT deleted on reset (preserves user data)\n preservedDirs: [\n '.safeword/learnings',\n '.safeword/tickets',\n '.safeword/tickets/completed',\n '.safeword/logs',\n ],\n\n // Files to delete on upgrade (renamed or removed in newer versions)\n deprecatedFiles: [\n '.safeword/templates/user-stories-template.md',\n // Consolidated into planning-guide.md and testing-guide.md (v0.8.0)\n '.safeword/guides/development-workflow.md',\n '.safeword/guides/tdd-best-practices.md',\n '.safeword/guides/user-story-guide.md',\n '.safeword/guides/test-definitions-guide.md',\n ],\n\n // Files owned by safeword (overwritten on upgrade if content changed)\n ownedFiles: {\n // Core files\n '.safeword/SAFEWORD.md': { template: 'SAFEWORD.md' },\n '.safeword/version': { content: () => VERSION },\n '.safeword/eslint-boundaries.config.mjs': {\n generator: ctx => generateBoundariesConfig(detectArchitecture(ctx.cwd)),\n },\n\n // Hooks (7 files)\n '.safeword/hooks/session-verify-agents.sh': { template: 'hooks/session-verify-agents.sh' },\n '.safeword/hooks/session-version.sh': { template: 'hooks/session-version.sh' },\n '.safeword/hooks/session-lint-check.sh': { template: 'hooks/session-lint-check.sh' },\n '.safeword/hooks/prompt-timestamp.sh': { template: 'hooks/prompt-timestamp.sh' },\n '.safeword/hooks/prompt-questions.sh': { template: 'hooks/prompt-questions.sh' },\n '.safeword/hooks/post-tool-lint.sh': { template: 'hooks/post-tool-lint.sh' },\n '.safeword/hooks/stop-quality.sh': { template: 'hooks/stop-quality.sh' },\n\n // Lib (2 files)\n '.safeword/lib/common.sh': { template: 'lib/common.sh' },\n '.safeword/lib/jq-fallback.sh': { template: 'lib/jq-fallback.sh' },\n\n // Guides (11 files)\n '.safeword/guides/architecture-guide.md': { template: 'guides/architecture-guide.md' },\n '.safeword/guides/cli-reference.md': { template: 'guides/cli-reference.md' },\n '.safeword/guides/code-philosophy.md': { template: 'guides/code-philosophy.md' },\n '.safeword/guides/context-files-guide.md': { template: 'guides/context-files-guide.md' },\n '.safeword/guides/data-architecture-guide.md': {\n template: 'guides/data-architecture-guide.md',\n },\n '.safeword/guides/design-doc-guide.md': { template: 'guides/design-doc-guide.md' },\n '.safeword/guides/learning-extraction.md': { template: 'guides/learning-extraction.md' },\n '.safeword/guides/llm-guide.md': { template: 'guides/llm-guide.md' },\n '.safeword/guides/planning-guide.md': { template: 'guides/planning-guide.md' },\n '.safeword/guides/testing-guide.md': { template: 'guides/testing-guide.md' },\n '.safeword/guides/zombie-process-cleanup.md': { template: 'guides/zombie-process-cleanup.md' },\n\n // Templates (7 files)\n '.safeword/templates/architecture-template.md': {\n template: 'doc-templates/architecture-template.md',\n },\n '.safeword/templates/design-doc-template.md': {\n template: 'doc-templates/design-doc-template.md',\n },\n '.safeword/templates/task-spec-template.md': {\n template: 'doc-templates/task-spec-template.md',\n },\n '.safeword/templates/test-definitions-feature.md': {\n template: 'doc-templates/test-definitions-feature.md',\n },\n '.safeword/templates/ticket-template.md': { template: 'doc-templates/ticket-template.md' },\n '.safeword/templates/feature-spec-template.md': {\n template: 'doc-templates/feature-spec-template.md',\n },\n '.safeword/templates/work-log-template.md': { template: 'doc-templates/work-log-template.md' },\n\n // Prompts (2 files)\n '.safeword/prompts/architecture.md': { template: 'prompts/architecture.md' },\n '.safeword/prompts/quality-review.md': { template: 'prompts/quality-review.md' },\n\n // Scripts (3 files)\n '.safeword/scripts/bisect-test-pollution.sh': { template: 'scripts/bisect-test-pollution.sh' },\n '.safeword/scripts/bisect-zombie-processes.sh': {\n template: 'scripts/bisect-zombie-processes.sh',\n },\n '.safeword/scripts/lint-md.sh': { template: 'scripts/lint-md.sh' },\n\n // Claude skills and commands (8 files)\n '.claude/skills/safeword-brainstorming/SKILL.md': {\n template: 'skills/safeword-brainstorming/SKILL.md',\n },\n '.claude/skills/safeword-debugging/SKILL.md': {\n template: 'skills/safeword-debugging/SKILL.md',\n },\n '.claude/skills/safeword-enforcing-tdd/SKILL.md': {\n template: 'skills/safeword-enforcing-tdd/SKILL.md',\n },\n '.claude/skills/safeword-quality-reviewer/SKILL.md': {\n template: 'skills/safeword-quality-reviewer/SKILL.md',\n },\n '.claude/skills/safeword-refactoring/SKILL.md': {\n template: 'skills/safeword-refactoring/SKILL.md',\n },\n '.claude/commands/architecture.md': { template: 'commands/architecture.md' },\n '.claude/commands/lint.md': { template: 'commands/lint.md' },\n '.claude/commands/quality-review.md': { template: 'commands/quality-review.md' },\n\n // Husky (1 file)\n '.husky/pre-commit': { content: HUSKY_PRE_COMMIT_CONTENT },\n\n // Cursor rules (6 files)\n '.cursor/rules/safeword-core.mdc': { template: 'cursor/rules/safeword-core.mdc' },\n '.cursor/rules/safeword-brainstorming.mdc': {\n template: 'cursor/rules/safeword-brainstorming.mdc',\n },\n '.cursor/rules/safeword-debugging.mdc': {\n template: 'cursor/rules/safeword-debugging.mdc',\n },\n '.cursor/rules/safeword-enforcing-tdd.mdc': {\n template: 'cursor/rules/safeword-enforcing-tdd.mdc',\n },\n '.cursor/rules/safeword-quality-reviewer.mdc': {\n template: 'cursor/rules/safeword-quality-reviewer.mdc',\n },\n '.cursor/rules/safeword-refactoring.mdc': {\n template: 'cursor/rules/safeword-refactoring.mdc',\n },\n\n // Cursor commands (3 files - same as Claude)\n '.cursor/commands/lint.md': { template: 'commands/lint.md' },\n '.cursor/commands/quality-review.md': { template: 'commands/quality-review.md' },\n '.cursor/commands/architecture.md': { template: 'commands/architecture.md' },\n\n // Cursor hooks adapters (2 files)\n '.safeword/hooks/cursor/after-file-edit.sh': { template: 'hooks/cursor/after-file-edit.sh' },\n '.safeword/hooks/cursor/stop.sh': { template: 'hooks/cursor/stop.sh' },\n },\n\n // Files created if missing, updated only if content matches current template\n managedFiles: {\n 'eslint.config.mjs': {\n generator: () => getEslintConfig({ boundaries: true }),\n },\n '.prettierrc': { generator: ctx => getPrettierConfig(ctx.projectType) },\n '.markdownlint-cli2.jsonc': { template: 'markdownlint-cli2.jsonc' },\n },\n\n // JSON files where we merge specific keys\n jsonMerges: {\n 'package.json': {\n keys: [\n 'scripts.lint',\n 'scripts.lint:md',\n 'scripts.format',\n 'scripts.format:check',\n 'scripts.knip',\n 'scripts.prepare',\n 'lint-staged',\n ],\n conditionalKeys: {\n publishableLibrary: ['scripts.publint'],\n shell: ['scripts.lint:sh'],\n },\n merge: (existing, ctx) => {\n const scripts = (existing.scripts as Record<string, string>) ?? {};\n const result = { ...existing };\n\n // Add scripts if not present\n if (!scripts.lint) scripts.lint = 'eslint .';\n if (!scripts['lint:md']) scripts['lint:md'] = 'markdownlint-cli2 \"**/*.md\" \"#node_modules\"';\n if (!scripts.format) scripts.format = 'prettier --write .';\n if (!scripts['format:check']) scripts['format:check'] = 'prettier --check .';\n if (!scripts.knip) scripts.knip = 'knip';\n if (!scripts.prepare) scripts.prepare = 'husky || true';\n\n // Conditional: publint for publishable libraries\n if (ctx.projectType.publishableLibrary && !scripts.publint) {\n scripts.publint = 'publint';\n }\n\n // Conditional: lint:sh for projects with shell scripts\n if (ctx.projectType.shell && !scripts['lint:sh']) {\n scripts['lint:sh'] = 'shellcheck **/*.sh';\n }\n\n result.scripts = scripts;\n\n // Add lint-staged config\n if (!existing['lint-staged']) {\n result['lint-staged'] = getLintStagedConfig(ctx.projectType);\n }\n\n return result;\n },\n unmerge: existing => {\n const result = { ...existing };\n const scripts = { ...(existing.scripts as Record<string, string>) };\n\n // Remove safeword-specific scripts but preserve lint/format (useful standalone)\n delete scripts['lint:md'];\n delete scripts['lint:sh'];\n delete scripts['format:check'];\n delete scripts.knip;\n delete scripts.prepare;\n delete scripts.publint;\n\n if (Object.keys(scripts).length > 0) {\n result.scripts = scripts;\n } else {\n delete result.scripts;\n }\n\n delete result['lint-staged'];\n\n return result;\n },\n },\n\n '.claude/settings.json': {\n keys: ['hooks'],\n merge: existing => {\n // Preserve non-safeword hooks while adding/updating safeword hooks\n const existingHooks = (existing.hooks as Record<string, unknown[]>) ?? {};\n const mergedHooks: Record<string, unknown[]> = { ...existingHooks };\n\n for (const [event, newHooks] of Object.entries(SETTINGS_HOOKS)) {\n const eventHooks = (mergedHooks[event] as unknown[]) ?? [];\n const nonSafewordHooks = filterOutSafewordHooks(eventHooks);\n mergedHooks[event] = [...nonSafewordHooks, ...newHooks];\n }\n\n return { ...existing, hooks: mergedHooks };\n },\n unmerge: existing => {\n // Remove only safeword hooks, preserve custom hooks\n const existingHooks = (existing.hooks as Record<string, unknown[]>) ?? {};\n const cleanedHooks: Record<string, unknown[]> = {};\n\n for (const [event, eventHooks] of Object.entries(existingHooks)) {\n const nonSafewordHooks = filterOutSafewordHooks(eventHooks as unknown[]);\n if (nonSafewordHooks.length > 0) {\n cleanedHooks[event] = nonSafewordHooks;\n }\n }\n\n const result = { ...existing };\n if (Object.keys(cleanedHooks).length > 0) {\n result.hooks = cleanedHooks;\n } else {\n delete result.hooks;\n }\n return result;\n },\n },\n\n '.mcp.json': {\n keys: ['mcpServers.context7', 'mcpServers.playwright'],\n removeFileIfEmpty: true,\n merge: existing => {\n const mcpServers = (existing.mcpServers as Record<string, unknown>) ?? {};\n return {\n ...existing,\n mcpServers: {\n ...mcpServers,\n context7: MCP_SERVERS.context7,\n playwright: MCP_SERVERS.playwright,\n },\n };\n },\n unmerge: existing => {\n const result = { ...existing };\n const mcpServers = { ...(existing.mcpServers as Record<string, unknown>) };\n\n delete mcpServers.context7;\n delete mcpServers.playwright;\n\n if (Object.keys(mcpServers).length > 0) {\n result.mcpServers = mcpServers;\n } else {\n delete result.mcpServers;\n }\n\n return result;\n },\n },\n\n '.cursor/mcp.json': {\n keys: ['mcpServers.context7', 'mcpServers.playwright'],\n removeFileIfEmpty: true,\n merge: existing => {\n const mcpServers = (existing.mcpServers as Record<string, unknown>) ?? {};\n return {\n ...existing,\n mcpServers: {\n ...mcpServers,\n context7: MCP_SERVERS.context7,\n playwright: MCP_SERVERS.playwright,\n },\n };\n },\n unmerge: existing => {\n const result = { ...existing };\n const mcpServers = { ...(existing.mcpServers as Record<string, unknown>) };\n\n delete mcpServers.context7;\n delete mcpServers.playwright;\n\n if (Object.keys(mcpServers).length > 0) {\n result.mcpServers = mcpServers;\n } else {\n delete result.mcpServers;\n }\n\n return result;\n },\n },\n\n '.cursor/hooks.json': {\n keys: ['version', 'hooks.afterFileEdit', 'hooks.stop'],\n removeFileIfEmpty: true,\n merge: existing => {\n const hooks = (existing.hooks as Record<string, unknown[]>) ?? {};\n return {\n ...existing,\n version: 1, // Required by Cursor\n hooks: {\n ...hooks,\n ...CURSOR_HOOKS,\n },\n };\n },\n unmerge: existing => {\n const result = { ...existing };\n const hooks = { ...(existing.hooks as Record<string, unknown[]>) };\n\n delete hooks.afterFileEdit;\n delete hooks.stop;\n\n if (Object.keys(hooks).length > 0) {\n result.hooks = hooks;\n } else {\n delete result.hooks;\n delete result.version;\n }\n\n return result;\n },\n },\n },\n\n // Text files where we patch specific content\n textPatches: {\n 'AGENTS.md': {\n operation: 'prepend',\n content: AGENTS_MD_LINK,\n marker: '.safeword/SAFEWORD.md',\n createIfMissing: true,\n },\n 'CLAUDE.md': {\n operation: 'prepend',\n content: AGENTS_MD_LINK,\n marker: '.safeword/SAFEWORD.md',\n createIfMissing: false, // Only patch if exists, don't create (AGENTS.md is primary)\n },\n },\n\n // NPM packages to install\n packages: {\n base: [\n 'eslint',\n 'prettier',\n '@eslint/js',\n 'eslint-plugin-import-x',\n 'eslint-import-resolver-typescript',\n 'eslint-plugin-sonarjs',\n 'eslint-plugin-unicorn',\n 'eslint-plugin-boundaries',\n 'eslint-plugin-playwright',\n '@microsoft/eslint-plugin-sdl',\n 'eslint-config-prettier',\n 'markdownlint-cli2',\n 'knip',\n 'husky',\n 'lint-staged',\n ],\n conditional: {\n typescript: ['typescript-eslint'],\n react: ['eslint-plugin-react', 'eslint-plugin-react-hooks', 'eslint-plugin-jsx-a11y'],\n nextjs: ['@next/eslint-plugin-next'],\n astro: ['eslint-plugin-astro', 'prettier-plugin-astro'],\n vue: ['eslint-plugin-vue'],\n svelte: ['eslint-plugin-svelte', 'prettier-plugin-svelte'],\n electron: ['@electron-toolkit/eslint-config'],\n vitest: ['@vitest/eslint-plugin'],\n tailwind: ['prettier-plugin-tailwindcss'],\n publishableLibrary: ['publint'],\n shell: ['shellcheck', 'prettier-plugin-sh'],\n },\n },\n};\n"],"mappings":";;;;;AAIA;AAAA,EACE;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;AAYjD,SAAS,kBAA0B;AACxC,QAAM,oBAAoB;AAI1B,QAAM,aAAa;AAAA,IACjB,KAAK,WAAW,MAAM,WAAW;AAAA;AAAA,IACjC,KAAK,WAAW,MAAM,MAAM,WAAW;AAAA;AAAA,IACvC,KAAK,WAAW,WAAW;AAAA;AAAA,EAC7B;AAEA,aAAW,aAAa,YAAY;AAClC,QAAI,WAAW,KAAK,WAAW,iBAAiB,CAAC,GAAG;AAClD,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,+BAA+B;AACjD;AAKO,SAAS,OAAO,MAAuB;AAC5C,SAAO,WAAW,IAAI;AACxB;AAKO,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,cAAc,MAAuB;AACnD,MAAI,CAAC,WAAW,IAAI,EAAG,QAAO;AAC9B,MAAI;AACF,cAAU,IAAI;AACd,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,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;;;ACtIA,SAAS,eAAAA,oBAAmB;AAC5B,SAAS,QAAAC,aAAY;AAmCd,SAAS,gBAAgB,KAAa,WAAW,GAAY;AAClE,QAAM,cAAc,oBAAI,IAAI,CAAC,gBAAgB,QAAQ,WAAW,CAAC;AAEjE,WAAS,KAAK,KAAa,OAAwB;AACjD,QAAI,QAAQ,SAAU,QAAO;AAE7B,QAAI;AACF,YAAM,UAAUD,aAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AACxD,iBAAW,SAAS,SAAS;AAC3B,YAAI,MAAM,OAAO,KAAK,MAAM,KAAK,SAAS,KAAK,GAAG;AAChD,iBAAO;AAAA,QACT;AACA,YAAI,MAAM,YAAY,KAAK,CAAC,YAAY,IAAI,MAAM,IAAI,GAAG;AACvD,cAAI,KAAKC,MAAK,KAAK,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG;AAC1C,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AACA,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,KAAK,CAAC;AACpB;AAKO,SAAS,kBAAkB,aAA0B,KAA2B;AACrF,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;AAGhE,QAAM,WAAW,MAAM,gBAAgB,GAAG,IAAI;AAE9C,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,IACpB,OAAO;AAAA,EACT;AACF;;;ACxGO,IAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBvB,SAAS,kBAAkB,aAAkC;AAClE,QAAM,SAAyB;AAAA,IAC7B,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,WAAW;AAAA,EACb;AAEA,QAAM,UAAoB,CAAC;AAE3B,MAAI,YAAY,MAAO,SAAQ,KAAK,uBAAuB;AAC3D,MAAI,YAAY,OAAQ,SAAQ,KAAK,wBAAwB;AAC7D,MAAI,YAAY,MAAO,SAAQ,KAAK,oBAAoB;AAExD,MAAI,YAAY,SAAU,SAAQ,KAAK,6BAA6B;AAEpE,MAAI,QAAQ,SAAS,GAAG;AACtB,WAAO,UAAU;AAAA,EACnB;AAEA,SAAO,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI;AAC3C;AASO,SAAS,oBAAoB,aAAoD;AACtF,QAAM,SAAmC;AAAA,IACvC,qCAAqC,CAAC,gBAAgB,kBAAkB;AAAA,IACxE,wBAAwB,CAAC,gBAAgB,kBAAkB;AAAA,IAC3D,2CAA2C,CAAC,kBAAkB;AAAA,IAC9D,QAAQ,CAAC,2BAA2B,kBAAkB;AAAA,EACxD;AAEA,MAAI,YAAY,OAAO;AACrB,WAAO,MAAM,IAAI,CAAC,cAAc,kBAAkB;AAAA,EACpD;AAEA,SAAO;AACT;;;ACrDO,SAAS,gBAAgB,SAA2C;AACzE,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaP,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;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,4BA4I1E,QAAQ,aAAa,sCAAsC,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOzF;AAIO,IAAM,eAAe;AAAA,EAC1B,eAAe,CAAC,EAAE,SAAS,8CAA8C,CAAC;AAAA,EAC1E,MAAM,CAAC,EAAE,SAAS,mCAAmC,CAAC;AACxD;AAGO,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;;;ACxPA,SAAS,QAAAC,aAAY;AACrB,SAAS,eAAAC,oBAAmB;AAQ5B,IAAM,sBAAsB;AAAA;AAAA,EAE1B,EAAE,OAAO,SAAS,MAAM,CAAC,SAAS,cAAc,SAAS,EAAE;AAAA;AAAA,EAE3D,EAAE,OAAO,SAAS,MAAM,CAAC,SAAS,WAAW,UAAU,UAAU,MAAM,EAAE;AAAA;AAAA,EAEzE,EAAE,OAAO,OAAO,MAAM,CAAC,OAAO,WAAW,EAAE;AAAA;AAAA,EAE3C,EAAE,OAAO,SAAS,MAAM,CAAC,SAAS,aAAa,EAAE;AAAA,EACjD,EAAE,OAAO,YAAY,MAAM,CAAC,YAAY,OAAO,UAAU,OAAO,EAAE;AAAA;AAAA,EAElE,EAAE,OAAO,cAAc,MAAM,CAAC,cAAc,IAAI,EAAE;AAAA;AAAA,EAElD,EAAE,OAAO,YAAY,MAAM,CAAC,YAAY,WAAW,SAAS,EAAE;AAAA;AAAA,EAE9D,EAAE,OAAO,OAAO,MAAM,CAAC,OAAO,SAAS,SAAS,UAAU,UAAU,EAAE;AACxE;AAQA,IAAM,YAAoC;AAAA,EACxC,OAAO,CAAC;AAAA,EACR,OAAO,CAAC,OAAO;AAAA,EACf,KAAK,CAAC,SAAS,OAAO;AAAA,EACtB,OAAO,CAAC,OAAO,SAAS,OAAO;AAAA,EAC/B,UAAU,CAAC,OAAO,SAAS,OAAO;AAAA,EAClC,YAAY,CAAC,SAAS,YAAY,OAAO,SAAS,OAAO;AAAA,EACzD,UAAU,CAAC,cAAc,SAAS,YAAY,OAAO,SAAS,OAAO;AAAA,EACrE,KAAK,CAAC,YAAY,cAAc,SAAS,YAAY,OAAO,SAAS,OAAO;AAC9E;AAgBA,SAAS,qBAAqB,YAA8B;AAC1D,QAAM,WAAqB,CAAC;AAG5B,QAAM,gBAAgB,CAAC,YAAY,QAAQ,QAAQ,SAAS;AAE5D,aAAW,QAAQ,eAAe;AAChC,UAAM,WAAWC,MAAK,YAAY,IAAI;AACtC,QAAI,OAAO,QAAQ,GAAG;AACpB,UAAI;AACF,cAAM,UAAUC,aAAY,UAAU,EAAE,eAAe,KAAK,CAAC;AAC7D,mBAAW,SAAS,SAAS;AAC3B,cAAI,MAAM,YAAY,KAAK,CAAC,MAAM,KAAK,WAAW,GAAG,GAAG;AACtD,qBAAS,KAAKD,MAAK,MAAM,MAAM,IAAI,CAAC;AAAA,UACtC;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,kBAAkB,UAA6B,OAAc,YAA6B;AACjG,SAAO,SAAS,KAAK,OAAK,EAAE,UAAU,SAAS,EAAE,QAAQ,WAAW,UAAU,CAAC;AACjF;AAKA,SAAS,eACP,YACA,YACA,YACA,UACM;AACN,aAAW,YAAY,qBAAqB;AAC1C,eAAW,WAAW,SAAS,MAAM;AACnC,YAAM,WAAWA,MAAK,YAAY,YAAY,OAAO;AACrD,UAAI,OAAO,QAAQ,KAAK,CAAC,kBAAkB,UAAU,SAAS,OAAO,UAAU,GAAG;AAChF,iBAAS,KAAK;AAAA,UACZ,OAAO,SAAS;AAAA,UAChB,SAAS,GAAG,UAAU,GAAG,OAAO;AAAA,UAChC,UAAU,GAAG,UAAU,GAAG,OAAO;AAAA,QACnC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;AAKA,SAAS,cAAc,YAAoB,UAAqC;AAC9E,QAAM,WAA8B,CAAC;AACrC,QAAM,SAAS,WAAW,GAAG,QAAQ,MAAM;AAG3C,iBAAe,YAAYA,MAAK,UAAU,KAAK,GAAG,GAAG,MAAM,QAAQ,QAAQ;AAC3E,iBAAe,YAAY,UAAU,QAAQ,QAAQ;AAErD,SAAO;AACT;AAMO,SAAS,mBAAmB,YAA0C;AAC3E,QAAM,WAA8B,CAAC;AAGrC,QAAM,WAAW,qBAAqB,UAAU;AAChD,QAAM,aAAa,SAAS,SAAS;AAErC,MAAI,YAAY;AAEd,eAAW,OAAO,UAAU;AAC1B,eAAS,KAAK,GAAG,cAAc,YAAY,GAAG,CAAC;AAAA,IACjD;AAAA,EACF;AAGA,WAAS,KAAK,GAAG,cAAc,YAAY,EAAE,CAAC;AAG9C,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,iBAAiB,SAAS,OAAO,OAAK;AAC1C,QAAI,KAAK,IAAI,EAAE,OAAO,EAAG,QAAO;AAChC,SAAK,IAAI,EAAE,OAAO;AAClB,WAAO;AAAA,EACT,CAAC;AAED,SAAO,EAAE,UAAU,gBAAgB,WAAW;AAChD;AAKA,SAAS,cAAc,IAA6B;AAClD,SAAO,kBAAkB,GAAG,KAAK,gBAAgB,GAAG,OAAO;AAC7D;AAKA,SAAS,qBAAqB,SAA0B;AACtD,SAAO,QAAQ,IAAI,OAAK,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI;AAC7C;AAKA,SAAS,aAAa,OAAc,gBAA2C;AAC7E,QAAM,gBAAgB,UAAU,KAAK;AACrC,MAAI,cAAc,WAAW,EAAG,QAAO;AAEvC,QAAM,UAAU,cAAc,OAAO,SAAO,eAAe,IAAI,GAAG,CAAC;AACnE,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,SAAO,qBAAqB,KAAK,eAAe,qBAAqB,OAAO,CAAC;AAC/E;AAKA,SAAS,kBAAkB,MAAoC;AAC7D,MAAI,KAAK,SAAS,WAAW,GAAG;AAC9B,WAAO;AAAA,EACT;AACA,QAAM,YAAY,KAAK,SAAS,IAAI,OAAK,EAAE,QAAQ,EAAE,KAAK,IAAI;AAC9D,QAAM,eAAe,KAAK,aAAa,gBAAgB;AACvD,SAAO,aAAa,SAAS,GAAG,YAAY;AAC9C;AAEO,SAAS,yBAAyB,MAAoC;AAC3E,QAAM,cAAc,KAAK,SAAS,SAAS;AAG3C,QAAM,kBAAkB,KAAK,SAAS,IAAI,QAAM,cAAc,EAAE,CAAC,EAAE,KAAK,KAAK;AAG7E,QAAM,iBAAiB,IAAI,IAAI,KAAK,SAAS,IAAI,OAAK,EAAE,KAAK,CAAC;AAC9D,QAAM,QAAQ,CAAC,GAAG,cAAc,EAC7B,IAAI,WAAS,aAAa,OAAO,cAAc,CAAC,EAChD,OAAO,CAAC,SAAyB,SAAS,IAAI;AACjD,QAAM,eAAe,MAAM,KAAK,KAAK;AAErC,QAAM,eAAe,kBAAkB,IAAI;AAE3C,SAAO;AAAA;AAAA;AAAA,KAGJ,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBf,eAAe;AAAA;AAAA;AAAA,YAIb,cACI;AAAA;AAAA;AAAA;AAAA,EAIN,YAAY;AAAA;AAAA,WAGN,EACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAMF;;;AC/PO,IAAM,2BAA2B;AAKjC,IAAM,cAAc;AAAA,EACzB,UAAU;AAAA,IACR,SAAS;AAAA,IACT,MAAM,CAAC,MAAM,8BAA8B;AAAA,EAC7C;AAAA,EACA,YAAY;AAAA,IACV,SAAS;AAAA,IACT,MAAM,CAAC,wBAAwB;AAAA,EACjC;AACF;;;ACRO,SAAS,YAAY,GAA4B;AACtD,SACE,OAAO,MAAM,YAAY,MAAM,QAAQ,WAAW,KAAK,MAAM,QAAS,EAAgB,KAAK;AAE/F;AAKO,SAAS,eAAe,GAAqB;AAClD,MAAI,CAAC,YAAY,CAAC,EAAG,QAAO;AAC5B,SAAO,EAAE,MAAM,KAAK,SAAO,OAAO,IAAI,YAAY,YAAY,IAAI,QAAQ,SAAS,WAAW,CAAC;AACjG;AAKO,SAAS,uBAAuB,OAA6B;AAClE,SAAO,MAAM,OAAO,OAAK,CAAC,eAAe,CAAC,CAAC;AAC7C;;;ACwCA,SAAS,gBAAgB,KAAsB;AAC7C,SACE,IAAI,WAAW,QAAQ,KACvB,IAAI,WAAW,UAAU,KACzB,IAAI,WAAW,mBAAmB,KAClC,IAAI,WAAW,cAAc,KAC7B,IAAI,WAAW,gBAAgB,KAC/B,IAAI,WAAW,0BAA0B,KACzC,QAAQ;AAEZ;AAMO,SAAS,wBAAkC;AAChD,SAAO,gBAAgB,SAAS,KAAK,OAAO,SAAO,gBAAgB,GAAG,CAAC;AACzE;AAKO,SAAS,6BAA6B,KAAuB;AAClE,QAAM,OAAO,gBAAgB,SAAS,YAAY,GAAG;AACrD,SAAO,OAAO,KAAK,OAAO,SAAO,gBAAgB,GAAG,CAAC,IAAI,CAAC;AAC5D;AAEO,IAAM,kBAAkC;AAAA,EAC7C,SAAS;AAAA;AAAA,EAGT,WAAW;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA;AAAA,EAGA,YAAY,CAAC,WAAW,kBAAkB,kBAAkB;AAAA;AAAA,EAG5D,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA;AAAA,EAGA,iBAAiB;AAAA,IACf;AAAA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA;AAAA,EAGA,YAAY;AAAA;AAAA,IAEV,yBAAyB,EAAE,UAAU,cAAc;AAAA,IACnD,qBAAqB,EAAE,SAAS,MAAM,QAAQ;AAAA,IAC9C,0CAA0C;AAAA,MACxC,WAAW,SAAO,yBAAyB,mBAAmB,IAAI,GAAG,CAAC;AAAA,IACxE;AAAA;AAAA,IAGA,4CAA4C,EAAE,UAAU,iCAAiC;AAAA,IACzF,sCAAsC,EAAE,UAAU,2BAA2B;AAAA,IAC7E,yCAAyC,EAAE,UAAU,8BAA8B;AAAA,IACnF,uCAAuC,EAAE,UAAU,4BAA4B;AAAA,IAC/E,uCAAuC,EAAE,UAAU,4BAA4B;AAAA,IAC/E,qCAAqC,EAAE,UAAU,0BAA0B;AAAA,IAC3E,mCAAmC,EAAE,UAAU,wBAAwB;AAAA;AAAA,IAGvE,2BAA2B,EAAE,UAAU,gBAAgB;AAAA,IACvD,gCAAgC,EAAE,UAAU,qBAAqB;AAAA;AAAA,IAGjE,0CAA0C,EAAE,UAAU,+BAA+B;AAAA,IACrF,qCAAqC,EAAE,UAAU,0BAA0B;AAAA,IAC3E,uCAAuC,EAAE,UAAU,4BAA4B;AAAA,IAC/E,2CAA2C,EAAE,UAAU,gCAAgC;AAAA,IACvF,+CAA+C;AAAA,MAC7C,UAAU;AAAA,IACZ;AAAA,IACA,wCAAwC,EAAE,UAAU,6BAA6B;AAAA,IACjF,2CAA2C,EAAE,UAAU,gCAAgC;AAAA,IACvF,iCAAiC,EAAE,UAAU,sBAAsB;AAAA,IACnE,sCAAsC,EAAE,UAAU,2BAA2B;AAAA,IAC7E,qCAAqC,EAAE,UAAU,0BAA0B;AAAA,IAC3E,8CAA8C,EAAE,UAAU,mCAAmC;AAAA;AAAA,IAG7F,gDAAgD;AAAA,MAC9C,UAAU;AAAA,IACZ;AAAA,IACA,8CAA8C;AAAA,MAC5C,UAAU;AAAA,IACZ;AAAA,IACA,6CAA6C;AAAA,MAC3C,UAAU;AAAA,IACZ;AAAA,IACA,mDAAmD;AAAA,MACjD,UAAU;AAAA,IACZ;AAAA,IACA,0CAA0C,EAAE,UAAU,mCAAmC;AAAA,IACzF,gDAAgD;AAAA,MAC9C,UAAU;AAAA,IACZ;AAAA,IACA,4CAA4C,EAAE,UAAU,qCAAqC;AAAA;AAAA,IAG7F,qCAAqC,EAAE,UAAU,0BAA0B;AAAA,IAC3E,uCAAuC,EAAE,UAAU,4BAA4B;AAAA;AAAA,IAG/E,8CAA8C,EAAE,UAAU,mCAAmC;AAAA,IAC7F,gDAAgD;AAAA,MAC9C,UAAU;AAAA,IACZ;AAAA,IACA,gCAAgC,EAAE,UAAU,qBAAqB;AAAA;AAAA,IAGjE,kDAAkD;AAAA,MAChD,UAAU;AAAA,IACZ;AAAA,IACA,8CAA8C;AAAA,MAC5C,UAAU;AAAA,IACZ;AAAA,IACA,kDAAkD;AAAA,MAChD,UAAU;AAAA,IACZ;AAAA,IACA,qDAAqD;AAAA,MACnD,UAAU;AAAA,IACZ;AAAA,IACA,gDAAgD;AAAA,MAC9C,UAAU;AAAA,IACZ;AAAA,IACA,oCAAoC,EAAE,UAAU,2BAA2B;AAAA,IAC3E,4BAA4B,EAAE,UAAU,mBAAmB;AAAA,IAC3D,sCAAsC,EAAE,UAAU,6BAA6B;AAAA;AAAA,IAG/E,qBAAqB,EAAE,SAAS,yBAAyB;AAAA;AAAA,IAGzD,mCAAmC,EAAE,UAAU,iCAAiC;AAAA,IAChF,4CAA4C;AAAA,MAC1C,UAAU;AAAA,IACZ;AAAA,IACA,wCAAwC;AAAA,MACtC,UAAU;AAAA,IACZ;AAAA,IACA,4CAA4C;AAAA,MAC1C,UAAU;AAAA,IACZ;AAAA,IACA,+CAA+C;AAAA,MAC7C,UAAU;AAAA,IACZ;AAAA,IACA,0CAA0C;AAAA,MACxC,UAAU;AAAA,IACZ;AAAA;AAAA,IAGA,4BAA4B,EAAE,UAAU,mBAAmB;AAAA,IAC3D,sCAAsC,EAAE,UAAU,6BAA6B;AAAA,IAC/E,oCAAoC,EAAE,UAAU,2BAA2B;AAAA;AAAA,IAG3E,6CAA6C,EAAE,UAAU,kCAAkC;AAAA,IAC3F,kCAAkC,EAAE,UAAU,uBAAuB;AAAA,EACvE;AAAA;AAAA,EAGA,cAAc;AAAA,IACZ,qBAAqB;AAAA,MACnB,WAAW,MAAM,gBAAgB,EAAE,YAAY,KAAK,CAAC;AAAA,IACvD;AAAA,IACA,eAAe,EAAE,WAAW,SAAO,kBAAkB,IAAI,WAAW,EAAE;AAAA,IACtE,4BAA4B,EAAE,UAAU,0BAA0B;AAAA,EACpE;AAAA;AAAA,EAGA,YAAY;AAAA,IACV,gBAAgB;AAAA,MACd,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,iBAAiB;AAAA,QACf,oBAAoB,CAAC,iBAAiB;AAAA,QACtC,OAAO,CAAC,iBAAiB;AAAA,MAC3B;AAAA,MACA,OAAO,CAAC,UAAU,QAAQ;AACxB,cAAM,UAAW,SAAS,WAAsC,CAAC;AACjE,cAAM,SAAS,EAAE,GAAG,SAAS;AAG7B,YAAI,CAAC,QAAQ,KAAM,SAAQ,OAAO;AAClC,YAAI,CAAC,QAAQ,SAAS,EAAG,SAAQ,SAAS,IAAI;AAC9C,YAAI,CAAC,QAAQ,OAAQ,SAAQ,SAAS;AACtC,YAAI,CAAC,QAAQ,cAAc,EAAG,SAAQ,cAAc,IAAI;AACxD,YAAI,CAAC,QAAQ,KAAM,SAAQ,OAAO;AAClC,YAAI,CAAC,QAAQ,QAAS,SAAQ,UAAU;AAGxC,YAAI,IAAI,YAAY,sBAAsB,CAAC,QAAQ,SAAS;AAC1D,kBAAQ,UAAU;AAAA,QACpB;AAGA,YAAI,IAAI,YAAY,SAAS,CAAC,QAAQ,SAAS,GAAG;AAChD,kBAAQ,SAAS,IAAI;AAAA,QACvB;AAEA,eAAO,UAAU;AAGjB,YAAI,CAAC,SAAS,aAAa,GAAG;AAC5B,iBAAO,aAAa,IAAI,oBAAoB,IAAI,WAAW;AAAA,QAC7D;AAEA,eAAO;AAAA,MACT;AAAA,MACA,SAAS,cAAY;AACnB,cAAM,SAAS,EAAE,GAAG,SAAS;AAC7B,cAAM,UAAU,EAAE,GAAI,SAAS,QAAmC;AAGlE,eAAO,QAAQ,SAAS;AACxB,eAAO,QAAQ,SAAS;AACxB,eAAO,QAAQ,cAAc;AAC7B,eAAO,QAAQ;AACf,eAAO,QAAQ;AACf,eAAO,QAAQ;AAEf,YAAI,OAAO,KAAK,OAAO,EAAE,SAAS,GAAG;AACnC,iBAAO,UAAU;AAAA,QACnB,OAAO;AACL,iBAAO,OAAO;AAAA,QAChB;AAEA,eAAO,OAAO,aAAa;AAE3B,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,yBAAyB;AAAA,MACvB,MAAM,CAAC,OAAO;AAAA,MACd,OAAO,cAAY;AAEjB,cAAM,gBAAiB,SAAS,SAAuC,CAAC;AACxE,cAAM,cAAyC,EAAE,GAAG,cAAc;AAElE,mBAAW,CAAC,OAAO,QAAQ,KAAK,OAAO,QAAQ,cAAc,GAAG;AAC9D,gBAAM,aAAc,YAAY,KAAK,KAAmB,CAAC;AACzD,gBAAM,mBAAmB,uBAAuB,UAAU;AAC1D,sBAAY,KAAK,IAAI,CAAC,GAAG,kBAAkB,GAAG,QAAQ;AAAA,QACxD;AAEA,eAAO,EAAE,GAAG,UAAU,OAAO,YAAY;AAAA,MAC3C;AAAA,MACA,SAAS,cAAY;AAEnB,cAAM,gBAAiB,SAAS,SAAuC,CAAC;AACxE,cAAM,eAA0C,CAAC;AAEjD,mBAAW,CAAC,OAAO,UAAU,KAAK,OAAO,QAAQ,aAAa,GAAG;AAC/D,gBAAM,mBAAmB,uBAAuB,UAAuB;AACvE,cAAI,iBAAiB,SAAS,GAAG;AAC/B,yBAAa,KAAK,IAAI;AAAA,UACxB;AAAA,QACF;AAEA,cAAM,SAAS,EAAE,GAAG,SAAS;AAC7B,YAAI,OAAO,KAAK,YAAY,EAAE,SAAS,GAAG;AACxC,iBAAO,QAAQ;AAAA,QACjB,OAAO;AACL,iBAAO,OAAO;AAAA,QAChB;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,aAAa;AAAA,MACX,MAAM,CAAC,uBAAuB,uBAAuB;AAAA,MACrD,mBAAmB;AAAA,MACnB,OAAO,cAAY;AACjB,cAAM,aAAc,SAAS,cAA0C,CAAC;AACxE,eAAO;AAAA,UACL,GAAG;AAAA,UACH,YAAY;AAAA,YACV,GAAG;AAAA,YACH,UAAU,YAAY;AAAA,YACtB,YAAY,YAAY;AAAA,UAC1B;AAAA,QACF;AAAA,MACF;AAAA,MACA,SAAS,cAAY;AACnB,cAAM,SAAS,EAAE,GAAG,SAAS;AAC7B,cAAM,aAAa,EAAE,GAAI,SAAS,WAAuC;AAEzE,eAAO,WAAW;AAClB,eAAO,WAAW;AAElB,YAAI,OAAO,KAAK,UAAU,EAAE,SAAS,GAAG;AACtC,iBAAO,aAAa;AAAA,QACtB,OAAO;AACL,iBAAO,OAAO;AAAA,QAChB;AAEA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,oBAAoB;AAAA,MAClB,MAAM,CAAC,uBAAuB,uBAAuB;AAAA,MACrD,mBAAmB;AAAA,MACnB,OAAO,cAAY;AACjB,cAAM,aAAc,SAAS,cAA0C,CAAC;AACxE,eAAO;AAAA,UACL,GAAG;AAAA,UACH,YAAY;AAAA,YACV,GAAG;AAAA,YACH,UAAU,YAAY;AAAA,YACtB,YAAY,YAAY;AAAA,UAC1B;AAAA,QACF;AAAA,MACF;AAAA,MACA,SAAS,cAAY;AACnB,cAAM,SAAS,EAAE,GAAG,SAAS;AAC7B,cAAM,aAAa,EAAE,GAAI,SAAS,WAAuC;AAEzE,eAAO,WAAW;AAClB,eAAO,WAAW;AAElB,YAAI,OAAO,KAAK,UAAU,EAAE,SAAS,GAAG;AACtC,iBAAO,aAAa;AAAA,QACtB,OAAO;AACL,iBAAO,OAAO;AAAA,QAChB;AAEA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,sBAAsB;AAAA,MACpB,MAAM,CAAC,WAAW,uBAAuB,YAAY;AAAA,MACrD,mBAAmB;AAAA,MACnB,OAAO,cAAY;AACjB,cAAM,QAAS,SAAS,SAAuC,CAAC;AAChE,eAAO;AAAA,UACL,GAAG;AAAA,UACH,SAAS;AAAA;AAAA,UACT,OAAO;AAAA,YACL,GAAG;AAAA,YACH,GAAG;AAAA,UACL;AAAA,QACF;AAAA,MACF;AAAA,MACA,SAAS,cAAY;AACnB,cAAM,SAAS,EAAE,GAAG,SAAS;AAC7B,cAAM,QAAQ,EAAE,GAAI,SAAS,MAAoC;AAEjE,eAAO,MAAM;AACb,eAAO,MAAM;AAEb,YAAI,OAAO,KAAK,KAAK,EAAE,SAAS,GAAG;AACjC,iBAAO,QAAQ;AAAA,QACjB,OAAO;AACL,iBAAO,OAAO;AACd,iBAAO,OAAO;AAAA,QAChB;AAEA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,aAAa;AAAA,IACX,aAAa;AAAA,MACX,WAAW;AAAA,MACX,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,iBAAiB;AAAA,IACnB;AAAA,IACA,aAAa;AAAA,MACX,WAAW;AAAA,MACX,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,iBAAiB;AAAA;AAAA,IACnB;AAAA,EACF;AAAA;AAAA,EAGA,UAAU;AAAA,IACR,MAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,aAAa;AAAA,MACX,YAAY,CAAC,mBAAmB;AAAA,MAChC,OAAO,CAAC,uBAAuB,6BAA6B,wBAAwB;AAAA,MACpF,QAAQ,CAAC,0BAA0B;AAAA,MACnC,OAAO,CAAC,uBAAuB,uBAAuB;AAAA,MACtD,KAAK,CAAC,mBAAmB;AAAA,MACzB,QAAQ,CAAC,wBAAwB,wBAAwB;AAAA,MACzD,UAAU,CAAC,iCAAiC;AAAA,MAC5C,QAAQ,CAAC,uBAAuB;AAAA,MAChC,UAAU,CAAC,6BAA6B;AAAA,MACxC,oBAAoB,CAAC,SAAS;AAAA,MAC9B,OAAO,CAAC,cAAc,oBAAoB;AAAA,IAC5C;AAAA,EACF;AACF;","names":["readdirSync","join","join","readdirSync","join","readdirSync"]}
@@ -1,9 +0,0 @@
1
- import {
2
- sync
3
- } from "./chunk-VZPFU4YI.js";
4
- import "./chunk-62YXVEKM.js";
5
- import "./chunk-ORQHKDT2.js";
6
- export {
7
- sync
8
- };
9
- //# sourceMappingURL=sync-A7VWZKQD.js.map