davenov-cc 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +11 -1
  2. package/bin/cli.js +229 -10
  3. package/package.json +2 -3
  4. package/install.js +0 -144
package/README.md CHANGED
@@ -47,7 +47,17 @@ npx davenov-cc@latest
47
47
 
48
48
  The `@latest` tag ensures you get the newest version.
49
49
 
50
- ### Behavior with existing files
50
+ ## Uninstalling
51
+
52
+ To remove all davenov-cc customizations from `~/.claude/`:
53
+
54
+ ```bash
55
+ npx davenov-cc --uninstall
56
+ ```
57
+
58
+ This only removes files installed by this package - your other customizations remain untouched.
59
+
60
+ ## Behavior with existing files
51
61
 
52
62
  - **Merges directories** - Existing directories are preserved, not deleted
53
63
  - **Overwrites matching files** - Files with the same path get overwritten
package/bin/cli.js CHANGED
@@ -1,16 +1,235 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const path = require('path');
4
- const { spawn } = require('child_process');
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const os = require("os");
6
+ const readline = require("readline");
5
7
 
6
- // Run install.js from the package root with --auto-override
7
- const installScript = path.join(__dirname, '..', 'install.js');
8
+ const CLAUDE_DIR = path.join(os.homedir(), ".claude");
9
+ const SOURCE_DIR = path.join(__dirname, "..");
8
10
 
