wogiflow 1.0.18 → 1.0.20
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/package.json +3 -2
- package/scripts/preuninstall.js +237 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wogiflow",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.20",
|
|
4
4
|
"description": "AI-powered development workflow management system with multi-model support",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"flow": "./scripts/flow",
|
|
12
12
|
"test": "node mcp-memory-server/test.js",
|
|
13
13
|
"memory-server": "node mcp-memory-server/index.js",
|
|
14
|
-
"postinstall": "node scripts/postinstall.js"
|
|
14
|
+
"postinstall": "node scripts/postinstall.js",
|
|
15
|
+
"preuninstall": "node scripts/preuninstall.js"
|
|
15
16
|
},
|
|
16
17
|
"files": [
|
|
17
18
|
"bin/",
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* WogiFlow preuninstall script
|
|
5
|
+
*
|
|
6
|
+
* Runs before npm uninstall to clean up WogiFlow-created files.
|
|
7
|
+
*
|
|
8
|
+
* Removes:
|
|
9
|
+
* - .workflow/ directory (all WogiFlow state and config)
|
|
10
|
+
* - .claude/commands/wogi-*.md (WogiFlow slash commands)
|
|
11
|
+
* - .claude/docs/ (WogiFlow documentation)
|
|
12
|
+
* - .claude/skills/ (WogiFlow skills - may contain user customizations)
|
|
13
|
+
* - .claude/hooks/ (WogiFlow hooks)
|
|
14
|
+
* - .claude/rules/ (WogiFlow rules)
|
|
15
|
+
* - CLAUDE.md (if contains WogiFlow marker)
|
|
16
|
+
*
|
|
17
|
+
* Preserves:
|
|
18
|
+
* - .claude/ directory structure (user may have other content)
|
|
19
|
+
* - User's git history
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const fs = require('fs');
|
|
23
|
+
const path = require('path');
|
|
24
|
+
|
|
25
|
+
// Get project root (where npm uninstall is run)
|
|
26
|
+
const PROJECT_ROOT = process.env.INIT_CWD || process.cwd();
|
|
27
|
+
|
|
28
|
+
// Directories to remove completely
|
|
29
|
+
const DIRS_TO_REMOVE = [
|
|
30
|
+
path.join(PROJECT_ROOT, '.workflow'),
|
|
31
|
+
path.join(PROJECT_ROOT, '.claude', 'docs'),
|
|
32
|
+
path.join(PROJECT_ROOT, '.claude', 'skills'),
|
|
33
|
+
path.join(PROJECT_ROOT, '.claude', 'hooks'),
|
|
34
|
+
path.join(PROJECT_ROOT, '.claude', 'rules')
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
// File patterns to remove
|
|
38
|
+
const CLAUDE_COMMANDS_DIR = path.join(PROJECT_ROOT, '.claude', 'commands');
|
|
39
|
+
const CLAUDE_MD_PATH = path.join(PROJECT_ROOT, 'CLAUDE.md');
|
|
40
|
+
|
|
41
|
+
// WogiFlow marker in CLAUDE.md - more explicit to avoid false positives
|
|
42
|
+
const WOGIFLOW_MARKER = 'WogiFlow methodology';
|
|
43
|
+
|
|
44
|
+
// Debug logging helper
|
|
45
|
+
function debugLog(message) {
|
|
46
|
+
if (process.env.DEBUG || process.env.WOGIFLOW_DEBUG) {
|
|
47
|
+
process.stderr.write(`[preuninstall] ${message}\n`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Recursively remove a directory
|
|
53
|
+
*/
|
|
54
|
+
function removeDir(dirPath) {
|
|
55
|
+
if (!fs.existsSync(dirPath)) {
|
|
56
|
+
return { removed: false, reason: 'not found' };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
fs.rmSync(dirPath, { recursive: true, force: true });
|
|
61
|
+
return { removed: true };
|
|
62
|
+
} catch (err) {
|
|
63
|
+
return { removed: false, reason: err.message };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Remove WogiFlow command files (wogi-*.md)
|
|
69
|
+
*/
|
|
70
|
+
function removeWogiCommands() {
|
|
71
|
+
if (!fs.existsSync(CLAUDE_COMMANDS_DIR)) {
|
|
72
|
+
return { count: 0, files: [] };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const removed = [];
|
|
76
|
+
const skipped = [];
|
|
77
|
+
try {
|
|
78
|
+
const files = fs.readdirSync(CLAUDE_COMMANDS_DIR);
|
|
79
|
+
for (const file of files) {
|
|
80
|
+
if (file.startsWith('wogi-') && file.endsWith('.md')) {
|
|
81
|
+
const filePath = path.join(CLAUDE_COMMANDS_DIR, file);
|
|
82
|
+
try {
|
|
83
|
+
fs.unlinkSync(filePath);
|
|
84
|
+
removed.push(file);
|
|
85
|
+
} catch (err) {
|
|
86
|
+
debugLog(`Failed to remove ${file}: ${err.message}`);
|
|
87
|
+
skipped.push(file);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} catch (err) {
|
|
92
|
+
debugLog(`Failed to read commands directory: ${err.message}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return { count: removed.length, files: removed, skipped };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Remove CLAUDE.md if it contains WogiFlow marker
|
|
100
|
+
* Note: Per security-patterns.md Rule #1, we don't use existsSync before readFileSync
|
|
101
|
+
* as it creates race conditions. The try-catch handles "file not found" gracefully.
|
|
102
|
+
*/
|
|
103
|
+
function removeClaudeMd() {
|
|
104
|
+
try {
|
|
105
|
+
const content = fs.readFileSync(CLAUDE_MD_PATH, 'utf-8');
|
|
106
|
+
if (content.includes(WOGIFLOW_MARKER)) {
|
|
107
|
+
fs.unlinkSync(CLAUDE_MD_PATH);
|
|
108
|
+
return { removed: true };
|
|
109
|
+
}
|
|
110
|
+
return { removed: false, reason: 'not a WogiFlow file' };
|
|
111
|
+
} catch (err) {
|
|
112
|
+
if (err.code === 'ENOENT') {
|
|
113
|
+
return { removed: false, reason: 'not found' };
|
|
114
|
+
}
|
|
115
|
+
debugLog(`Failed to process CLAUDE.md: ${err.message}`);
|
|
116
|
+
return { removed: false, reason: err.message };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Clean up empty .claude directory if nothing left
|
|
122
|
+
* Returns info about what was preserved (for user visibility)
|
|
123
|
+
*/
|
|
124
|
+
function cleanupClaudeDir() {
|
|
125
|
+
const claudeDir = path.join(PROJECT_ROOT, '.claude');
|
|
126
|
+
const result = { removed: false, preserved: [] };
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const remaining = fs.readdirSync(claudeDir);
|
|
130
|
+
|
|
131
|
+
// Only remove if empty or only contains 'commands' with no files
|
|
132
|
+
if (remaining.length === 0) {
|
|
133
|
+
fs.rmdirSync(claudeDir);
|
|
134
|
+
result.removed = true;
|
|
135
|
+
} else if (remaining.length === 1 && remaining[0] === 'commands') {
|
|
136
|
+
const commandsDir = path.join(claudeDir, 'commands');
|
|
137
|
+
const commandFiles = fs.readdirSync(commandsDir);
|
|
138
|
+
if (commandFiles.length === 0) {
|
|
139
|
+
fs.rmdirSync(commandsDir);
|
|
140
|
+
fs.rmdirSync(claudeDir);
|
|
141
|
+
result.removed = true;
|
|
142
|
+
} else {
|
|
143
|
+
// Log non-WogiFlow files being preserved
|
|
144
|
+
result.preserved = commandFiles.filter(f => !f.startsWith('wogi-'));
|
|
145
|
+
if (result.preserved.length > 0) {
|
|
146
|
+
debugLog(`Preserving non-WogiFlow commands: ${result.preserved.join(', ')}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
} else {
|
|
150
|
+
// Other content in .claude - log what's being preserved
|
|
151
|
+
result.preserved = remaining;
|
|
152
|
+
debugLog(`Preserving .claude contents: ${remaining.join(', ')}`);
|
|
153
|
+
}
|
|
154
|
+
} catch (err) {
|
|
155
|
+
if (err.code !== 'ENOENT') {
|
|
156
|
+
debugLog(`Cleanup error: ${err.message}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Check if we should be silent
|
|
165
|
+
*/
|
|
166
|
+
function shouldBeSilent() {
|
|
167
|
+
return process.env.CI || process.env.WOGIFLOW_SILENT_UNINSTALL;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Main entry point
|
|
172
|
+
*/
|
|
173
|
+
function main() {
|
|
174
|
+
const silent = shouldBeSilent();
|
|
175
|
+
const results = {
|
|
176
|
+
directories: [],
|
|
177
|
+
commands: null,
|
|
178
|
+
claudeMd: null
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// Remove directories
|
|
182
|
+
for (const dir of DIRS_TO_REMOVE) {
|
|
183
|
+
const relativePath = path.relative(PROJECT_ROOT, dir);
|
|
184
|
+
const result = removeDir(dir);
|
|
185
|
+
results.directories.push({ path: relativePath, ...result });
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Remove wogi-*.md commands
|
|
189
|
+
results.commands = removeWogiCommands();
|
|
190
|
+
|
|
191
|
+
// Remove CLAUDE.md if WogiFlow-generated
|
|
192
|
+
results.claudeMd = removeClaudeMd();
|
|
193
|
+
|
|
194
|
+
// Clean up empty .claude directory
|
|
195
|
+
results.claudeDir = cleanupClaudeDir();
|
|
196
|
+
|
|
197
|
+
// Output summary
|
|
198
|
+
if (!silent) {
|
|
199
|
+
const removedDirs = results.directories.filter(d => d.removed);
|
|
200
|
+
const removedCount = removedDirs.length + results.commands.count + (results.claudeMd.removed ? 1 : 0);
|
|
201
|
+
|
|
202
|
+
if (removedCount > 0) {
|
|
203
|
+
process.stderr.write('\n\x1b[36mWogiFlow cleanup:\x1b[0m\n');
|
|
204
|
+
|
|
205
|
+
for (const dir of removedDirs) {
|
|
206
|
+
process.stderr.write(` \x1b[31m✗\x1b[0m Removed ${dir.path}/\n`);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (results.commands.count > 0) {
|
|
210
|
+
process.stderr.write(` \x1b[31m✗\x1b[0m Removed ${results.commands.count} command(s): ${results.commands.files.join(', ')}\n`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (results.claudeMd.removed) {
|
|
214
|
+
process.stderr.write(` \x1b[31m✗\x1b[0m Removed CLAUDE.md\n`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Show preserved files (user's custom content)
|
|
218
|
+
if (results.claudeDir && results.claudeDir.preserved && results.claudeDir.preserved.length > 0) {
|
|
219
|
+
process.stderr.write(`\n\x1b[33mPreserved:\x1b[0m ${results.claudeDir.preserved.join(', ')} (not WogiFlow files)\n`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
process.stderr.write('\n\x1b[2mWogiFlow has been uninstalled. Your git history is preserved.\x1b[0m\n\n');
|
|
223
|
+
} else {
|
|
224
|
+
process.stderr.write('\x1b[36mWogiFlow:\x1b[0m No files to clean up.\n');
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Run
|
|
230
|
+
try {
|
|
231
|
+
main();
|
|
232
|
+
} catch (err) {
|
|
233
|
+
// Don't fail npm uninstall on preuninstall errors
|
|
234
|
+
if (!process.env.CI) {
|
|
235
|
+
process.stderr.write(`\x1b[33mWogiFlow cleanup warning:\x1b[0m ${err.message}\n`);
|
|
236
|
+
}
|
|
237
|
+
}
|