safeword 0.9.0 → 0.11.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-MLYBKA5Z.js → check-EQ3IJPBM.js} +8 -6
- package/dist/{check-MLYBKA5Z.js.map → check-EQ3IJPBM.js.map} +1 -1
- package/dist/chunk-DYLHQBW3.js +132 -0
- package/dist/chunk-DYLHQBW3.js.map +1 -0
- package/dist/{chunk-UUKED7KU.js → chunk-KL2JTWK6.js} +110 -192
- package/dist/chunk-KL2JTWK6.js.map +1 -0
- package/dist/chunk-NDY7IUE7.js +229 -0
- package/dist/chunk-NDY7IUE7.js.map +1 -0
- package/dist/cli.js +9 -5
- package/dist/cli.js.map +1 -1
- package/dist/{diff-Q44YDA2W.js → diff-6EDSOICP.js} +8 -6
- package/dist/{diff-Q44YDA2W.js.map → diff-6EDSOICP.js.map} +1 -1
- package/dist/{reset-EEFVJ5GB.js → reset-HJBALSYG.js} +11 -8
- package/dist/reset-HJBALSYG.js.map +1 -0
- package/dist/{setup-WZ3F25KX.js → setup-SOWUS7ZI.js} +41 -13
- package/dist/setup-SOWUS7ZI.js.map +1 -0
- package/dist/sync-config-XTMQBCIH.js +14 -0
- package/dist/sync-config-XTMQBCIH.js.map +1 -0
- package/dist/{upgrade-WB7N3GWG.js → upgrade-KJLOX4DD.js} +8 -6
- package/dist/{upgrade-WB7N3GWG.js.map → upgrade-KJLOX4DD.js.map} +1 -1
- package/package.json +2 -2
- package/templates/commands/audit.md +41 -0
- package/templates/commands/lint.md +1 -4
- package/templates/hooks/cursor/after-file-edit.sh +1 -9
- package/templates/hooks/post-tool-lint.sh +1 -9
- package/templates/skills/safeword-debugging/SKILL.md +15 -15
- package/dist/chunk-UUKED7KU.js.map +0 -1
- package/dist/reset-EEFVJ5GB.js.map +0 -1
- package/dist/setup-WZ3F25KX.js.map +0 -1
- package/templates/markdownlint-cli2.jsonc +0 -24
- package/templates/scripts/lint-md.sh +0 -16
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SAFEWORD_SCHEMA,
|
|
3
3
|
createProjectContext,
|
|
4
|
+
reconcile
|
|
5
|
+
} from "./chunk-KL2JTWK6.js";
|
|
6
|
+
import "./chunk-ORQHKDT2.js";
|
|
7
|
+
import {
|
|
4
8
|
error,
|
|
5
9
|
exists,
|
|
6
10
|
header,
|
|
7
11
|
info,
|
|
8
12
|
listItem,
|
|
9
|
-
reconcile,
|
|
10
13
|
success,
|
|
11
14
|
warn
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-ORQHKDT2.js";
|
|
15
|
+
} from "./chunk-DYLHQBW3.js";
|
|
14
16
|
|
|
15
17
|
// src/commands/reset.ts
|
|
16
18
|
import { execSync } from "child_process";
|
|
@@ -40,9 +42,8 @@ function printResetSummary(result, fullReset) {
|
|
|
40
42
|
info("\nPreserved (use --full to remove):");
|
|
41
43
|
listItem("eslint.config.mjs");
|
|
42
44
|
listItem(".prettierrc");
|
|
43
|
-
listItem(".
|
|
44
|
-
listItem("
|
|
45
|
-
listItem("devDependencies (eslint, prettier, husky, lint-staged, etc.)");
|
|
45
|
+
listItem("package.json (scripts)");
|
|
46
|
+
listItem("devDependencies (eslint, prettier, etc.)");
|
|
46
47
|
}
|
|
47
48
|
success("\nSafeword configuration removed");
|
|
48
49
|
}
|
|
@@ -56,7 +57,9 @@ async function reset(options) {
|
|
|
56
57
|
const fullReset = options.full ?? false;
|
|
57
58
|
const mode = fullReset ? "uninstall-full" : "uninstall";
|
|
58
59
|
header("Safeword Reset");
|
|
59
|
-
info(
|
|
60
|
+
info(
|
|
61
|
+
fullReset ? "Performing full reset (including linting configuration)..." : "Removing safeword configuration..."
|
|
62
|
+
);
|
|
60
63
|
try {
|
|
61
64
|
const ctx = createProjectContext(cwd);
|
|
62
65
|
const result = await reconcile(SAFEWORD_SCHEMA, mode, ctx);
|
|
@@ -70,4 +73,4 @@ async function reset(options) {
|
|
|
70
73
|
export {
|
|
71
74
|
reset
|
|
72
75
|
};
|
|
73
|
-
//# sourceMappingURL=reset-
|
|
76
|
+
//# sourceMappingURL=reset-HJBALSYG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/reset.ts"],"sourcesContent":["/**\n * Reset command - Remove safeword configuration from project\n *\n * Uses reconcile() with mode='uninstall' or 'uninstall-full' to remove configuration.\n *\n * By default, preserves linting configuration (eslint, prettier, etc.)\n * Use --full to also remove linting config and uninstall npm packages\n */\n\nimport { execSync } from 'node:child_process';\nimport nodePath from 'node:path';\n\nimport { reconcile, type ReconcileResult } from '../reconcile.js';\nimport { SAFEWORD_SCHEMA } from '../schema.js';\nimport { createProjectContext } from '../utils/context.js';\nimport { exists } from '../utils/fs.js';\nimport { error, header, info, listItem, success, warn } from '../utils/output.js';\n\nexport interface ResetOptions {\n yes?: boolean;\n full?: boolean;\n}\n\nfunction uninstallPackages(cwd: string, packages: string[]): void {\n if (packages.length === 0) return;\n\n info('\\nUninstalling devDependencies...');\n const uninstallCmd = `npm uninstall ${packages.join(' ')}`;\n info(`Running: ${uninstallCmd}`);\n\n try {\n execSync(uninstallCmd, { cwd, stdio: 'inherit' });\n success('Uninstalled safeword devDependencies');\n } catch {\n warn('Failed to uninstall some packages. Run manually:');\n listItem(uninstallCmd);\n }\n}\n\nfunction printResetSummary(result: ReconcileResult, fullReset: boolean): void {\n header('Reset Complete');\n\n if (result.removed.length > 0) {\n info('\\nRemoved:');\n for (const item of result.removed) {\n listItem(item);\n }\n }\n\n if (!fullReset) {\n info('\\nPreserved (use --full to remove):');\n listItem('eslint.config.mjs');\n listItem('.prettierrc');\n listItem('package.json (scripts)');\n listItem('devDependencies (eslint, prettier, etc.)');\n }\n\n success('\\nSafeword configuration removed');\n}\n\nexport async function reset(options: ResetOptions): Promise<void> {\n const cwd = process.cwd();\n const safewordDirectory = nodePath.join(cwd, '.safeword');\n\n if (!exists(safewordDirectory)) {\n info('Nothing to remove. Project is not configured with safeword.');\n return;\n }\n\n const fullReset = options.full ?? false;\n const mode = fullReset ? 'uninstall-full' : 'uninstall';\n\n header('Safeword Reset');\n info(\n fullReset\n ? 'Performing full reset (including linting configuration)...'\n : 'Removing safeword configuration...',\n );\n\n try {\n const ctx = createProjectContext(cwd);\n const result = await reconcile(SAFEWORD_SCHEMA, mode, ctx);\n\n if (fullReset) uninstallPackages(cwd, result.packagesToRemove);\n printResetSummary(result, fullReset);\n } catch (error_) {\n error(`Reset failed: ${error_ instanceof Error ? error_.message : 'Unknown error'}`);\n process.exit(1);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AASA,SAAS,gBAAgB;AACzB,OAAO,cAAc;AAarB,SAAS,kBAAkB,KAAa,UAA0B;AAChE,MAAI,SAAS,WAAW,EAAG;AAE3B,OAAK,mCAAmC;AACxC,QAAM,eAAe,iBAAiB,SAAS,KAAK,GAAG,CAAC;AACxD,OAAK,YAAY,YAAY,EAAE;AAE/B,MAAI;AACF,aAAS,cAAc,EAAE,KAAK,OAAO,UAAU,CAAC;AAChD,YAAQ,sCAAsC;AAAA,EAChD,QAAQ;AACN,SAAK,kDAAkD;AACvD,aAAS,YAAY;AAAA,EACvB;AACF;AAEA,SAAS,kBAAkB,QAAyB,WAA0B;AAC5E,SAAO,gBAAgB;AAEvB,MAAI,OAAO,QAAQ,SAAS,GAAG;AAC7B,SAAK,YAAY;AACjB,eAAW,QAAQ,OAAO,SAAS;AACjC,eAAS,IAAI;AAAA,IACf;AAAA,EACF;AAEA,MAAI,CAAC,WAAW;AACd,SAAK,qCAAqC;AAC1C,aAAS,mBAAmB;AAC5B,aAAS,aAAa;AACtB,aAAS,wBAAwB;AACjC,aAAS,0CAA0C;AAAA,EACrD;AAEA,UAAQ,kCAAkC;AAC5C;AAEA,eAAsB,MAAM,SAAsC;AAChE,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,oBAAoB,SAAS,KAAK,KAAK,WAAW;AAExD,MAAI,CAAC,OAAO,iBAAiB,GAAG;AAC9B,SAAK,6DAA6D;AAClE;AAAA,EACF;AAEA,QAAM,YAAY,QAAQ,QAAQ;AAClC,QAAM,OAAO,YAAY,mBAAmB;AAE5C,SAAO,gBAAgB;AACvB;AAAA,IACE,YACI,+DACA;AAAA,EACN;AAEA,MAAI;AACF,UAAM,MAAM,qBAAqB,GAAG;AACpC,UAAM,SAAS,MAAM,UAAU,iBAAiB,MAAM,GAAG;AAEzD,QAAI,UAAW,mBAAkB,KAAK,OAAO,gBAAgB;AAC7D,sBAAkB,QAAQ,SAAS;AAAA,EACrC,SAAS,QAAQ;AACf,UAAM,iBAAiB,kBAAkB,QAAQ,OAAO,UAAU,eAAe,EAAE;AACnF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;","names":[]}
|
|
@@ -1,20 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildArchitecture,
|
|
3
|
+
hasArchitectureDetected,
|
|
4
|
+
syncConfigCore
|
|
5
|
+
} from "./chunk-NDY7IUE7.js";
|
|
1
6
|
import {
|
|
2
7
|
SAFEWORD_SCHEMA,
|
|
3
8
|
createProjectContext,
|
|
9
|
+
isGitRepo,
|
|
10
|
+
reconcile
|
|
11
|
+
} from "./chunk-KL2JTWK6.js";
|
|
12
|
+
import {
|
|
13
|
+
VERSION
|
|
14
|
+
} from "./chunk-ORQHKDT2.js";
|
|
15
|
+
import {
|
|
4
16
|
error,
|
|
5
17
|
exists,
|
|
6
18
|
header,
|
|
7
19
|
info,
|
|
8
|
-
isGitRepo,
|
|
9
20
|
listItem,
|
|
10
|
-
reconcile,
|
|
11
21
|
success,
|
|
12
22
|
warn,
|
|
13
23
|
writeJson
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import {
|
|
16
|
-
VERSION
|
|
17
|
-
} from "./chunk-ORQHKDT2.js";
|
|
24
|
+
} from "./chunk-DYLHQBW3.js";
|
|
18
25
|
|
|
19
26
|
// src/commands/setup.ts
|
|
20
27
|
import { execSync } from "child_process";
|
|
@@ -40,12 +47,13 @@ function installDependencies(cwd, packages) {
|
|
|
40
47
|
listItem(installCmd);
|
|
41
48
|
}
|
|
42
49
|
}
|
|
43
|
-
function printSetupSummary(result, packageJsonCreated) {
|
|
50
|
+
function printSetupSummary(result, packageJsonCreated, archFiles = []) {
|
|
44
51
|
header("Setup Complete");
|
|
45
|
-
|
|
52
|
+
const allCreated = [...result.created, ...archFiles];
|
|
53
|
+
if (allCreated.length > 0 || packageJsonCreated) {
|
|
46
54
|
info("\nCreated:");
|
|
47
55
|
if (packageJsonCreated) listItem("package.json");
|
|
48
|
-
for (const file of
|
|
56
|
+
for (const file of allCreated) listItem(file);
|
|
49
57
|
}
|
|
50
58
|
if (result.updated.length > 0) {
|
|
51
59
|
info("\nModified:");
|
|
@@ -73,13 +81,33 @@ async function setup(options) {
|
|
|
73
81
|
const ctx = createProjectContext(cwd);
|
|
74
82
|
const result = await reconcile(SAFEWORD_SCHEMA, "install", ctx);
|
|
75
83
|
success("Created .safeword directory and configuration");
|
|
84
|
+
const arch = buildArchitecture(cwd);
|
|
85
|
+
const archFiles = [];
|
|
86
|
+
if (hasArchitectureDetected(arch)) {
|
|
87
|
+
const syncResult = syncConfigCore(cwd, arch);
|
|
88
|
+
if (syncResult.generatedConfig) archFiles.push(".safeword/depcruise-config.js");
|
|
89
|
+
if (syncResult.createdMainConfig) archFiles.push(".dependency-cruiser.js");
|
|
90
|
+
const detected = [];
|
|
91
|
+
if (arch.elements.length > 0) {
|
|
92
|
+
detected.push(arch.elements.map((element) => element.location).join(", "));
|
|
93
|
+
}
|
|
94
|
+
if (arch.workspaces && arch.workspaces.length > 0) {
|
|
95
|
+
detected.push(`workspaces: ${arch.workspaces.join(", ")}`);
|
|
96
|
+
}
|
|
97
|
+
info(`
|
|
98
|
+
Architecture detected: ${detected.join("; ")}`);
|
|
99
|
+
info("Generated dependency-cruiser config for /audit command");
|
|
100
|
+
}
|
|
76
101
|
installDependencies(cwd, result.packagesToInstall);
|
|
77
102
|
if (!isGitRepo(cwd)) {
|
|
78
103
|
const isNonInteractive = options.yes || !process.stdin.isTTY;
|
|
79
|
-
warn(
|
|
80
|
-
|
|
104
|
+
warn(
|
|
105
|
+
isNonInteractive ? "Skipped Husky setup (no git repository)" : "Skipped Husky setup (no .git directory)"
|
|
106
|
+
);
|
|
107
|
+
if (!isNonInteractive)
|
|
108
|
+
info("Initialize git and run safeword upgrade to enable pre-commit hooks");
|
|
81
109
|
}
|
|
82
|
-
printSetupSummary(result, packageJsonCreated);
|
|
110
|
+
printSetupSummary(result, packageJsonCreated, archFiles);
|
|
83
111
|
} catch (error_) {
|
|
84
112
|
error(`Setup failed: ${error_ instanceof Error ? error_.message : "Unknown error"}`);
|
|
85
113
|
process.exit(1);
|
|
@@ -88,4 +116,4 @@ async function setup(options) {
|
|
|
88
116
|
export {
|
|
89
117
|
setup
|
|
90
118
|
};
|
|
91
|
-
//# sourceMappingURL=setup-
|
|
119
|
+
//# sourceMappingURL=setup-SOWUS7ZI.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 { execSync } from 'node:child_process';\nimport nodePath from 'node:path';\n\nimport { reconcile, type ReconcileResult } from '../reconcile.js';\nimport { SAFEWORD_SCHEMA } from '../schema.js';\nimport { createProjectContext } from '../utils/context.js';\nimport { exists, writeJson } from '../utils/fs.js';\nimport { isGitRepo } from '../utils/git.js';\nimport { error, header, info, listItem, success, warn } from '../utils/output.js';\nimport { VERSION } from '../version.js';\nimport { buildArchitecture, hasArchitectureDetected, syncConfigCore } from './sync-config.js';\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\nfunction ensurePackageJson(cwd: string): boolean {\n const packageJsonPath = nodePath.join(cwd, 'package.json');\n if (exists(packageJsonPath)) return false;\n\n const dirName = nodePath.basename(cwd) || 'project';\n const defaultPackageJson: PackageJson = { name: dirName, version: '0.1.0', scripts: {} };\n writeJson(packageJsonPath, defaultPackageJson);\n return true;\n}\n\nfunction installDependencies(cwd: string, packages: string[]): void {\n if (packages.length === 0) return;\n\n info('\\nInstalling linting dependencies...');\n const installCmd = `npm install -D ${packages.join(' ')}`;\n info(`Running: ${installCmd}`);\n\n try {\n execSync(installCmd, { cwd, stdio: 'inherit' });\n success('Installed linting dependencies');\n } catch {\n warn('Failed to install dependencies. Run manually:');\n listItem(installCmd);\n }\n}\n\nfunction printSetupSummary(\n result: ReconcileResult,\n packageJsonCreated: boolean,\n archFiles: string[] = [],\n): void {\n header('Setup Complete');\n\n const allCreated = [...result.created, ...archFiles];\n if (allCreated.length > 0 || packageJsonCreated) {\n info('\\nCreated:');\n if (packageJsonCreated) listItem('package.json');\n for (const file of allCreated) listItem(file);\n }\n\n if (result.updated.length > 0) {\n info('\\nModified:');\n for (const file of result.updated) listItem(file);\n }\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}\n\nexport async function setup(options: SetupOptions): Promise<void> {\n const cwd = process.cwd();\n const safewordDirectory = nodePath.join(cwd, '.safeword');\n\n if (exists(safewordDirectory)) {\n error('Already configured. Run `safeword upgrade` to update.');\n process.exit(1);\n }\n\n const packageJsonCreated = ensurePackageJson(cwd);\n\n header('Safeword Setup');\n info(`Version: ${VERSION}`);\n if (packageJsonCreated) info('Created package.json (none found)');\n\n try {\n info('\\nCreating safeword configuration...');\n const ctx = createProjectContext(cwd);\n const result = await reconcile(SAFEWORD_SCHEMA, 'install', ctx);\n success('Created .safeword directory and configuration');\n\n // Detect architecture and workspaces, generate depcruise configs if found\n const arch = buildArchitecture(cwd);\n const archFiles: string[] = [];\n\n if (hasArchitectureDetected(arch)) {\n const syncResult = syncConfigCore(cwd, arch);\n if (syncResult.generatedConfig) archFiles.push('.safeword/depcruise-config.js');\n if (syncResult.createdMainConfig) archFiles.push('.dependency-cruiser.js');\n\n const detected: string[] = [];\n if (arch.elements.length > 0) {\n detected.push(arch.elements.map(element => element.location).join(', '));\n }\n if (arch.workspaces && arch.workspaces.length > 0) {\n detected.push(`workspaces: ${arch.workspaces.join(', ')}`);\n }\n info(`\\nArchitecture detected: ${detected.join('; ')}`);\n info('Generated dependency-cruiser config for /audit command');\n }\n\n installDependencies(cwd, result.packagesToInstall);\n\n if (!isGitRepo(cwd)) {\n const isNonInteractive = options.yes || !process.stdin.isTTY;\n warn(\n isNonInteractive\n ? 'Skipped Husky setup (no git repository)'\n : 'Skipped Husky setup (no .git directory)',\n );\n if (!isNonInteractive)\n info('Initialize git and run safeword upgrade to enable pre-commit hooks');\n }\n\n printSetupSummary(result, packageJsonCreated, archFiles);\n } catch (error_) {\n error(`Setup failed: ${error_ instanceof Error ? error_.message : 'Unknown error'}`);\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildArchitecture,
|
|
3
|
+
hasArchitectureDetected,
|
|
4
|
+
syncConfig,
|
|
5
|
+
syncConfigCore
|
|
6
|
+
} from "./chunk-NDY7IUE7.js";
|
|
7
|
+
import "./chunk-DYLHQBW3.js";
|
|
8
|
+
export {
|
|
9
|
+
buildArchitecture,
|
|
10
|
+
hasArchitectureDetected,
|
|
11
|
+
syncConfig,
|
|
12
|
+
syncConfigCore
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=sync-config-XTMQBCIH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -4,19 +4,21 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
SAFEWORD_SCHEMA,
|
|
6
6
|
createProjectContext,
|
|
7
|
+
reconcile
|
|
8
|
+
} from "./chunk-KL2JTWK6.js";
|
|
9
|
+
import {
|
|
10
|
+
VERSION
|
|
11
|
+
} from "./chunk-ORQHKDT2.js";
|
|
12
|
+
import {
|
|
7
13
|
error,
|
|
8
14
|
exists,
|
|
9
15
|
header,
|
|
10
16
|
info,
|
|
11
17
|
listItem,
|
|
12
18
|
readFileSafe,
|
|
13
|
-
reconcile,
|
|
14
19
|
success,
|
|
15
20
|
warn
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import {
|
|
18
|
-
VERSION
|
|
19
|
-
} from "./chunk-ORQHKDT2.js";
|
|
21
|
+
} from "./chunk-DYLHQBW3.js";
|
|
20
22
|
|
|
21
23
|
// src/commands/upgrade.ts
|
|
22
24
|
import nodePath from "path";
|
|
@@ -73,4 +75,4 @@ async function upgrade() {
|
|
|
73
75
|
export {
|
|
74
76
|
upgrade
|
|
75
77
|
};
|
|
76
|
-
//# sourceMappingURL=upgrade-
|
|
78
|
+
//# sourceMappingURL=upgrade-KJLOX4DD.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/upgrade.ts"],"sourcesContent":["/**\n * Upgrade command - Update safeword configuration to latest version\n *\n * Uses reconcile() with mode='upgrade' to update all managed files.\n */\n\nimport nodePath from 'node:path';\n\nimport { reconcile, type ReconcileResult } from '../reconcile.js';\nimport { SAFEWORD_SCHEMA } from '../schema.js';\nimport { createProjectContext } from '../utils/context.js';\nimport { exists, readFileSafe } from '../utils/fs.js';\nimport { error, header, info, listItem, success, warn } from '../utils/output.js';\nimport { compareVersions } from '../utils/version.js';\nimport { VERSION } from '../version.js';\n\nfunction getProjectVersion(safewordDirectory: string): string {\n const versionPath = nodePath.join(safewordDirectory, 'version');\n return readFileSafe(versionPath)?.trim() ?? '0.0.0';\n}\n\nfunction printUpgradeSummary(result: ReconcileResult, projectVersion: string): void {\n header('Upgrade Complete');\n info(`\\nVersion: v${projectVersion} → v${VERSION}`);\n\n if (result.created.length > 0) {\n info('\\nCreated:');\n for (const file of result.created) listItem(file);\n }\n\n if (result.updated.length > 0) {\n info('\\nUpdated:');\n for (const file of result.updated) listItem(file);\n }\n\n if (result.packagesToRemove.length > 0) {\n warn(`\\n${result.packagesToRemove.length} package(s) are now bundled in eslint-plugin-safeword:`);\n for (const pkg of result.packagesToRemove) listItem(pkg);\n info(\"\\nIf you don't use these elsewhere, you can remove them:\");\n listItem(`npm uninstall ${result.packagesToRemove.join(' ')}`);\n }\n\n success(`\\nSafeword upgraded to v${VERSION}`);\n}\n\nexport async function upgrade(): Promise<void> {\n const cwd = process.cwd();\n const safewordDirectory = nodePath.join(cwd, '.safeword');\n\n if (!exists(safewordDirectory)) {\n error('Not configured. Run `safeword setup` first.');\n process.exit(1);\n }\n\n const projectVersion = getProjectVersion(safewordDirectory);\n\n if (compareVersions(VERSION, projectVersion) < 0) {\n error(`CLI v${VERSION} is older than project v${projectVersion}.`);\n error('Update the CLI first: npm install -g safeword');\n process.exit(1);\n }\n\n header('Safeword Upgrade');\n info(`Upgrading from v${projectVersion} to v${VERSION}`);\n\n try {\n const ctx = createProjectContext(cwd);\n const result = await reconcile(SAFEWORD_SCHEMA, 'upgrade', ctx);\n printUpgradeSummary(result, projectVersion);\n } catch (error_) {\n error(`Upgrade failed: ${error_ instanceof Error ? error_.message : 'Unknown error'}`);\n process.exit(1);\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/commands/upgrade.ts"],"sourcesContent":["/**\n * Upgrade command - Update safeword configuration to latest version\n *\n * Uses reconcile() with mode='upgrade' to update all managed files.\n */\n\nimport nodePath from 'node:path';\n\nimport { reconcile, type ReconcileResult } from '../reconcile.js';\nimport { SAFEWORD_SCHEMA } from '../schema.js';\nimport { createProjectContext } from '../utils/context.js';\nimport { exists, readFileSafe } from '../utils/fs.js';\nimport { error, header, info, listItem, success, warn } from '../utils/output.js';\nimport { compareVersions } from '../utils/version.js';\nimport { VERSION } from '../version.js';\n\nfunction getProjectVersion(safewordDirectory: string): string {\n const versionPath = nodePath.join(safewordDirectory, 'version');\n return readFileSafe(versionPath)?.trim() ?? '0.0.0';\n}\n\nfunction printUpgradeSummary(result: ReconcileResult, projectVersion: string): void {\n header('Upgrade Complete');\n info(`\\nVersion: v${projectVersion} → v${VERSION}`);\n\n if (result.created.length > 0) {\n info('\\nCreated:');\n for (const file of result.created) listItem(file);\n }\n\n if (result.updated.length > 0) {\n info('\\nUpdated:');\n for (const file of result.updated) listItem(file);\n }\n\n if (result.packagesToRemove.length > 0) {\n warn(`\\n${result.packagesToRemove.length} package(s) are now bundled in eslint-plugin-safeword:`);\n for (const pkg of result.packagesToRemove) listItem(pkg);\n info(\"\\nIf you don't use these elsewhere, you can remove them:\");\n listItem(`npm uninstall ${result.packagesToRemove.join(' ')}`);\n }\n\n success(`\\nSafeword upgraded to v${VERSION}`);\n}\n\nexport async function upgrade(): Promise<void> {\n const cwd = process.cwd();\n const safewordDirectory = nodePath.join(cwd, '.safeword');\n\n if (!exists(safewordDirectory)) {\n error('Not configured. Run `safeword setup` first.');\n process.exit(1);\n }\n\n const projectVersion = getProjectVersion(safewordDirectory);\n\n if (compareVersions(VERSION, projectVersion) < 0) {\n error(`CLI v${VERSION} is older than project v${projectVersion}.`);\n error('Update the CLI first: npm install -g safeword');\n process.exit(1);\n }\n\n header('Safeword Upgrade');\n info(`Upgrading from v${projectVersion} to v${VERSION}`);\n\n try {\n const ctx = createProjectContext(cwd);\n const result = await reconcile(SAFEWORD_SCHEMA, 'upgrade', ctx);\n printUpgradeSummary(result, projectVersion);\n } catch (error_) {\n error(`Upgrade failed: ${error_ instanceof Error ? error_.message : 'Unknown error'}`);\n process.exit(1);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAMA,OAAO,cAAc;AAUrB,SAAS,kBAAkB,mBAAmC;AAC5D,QAAM,cAAc,SAAS,KAAK,mBAAmB,SAAS;AAC9D,SAAO,aAAa,WAAW,GAAG,KAAK,KAAK;AAC9C;AAEA,SAAS,oBAAoB,QAAyB,gBAA8B;AAClF,SAAO,kBAAkB;AACzB,OAAK;AAAA,YAAe,cAAc,YAAO,OAAO,EAAE;AAElD,MAAI,OAAO,QAAQ,SAAS,GAAG;AAC7B,SAAK,YAAY;AACjB,eAAW,QAAQ,OAAO,QAAS,UAAS,IAAI;AAAA,EAClD;AAEA,MAAI,OAAO,QAAQ,SAAS,GAAG;AAC7B,SAAK,YAAY;AACjB,eAAW,QAAQ,OAAO,QAAS,UAAS,IAAI;AAAA,EAClD;AAEA,MAAI,OAAO,iBAAiB,SAAS,GAAG;AACtC,SAAK;AAAA,EAAK,OAAO,iBAAiB,MAAM,wDAAwD;AAChG,eAAW,OAAO,OAAO,iBAAkB,UAAS,GAAG;AACvD,SAAK,0DAA0D;AAC/D,aAAS,iBAAiB,OAAO,iBAAiB,KAAK,GAAG,CAAC,EAAE;AAAA,EAC/D;AAEA,UAAQ;AAAA,wBAA2B,OAAO,EAAE;AAC9C;AAEA,eAAsB,UAAyB;AAC7C,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,oBAAoB,SAAS,KAAK,KAAK,WAAW;AAExD,MAAI,CAAC,OAAO,iBAAiB,GAAG;AAC9B,UAAM,6CAA6C;AACnD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,iBAAiB,kBAAkB,iBAAiB;AAE1D,MAAI,gBAAgB,SAAS,cAAc,IAAI,GAAG;AAChD,UAAM,QAAQ,OAAO,2BAA2B,cAAc,GAAG;AACjE,UAAM,+CAA+C;AACrD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO,kBAAkB;AACzB,OAAK,mBAAmB,cAAc,QAAQ,OAAO,EAAE;AAEvD,MAAI;AACF,UAAM,MAAM,qBAAqB,GAAG;AACpC,UAAM,SAAS,MAAM,UAAU,iBAAiB,WAAW,GAAG;AAC9D,wBAAoB,QAAQ,cAAc;AAAA,EAC5C,SAAS,QAAQ;AACf,UAAM,mBAAmB,kBAAkB,QAAQ,OAAO,UAAU,eAAe,EAAE;AACrF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "safeword",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "CLI for setting up and managing safeword development environments",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"@types/node": "^20.10.0",
|
|
39
39
|
"tsup": "^8.0.0",
|
|
40
40
|
"typescript": "^5.3.0",
|
|
41
|
-
"vitest": "^
|
|
41
|
+
"vitest": "^4.0.15"
|
|
42
42
|
},
|
|
43
43
|
"keywords": [
|
|
44
44
|
"cli",
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run comprehensive code audit for architecture and dead code
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Audit
|
|
6
|
+
|
|
7
|
+
Run a comprehensive code audit. Execute these commands and report results.
|
|
8
|
+
|
|
9
|
+
## Instructions
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# 1. Refresh config (detect current architecture)
|
|
13
|
+
npx safeword sync-config 2>&1
|
|
14
|
+
|
|
15
|
+
# 2. Architecture check (circular deps, layer violations)
|
|
16
|
+
npx depcruise --output-type err --config .dependency-cruiser.js . 2>&1 || true
|
|
17
|
+
|
|
18
|
+
# 3. Dead code check + auto-fix (unused exports, deps)
|
|
19
|
+
npx knip --fix 2>&1 || true
|
|
20
|
+
|
|
21
|
+
# 4. Outdated packages (informational)
|
|
22
|
+
npm outdated 2>&1 || true
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Report Format
|
|
26
|
+
|
|
27
|
+
After running, report in this format:
|
|
28
|
+
|
|
29
|
+
**Fixed:**
|
|
30
|
+
|
|
31
|
+
- [What knip auto-fixed - unused exports, dependencies]
|
|
32
|
+
|
|
33
|
+
**Errors (manual fix required):**
|
|
34
|
+
|
|
35
|
+
- [Circular dependencies - show the cycle path]
|
|
36
|
+
- [Layer violations - show the invalid import]
|
|
37
|
+
|
|
38
|
+
**Info:**
|
|
39
|
+
|
|
40
|
+
- [Unused files to review - may be intentional]
|
|
41
|
+
- [Outdated packages - optional to update]
|
|
@@ -17,10 +17,7 @@ npm run lint 2>&1 || true
|
|
|
17
17
|
# 2. Prettier - format all files
|
|
18
18
|
npm run format 2>&1 || true
|
|
19
19
|
|
|
20
|
-
# 3.
|
|
21
|
-
npm run lint:md 2>&1 || true
|
|
22
|
-
|
|
23
|
-
# 4. TypeScript type check (if tsconfig.json exists)
|
|
20
|
+
# 3. TypeScript type check (if tsconfig.json exists)
|
|
24
21
|
[ -f tsconfig.json ] && npx tsc --noEmit 2>&1 || true
|
|
25
22
|
```
|
|
26
23
|
|
|
@@ -37,16 +37,8 @@ case "$file" in
|
|
|
37
37
|
npx prettier --write "$file" 2>/dev/null
|
|
38
38
|
;;
|
|
39
39
|
|
|
40
|
-
# Markdown - markdownlint first, then Prettier
|
|
41
|
-
*.md)
|
|
42
|
-
if ! errors=$(npx markdownlint-cli2 --fix "$file" 2>&1); then
|
|
43
|
-
[ -n "$errors" ] && echo "$errors"
|
|
44
|
-
fi
|
|
45
|
-
npx prettier --write "$file" 2>/dev/null
|
|
46
|
-
;;
|
|
47
|
-
|
|
48
40
|
# Other supported formats - prettier only
|
|
49
|
-
*.json|*.css|*.scss|*.html|*.yaml|*.yml|*.graphql)
|
|
41
|
+
*.md|*.json|*.css|*.scss|*.html|*.yaml|*.yml|*.graphql)
|
|
50
42
|
npx prettier --write "$file" 2>/dev/null
|
|
51
43
|
;;
|
|
52
44
|
|
|
@@ -30,16 +30,8 @@ case "$file" in
|
|
|
30
30
|
npx prettier --write "$file" 2>/dev/null
|
|
31
31
|
;;
|
|
32
32
|
|
|
33
|
-
# Markdown - markdownlint first, then Prettier
|
|
34
|
-
*.md)
|
|
35
|
-
if ! errors=$(npx markdownlint-cli2 --fix "$file" 2>&1); then
|
|
36
|
-
[ -n "$errors" ] && echo "$errors"
|
|
37
|
-
fi
|
|
38
|
-
npx prettier --write "$file" 2>/dev/null
|
|
39
|
-
;;
|
|
40
|
-
|
|
41
33
|
# Other supported formats - prettier only
|
|
42
|
-
*.json|*.css|*.scss|*.html|*.yaml|*.yml|*.graphql)
|
|
34
|
+
*.md|*.json|*.css|*.scss|*.html|*.yaml|*.yml|*.graphql)
|
|
43
35
|
npx prettier --write "$file" 2>/dev/null
|
|
44
36
|
;;
|
|
45
37
|
|
|
@@ -34,7 +34,7 @@ Complete each phase before proceeding.
|
|
|
34
34
|
|
|
35
35
|
**BEFORE attempting ANY fix:**
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
#### 1. Read Error Messages Completely
|
|
38
38
|
|
|
39
39
|
```text
|
|
40
40
|
Don't skip past errors. They often contain the exact solution.
|
|
@@ -43,7 +43,7 @@ Don't skip past errors. They often contain the exact solution.
|
|
|
43
43
|
- Warnings that preceded the error
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
#### 2. Reproduce Consistently
|
|
47
47
|
|
|
48
48
|
| Can reproduce? | Action |
|
|
49
49
|
| --------------- | ---------------------------------------------------- |
|
|
@@ -51,7 +51,7 @@ Don't skip past errors. They often contain the exact solution.
|
|
|
51
51
|
| Sometimes | Gather more data - when does it happen vs not? |
|
|
52
52
|
| Never | Cannot debug what you cannot reproduce - gather logs |
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
#### 3. Check Recent Changes
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
57
|
git diff HEAD~5 # Recent code changes
|
|
@@ -60,7 +60,7 @@ git log --oneline -10 # Recent commits
|
|
|
60
60
|
|
|
61
61
|
What changed that could cause this? Dependencies? Config? Environment?
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
#### 4. Trace Data Flow (Root Cause Tracing)
|
|
64
64
|
|
|
65
65
|
When error is deep in call stack:
|
|
66
66
|
|
|
@@ -78,7 +78,7 @@ Symptom: Error at line 50 in utils.js
|
|
|
78
78
|
3. Trace up until you find the SOURCE
|
|
79
79
|
4. Fix at source, not at symptom
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
#### 5. Multi-Component Systems
|
|
82
82
|
|
|
83
83
|
When system has multiple layers (API → service → database):
|
|
84
84
|
|
|
@@ -93,11 +93,11 @@ Run once to find WHERE it breaks. Then investigate that layer.
|
|
|
93
93
|
|
|
94
94
|
### Phase 2: Pattern Analysis
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
#### 1. Find Working Examples
|
|
97
97
|
|
|
98
98
|
Locate similar working code in same codebase. What works that's similar?
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
#### 2. Identify Differences
|
|
101
101
|
|
|
102
102
|
| Working code | Broken code | Could this matter? |
|
|
103
103
|
| ---------------- | -------------- | ------------------ |
|
|
@@ -108,7 +108,7 @@ List ALL differences. Don't assume "that can't matter."
|
|
|
108
108
|
|
|
109
109
|
### Phase 3: Hypothesis Testing
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
#### 1. Form Single Hypothesis
|
|
112
112
|
|
|
113
113
|
Write it down: "I think X is the root cause because Y"
|
|
114
114
|
|
|
@@ -117,7 +117,7 @@ Be specific:
|
|
|
117
117
|
- ❌ "Something's wrong with the database"
|
|
118
118
|
- ✅ "Connection pool exhausted because connections aren't released in error path"
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
#### 2. Test Minimally
|
|
121
121
|
|
|
122
122
|
| Rule | Why |
|
|
123
123
|
| ------------------------ | ---------------------- |
|
|
@@ -125,7 +125,7 @@ Be specific:
|
|
|
125
125
|
| Smallest possible change | Avoid side effects |
|
|
126
126
|
| Don't bundle fixes | Can't tell what helped |
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
#### 3. Evaluate Result
|
|
129
129
|
|
|
130
130
|
| Result | Action |
|
|
131
131
|
| --------------- | --------------------------------------- |
|
|
@@ -135,7 +135,7 @@ Be specific:
|
|
|
135
135
|
|
|
136
136
|
### Phase 4: Implementation
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
#### 1. Create Failing Test
|
|
139
139
|
|
|
140
140
|
Before fixing, write test that fails due to the bug:
|
|
141
141
|
|
|
@@ -146,26 +146,26 @@ it('handles empty input without crashing', () => {
|
|
|
146
146
|
});
|
|
147
147
|
```
|
|
148
148
|
|
|
149
|
-
|
|
149
|
+
#### 2. Implement Fix
|
|
150
150
|
|
|
151
151
|
- Address ROOT CAUSE identified in Phase 1
|
|
152
152
|
- ONE change
|
|
153
153
|
- No "while I'm here" improvements
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
#### 3. Verify
|
|
156
156
|
|
|
157
157
|
- [ ] New test passes
|
|
158
158
|
- [ ] Existing tests still pass
|
|
159
159
|
- [ ] Issue actually resolved (not just test passing)
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
#### 4. If Fix Doesn't Work
|
|
162
162
|
|
|
163
163
|
| Fix attempts | Action |
|
|
164
164
|
| ------------ | ---------------------------------------- |
|
|
165
165
|
| 1-2 | Return to Phase 1 with new information |
|
|
166
166
|
| 3+ | STOP - Question architecture (see below) |
|
|
167
167
|
|
|
168
|
-
|
|
168
|
+
#### 5. After 3+ Failed Fixes: Question Architecture
|
|
169
169
|
|
|
170
170
|
Pattern indicating architectural problem:
|
|
171
171
|
|