9
- const child = spawn(process.execPath, [installScript, '--auto-override'], {
10
- stdio: 'inherit',
11
- cwd: path.join(__dirname, '..')
12
- });
11
+ // Parse command line arguments
12
+ const args = process.argv.slice(2);
13
+ const AUTO_OVERRIDE = args.includes("--auto-override");
14
+ const UNINSTALL = args.includes("--uninstall");
15
+
16
+ // Directories to install/uninstall
17
+ const CUSTOMIZATION_DIRS = ["commands", "skills"];
18
+
19
+ // Files/folders installed by this package (for uninstall)
20
+ const INSTALLED_ITEMS = {
21
+ commands: ["davenov:cc:interview.md", "davenov:cc:rule.md", "davenov:cc:update.md"],
22
+ skills: [
23
+ "davenov:cc:expert-convex-nextjs",
24
+ "davenov:cc:expert-evolu-nextjs",
25
+ "davenov:cc:expert-nextjs-16",
26
+ "davenov:cc:expert-build-nostr"
27
+ ]
28
+ };
29
+
30
+ function createReadlineInterface() {
31
+ return readline.createInterface({
32
+ input: process.stdin,
33
+ output: process.stdout,
34
+ });
35
+ }
36
+
37
+ async function prompt(rl, question) {
38
+ return new Promise((resolve) => {
39
+ rl.question(question, resolve);
40
+ });
41
+ }
42
+
43
+ function copyRecursive(src, dest) {
44
+ const stats = fs.statSync(src);
45
+
46
+ if (stats.isDirectory()) {
47
+ if (!fs.existsSync(dest)) {
48
+ fs.mkdirSync(dest, { recursive: true });
49
+ }
50
+
51
+ const entries = fs.readdirSync(src);
52
+ for (const entry of entries) {
53
+ copyRecursive(path.join(src, entry), path.join(dest, entry));
54
+ }
55
+ } else {
56
+ fs.copyFileSync(src, dest);
57
+ }
58
+ }
59
+
60
+ function countFiles(dir) {
61
+ let count = 0;
62
+ if (!fs.existsSync(dir)) return 0;
63
+
64
+ const entries = fs.readdirSync(dir);
65
+ for (const entry of entries) {
66
+ const fullPath = path.join(dir, entry);
67
+ const stats = fs.statSync(fullPath);
68
+ if (stats.isDirectory()) {
69
+ count += countFiles(fullPath);
70
+ } else {
71
+ count++;
72
+ }
73
+ }
74
+ return count;
75
+ }
76
+
77
+ function removeRecursive(target) {
78
+ if (!fs.existsSync(target)) return false;
79
+
80
+ const stats = fs.statSync(target);
81
+ if (stats.isDirectory()) {
82
+ fs.rmSync(target, { recursive: true, force: true });
83
+ } else {
84
+ fs.unlinkSync(target);
85
+ }
86
+ return true;
87
+ }
88
+
89
+ async function uninstall(rl) {
90
+ console.log("\nšŸ—‘ļø Claude Code Customizations Uninstaller\n");
91
+ console.log(`Target: ${CLAUDE_DIR}\n`);
92
+
93
+ // Check what's installed
94
+ const installed = [];
95
+ for (const [dir, items] of Object.entries(INSTALLED_ITEMS)) {
96
+ for (const item of items) {
97
+ const fullPath = path.join(CLAUDE_DIR, dir, item);
98
+ if (fs.existsSync(fullPath)) {
99
+ installed.push({ dir, item, fullPath });
100
+ }
101
+ }
102
+ }
103
+
104
+ if (installed.length === 0) {
105
+ console.log("No davenov-cc customizations found to uninstall.");
106
+ return;
107
+ }
108
+
109
+ console.log("Found installed customizations:");
110
+ for (const { dir, item } of installed) {
111
+ console.log(` - ${dir}/${item}`);
112
+ }
113
+ console.log();
114
+
115
+ if (!AUTO_OVERRIDE) {
116
+ const answer = await prompt(
117
+ rl,
118
+ "Do you want to remove these customizations? (y/N): "
119
+ );
120
+
121
+ if (answer.toLowerCase() !== "y") {
122
+ console.log("\nUninstall cancelled.");
123
+ return;
124
+ }
125
+ } else {
126
+ console.log("Auto-override enabled, proceeding...");
127
+ }
128
+
129
+ console.log("\nRemoving...\n");
130
+
131
+ let removed = 0;
132
+ for (const { dir, item, fullPath } of installed) {
133
+ if (removeRecursive(fullPath)) {
134
+ console.log(` āœ“ ${dir}/${item}`);
135
+ removed++;
136
+ }
137
+ }
138
+
139
+ console.log(`\nāœ… Uninstall complete! Removed ${removed} item(s).\n`);
140
+ }
141
+
142
+ async function install(rl) {
143
+ console.log("\nšŸ“¦ Claude Code Customizations Installer\n");
144
+ console.log(`Source: ${SOURCE_DIR}`);
145
+ console.log(`Target: ${CLAUDE_DIR}\n`);
146
+
147
+ // Check what we have to install
148
+ const available = CUSTOMIZATION_DIRS.filter((dir) =>
149
+ fs.existsSync(path.join(SOURCE_DIR, dir))
150
+ );
151
+
152
+ if (available.length === 0) {
153
+ console.log("No customizations found to install.");
154
+ process.exit(0);
155
+ }
156
+
157
+ console.log("Available customizations:");
158
+ for (const dir of available) {
159
+ const srcPath = path.join(SOURCE_DIR, dir);
160
+ const fileCount = countFiles(srcPath);
161
+ console.log(` - ${dir}/ (${fileCount} files)`);
162
+ }
163
+ console.log();
164
+
165
+ // Check for existing files
166
+ const existing = available.filter((dir) =>
167
+ fs.existsSync(path.join(CLAUDE_DIR, dir))
168
+ );
169
+
170
+ if (existing.length > 0) {
171
+ console.log("āš ļø The following directories already exist:");
172
+ for (const dir of existing) {
173
+ console.log(` - ${path.join(CLAUDE_DIR, dir)}`);
174
+ }
175
+ console.log();
176
+
177
+ if (AUTO_OVERRIDE) {
178
+ console.log("Auto-override enabled, proceeding...");
179
+ } else {
180
+ const answer = await prompt(
181
+ rl,
182
+ "Do you want to overwrite existing files? (y/N): "
183
+ );
184
+
185
+ if (answer.toLowerCase() !== "y") {
186
+ console.log("\nInstallation cancelled.");
187
+ rl.close();
188
+ process.exit(0);
189
+ }
190
+ }
191
+ }
192
+
193
+ // Ensure .claude directory exists
194
+ if (!fs.existsSync(CLAUDE_DIR)) {
195
+ fs.mkdirSync(CLAUDE_DIR, { recursive: true });
196
+ console.log(`Created ${CLAUDE_DIR}`);
197
+ }
198
+
199
+ // Install each directory
200
+ console.log("\nInstalling...\n");
201
+
202
+ for (const dir of available) {
203
+ const srcPath = path.join(SOURCE_DIR, dir);
204
+ const destPath = path.join(CLAUDE_DIR, dir);
205
+
206
+ console.log(` ${dir}/`);
207
+ copyRecursive(srcPath, destPath);
208
+ }
209
+
210
+ console.log("\nāœ… Installation complete!\n");
211
+ console.log("Your customizations are now available in Claude Code.");
212
+ }
213
+
214
+ async function main() {
215
+ const rl = createReadlineInterface();
216
+
217
+ try {
218
+ if (UNINSTALL) {
219
+ await uninstall(rl);
220
+ } else {
221
+ // Default to auto-override when run via npx (no TTY interaction expected)
222
+ if (!process.stdin.isTTY && !AUTO_OVERRIDE) {
223
+ args.push("--auto-override");
224
+ }
225
+ await install(rl);
226
+ }
227
+ } finally {
228
+ rl.close();
229
+ }
230
+ }
13
231
 
