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