safeword 0.6.8 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{check-OYYSYHFP.js → check-QGZJ62PY.js} +73 -57
- package/dist/check-QGZJ62PY.js.map +1 -0
- package/dist/{chunk-ZS3Z3Q37.js → chunk-QPO3C3FP.js} +285 -65
- package/dist/chunk-QPO3C3FP.js.map +1 -0
- package/dist/{chunk-LNSEDZIW.js → chunk-YMLVQC4V.js} +159 -152
- package/dist/chunk-YMLVQC4V.js.map +1 -0
- package/dist/cli.js +6 -6
- package/dist/{diff-325TIZ63.js → diff-654SSCFQ.js} +51 -53
- package/dist/diff-654SSCFQ.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/{reset-ZGJIKMUW.js → reset-IU6AIT7C.js} +3 -3
- package/dist/{setup-GAMXTFM2.js → setup-5IQ4KV2M.js} +17 -20
- package/dist/setup-5IQ4KV2M.js.map +1 -0
- package/dist/{sync-BFMXZEHM.js → sync-YBQEISFI.js} +8 -26
- package/dist/sync-YBQEISFI.js.map +1 -0
- package/dist/{upgrade-X4GREJXN.js → upgrade-RRTWEQIP.js} +3 -3
- package/package.json +1 -1
- package/templates/SAFEWORD.md +141 -73
- package/templates/commands/architecture.md +1 -1
- package/templates/commands/lint.md +1 -0
- package/templates/commands/quality-review.md +1 -1
- package/templates/cursor/rules/safeword-core.mdc +5 -0
- package/templates/doc-templates/architecture-template.md +1 -1
- package/templates/doc-templates/task-spec-template.md +151 -0
- package/templates/doc-templates/ticket-template.md +2 -4
- package/templates/guides/architecture-guide.md +2 -2
- package/templates/guides/code-philosophy.md +1 -1
- package/templates/guides/context-files-guide.md +3 -3
- package/templates/guides/design-doc-guide.md +2 -2
- package/templates/guides/development-workflow.md +2 -2
- package/templates/guides/learning-extraction.md +9 -9
- package/templates/guides/tdd-best-practices.md +39 -38
- package/templates/guides/test-definitions-guide.md +15 -14
- package/templates/hooks/cursor/after-file-edit.sh +66 -0
- package/templates/hooks/cursor/stop.sh +50 -0
- package/templates/hooks/post-tool-lint.sh +19 -5
- package/templates/hooks/prompt-questions.sh +1 -1
- package/templates/hooks/prompt-timestamp.sh +8 -1
- package/templates/hooks/session-lint-check.sh +1 -1
- package/templates/hooks/session-verify-agents.sh +1 -1
- package/templates/hooks/session-version.sh +1 -1
- package/templates/hooks/stop-quality.sh +2 -2
- package/templates/markdownlint-cli2.jsonc +18 -19
- package/templates/scripts/bisect-test-pollution.sh +87 -0
- package/templates/scripts/bisect-zombie-processes.sh +129 -0
- package/templates/scripts/lint-md.sh +16 -0
- package/templates/skills/safeword-quality-reviewer/SKILL.md +3 -3
- package/templates/skills/safeword-systematic-debugger/SKILL.md +246 -0
- package/templates/skills/safeword-tdd-enforcer/SKILL.md +221 -0
- package/dist/check-OYYSYHFP.js.map +0 -1
- package/dist/chunk-LNSEDZIW.js.map +0 -1
- package/dist/chunk-ZS3Z3Q37.js.map +0 -1
- package/dist/diff-325TIZ63.js.map +0 -1
- package/dist/setup-GAMXTFM2.js.map +0 -1
- package/dist/sync-BFMXZEHM.js.map +0 -1
- /package/dist/{reset-ZGJIKMUW.js.map → reset-IU6AIT7C.js.map} +0 -0
- /package/dist/{upgrade-X4GREJXN.js.map → upgrade-RRTWEQIP.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/output.ts","../src/utils/git.ts","../src/utils/context.ts","../src/reconcile.ts"],"sourcesContent":["/**\n * Console output utilities for consistent CLI messaging\n */\n\n/**\n * Print info message\n */\nexport function info(message: string): void {\n console.log(message);\n}\n\n/**\n * Print success message\n */\nexport function success(message: string): void {\n console.log(`✓ ${message}`);\n}\n\n/**\n * Print warning message\n */\nexport function warn(message: string): void {\n console.warn(`⚠ ${message}`);\n}\n\n/**\n * Print error message to stderr\n */\nexport function error(message: string): void {\n console.error(`✗ ${message}`);\n}\n\n/**\n * Print a blank line\n */\nexport function blank(): void {\n console.log('');\n}\n\n/**\n * Print a section header\n */\nexport function header(title: string): void {\n console.log(`\\n${title}`);\n console.log('─'.repeat(title.length));\n}\n\n/**\n * Print a list item\n */\nexport function listItem(item: string, indent = 2): void {\n console.log(`${' '.repeat(indent)}• ${item}`);\n}\n\n/**\n * Print key-value pair\n */\nexport function keyValue(key: string, value: string): void {\n console.log(` ${key}: ${value}`);\n}\n","/**\n * Git utilities for CLI operations\n */\n\nimport { join } from 'node:path';\nimport { exists } from './fs.js';\n\n/**\n * Check if directory is a git repository\n */\nexport function isGitRepo(cwd: string): boolean {\n return exists(join(cwd, '.git'));\n}\n","/**\n * Project Context Utilities\n *\n * Shared helpers for creating ProjectContext objects used by reconcile().\n */\n\nimport { join } from 'node:path';\nimport { readJson } from './fs.js';\nimport { isGitRepo } from './git.js';\nimport { detectProjectType, type PackageJson } from './project-detector.js';\nimport type { ProjectContext } from '../schema.js';\n\n/**\n * Create a ProjectContext from the current working directory.\n *\n * Reads package.json and detects project type for use with reconcile().\n */\nexport function createProjectContext(cwd: string): ProjectContext {\n const packageJson = readJson<PackageJson>(join(cwd, 'package.json'));\n\n return {\n cwd,\n projectType: detectProjectType(packageJson ?? {}, cwd),\n devDeps: packageJson?.devDependencies ?? {},\n isGitRepo: isGitRepo(cwd),\n };\n}\n","/**\n * Reconciliation Engine\n *\n * Computes and executes plans based on SAFEWORD_SCHEMA and project state.\n * This is the single source of truth for all file/dir/config operations.\n */\n\nimport { join } from 'node:path';\nimport {\n exists,\n ensureDir,\n writeFile,\n readFile,\n readFileSafe,\n readJson,\n writeJson,\n remove,\n removeIfEmpty,\n makeScriptsExecutable,\n getTemplatesDir,\n} from './utils/fs.js';\nimport type {\n SafewordSchema,\n ProjectContext,\n FileDefinition,\n JsonMergeDefinition,\n TextPatchDefinition,\n} from './schema.js';\nimport type { ProjectType } from './utils/project-detector.js';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst HUSKY_DIR = '.husky';\n\n/** Check if path should be skipped in non-git repos (husky files) */\nfunction shouldSkipForNonGit(path: string, isGitRepo: boolean): boolean {\n return path.startsWith(HUSKY_DIR) && !isGitRepo;\n}\n\n/** Plan mkdir actions for directories that don't exist */\nfunction planMissingDirs(\n dirs: string[],\n cwd: string,\n isGitRepo: boolean,\n): { actions: Action[]; created: string[] } {\n const actions: Action[] = [];\n const created: string[] = [];\n for (const dir of dirs) {\n if (shouldSkipForNonGit(dir, isGitRepo)) continue;\n if (!exists(join(cwd, dir))) {\n actions.push({ type: 'mkdir', path: dir });\n created.push(dir);\n }\n }\n return { actions, created };\n}\n\n/** Plan text-patch actions for files missing the marker */\nfunction planTextPatches(patches: Record<string, TextPatchDefinition>, cwd: string): Action[] {\n const actions: Action[] = [];\n for (const [filePath, def] of Object.entries(patches)) {\n const content = readFileSafe(join(cwd, filePath)) ?? '';\n if (!content.includes(def.marker)) {\n actions.push({ type: 'text-patch', path: filePath, definition: def });\n }\n }\n return actions;\n}\n\n/** Plan rmdir actions for directories that exist */\nfunction planExistingDirsRemoval(\n dirs: string[],\n cwd: string,\n): { actions: Action[]; removed: string[] } {\n const actions: Action[] = [];\n const removed: string[] = [];\n for (const dir of dirs) {\n if (exists(join(cwd, dir))) {\n actions.push({ type: 'rmdir', path: dir });\n removed.push(dir);\n }\n }\n return { actions, removed };\n}\n\n/** Plan rm actions for files that exist */\nfunction planExistingFilesRemoval(\n files: string[],\n cwd: string,\n): { actions: Action[]; removed: string[] } {\n const actions: Action[] = [];\n const removed: string[] = [];\n for (const filePath of files) {\n if (exists(join(cwd, filePath))) {\n actions.push({ type: 'rm', path: filePath });\n removed.push(filePath);\n }\n }\n return { actions, removed };\n}\n\n/** Check if a .claude path needs parent dir cleanup */\nfunction getClaudeParentDirForCleanup(filePath: string): string | null {\n if (!filePath.startsWith('.claude/')) return null;\n const parentDir = filePath.slice(0, Math.max(0, filePath.lastIndexOf('/')));\n if (\n !parentDir ||\n parentDir === '.claude' ||\n parentDir === '.claude/skills' ||\n parentDir === '.claude/commands'\n ) {\n return null;\n }\n return parentDir;\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type ReconcileMode = 'install' | 'upgrade' | 'uninstall' | 'uninstall-full';\n\nexport type Action =\n | { type: 'mkdir'; path: string }\n | { type: 'rmdir'; path: string }\n | { type: 'write'; path: string; content: string }\n | { type: 'rm'; path: string }\n | { type: 'chmod'; paths: string[] }\n | { type: 'json-merge'; path: string; definition: JsonMergeDefinition }\n | { type: 'json-unmerge'; path: string; definition: JsonMergeDefinition }\n | { type: 'text-patch'; path: string; definition: TextPatchDefinition }\n | { type: 'text-unpatch'; path: string; definition: TextPatchDefinition };\n\nexport interface ReconcileResult {\n actions: Action[];\n applied: boolean;\n created: string[];\n updated: string[];\n removed: string[];\n packagesToInstall: string[];\n packagesToRemove: string[];\n}\n\nexport interface ReconcileOptions {\n dryRun?: boolean;\n}\n\n// ============================================================================\n// Main reconcile function\n// ============================================================================\n\nexport async function reconcile(\n schema: SafewordSchema,\n mode: ReconcileMode,\n ctx: ProjectContext,\n options?: ReconcileOptions,\n): Promise<ReconcileResult> {\n const dryRun = options?.dryRun ?? false;\n\n const plan = computePlan(schema, mode, ctx);\n\n if (dryRun) {\n return {\n actions: plan.actions,\n applied: false,\n created: plan.wouldCreate,\n updated: plan.wouldUpdate,\n removed: plan.wouldRemove,\n packagesToInstall: plan.packagesToInstall,\n packagesToRemove: plan.packagesToRemove,\n };\n }\n\n const result = executePlan(plan, ctx);\n\n return {\n actions: plan.actions,\n applied: true,\n created: result.created,\n updated: result.updated,\n removed: result.removed,\n packagesToInstall: plan.packagesToInstall,\n packagesToRemove: plan.packagesToRemove,\n };\n}\n\n// ============================================================================\n// Plan computation\n// ============================================================================\n\ninterface ReconcilePlan {\n actions: Action[];\n wouldCreate: string[];\n wouldUpdate: string[];\n wouldRemove: string[];\n packagesToInstall: string[];\n packagesToRemove: string[];\n}\n\nfunction computePlan(\n schema: SafewordSchema,\n mode: ReconcileMode,\n ctx: ProjectContext,\n): ReconcilePlan {\n switch (mode) {\n case 'install': {\n return computeInstallPlan(schema, ctx);\n }\n case 'upgrade': {\n return computeUpgradePlan(schema, ctx);\n }\n case 'uninstall': {\n return computeUninstallPlan(schema, ctx, false);\n }\n case 'uninstall-full': {\n return computeUninstallPlan(schema, ctx, true);\n }\n }\n}\n\nfunction computeInstallPlan(schema: SafewordSchema, ctx: ProjectContext): ReconcilePlan {\n const actions: Action[] = [];\n const wouldCreate: string[] = [];\n\n // 1. Create all directories (skip .husky if not a git repo)\n const allDirs = [...schema.ownedDirs, ...schema.sharedDirs, ...schema.preservedDirs];\n const missingDirs = planMissingDirs(allDirs, ctx.cwd, ctx.isGitRepo);\n actions.push(...missingDirs.actions);\n wouldCreate.push(...missingDirs.created);\n\n // 2. Write all owned files (skip .husky files if not a git repo)\n for (const [filePath, def] of Object.entries(schema.ownedFiles)) {\n if (shouldSkipForNonGit(filePath, ctx.isGitRepo)) continue;\n\n const content = resolveFileContent(def, ctx);\n actions.push({ type: 'write', path: filePath, content });\n wouldCreate.push(filePath);\n }\n\n // 3. Write managed files (only if missing)\n for (const [filePath, def] of Object.entries(schema.managedFiles)) {\n const fullPath = join(ctx.cwd, filePath);\n if (!exists(fullPath)) {\n const content = resolveFileContent(def, ctx);\n actions.push({ type: 'write', path: filePath, content });\n wouldCreate.push(filePath);\n }\n }\n\n // 4. chmod hook/lib directories (only .husky if git repo)\n const chmodPaths = ['.safeword/hooks', '.safeword/hooks/cursor', '.safeword/lib'];\n if (ctx.isGitRepo) chmodPaths.push(HUSKY_DIR);\n actions.push({ type: 'chmod', paths: chmodPaths });\n\n // 5. JSON merges\n for (const [filePath, def] of Object.entries(schema.jsonMerges)) {\n actions.push({ type: 'json-merge', path: filePath, definition: def });\n }\n\n // 6. Text patches\n for (const [filePath, def] of Object.entries(schema.textPatches)) {\n actions.push({ type: 'text-patch', path: filePath, definition: def });\n if (def.createIfMissing && !exists(join(ctx.cwd, filePath))) {\n wouldCreate.push(filePath);\n }\n }\n\n // 7. Compute packages to install (husky/lint-staged skipped if no git repo)\n const packagesToInstall = computePackagesToInstall(\n schema,\n ctx.projectType,\n ctx.devDeps,\n ctx.isGitRepo,\n );\n\n return {\n actions,\n wouldCreate,\n wouldUpdate: [],\n wouldRemove: [],\n packagesToInstall,\n packagesToRemove: [],\n };\n}\n\nfunction computeUpgradePlan(schema: SafewordSchema, ctx: ProjectContext): ReconcilePlan {\n const actions: Action[] = [];\n const wouldCreate: string[] = [];\n const wouldUpdate: string[] = [];\n\n // 1. Ensure directories exist (skip .husky if not a git repo)\n const allDirs = [...schema.ownedDirs, ...schema.sharedDirs, ...schema.preservedDirs];\n const missingDirs = planMissingDirs(allDirs, ctx.cwd, ctx.isGitRepo);\n actions.push(...missingDirs.actions);\n wouldCreate.push(...missingDirs.created);\n\n // 2. Update owned files if content changed (skip .husky files if not a git repo)\n for (const [filePath, def] of Object.entries(schema.ownedFiles)) {\n if (shouldSkipForNonGit(filePath, ctx.isGitRepo)) continue;\n\n const fullPath = join(ctx.cwd, filePath);\n const newContent = resolveFileContent(def, ctx);\n\n if (!fileNeedsUpdate(fullPath, newContent)) continue;\n\n actions.push({ type: 'write', path: filePath, content: newContent });\n if (exists(fullPath)) {\n wouldUpdate.push(filePath);\n } else {\n wouldCreate.push(filePath);\n }\n }\n\n // 3. Update managed files only if content matches current template\n for (const [filePath, def] of Object.entries(schema.managedFiles)) {\n const fullPath = join(ctx.cwd, filePath);\n const newContent = resolveFileContent(def, ctx);\n\n if (!exists(fullPath)) {\n // Missing - create it\n actions.push({ type: 'write', path: filePath, content: newContent });\n wouldCreate.push(filePath);\n }\n // If file exists, don't update during upgrade - user may have customized it\n }\n\n // 4. chmod (only .husky if git repo)\n const chmodPathsUpgrade = ['.safeword/hooks', '.safeword/hooks/cursor', '.safeword/lib'];\n if (ctx.isGitRepo) chmodPathsUpgrade.push(HUSKY_DIR);\n actions.push({ type: 'chmod', paths: chmodPathsUpgrade });\n\n // 5. JSON merges (always apply to ensure keys are present)\n for (const [filePath, def] of Object.entries(schema.jsonMerges)) {\n actions.push({ type: 'json-merge', path: filePath, definition: def });\n }\n\n // 6. Text patches (only if marker missing)\n actions.push(...planTextPatches(schema.textPatches, ctx.cwd));\n\n // 7. Compute packages to install (husky/lint-staged skipped if no git repo)\n const packagesToInstall = computePackagesToInstall(\n schema,\n ctx.projectType,\n ctx.devDeps,\n ctx.isGitRepo,\n );\n\n return {\n actions,\n wouldCreate,\n wouldUpdate,\n wouldRemove: [],\n packagesToInstall,\n packagesToRemove: [],\n };\n}\n\nfunction computeUninstallPlan(\n schema: SafewordSchema,\n ctx: ProjectContext,\n full: boolean,\n): ReconcilePlan {\n const actions: Action[] = [];\n const wouldRemove: string[] = [];\n\n // 1. Remove all owned files and track parent dirs for cleanup\n const ownedFiles = planExistingFilesRemoval(Object.keys(schema.ownedFiles), ctx.cwd);\n actions.push(...ownedFiles.actions);\n wouldRemove.push(...ownedFiles.removed);\n\n // Collect parent dirs that need cleanup (for .claude/* skill dirs)\n const dirsToCleanup = new Set<string>();\n for (const filePath of ownedFiles.removed) {\n const parentDir = getClaudeParentDirForCleanup(filePath);\n if (parentDir) dirsToCleanup.add(parentDir);\n }\n const cleanupDirs = planExistingDirsRemoval([...dirsToCleanup], ctx.cwd);\n actions.push(...cleanupDirs.actions);\n wouldRemove.push(...cleanupDirs.removed);\n\n // 2. JSON unmerges\n for (const [filePath, def] of Object.entries(schema.jsonMerges)) {\n actions.push({ type: 'json-unmerge', path: filePath, definition: def });\n }\n\n // 3. Text unpatches\n for (const [filePath, def] of Object.entries(schema.textPatches)) {\n const fullPath = join(ctx.cwd, filePath);\n if (exists(fullPath)) {\n const content = readFileSafe(fullPath) ?? '';\n if (content.includes(def.marker)) {\n actions.push({ type: 'text-unpatch', path: filePath, definition: def });\n }\n }\n }\n\n // 4. Remove preserved directories first (reverse order, only if empty)\n const preserved = planExistingDirsRemoval(schema.preservedDirs.toReversed(), ctx.cwd);\n actions.push(...preserved.actions);\n wouldRemove.push(...preserved.removed);\n\n // 5. Remove owned directories (reverse order ensures children before parents)\n const owned = planExistingDirsRemoval(schema.ownedDirs.toReversed(), ctx.cwd);\n actions.push(...owned.actions);\n wouldRemove.push(...owned.removed);\n\n // 6. Full uninstall: remove managed files\n if (full) {\n const managed = planExistingFilesRemoval(Object.keys(schema.managedFiles), ctx.cwd);\n actions.push(...managed.actions);\n wouldRemove.push(...managed.removed);\n }\n\n // 7. Compute packages to remove (full only)\n const packagesToRemove = full\n ? computePackagesToRemove(schema, ctx.projectType, ctx.devDeps)\n : [];\n\n return {\n actions,\n wouldCreate: [],\n wouldUpdate: [],\n wouldRemove,\n packagesToInstall: [],\n packagesToRemove,\n };\n}\n\n// ============================================================================\n// Plan execution\n// ============================================================================\n\ninterface ExecutionResult {\n created: string[];\n updated: string[];\n removed: string[];\n}\n\nfunction executePlan(plan: ReconcilePlan, ctx: ProjectContext): ExecutionResult {\n const created: string[] = [];\n const updated: string[] = [];\n const removed: string[] = [];\n const result = { created, updated, removed };\n\n for (const action of plan.actions) {\n executeAction(action, ctx, result);\n }\n\n return result;\n}\n\nfunction executeAction(action: Action, ctx: ProjectContext, result: ExecutionResult): void {\n switch (action.type) {\n case 'mkdir': {\n ensureDir(join(ctx.cwd, action.path));\n result.created.push(action.path);\n break;\n }\n\n case 'rmdir': {\n // Use removeIfEmpty to preserve directories with user content\n if (removeIfEmpty(join(ctx.cwd, action.path))) {\n result.removed.push(action.path);\n }\n break;\n }\n\n case 'write': {\n executeWrite(ctx.cwd, action.path, action.content, result);\n break;\n }\n\n case 'rm': {\n remove(join(ctx.cwd, action.path));\n result.removed.push(action.path);\n break;\n }\n\n case 'chmod': {\n for (const path of action.paths) {\n const fullPath = join(ctx.cwd, path);\n if (exists(fullPath)) makeScriptsExecutable(fullPath);\n }\n break;\n }\n\n case 'json-merge': {\n executeJsonMerge(ctx.cwd, action.path, action.definition, ctx);\n break;\n }\n\n case 'json-unmerge': {\n executeJsonUnmerge(ctx.cwd, action.path, action.definition);\n break;\n }\n\n case 'text-patch': {\n executeTextPatch(ctx.cwd, action.path, action.definition);\n break;\n }\n\n case 'text-unpatch': {\n executeTextUnpatch(ctx.cwd, action.path, action.definition);\n break;\n }\n }\n}\n\nfunction executeWrite(cwd: string, path: string, content: string, result: ExecutionResult): void {\n const fullPath = join(cwd, path);\n const existed = exists(fullPath);\n writeFile(fullPath, content);\n (existed ? result.updated : result.created).push(path);\n}\n\n// ============================================================================\n// Helper functions\n// ============================================================================\n\nfunction resolveFileContent(def: FileDefinition, ctx: ProjectContext): string {\n if (def.template) {\n const templatesDir = getTemplatesDir();\n return readFile(join(templatesDir, def.template));\n }\n\n if (def.content) {\n return typeof def.content === 'function' ? def.content() : def.content;\n }\n\n if (def.generator) {\n return def.generator(ctx);\n }\n\n throw new Error('FileDefinition must have template, content, or generator');\n}\n\nfunction fileNeedsUpdate(installedPath: string, newContent: string): boolean {\n if (!exists(installedPath)) return true;\n const currentContent = readFileSafe(installedPath);\n return currentContent?.trim() !== newContent.trim();\n}\n\n// Packages that require git repo\nconst GIT_ONLY_PACKAGES = new Set(['husky', 'lint-staged']);\n\nexport function computePackagesToInstall(\n schema: SafewordSchema,\n projectType: ProjectType,\n installedDevDeps: Record<string, string>,\n isGitRepo = true,\n): string[] {\n let needed = [...schema.packages.base];\n\n // Filter out git-only packages when not in a git repo\n if (!isGitRepo) {\n needed = needed.filter(pkg => !GIT_ONLY_PACKAGES.has(pkg));\n }\n\n for (const [key, deps] of Object.entries(schema.packages.conditional)) {\n if (projectType[key as keyof ProjectType]) {\n needed.push(...deps);\n }\n }\n\n return needed.filter(pkg => !(pkg in installedDevDeps));\n}\n\nfunction computePackagesToRemove(\n schema: SafewordSchema,\n projectType: ProjectType,\n installedDevDeps: Record<string, string>,\n): string[] {\n const safewordPackages = [...schema.packages.base];\n\n for (const [key, deps] of Object.entries(schema.packages.conditional)) {\n if (projectType[key as keyof ProjectType]) {\n safewordPackages.push(...deps);\n }\n }\n\n // Only remove packages that are actually installed\n return safewordPackages.filter(pkg => pkg in installedDevDeps);\n}\n\nfunction executeJsonMerge(\n cwd: string,\n path: string,\n def: JsonMergeDefinition,\n ctx: ProjectContext,\n): void {\n const fullPath = join(cwd, path);\n const existing = readJson<Record<string, unknown>>(fullPath) ?? {};\n const merged = def.merge(existing, ctx);\n writeJson(fullPath, merged);\n}\n\nfunction executeJsonUnmerge(cwd: string, path: string, def: JsonMergeDefinition): void {\n const fullPath = join(cwd, path);\n if (!exists(fullPath)) return;\n\n const existing = readJson<Record<string, unknown>>(fullPath);\n if (!existing) return;\n\n const unmerged = def.unmerge(existing);\n\n // Check if file should be removed\n if (def.removeFileIfEmpty) {\n const remainingKeys = Object.keys(unmerged).filter(\n k => unmerged[k] !== undefined && unmerged[k] !== null,\n );\n if (remainingKeys.length === 0) {\n remove(fullPath);\n return;\n }\n }\n\n writeJson(fullPath, unmerged);\n}\n\nfunction executeTextPatch(cwd: string, path: string, def: TextPatchDefinition): void {\n const fullPath = join(cwd, path);\n let content = readFileSafe(fullPath) ?? '';\n\n // Check if already patched\n if (content.includes(def.marker)) return;\n\n // Apply patch\n content = def.operation === 'prepend' ? def.content + content : content + def.content;\n\n writeFile(fullPath, content);\n}\n\nfunction executeTextUnpatch(cwd: string, path: string, def: TextPatchDefinition): void {\n const fullPath = join(cwd, path);\n const content = readFileSafe(fullPath);\n if (!content) return;\n\n // Remove the patched content\n // First try to remove the full content block\n let unpatched = content.replace(def.content, '');\n\n // If full content wasn't found but marker exists, remove lines containing the marker\n if (unpatched === content && content.includes(def.marker)) {\n // Remove lines containing the marker\n const lines = content.split('\\n');\n const filtered = lines.filter(line => !line.includes(def.marker));\n unpatched = filtered.join('\\n').replace(/^\\n+/, ''); // Remove leading empty lines\n }\n\n writeFile(fullPath, unpatched);\n}\n"],"mappings":"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","names":["join","join","join","isGitRepo","join"]}
|
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-
|
|
11
|
+
const { setup } = await import("./setup-5IQ4KV2M.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-
|
|
15
|
+
const { check } = await import("./check-QGZJ62PY.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-
|
|
19
|
+
const { upgrade } = await import("./upgrade-RRTWEQIP.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-
|
|
23
|
+
const { diff } = await import("./diff-654SSCFQ.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-
|
|
27
|
+
const { reset } = await import("./reset-IU6AIT7C.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-
|
|
31
|
+
const { sync } = await import("./sync-YBQEISFI.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-
|
|
9
|
+
} from "./chunk-YMLVQC4V.js";
|
|
10
10
|
import {
|
|
11
11
|
SAFEWORD_SCHEMA,
|
|
12
12
|
exists,
|
|
13
13
|
readFileSafe
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-QPO3C3FP.js";
|
|
15
15
|
import {
|
|
16
16
|
VERSION
|
|
17
17
|
} from "./chunk-ORQHKDT2.js";
|
|
@@ -21,9 +21,7 @@ import { join } from "path";
|
|
|
21
21
|
function createUnifiedDiff(oldContent, newContent, filename) {
|
|
22
22
|
const oldLines = oldContent.split("\n");
|
|
23
23
|
const newLines = newContent.split("\n");
|
|
24
|
-
const lines = [];
|
|
25
|
-
lines.push(`--- a/${filename}`);
|
|
26
|
-
lines.push(`+++ b/${filename}`);
|
|
24
|
+
const lines = [`--- a/${filename}`, `+++ b/${filename}`];
|
|
27
25
|
let hasChanges = false;
|
|
28
26
|
const maxLines = Math.max(oldLines.length, newLines.length);
|
|
29
27
|
for (let i = 0; i < maxLines; i++) {
|
|
@@ -47,6 +45,47 @@ function createUnifiedDiff(oldContent, newContent, filename) {
|
|
|
47
45
|
lines.splice(2, 0, `@@ -1,${oldLines.length} +1,${newLines.length} @@`);
|
|
48
46
|
return lines.join("\n");
|
|
49
47
|
}
|
|
48
|
+
function listFileCategory(categoryName, files) {
|
|
49
|
+
if (files.length === 0) return;
|
|
50
|
+
info(`
|
|
51
|
+
${categoryName}:`);
|
|
52
|
+
for (const file of files) {
|
|
53
|
+
listItem(file.path);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function showModifiedDiffs(files) {
|
|
57
|
+
for (const file of files) {
|
|
58
|
+
if (!file.currentContent || !file.newContent) continue;
|
|
59
|
+
info(`
|
|
60
|
+
${file.path}:`);
|
|
61
|
+
const diffOutput = createUnifiedDiff(file.currentContent, file.newContent, file.path);
|
|
62
|
+
if (diffOutput) {
|
|
63
|
+
console.log(diffOutput);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function showAddedPreviews(files) {
|
|
68
|
+
for (const file of files) {
|
|
69
|
+
if (!file.newContent) continue;
|
|
70
|
+
info(`
|
|
71
|
+
${file.path}: (new file)`);
|
|
72
|
+
const allLines = file.newContent.split("\n");
|
|
73
|
+
const lines = allLines.slice(0, 10);
|
|
74
|
+
for (const line of lines) {
|
|
75
|
+
console.log(`+${line}`);
|
|
76
|
+
}
|
|
77
|
+
if (allLines.length > 10) {
|
|
78
|
+
console.log("... (truncated)");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function showPackagesToInstall(packages) {
|
|
83
|
+
if (packages.length === 0) return;
|
|
84
|
+
info("\nPackages to install:");
|
|
85
|
+
for (const pkg of packages) {
|
|
86
|
+
listItem(pkg);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
50
89
|
function actionsToDiffs(actions, cwd) {
|
|
51
90
|
const diffs = [];
|
|
52
91
|
const seenPaths = /* @__PURE__ */ new Set();
|
|
@@ -106,55 +145,14 @@ Summary: ${added.length} added, ${modified.length} modified, ${unchanged.length}
|
|
|
106
145
|
info(`
|
|
107
146
|
Packages to install: ${result.packagesToInstall.length}`);
|
|
108
147
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
listItem(file.path);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
if (modified.length > 0) {
|
|
116
|
-
info("\nModified:");
|
|
117
|
-
for (const file of modified) {
|
|
118
|
-
listItem(file.path);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
if (unchanged.length > 0) {
|
|
122
|
-
info("\nUnchanged:");
|
|
123
|
-
for (const file of unchanged) {
|
|
124
|
-
listItem(file.path);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
148
|
+
listFileCategory("Added", added);
|
|
149
|
+
listFileCategory("Modified", modified);
|
|
150
|
+
listFileCategory("Unchanged", unchanged);
|
|
127
151
|
if (options.verbose) {
|
|
128
152
|
header("Detailed Changes");
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
${file.path}:`);
|
|
133
|
-
const diffOutput = createUnifiedDiff(file.currentContent, file.newContent, file.path);
|
|
134
|
-
if (diffOutput) {
|
|
135
|
-
console.log(diffOutput);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
for (const file of added) {
|
|
140
|
-
if (file.newContent) {
|
|
141
|
-
info(`
|
|
142
|
-
${file.path}: (new file)`);
|
|
143
|
-
const lines = file.newContent.split("\n").slice(0, 10);
|
|
144
|
-
for (const line of lines) {
|
|
145
|
-
console.log(`+${line}`);
|
|
146
|
-
}
|
|
147
|
-
if (file.newContent.split("\n").length > 10) {
|
|
148
|
-
console.log("... (truncated)");
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
if (result.packagesToInstall.length > 0) {
|
|
153
|
-
info("\nPackages to install:");
|
|
154
|
-
for (const pkg of result.packagesToInstall) {
|
|
155
|
-
listItem(pkg);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
153
|
+
showModifiedDiffs(modified);
|
|
154
|
+
showAddedPreviews(added);
|
|
155
|
+
showPackagesToInstall(result.packagesToInstall);
|
|
158
156
|
}
|
|
159
157
|
if (added.length === 0 && modified.length === 0 && result.packagesToInstall.length === 0) {
|
|
160
158
|
success("\nNo changes needed - configuration is up to date");
|
|
@@ -165,4 +163,4 @@ ${file.path}: (new file)`);
|
|
|
165
163
|
export {
|
|
166
164
|
diff
|
|
167
165
|
};
|
|
168
|
-
//# sourceMappingURL=diff-
|
|
166
|
+
//# sourceMappingURL=diff-654SSCFQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/diff.ts"],"sourcesContent":["/**\n * Diff command - Preview changes that would be made by upgrade\n *\n * Uses reconcile() with dryRun to compute what would change.\n */\n\nimport { join } from 'node:path';\nimport { VERSION } from '../version.js';\nimport { exists, readFileSafe } from '../utils/fs.js';\nimport { info, success, error, header, listItem } from '../utils/output.js';\nimport { createProjectContext } from '../utils/context.js';\nimport { reconcile, type Action } from '../reconcile.js';\nimport { SAFEWORD_SCHEMA } from '../schema.js';\n\nexport interface DiffOptions {\n verbose?: boolean;\n}\n\ninterface FileDiff {\n path: string;\n status: 'added' | 'modified' | 'unchanged';\n currentContent?: string;\n newContent?: string;\n}\n\n/**\n * Create a unified diff between two strings\n */\nfunction createUnifiedDiff(oldContent: string, newContent: string, filename: string): string {\n const oldLines = oldContent.split('\\n');\n const newLines = newContent.split('\\n');\n\n const lines: string[] = [`--- a/${filename}`, `+++ b/${filename}`];\n\n // Simple diff - show all changes\n let hasChanges = false;\n\n const maxLines = Math.max(oldLines.length, newLines.length);\n\n for (let i = 0; i < maxLines; i++) {\n const oldLine = oldLines[i];\n const newLine = newLines[i];\n\n if (oldLine === newLine) {\n lines.push(` ${oldLine ?? ''}`);\n } else {\n hasChanges = true;\n if (oldLine !== undefined) {\n lines.push(`-${oldLine}`);\n }\n if (newLine !== undefined) {\n lines.push(`+${newLine}`);\n }\n }\n }\n\n if (!hasChanges) {\n return '';\n }\n\n // Add context marker\n lines.splice(2, 0, `@@ -1,${oldLines.length} +1,${newLines.length} @@`);\n\n return lines.join('\\n');\n}\n\n/** List files by category */\nfunction listFileCategory(categoryName: string, files: FileDiff[]): void {\n if (files.length === 0) return;\n info(`\\n${categoryName}:`);\n for (const file of files) {\n listItem(file.path);\n }\n}\n\n/** Show verbose diff output for modified files */\nfunction showModifiedDiffs(files: FileDiff[]): void {\n for (const file of files) {\n if (!file.currentContent || !file.newContent) continue;\n info(`\\n${file.path}:`);\n const diffOutput = createUnifiedDiff(file.currentContent, file.newContent, file.path);\n if (diffOutput) {\n console.log(diffOutput);\n }\n }\n}\n\n/** Show verbose output for added files (truncated preview) */\nfunction showAddedPreviews(files: FileDiff[]): void {\n for (const file of files) {\n if (!file.newContent) continue;\n info(`\\n${file.path}: (new file)`);\n const allLines = file.newContent.split('\\n');\n const lines = allLines.slice(0, 10);\n for (const line of lines) {\n console.log(`+${line}`);\n }\n if (allLines.length > 10) {\n console.log('... (truncated)');\n }\n }\n}\n\n/** Show packages to install */\nfunction showPackagesToInstall(packages: string[]): void {\n if (packages.length === 0) return;\n info('\\nPackages to install:');\n for (const pkg of packages) {\n listItem(pkg);\n }\n}\n\n/**\n * Convert reconcile actions to file diffs\n */\nfunction actionsToDiffs(actions: Action[], cwd: string): FileDiff[] {\n const diffs: FileDiff[] = [];\n const seenPaths = new Set<string>();\n\n for (const action of actions) {\n if (action.type === 'write') {\n if (seenPaths.has(action.path)) continue;\n seenPaths.add(action.path);\n\n const fullPath = join(cwd, action.path);\n const currentContent = readFileSafe(fullPath);\n\n if (currentContent === null) {\n diffs.push({\n path: action.path,\n status: 'added',\n newContent: action.content,\n });\n } else if (currentContent.trim() !== action.content.trim()) {\n diffs.push({\n path: action.path,\n status: 'modified',\n currentContent,\n newContent: action.content,\n });\n } else {\n diffs.push({\n path: action.path,\n status: 'unchanged',\n currentContent,\n newContent: action.content,\n });\n }\n }\n }\n\n return diffs;\n}\n\nexport async function diff(options: DiffOptions): Promise<void> {\n const cwd = process.cwd();\n const safewordDir = join(cwd, '.safeword');\n\n // Check if configured\n if (!exists(safewordDir)) {\n error('Not configured. Run `safeword setup` first.');\n process.exit(1);\n }\n\n // Read project version\n const versionPath = join(safewordDir, 'version');\n const projectVersion = readFileSafe(versionPath)?.trim() ?? 'unknown';\n\n header('Safeword Diff');\n info(`Changes from v${projectVersion} → v${VERSION}`);\n\n // Use reconcile with dryRun to compute changes\n const ctx = createProjectContext(cwd);\n const result = await reconcile(SAFEWORD_SCHEMA, 'upgrade', ctx, { dryRun: true });\n\n // Convert actions to file diffs\n const diffs = actionsToDiffs(result.actions, cwd);\n\n const added = diffs.filter(d => d.status === 'added');\n const modified = diffs.filter(d => d.status === 'modified');\n const unchanged = diffs.filter(d => d.status === 'unchanged');\n\n // Summary\n info(\n `\\nSummary: ${added.length} added, ${modified.length} modified, ${unchanged.length} unchanged`,\n );\n\n // Package changes\n if (result.packagesToInstall.length > 0) {\n info(`\\nPackages to install: ${result.packagesToInstall.length}`);\n }\n\n // List by category\n listFileCategory('Added', added);\n listFileCategory('Modified', modified);\n listFileCategory('Unchanged', unchanged);\n\n // Verbose output - show actual diffs\n if (options.verbose) {\n header('Detailed Changes');\n showModifiedDiffs(modified);\n showAddedPreviews(added);\n showPackagesToInstall(result.packagesToInstall);\n }\n\n if (added.length === 0 && modified.length === 0 && result.packagesToInstall.length === 0) {\n success('\\nNo changes needed - configuration is up to date');\n } else {\n info('\\nRun `safeword upgrade` to apply these changes');\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
reconcile,
|
|
8
8
|
success,
|
|
9
9
|
warn
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-YMLVQC4V.js";
|
|
11
11
|
import {
|
|
12
12
|
SAFEWORD_SCHEMA,
|
|
13
13
|
exists
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-QPO3C3FP.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-
|
|
74
|
+
//# sourceMappingURL=reset-IU6AIT7C.js.map
|
|
@@ -8,12 +8,12 @@ import {
|
|
|
8
8
|
reconcile,
|
|
9
9
|
success,
|
|
10
10
|
warn
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-YMLVQC4V.js";
|
|
12
12
|
import {
|
|
13
13
|
SAFEWORD_SCHEMA,
|
|
14
14
|
exists,
|
|
15
15
|
writeJson
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-QPO3C3FP.js";
|
|
17
17
|
import {
|
|
18
18
|
VERSION
|
|
19
19
|
} from "./chunk-ORQHKDT2.js";
|
|
@@ -21,6 +21,17 @@ import {
|
|
|
21
21
|
// src/commands/setup.ts
|
|
22
22
|
import { join, basename } from "path";
|
|
23
23
|
import { execSync } from "child_process";
|
|
24
|
+
function printChangesSummary(created, updated, packageJsonCreated) {
|
|
25
|
+
if (created.length > 0 || packageJsonCreated) {
|
|
26
|
+
info("\nCreated:");
|
|
27
|
+
if (packageJsonCreated) listItem("package.json");
|
|
28
|
+
for (const file of created) listItem(file);
|
|
29
|
+
}
|
|
30
|
+
if (updated.length > 0) {
|
|
31
|
+
info("\nModified:");
|
|
32
|
+
for (const file of updated) listItem(file);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
24
35
|
async function setup(options) {
|
|
25
36
|
const cwd = process.cwd();
|
|
26
37
|
const safewordDir = join(cwd, ".safeword");
|
|
@@ -72,32 +83,18 @@ async function setup(options) {
|
|
|
72
83
|
}
|
|
73
84
|
}
|
|
74
85
|
header("Setup Complete");
|
|
75
|
-
|
|
76
|
-
info("\nCreated:");
|
|
77
|
-
if (packageJsonCreated) {
|
|
78
|
-
listItem("package.json");
|
|
79
|
-
}
|
|
80
|
-
for (const file of result.created) {
|
|
81
|
-
listItem(file);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
if (result.updated.length > 0) {
|
|
85
|
-
info("\nModified:");
|
|
86
|
-
for (const file of result.updated) {
|
|
87
|
-
listItem(file);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
86
|
+
printChangesSummary(result.created, result.updated, packageJsonCreated);
|
|
90
87
|
info("\nNext steps:");
|
|
91
88
|
listItem("Run `safeword check` to verify setup");
|
|
92
89
|
listItem("Commit the new files to git");
|
|
93
90
|
success(`
|
|
94
91
|
Safeword ${VERSION} installed successfully!`);
|
|
95
|
-
} catch (
|
|
96
|
-
error(`Setup failed: ${
|
|
92
|
+
} catch (error_) {
|
|
93
|
+
error(`Setup failed: ${error_ instanceof Error ? error_.message : "Unknown error"}`);
|
|
97
94
|
process.exit(1);
|
|
98
95
|
}
|
|
99
96
|
}
|
|
100
97
|
export {
|
|
101
98
|
setup
|
|
102
99
|
};
|
|
103
|
-
//# sourceMappingURL=setup-
|
|
100
|
+
//# sourceMappingURL=setup-5IQ4KV2M.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/setup.ts"],"sourcesContent":["/**\n * Setup command - Initialize safeword in a project\n *\n * Uses reconcile() with mode='install' to create all managed files.\n */\n\nimport { join, basename } from 'node:path';\nimport { VERSION } from '../version.js';\nimport { exists, writeJson } from '../utils/fs.js';\nimport { info, success, warn, error, header, listItem } from '../utils/output.js';\nimport { isGitRepo } from '../utils/git.js';\nimport { createProjectContext } from '../utils/context.js';\nimport { reconcile } from '../reconcile.js';\nimport { SAFEWORD_SCHEMA } from '../schema.js';\nimport { execSync } from 'node:child_process';\n\nexport interface SetupOptions {\n yes?: boolean;\n}\n\ninterface PackageJson {\n name?: string;\n version?: string;\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n 'lint-staged'?: Record<string, string[]>;\n}\n\n/** Print file changes summary */\nfunction printChangesSummary(\n created: string[],\n updated: string[],\n packageJsonCreated: boolean,\n): void {\n if (created.length > 0 || packageJsonCreated) {\n info('\\nCreated:');\n if (packageJsonCreated) listItem('package.json');\n for (const file of created) listItem(file);\n }\n\n if (updated.length > 0) {\n info('\\nModified:');\n for (const file of updated) listItem(file);\n }\n}\n\nexport async function setup(options: SetupOptions): Promise<void> {\n const cwd = process.cwd();\n const safewordDir = join(cwd, '.safeword');\n\n // Check if already configured\n if (exists(safewordDir)) {\n error('Already configured. Run `safeword upgrade` to update.');\n process.exit(1);\n }\n\n // Check for package.json, create if missing\n const packageJsonPath = join(cwd, 'package.json');\n let packageJsonCreated = false;\n if (!exists(packageJsonPath)) {\n const dirName = basename(cwd) || 'project';\n const defaultPackageJson: PackageJson = {\n name: dirName,\n version: '0.1.0',\n scripts: {},\n };\n writeJson(packageJsonPath, defaultPackageJson);\n packageJsonCreated = true;\n }\n\n const isNonInteractive = options.yes || !process.stdin.isTTY;\n\n header('Safeword Setup');\n info(`Version: ${VERSION}`);\n\n if (packageJsonCreated) {\n info('Created package.json (none found)');\n }\n\n try {\n // Use reconcile with mode='install' to create all managed files\n info('\\nCreating safeword configuration...');\n const ctx = createProjectContext(cwd);\n const result = await reconcile(SAFEWORD_SCHEMA, 'install', ctx);\n\n success('Created .safeword directory and configuration');\n\n // Install npm dependencies\n if (result.packagesToInstall.length > 0) {\n info('\\nInstalling linting dependencies...');\n\n try {\n const installCmd = `npm install -D ${result.packagesToInstall.join(' ')}`;\n info(`Running: ${installCmd}`);\n // eslint-disable-next-line sonarjs/os-command -- npm install with known package names\n execSync(installCmd, { cwd, stdio: 'inherit' });\n success('Installed linting dependencies');\n } catch {\n warn('Failed to install dependencies. Run manually:');\n listItem(`npm install -D ${result.packagesToInstall.join(' ')}`);\n }\n }\n\n // Report Husky status\n if (!isGitRepo(cwd)) {\n if (isNonInteractive) {\n warn('Skipped Husky setup (no git repository)');\n } else {\n warn('Skipped Husky setup (no .git directory)');\n info('Initialize git and run safeword upgrade to enable pre-commit hooks');\n }\n }\n\n // Print summary\n header('Setup Complete');\n printChangesSummary(result.created, result.updated, packageJsonCreated);\n\n info('\\nNext steps:');\n listItem('Run `safeword check` to verify setup');\n listItem('Commit the new files to git');\n\n success(`\\nSafeword ${VERSION} installed successfully!`);\n } catch (error_) {\n error(`Setup failed: ${error_ instanceof Error ? error_.message : 'Unknown error'}`);\n process.exit(1);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAMA,SAAS,MAAM,gBAAgB;AAQ/B,SAAS,gBAAgB;AAgBzB,SAAS,oBACP,SACA,SACA,oBACM;AACN,MAAI,QAAQ,SAAS,KAAK,oBAAoB;AAC5C,SAAK,YAAY;AACjB,QAAI,mBAAoB,UAAS,cAAc;AAC/C,eAAW,QAAQ,QAAS,UAAS,IAAI;AAAA,EAC3C;AAEA,MAAI,QAAQ,SAAS,GAAG;AACtB,SAAK,aAAa;AAClB,eAAW,QAAQ,QAAS,UAAS,IAAI;AAAA,EAC3C;AACF;AAEA,eAAsB,MAAM,SAAsC;AAChE,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,cAAc,KAAK,KAAK,WAAW;AAGzC,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,uDAAuD;AAC7D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,kBAAkB,KAAK,KAAK,cAAc;AAChD,MAAI,qBAAqB;AACzB,MAAI,CAAC,OAAO,eAAe,GAAG;AAC5B,UAAM,UAAU,SAAS,GAAG,KAAK;AACjC,UAAM,qBAAkC;AAAA,MACtC,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS,CAAC;AAAA,IACZ;AACA,cAAU,iBAAiB,kBAAkB;AAC7C,yBAAqB;AAAA,EACvB;AAEA,QAAM,mBAAmB,QAAQ,OAAO,CAAC,QAAQ,MAAM;AAEvD,SAAO,gBAAgB;AACvB,OAAK,YAAY,OAAO,EAAE;AAE1B,MAAI,oBAAoB;AACtB,SAAK,mCAAmC;AAAA,EAC1C;AAEA,MAAI;AAEF,SAAK,sCAAsC;AAC3C,UAAM,MAAM,qBAAqB,GAAG;AACpC,UAAM,SAAS,MAAM,UAAU,iBAAiB,WAAW,GAAG;AAE9D,YAAQ,+CAA+C;AAGvD,QAAI,OAAO,kBAAkB,SAAS,GAAG;AACvC,WAAK,sCAAsC;AAE3C,UAAI;AACF,cAAM,aAAa,kBAAkB,OAAO,kBAAkB,KAAK,GAAG,CAAC;AACvE,aAAK,YAAY,UAAU,EAAE;AAE7B,iBAAS,YAAY,EAAE,KAAK,OAAO,UAAU,CAAC;AAC9C,gBAAQ,gCAAgC;AAAA,MAC1C,QAAQ;AACN,aAAK,+CAA+C;AACpD,iBAAS,kBAAkB,OAAO,kBAAkB,KAAK,GAAG,CAAC,EAAE;AAAA,MACjE;AAAA,IACF;AAGA,QAAI,CAAC,UAAU,GAAG,GAAG;AACnB,UAAI,kBAAkB;AACpB,aAAK,yCAAyC;AAAA,MAChD,OAAO;AACL,aAAK,yCAAyC;AAC9C,aAAK,oEAAoE;AAAA,MAC3E;AAAA,IACF;AAGA,WAAO,gBAAgB;AACvB,wBAAoB,OAAO,SAAS,OAAO,SAAS,kBAAkB;AAEtE,SAAK,eAAe;AACpB,aAAS,sCAAsC;AAC/C,aAAS,6BAA6B;AAEtC,YAAQ;AAAA,WAAc,OAAO,0BAA0B;AAAA,EACzD,SAAS,QAAQ;AACf,UAAM,iBAAiB,kBAAkB,QAAQ,OAAO,UAAU,eAAe,EAAE;AACnF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;","names":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
detectProjectType,
|
|
4
4
|
exists,
|
|
5
5
|
readJson
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-QPO3C3FP.js";
|
|
7
7
|
import "./chunk-ORQHKDT2.js";
|
|
8
8
|
|
|
9
9
|
// src/commands/sync.ts
|
|
@@ -22,29 +22,11 @@ var BASE_ESLINT_PACKAGES = [
|
|
|
22
22
|
function getRequiredPlugins(projectType) {
|
|
23
23
|
const plugins = [...BASE_ESLINT_PACKAGES];
|
|
24
24
|
const { conditional } = SAFEWORD_SCHEMA.packages;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
if (projectType.nextjs && conditional.nextjs) {
|
|
32
|
-
plugins.push(...conditional.nextjs);
|
|
33
|
-
}
|
|
34
|
-
if (projectType.astro && conditional.astro) {
|
|
35
|
-
plugins.push(...conditional.astro);
|
|
36
|
-
}
|
|
37
|
-
if (projectType.vue && conditional.vue) {
|
|
38
|
-
plugins.push(...conditional.vue);
|
|
39
|
-
}
|
|
40
|
-
if (projectType.svelte && conditional.svelte) {
|
|
41
|
-
plugins.push(...conditional.svelte);
|
|
42
|
-
}
|
|
43
|
-
if (projectType.electron && conditional.electron) {
|
|
44
|
-
plugins.push(...conditional.electron);
|
|
45
|
-
}
|
|
46
|
-
if (projectType.vitest && conditional.vitest) {
|
|
47
|
-
plugins.push(...conditional.vitest);
|
|
25
|
+
for (const [key, deps] of Object.entries(conditional)) {
|
|
26
|
+
const isActive = key === "react" ? projectType.react || projectType.nextjs : projectType[key];
|
|
27
|
+
if (isActive && deps) {
|
|
28
|
+
plugins.push(...deps);
|
|
29
|
+
}
|
|
48
30
|
}
|
|
49
31
|
return plugins;
|
|
50
32
|
}
|
|
@@ -86,7 +68,7 @@ async function sync(options = {}) {
|
|
|
86
68
|
cwd,
|
|
87
69
|
stdio: options.quiet ? "pipe" : "inherit"
|
|
88
70
|
});
|
|
89
|
-
} catch
|
|
71
|
+
} catch {
|
|
90
72
|
const pluginList = missingPlugins.join(" ");
|
|
91
73
|
console.error(`
|
|
92
74
|
\u2717 Failed to install ESLint plugins
|
|
@@ -114,4 +96,4 @@ Run manually when online:`);
|
|
|
114
96
|
export {
|
|
115
97
|
sync
|
|
116
98
|
};
|
|
117
|
-
//# sourceMappingURL=sync-
|
|
99
|
+
//# sourceMappingURL=sync-YBQEISFI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/sync.ts"],"sourcesContent":["/**\n * Sync command - Keep linting plugins in sync with project dependencies\n *\n * Detects frameworks in package.json and ensures the corresponding ESLint plugins\n * are installed. Designed to be called from Husky pre-commit hook.\n *\n * Behavior:\n * - Fast exit when nothing needs to change\n * - Installs missing plugins\n * - Optionally stages modified files (--stage flag for pre-commit)\n * - Clear error message if installation fails\n */\n\nimport { join } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { exists, readJson } from '../utils/fs.js';\nimport {\n detectProjectType,\n type PackageJson,\n type ProjectType,\n} from '../utils/project-detector.js';\nimport { SAFEWORD_SCHEMA } from '../schema.js';\n\nexport interface SyncOptions {\n quiet?: boolean;\n stage?: boolean;\n}\n\n/**\n * Base ESLint packages always required for linting.\n * Explicit list for clarity - sync only cares about ESLint plugins.\n *\n * NOTE: This is a subset of SAFEWORD_SCHEMA.packages.base (which includes\n * prettier, markdownlint-cli2, husky, lint-staged, knip). When adding new\n * ESLint packages to schema.ts, also add them here if they should be\n * auto-installed on pre-commit.\n */\nconst BASE_ESLINT_PACKAGES = [\n 'eslint',\n '@eslint/js',\n 'eslint-plugin-import-x',\n 'eslint-plugin-sonarjs',\n '@microsoft/eslint-plugin-sdl',\n 'eslint-config-prettier',\n 'eslint-plugin-boundaries',\n 'eslint-plugin-playwright',\n];\n\n/**\n * Get required ESLint packages based on project type.\n * Uses explicit base list + SAFEWORD_SCHEMA.packages.conditional for frameworks.\n */\nfunction getRequiredPlugins(projectType: ProjectType): string[] {\n const plugins: string[] = [...BASE_ESLINT_PACKAGES];\n const { conditional } = SAFEWORD_SCHEMA.packages;\n\n // Add conditional packages from schema based on detected project type\n for (const [key, deps] of Object.entries(conditional)) {\n // Special case: react plugins also needed for nextjs\n const isActive =\n key === 'react'\n ? projectType.react || projectType.nextjs\n : projectType[key as keyof ProjectType];\n\n if (isActive && deps) {\n plugins.push(...deps);\n }\n }\n\n return plugins;\n}\n\n/**\n * Check which packages are missing from devDependencies\n */\nfunction getMissingPackages(required: string[], installed: Record<string, string>): string[] {\n return required.filter(pkg => !(pkg in installed));\n}\n\n/**\n * Sync linting configuration with current project dependencies\n */\nexport async function sync(options: SyncOptions = {}): Promise<void> {\n const cwd = process.cwd();\n const safewordDir = join(cwd, '.safeword');\n const packageJsonPath = join(cwd, 'package.json');\n\n // Must be in a safeword project\n if (!exists(safewordDir)) {\n if (!options.quiet) {\n console.error('Not a safeword project. Run `safeword setup` first.');\n }\n process.exit(1);\n }\n\n if (!exists(packageJsonPath)) {\n if (!options.quiet) {\n console.error('No package.json found.');\n }\n process.exit(1);\n }\n\n const packageJson = readJson<PackageJson>(packageJsonPath);\n if (!packageJson) {\n process.exit(1);\n }\n\n // Detect current project type\n const projectType = detectProjectType(packageJson);\n const devDeps = packageJson.devDependencies || {};\n\n // Check for missing plugins\n const requiredPlugins = getRequiredPlugins(projectType);\n const missingPlugins = getMissingPackages(requiredPlugins, devDeps);\n\n // Fast exit if nothing to install\n if (missingPlugins.length === 0) {\n return;\n }\n\n // Install missing plugins\n if (!options.quiet) {\n console.log(`Installing missing ESLint plugins: ${missingPlugins.join(', ')}`);\n }\n\n try {\n // eslint-disable-next-line sonarjs/os-command -- npm install with known package names\n execSync(`npm install -D ${missingPlugins.join(' ')}`, {\n cwd,\n stdio: options.quiet ? 'pipe' : 'inherit',\n });\n } catch {\n // Clear error message for network/install failures\n const pluginList = missingPlugins.join(' ');\n console.error(`\\n✗ Failed to install ESLint plugins\\n`);\n console.error(`Your project needs: ${pluginList}`);\n console.error(`\\nRun manually when online:`);\n console.error(` npm install -D ${pluginList}\\n`);\n process.exit(1);\n }\n\n // Stage modified files if --stage flag is set (for pre-commit hook)\n if (options.stage) {\n try {\n // eslint-disable-next-line sonarjs/no-os-command-from-path -- git with fixed args\n execSync('git add package.json package-lock.json', {\n cwd,\n stdio: 'pipe',\n });\n } catch {\n // Not in a git repo or git add failed - ignore\n }\n }\n\n if (!options.quiet) {\n console.log(`✓ Installed ${missingPlugins.length} ESLint plugin(s)`);\n }\n}\n"],"mappings":";;;;;;;;;AAaA,SAAS,YAAY;AACrB,SAAS,gBAAgB;AAuBzB,IAAM,uBAAuB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMA,SAAS,mBAAmB,aAAoC;AAC9D,QAAM,UAAoB,CAAC,GAAG,oBAAoB;AAClD,QAAM,EAAE,YAAY,IAAI,gBAAgB;AAGxC,aAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,WAAW,GAAG;AAErD,UAAM,WACJ,QAAQ,UACJ,YAAY,SAAS,YAAY,SACjC,YAAY,GAAwB;AAE1C,QAAI,YAAY,MAAM;AACpB,cAAQ,KAAK,GAAG,IAAI;AAAA,IACtB;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,mBAAmB,UAAoB,WAA6C;AAC3F,SAAO,SAAS,OAAO,SAAO,EAAE,OAAO,UAAU;AACnD;AAKA,eAAsB,KAAK,UAAuB,CAAC,GAAkB;AACnE,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,cAAc,KAAK,KAAK,WAAW;AACzC,QAAM,kBAAkB,KAAK,KAAK,cAAc;AAGhD,MAAI,CAAC,OAAO,WAAW,GAAG;AACxB,QAAI,CAAC,QAAQ,OAAO;AAClB,cAAQ,MAAM,qDAAqD;AAAA,IACrE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,CAAC,OAAO,eAAe,GAAG;AAC5B,QAAI,CAAC,QAAQ,OAAO;AAClB,cAAQ,MAAM,wBAAwB;AAAA,IACxC;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,cAAc,SAAsB,eAAe;AACzD,MAAI,CAAC,aAAa;AAChB,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,cAAc,kBAAkB,WAAW;AACjD,QAAM,UAAU,YAAY,mBAAmB,CAAC;AAGhD,QAAM,kBAAkB,mBAAmB,WAAW;AACtD,QAAM,iBAAiB,mBAAmB,iBAAiB,OAAO;AAGlE,MAAI,eAAe,WAAW,GAAG;AAC/B;AAAA,EACF;AAGA,MAAI,CAAC,QAAQ,OAAO;AAClB,YAAQ,IAAI,sCAAsC,eAAe,KAAK,IAAI,CAAC,EAAE;AAAA,EAC/E;AAEA,MAAI;AAEF,aAAS,kBAAkB,eAAe,KAAK,GAAG,CAAC,IAAI;AAAA,MACrD;AAAA,MACA,OAAO,QAAQ,QAAQ,SAAS;AAAA,IAClC,CAAC;AAAA,EACH,QAAQ;AAEN,UAAM,aAAa,eAAe,KAAK,GAAG;AAC1C,YAAQ,MAAM;AAAA;AAAA,CAAwC;AACtD,YAAQ,MAAM,uBAAuB,UAAU,EAAE;AACjD,YAAQ,MAAM;AAAA,0BAA6B;AAC3C,YAAQ,MAAM,oBAAoB,UAAU;AAAA,CAAI;AAChD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,MAAI,QAAQ,OAAO;AACjB,QAAI;AAEF,eAAS,0CAA0C;AAAA,QACjD;AAAA,QACA,OAAO;AAAA,MACT,CAAC;AAAA,IACH,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,MAAI,CAAC,QAAQ,OAAO;AAClB,YAAQ,IAAI,oBAAe,eAAe,MAAM,mBAAmB;AAAA,EACrE;AACF;","names":[]}
|
|
@@ -9,12 +9,12 @@ import {
|
|
|
9
9
|
listItem,
|
|
10
10
|
reconcile,
|
|
11
11
|
success
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-YMLVQC4V.js";
|
|
13
13
|
import {
|
|
14
14
|
SAFEWORD_SCHEMA,
|
|
15
15
|
exists,
|
|
16
16
|
readFileSafe
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-QPO3C3FP.js";
|
|
18
18
|
import {
|
|
19
19
|
VERSION
|
|
20
20
|
} from "./chunk-ORQHKDT2.js";
|
|
@@ -70,4 +70,4 @@ Safeword upgraded to v${VERSION}`);
|
|
|
70
70
|
export {
|
|
71
71
|
upgrade
|
|
72
72
|
};
|
|
73
|
-
//# sourceMappingURL=upgrade-
|
|
73
|
+
//# sourceMappingURL=upgrade-RRTWEQIP.js.map
|