14
- child.on('close', (code) => {
15
- process.exit(code);
232
+ main().catch((err) => {
233
+ console.error("Error:", err.message);
234
+ process.exit(1);
16
235
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "davenov-cc",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Claude Code customizations - skills and slash commands for enhanced AI-assisted development",
5
5
  "bin": {
6
6
  "davenov-cc": "./bin/cli.js"
@@ -29,7 +29,6 @@
29
29
  "files": [
30
30
  "bin/",
31
31
  "commands/",
32
- "skills/",
33
- "install.js"
32
+ "skills/"
34
33
  ]
35
34
  }
package/install.js DELETED
@@ -1,144 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const fs = require("fs");
4
- const path = require("path");
5
- const os = require("os");
6
- const readline = require("readline");
7
-
8
- const CLAUDE_DIR = path.join(os.homedir(), ".claude");
9
- const SOURCE_DIR = __dirname;
10
-
11
- // Parse command line arguments
12
- const args = process.argv.slice(2);
13
- const AUTO_OVERRIDE = args.includes("--auto-override");
14
-
15
- // Directories to install
16
- const CUSTOMIZATION_DIRS = ["commands", "skills"];
17
-
18
- function createReadlineInterface() {
19
- return readline.createInterface({
20
- input: process.stdin,
21
- output: process.stdout,
22
- });
23
- }
24
-
25
- async function prompt(rl, question) {
26
- return new Promise((resolve) => {
27
- rl.question(question, resolve);
28
- });
29
- }
30
-
31
- function copyRecursive(src, dest) {
32
- const stats = fs.statSync(src);
33
-
34
- if (stats.isDirectory()) {
35
- if (!fs.existsSync(dest)) {
36
- fs.mkdirSync(dest, { recursive: true });
37
- }
38
-
39
- const entries = fs.readdirSync(src);
40
- for (const entry of entries) {
41
- copyRecursive(path.join(src, entry), path.join(dest, entry));
42
- }
43
- } else {
44
- fs.copyFileSync(src, dest);
45
- }
46
- }
47
-
48
- function countFiles(dir) {
49
- let count = 0;
50
- if (!fs.existsSync(dir)) return 0;
51
-
52
- const entries = fs.readdirSync(dir);
53
- for (const entry of entries) {
54
- const fullPath = path.join(dir, entry);
55
- const stats = fs.statSync(fullPath);
56
- if (stats.isDirectory()) {
57
- count += countFiles(fullPath);
58
- } else {
59
- count++;
60
- }
61
- }
62
- return count;
63
- }
64
-
65
- async function main() {
66
- console.log("\nšŸ“¦ Claude Code Customizations Installer\n");
67
- console.log(`Source: ${SOURCE_DIR}`);
68
- console.log(`Target: ${CLAUDE_DIR}\n`);
69
-
70
- // Check what we have to install
71
- const available = CUSTOMIZATION_DIRS.filter((dir) =>
72
- fs.existsSync(path.join(SOURCE_DIR, dir))
73
- );
74
-
75
- if (available.length === 0) {
76
- console.log("No customizations found to install.");
77
- process.exit(0);
78
- }
79
-
80
- console.log("Available customizations:");
81
- for (const dir of available) {
82
- const srcPath = path.join(SOURCE_DIR, dir);
83
- const fileCount = countFiles(srcPath);
84
- console.log(` - ${dir}/ (${fileCount} files)`);
85
- }
86
- console.log();
87
-
88
- // Check for existing files
89
- const existing = available.filter((dir) =>
90
- fs.existsSync(path.join(CLAUDE_DIR, dir))
91
- );
92
-
93
- const rl = createReadlineInterface();
94
-
95
- if (existing.length > 0) {
96
- console.log("āš ļø The following directories already exist:");
97
- for (const dir of existing) {
98
- console.log(` - ${path.join(CLAUDE_DIR, dir)}`);
99
- }
100
- console.log();
101
-
102
- if (AUTO_OVERRIDE) {
103
- console.log("Auto-override enabled, proceeding...");
104
- } else {
105
- const answer = await prompt(
106
- rl,
107
- "Do you want to overwrite existing files? (y/N): "
108
- );
109
-
110
- if (answer.toLowerCase() !== "y") {
111
- console.log("\nInstallation cancelled.");
112
- rl.close();
113
- process.exit(0);
114
- }
115
- }
116
- }
117
-
118
- // Ensure .claude directory exists
119
- if (!fs.existsSync(CLAUDE_DIR)) {
120
- fs.mkdirSync(CLAUDE_DIR, { recursive: true });
121
- console.log(`Created ${CLAUDE_DIR}`);
122
- }
123
-
124
- // Install each directory
125
- console.log("\nInstalling...\n");
126
-
127
- for (const dir of available) {
128
- const srcPath = path.join(SOURCE_DIR, dir);
129
- const destPath = path.join(CLAUDE_DIR, dir);
130
-
131
- console.log(` ${dir}/`);
132
- copyRecursive(srcPath, destPath);
133
- }
134
-
135
- console.log("\nāœ… Installation complete!\n");
136
- console.log("Your customizations are now available in Claude Code.");
137
-
138
- rl.close();
139
- }
140
-
141
- main().catch((err) => {
142
- console.error("Error:", err.message);
143
- process.exit(1);
144
- });