wtf-p 0.1.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.
Files changed (92) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +338 -0
  3. package/bin/install.js +358 -0
  4. package/bin/uninstall.js +485 -0
  5. package/commands/wtfp/analyze-bib.md +326 -0
  6. package/commands/wtfp/check-refs.md +205 -0
  7. package/commands/wtfp/create-outline.md +275 -0
  8. package/commands/wtfp/discuss-section.md +71 -0
  9. package/commands/wtfp/export-latex.md +216 -0
  10. package/commands/wtfp/help.md +342 -0
  11. package/commands/wtfp/insert-section.md +130 -0
  12. package/commands/wtfp/list-assumptions.md +109 -0
  13. package/commands/wtfp/map-project.md +197 -0
  14. package/commands/wtfp/new-paper.md +443 -0
  15. package/commands/wtfp/pause-writing.md +145 -0
  16. package/commands/wtfp/plan-revision.md +180 -0
  17. package/commands/wtfp/plan-section.md +247 -0
  18. package/commands/wtfp/polish-prose.md +177 -0
  19. package/commands/wtfp/progress.md +325 -0
  20. package/commands/wtfp/remove-section.md +147 -0
  21. package/commands/wtfp/research-gap.md +235 -0
  22. package/commands/wtfp/resume-writing.md +142 -0
  23. package/commands/wtfp/review-section.md +409 -0
  24. package/commands/wtfp/submit-milestone.md +211 -0
  25. package/commands/wtfp/write-section.md +273 -0
  26. package/package.json +40 -0
  27. package/write-the-f-paper/references/checkpoints.md +213 -0
  28. package/write-the-f-paper/references/continuation-format.md +223 -0
  29. package/write-the-f-paper/references/git-integration.md +241 -0
  30. package/write-the-f-paper/references/imrad-structure.md +212 -0
  31. package/write-the-f-paper/references/length-estimation.md +148 -0
  32. package/write-the-f-paper/references/plan-format.md +361 -0
  33. package/write-the-f-paper/references/principles.md +158 -0
  34. package/write-the-f-paper/references/questioning.md +132 -0
  35. package/write-the-f-paper/references/research-pitfalls.md +208 -0
  36. package/write-the-f-paper/templates/config.json +30 -0
  37. package/write-the-f-paper/templates/context.md +179 -0
  38. package/write-the-f-paper/templates/continue-here.md +142 -0
  39. package/write-the-f-paper/templates/data-inventory.md +142 -0
  40. package/write-the-f-paper/templates/discovery.md +146 -0
  41. package/write-the-f-paper/templates/issues.md +59 -0
  42. package/write-the-f-paper/templates/manuscript.md +253 -0
  43. package/write-the-f-paper/templates/narrative-arc.md +227 -0
  44. package/write-the-f-paper/templates/outline.md +274 -0
  45. package/write-the-f-paper/templates/phase-prompt.md +348 -0
  46. package/write-the-f-paper/templates/prior-drafts.md +204 -0
  47. package/write-the-f-paper/templates/project-context/argument-structure.md +267 -0
  48. package/write-the-f-paper/templates/project-context/bibliography.md +152 -0
  49. package/write-the-f-paper/templates/project-context/gaps.md +122 -0
  50. package/write-the-f-paper/templates/project-context/imrad.md +140 -0
  51. package/write-the-f-paper/templates/project-context/peer-review.md +152 -0
  52. package/write-the-f-paper/templates/project-context/style-guide.md +198 -0
  53. package/write-the-f-paper/templates/project-context/tools.md +170 -0
  54. package/write-the-f-paper/templates/project.md +185 -0
  55. package/write-the-f-paper/templates/research.md +384 -0
  56. package/write-the-f-paper/templates/review-comments.md +253 -0
  57. package/write-the-f-paper/templates/revision-issues.md +169 -0
  58. package/write-the-f-paper/templates/roadmap.md +187 -0
  59. package/write-the-f-paper/templates/section-archive.md +178 -0
  60. package/write-the-f-paper/templates/section-context.md +114 -0
  61. package/write-the-f-paper/templates/section.md +128 -0
  62. package/write-the-f-paper/templates/state.md +244 -0
  63. package/write-the-f-paper/templates/summary.md +277 -0
  64. package/write-the-f-paper/venues/acm-cs.yaml +102 -0
  65. package/write-the-f-paper/venues/arxiv-ml.yaml +103 -0
  66. package/write-the-f-paper/venues/ieee-cs.yaml +100 -0
  67. package/write-the-f-paper/venues/nature.yaml +81 -0
  68. package/write-the-f-paper/venues/thesis-chapter.yaml +101 -0
  69. package/write-the-f-paper/workflows/create-outline.md +462 -0
  70. package/write-the-f-paper/workflows/create-outline.wcn.md +194 -0
  71. package/write-the-f-paper/workflows/discuss-section.md +249 -0
  72. package/write-the-f-paper/workflows/discuss-section.wcn.md +63 -0
  73. package/write-the-f-paper/workflows/execute-section.md +704 -0
  74. package/write-the-f-paper/workflows/execute-section.wcn.md +219 -0
  75. package/write-the-f-paper/workflows/list-assumptions.md +183 -0
  76. package/write-the-f-paper/workflows/list-assumptions.wcn.md +42 -0
  77. package/write-the-f-paper/workflows/lit-review-phase.md +281 -0
  78. package/write-the-f-paper/workflows/lit-review-phase.wcn.md +92 -0
  79. package/write-the-f-paper/workflows/map-project.md +359 -0
  80. package/write-the-f-paper/workflows/map-project.wcn.md +73 -0
  81. package/write-the-f-paper/workflows/plan-section.md +409 -0
  82. package/write-the-f-paper/workflows/plan-section.wcn.md +236 -0
  83. package/write-the-f-paper/workflows/research-gap.md +469 -0
  84. package/write-the-f-paper/workflows/research-gap.wcn.md +119 -0
  85. package/write-the-f-paper/workflows/resume-paper.md +274 -0
  86. package/write-the-f-paper/workflows/resume-paper.wcn.md +93 -0
  87. package/write-the-f-paper/workflows/review-section.md +329 -0
  88. package/write-the-f-paper/workflows/review-section.wcn.md +91 -0
  89. package/write-the-f-paper/workflows/submit-draft.md +368 -0
  90. package/write-the-f-paper/workflows/submit-draft.wcn.md +69 -0
  91. package/write-the-f-paper/workflows/transition.md +375 -0
  92. package/write-the-f-paper/workflows/transition.wcn.md +113 -0
@@ -0,0 +1,485 @@
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
+ // Colors
9
+ const cyan = '\x1b[36m';
10
+ const green = '\x1b[32m';
11
+ const yellow = '\x1b[33m';
12
+ const red = '\x1b[31m';
13
+ const magenta = '\x1b[35m';
14
+ const dim = '\x1b[2m';
15
+ const reset = '\x1b[0m';
16
+
17
+ // Get version from package.json
18
+ let version = 'unknown';
19
+ try {
20
+ const pkg = require('../package.json');
21
+ version = pkg.version;
22
+ } catch {
23
+ // Running standalone
24
+ }
25
+
26
+ const banner = `
27
+ ${magenta}██╗ ██╗████████╗███████╗ ██████╗
28
+ ██║ ██║╚══██╔══╝██╔════╝ ██╔══██╗
29
+ ██║ █╗ ██║ ██║ █████╗ █████╗██████╔╝
30
+ ██║███╗██║ ██║ ██╔══╝ ╚════╝██╔═══╝
31
+ ╚███╔███╔╝ ██║ ██║ ██║
32
+ ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝${reset}
33
+
34
+ ${cyan}WTF-P Uninstaller${reset} ${dim}v${version}${reset}
35
+ `;
36
+
37
+ // Parse args
38
+ const args = process.argv.slice(2);
39
+ const hasGlobal = args.includes('--global') || args.includes('-g');
40
+ const hasLocal = args.includes('--local') || args.includes('-l');
41
+ const hasForce = args.includes('--force') || args.includes('-f');
42
+ const hasBackup = args.includes('--backup') || args.includes('-b');
43
+ const hasDryRun = args.includes('--dry-run') || args.includes('-n');
44
+ const hasCleanBackups = args.includes('--clean-backups');
45
+
46
+ // Parse --config-dir argument
47
+ function parseConfigDirArg() {
48
+ const configDirIndex = args.findIndex(arg => arg === '--config-dir' || arg === '-c');
49
+ if (configDirIndex !== -1) {
50
+ const nextArg = args[configDirIndex + 1];
51
+ if (!nextArg || nextArg.startsWith('-')) {
52
+ console.error(` ${yellow}--config-dir requires a path argument${reset}`);
53
+ process.exit(1);
54
+ }
55
+ return nextArg;
56
+ }
57
+ const configDirArg = args.find(arg => arg.startsWith('--config-dir=') || arg.startsWith('-c='));
58
+ if (configDirArg) {
59
+ return configDirArg.split('=')[1];
60
+ }
61
+ return null;
62
+ }
63
+ const explicitConfigDir = parseConfigDirArg();
64
+ const hasHelp = args.includes('--help') || args.includes('-h');
65
+
66
+ console.log(banner);
67
+
68
+ // Show help if requested
69
+ if (hasHelp) {
70
+ console.log(` ${yellow}Usage:${reset} npx wtf-p-uninstall [options]
71
+
72
+ ${yellow}Options:${reset}
73
+ ${cyan}-g, --global${reset} Uninstall from Claude config directory
74
+ ${cyan}-l, --local${reset} Uninstall from ./.claude in current directory
75
+ ${cyan}-c, --config-dir <path>${reset} Specify custom Claude config directory
76
+ ${cyan}-f, --force${reset} Skip confirmation prompts
77
+ ${cyan}-b, --backup${reset} Backup files before removing
78
+ ${cyan}-n, --dry-run${reset} Show what would be removed without removing
79
+ ${cyan}--clean-backups${reset} Also remove .backup-* files from prior installs
80
+ ${cyan}-h, --help${reset} Show this help message
81
+
82
+ ${yellow}What gets removed:${reset}
83
+ ${dim}commands/wtfp/${reset} - WTF-P slash commands
84
+ ${dim}write-the-f-paper/${reset} - WTF-P skill and workflows
85
+
86
+ ${yellow}What stays intact:${reset}
87
+ ${dim}CLAUDE.md${reset} - Your personal instructions (never touched)
88
+ ${dim}commands/${reset} - Other slash commands you may have
89
+ ${dim}settings.json${reset} - Your Claude settings
90
+ ${dim}Other directories${reset} - Any other config or plugins
91
+
92
+ ${yellow}Examples:${reset}
93
+ ${dim}# Interactive uninstall from ~/.claude${reset}
94
+ npx wtf-p-uninstall --global
95
+
96
+ ${dim}# Preview what would be removed${reset}
97
+ npx wtf-p-uninstall --global --dry-run
98
+
99
+ ${dim}# Backup before removing${reset}
100
+ npx wtf-p-uninstall --global --backup
101
+
102
+ ${dim}# Also clean up backup files from prior installs${reset}
103
+ npx wtf-p-uninstall --global --clean-backups
104
+
105
+ ${dim}# Uninstall from custom location${reset}
106
+ npx wtf-p-uninstall --global --config-dir ~/.claude-research
107
+ `);
108
+ process.exit(0);
109
+ }
110
+
111
+ /**
112
+ * Expand ~ to home directory
113
+ */
114
+ function expandTilde(filePath) {
115
+ if (filePath && filePath.startsWith('~/')) {
116
+ return path.join(os.homedir(), filePath.slice(2));
117
+ }
118
+ return filePath;
119
+ }
120
+
121
+ /**
122
+ * Create readline interface for prompts
123
+ */
124
+ function createRL() {
125
+ return readline.createInterface({
126
+ input: process.stdin,
127
+ output: process.stdout
128
+ });
129
+ }
130
+
131
+ /**
132
+ * Prompt user with a question
133
+ */
134
+ function prompt(rl, question) {
135
+ return new Promise(resolve => {
136
+ rl.question(question, answer => resolve(answer.trim().toLowerCase()));
137
+ });
138
+ }
139
+
140
+ /**
141
+ * Generate backup directory path with timestamp
142
+ */
143
+ function getBackupDir(claudeDir) {
144
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
145
+ return path.join(claudeDir, `.wtfp-backup-${timestamp}`);
146
+ }
147
+
148
+ /**
149
+ * Recursively collect all files in a directory
150
+ */
151
+ function collectFiles(dir, files = []) {
152
+ if (!fs.existsSync(dir)) return files;
153
+
154
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
155
+ for (const entry of entries) {
156
+ const fullPath = path.join(dir, entry.name);
157
+ if (entry.isDirectory()) {
158
+ collectFiles(fullPath, files);
159
+ } else {
160
+ files.push(fullPath);
161
+ }
162
+ }
163
+ return files;
164
+ }
165
+
166
+ /**
167
+ * Recursively remove directory
168
+ */
169
+ function removeDir(dir) {
170
+ if (!fs.existsSync(dir)) return;
171
+ fs.rmSync(dir, { recursive: true, force: true });
172
+ }
173
+
174
+ /**
175
+ * Copy directory recursively
176
+ */
177
+ function copyDir(src, dest) {
178
+ fs.mkdirSync(dest, { recursive: true });
179
+ const entries = fs.readdirSync(src, { withFileTypes: true });
180
+ for (const entry of entries) {
181
+ const srcPath = path.join(src, entry.name);
182
+ const destPath = path.join(dest, entry.name);
183
+ if (entry.isDirectory()) {
184
+ copyDir(srcPath, destPath);
185
+ } else {
186
+ fs.copyFileSync(srcPath, destPath);
187
+ }
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Find backup files in a directory
193
+ */
194
+ function findBackupFiles(dir, backups = []) {
195
+ if (!fs.existsSync(dir)) return backups;
196
+
197
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
198
+ for (const entry of entries) {
199
+ const fullPath = path.join(dir, entry.name);
200
+ if (entry.isDirectory()) {
201
+ // Check for .wtfp-backup-* directories
202
+ if (entry.name.startsWith('.wtfp-backup-')) {
203
+ backups.push(fullPath);
204
+ } else {
205
+ findBackupFiles(fullPath, backups);
206
+ }
207
+ } else if (entry.name.includes('.backup-')) {
208
+ backups.push(fullPath);
209
+ }
210
+ }
211
+ return backups;
212
+ }
213
+
214
+ /**
215
+ * Detect what's installed
216
+ */
217
+ function detectInstallation(claudeDir) {
218
+ const wtfpCommands = path.join(claudeDir, 'commands', 'wtfp');
219
+ const wtfpSkill = path.join(claudeDir, 'write-the-f-paper');
220
+
221
+ const installed = {
222
+ commands: fs.existsSync(wtfpCommands) ? wtfpCommands : null,
223
+ skill: fs.existsSync(wtfpSkill) ? wtfpSkill : null,
224
+ commandFiles: [],
225
+ skillFiles: []
226
+ };
227
+
228
+ if (installed.commands) {
229
+ installed.commandFiles = collectFiles(installed.commands);
230
+ }
231
+ if (installed.skill) {
232
+ installed.skillFiles = collectFiles(installed.skill);
233
+ }
234
+
235
+ return installed;
236
+ }
237
+
238
+ /**
239
+ * Uninstall from the specified directory
240
+ */
241
+ async function uninstall(isGlobal) {
242
+ const configDir = expandTilde(explicitConfigDir) || expandTilde(process.env.CLAUDE_CONFIG_DIR);
243
+ const defaultGlobalDir = configDir || path.join(os.homedir(), '.claude');
244
+ const claudeDir = isGlobal
245
+ ? defaultGlobalDir
246
+ : path.join(process.cwd(), '.claude');
247
+
248
+ const locationLabel = isGlobal
249
+ ? claudeDir.replace(os.homedir(), '~')
250
+ : claudeDir.replace(process.cwd(), '.');
251
+
252
+ console.log(` Checking ${cyan}${locationLabel}${reset} for WTF-P installation...\n`);
253
+
254
+ // Detect installation
255
+ const installed = detectInstallation(claudeDir);
256
+ const totalFiles = installed.commandFiles.length + installed.skillFiles.length;
257
+
258
+ if (!installed.commands && !installed.skill) {
259
+ console.log(` ${yellow}No WTF-P installation found in ${locationLabel}${reset}\n`);
260
+
261
+ // Check for backups if requested
262
+ if (hasCleanBackups) {
263
+ const backups = findBackupFiles(claudeDir);
264
+ if (backups.length > 0) {
265
+ console.log(` Found ${backups.length} backup file(s)/folder(s) to clean:\n`);
266
+ for (const b of backups.slice(0, 10)) {
267
+ console.log(` ${dim}${b.replace(claudeDir, '.')}${reset}`);
268
+ }
269
+ if (backups.length > 10) {
270
+ console.log(` ${dim}... and ${backups.length - 10} more${reset}`);
271
+ }
272
+ console.log();
273
+
274
+ if (!hasDryRun && !hasForce) {
275
+ const rl = createRL();
276
+ const answer = await prompt(rl, ` Remove these backup files? [y/N]: `);
277
+ rl.close();
278
+ if (answer !== 'y' && answer !== 'yes') {
279
+ console.log(`\n ${yellow}Aborted.${reset}\n`);
280
+ return;
281
+ }
282
+ }
283
+
284
+ if (!hasDryRun) {
285
+ for (const b of backups) {
286
+ if (fs.statSync(b).isDirectory()) {
287
+ removeDir(b);
288
+ } else {
289
+ fs.unlinkSync(b);
290
+ }
291
+ console.log(` ${red}-${reset} ${dim}${b.replace(claudeDir, '.')}${reset}`);
292
+ }
293
+ console.log(`\n ${green}Cleaned ${backups.length} backup file(s).${reset}\n`);
294
+ } else {
295
+ console.log(` ${yellow}Dry run: would remove ${backups.length} backup file(s).${reset}\n`);
296
+ }
297
+ } else {
298
+ console.log(` No backup files found.\n`);
299
+ }
300
+ }
301
+ return;
302
+ }
303
+
304
+ // Show what will be removed
305
+ console.log(` ${yellow}Found WTF-P installation:${reset}\n`);
306
+
307
+ if (installed.commands) {
308
+ console.log(` ${cyan}commands/wtfp/${reset} (${installed.commandFiles.length} files)`);
309
+ }
310
+ if (installed.skill) {
311
+ console.log(` ${cyan}write-the-f-paper/${reset} (${installed.skillFiles.length} files)`);
312
+ }
313
+ console.log();
314
+
315
+ // Check for backups to clean (only outside wtfp directories since those get removed anyway)
316
+ let backups = [];
317
+ if (hasCleanBackups) {
318
+ const allBackups = findBackupFiles(claudeDir);
319
+ // Filter out backups inside directories we're already removing
320
+ backups = allBackups.filter(b => {
321
+ if (installed.commands && b.startsWith(installed.commands)) return false;
322
+ if (installed.skill && b.startsWith(installed.skill)) return false;
323
+ return true;
324
+ });
325
+ if (backups.length > 0) {
326
+ console.log(` ${dim}+ ${backups.length} backup file(s) outside wtfp dirs will also be removed${reset}\n`);
327
+ }
328
+ }
329
+
330
+ // Dry run stops here
331
+ if (hasDryRun) {
332
+ console.log(` ${yellow}Dry run: would remove ${totalFiles} file(s) in 2 directories.${reset}\n`);
333
+ return;
334
+ }
335
+
336
+ // Confirm unless --force
337
+ if (!hasForce) {
338
+ const rl = createRL();
339
+ const answer = await prompt(rl, ` Remove ${totalFiles} file(s)? [y/N]: `);
340
+ rl.close();
341
+
342
+ if (answer !== 'y' && answer !== 'yes') {
343
+ console.log(`\n ${yellow}Aborted.${reset}\n`);
344
+ return;
345
+ }
346
+ console.log();
347
+ }
348
+
349
+ // Backup if requested
350
+ if (hasBackup) {
351
+ const backupDir = getBackupDir(claudeDir);
352
+ fs.mkdirSync(backupDir, { recursive: true });
353
+
354
+ if (installed.commands) {
355
+ const dest = path.join(backupDir, 'commands', 'wtfp');
356
+ copyDir(installed.commands, dest);
357
+ }
358
+ if (installed.skill) {
359
+ const dest = path.join(backupDir, 'write-the-f-paper');
360
+ copyDir(installed.skill, dest);
361
+ }
362
+
363
+ const backupLabel = backupDir.replace(os.homedir(), '~').replace(process.cwd(), '.');
364
+ console.log(` ${cyan}↻${reset} Backed up to ${dim}${backupLabel}${reset}\n`);
365
+ }
366
+
367
+ // Remove directories
368
+ if (installed.commands) {
369
+ removeDir(installed.commands);
370
+ console.log(` ${red}-${reset} ${dim}commands/wtfp/${reset}`);
371
+
372
+ // Clean up empty commands dir
373
+ const commandsDir = path.join(claudeDir, 'commands');
374
+ if (fs.existsSync(commandsDir)) {
375
+ const remaining = fs.readdirSync(commandsDir);
376
+ if (remaining.length === 0) {
377
+ fs.rmdirSync(commandsDir);
378
+ console.log(` ${red}-${reset} ${dim}commands/${reset} ${dim}(empty)${reset}`);
379
+ }
380
+ }
381
+ }
382
+
383
+ if (installed.skill) {
384
+ removeDir(installed.skill);
385
+ console.log(` ${red}-${reset} ${dim}write-the-f-paper/${reset}`);
386
+ }
387
+
388
+ // Clean backups if requested
389
+ if (hasCleanBackups && backups.length > 0) {
390
+ for (const b of backups) {
391
+ if (fs.statSync(b).isDirectory()) {
392
+ removeDir(b);
393
+ } else {
394
+ fs.unlinkSync(b);
395
+ }
396
+ }
397
+ console.log(` ${red}-${reset} ${dim}${backups.length} backup file(s)${reset}`);
398
+ }
399
+
400
+ console.log(`
401
+ ${green}Done!${reset} WTF-P has been uninstalled.
402
+
403
+ ${dim}Your CLAUDE.md and other configs remain untouched.${reset}
404
+
405
+ To reinstall: ${cyan}npx wtf-p --global${reset}
406
+ `);
407
+ }
408
+
409
+ /**
410
+ * Prompt for uninstall location
411
+ */
412
+ async function promptLocation() {
413
+ const rl = createRL();
414
+
415
+ const configDir = expandTilde(explicitConfigDir) || expandTilde(process.env.CLAUDE_CONFIG_DIR);
416
+ const globalPath = configDir || path.join(os.homedir(), '.claude');
417
+ const globalLabel = globalPath.replace(os.homedir(), '~');
418
+ const localPath = path.join(process.cwd(), '.claude');
419
+
420
+ // Check what's installed where
421
+ const globalInstalled = detectInstallation(globalPath);
422
+ const localInstalled = detectInstallation(localPath);
423
+
424
+ const hasGlobalInstall = globalInstalled.commands || globalInstalled.skill;
425
+ const hasLocalInstall = localInstalled.commands || localInstalled.skill;
426
+
427
+ if (!hasGlobalInstall && !hasLocalInstall) {
428
+ console.log(` ${yellow}No WTF-P installation found.${reset}\n`);
429
+ console.log(` Checked:`);
430
+ console.log(` ${dim}${globalLabel}${reset}`);
431
+ console.log(` ${dim}./.claude${reset}\n`);
432
+ rl.close();
433
+ return;
434
+ }
435
+
436
+ console.log(` ${yellow}Where would you like to uninstall from?${reset}\n`);
437
+
438
+ if (hasGlobalInstall) {
439
+ const count = globalInstalled.commandFiles.length + globalInstalled.skillFiles.length;
440
+ console.log(` ${cyan}1${reset}) Global ${dim}(${globalLabel})${reset} - ${count} files`);
441
+ } else {
442
+ console.log(` ${dim}1) Global (${globalLabel}) - not installed${reset}`);
443
+ }
444
+
445
+ if (hasLocalInstall) {
446
+ const count = localInstalled.commandFiles.length + localInstalled.skillFiles.length;
447
+ console.log(` ${cyan}2${reset}) Local ${dim}(./.claude)${reset} - ${count} files`);
448
+ } else {
449
+ console.log(` ${dim}2) Local (./.claude) - not installed${reset}`);
450
+ }
451
+ console.log();
452
+
453
+ const answer = await prompt(rl, ` Choice: `);
454
+ rl.close();
455
+
456
+ if (answer === '1' && hasGlobalInstall) {
457
+ await uninstall(true);
458
+ } else if (answer === '2' && hasLocalInstall) {
459
+ await uninstall(false);
460
+ } else {
461
+ console.log(`\n ${yellow}Invalid choice or no installation at that location.${reset}\n`);
462
+ }
463
+ }
464
+
465
+ // Main
466
+ async function main() {
467
+ if (hasGlobal && hasLocal) {
468
+ console.error(` ${yellow}Cannot specify both --global and --local${reset}`);
469
+ process.exit(1);
470
+ } else if (explicitConfigDir && hasLocal) {
471
+ console.error(` ${yellow}Cannot use --config-dir with --local${reset}`);
472
+ process.exit(1);
473
+ } else if (hasGlobal) {
474
+ await uninstall(true);
475
+ } else if (hasLocal) {
476
+ await uninstall(false);
477
+ } else {
478
+ await promptLocation();
479
+ }
480
+ }
481
+
482
+ main().catch(err => {
483
+ console.error(` ${red}Error:${reset} ${err.message}`);
484
+ process.exit(1);
485
+ });