wogiflow 1.0.19 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wogiflow",
3
- "version": "1.0.19",
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": {
@@ -38,8 +38,15 @@ const DIRS_TO_REMOVE = [
38
38
  const CLAUDE_COMMANDS_DIR = path.join(PROJECT_ROOT, '.claude', 'commands');
39
39
  const CLAUDE_MD_PATH = path.join(PROJECT_ROOT, 'CLAUDE.md');
40
40
 
41
- // WogiFlow marker in CLAUDE.md
42
- const WOGIFLOW_MARKER = 'WogiFlow';
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
+ }
43
50
 
44
51
  /**
45
52
  * Recursively remove a directory
@@ -66,6 +73,7 @@ function removeWogiCommands() {
66
73
  }
67
74
 
68
75
  const removed = [];
76
+ const skipped = [];
69
77
  try {
70
78
  const files = fs.readdirSync(CLAUDE_COMMANDS_DIR);
71
79
  for (const file of files) {
@@ -75,25 +83,24 @@ function removeWogiCommands() {
75
83
  fs.unlinkSync(filePath);
76
84
  removed.push(file);
77
85
  } catch (err) {
78
- // Ignore individual file errors
86
+ debugLog(`Failed to remove ${file}: ${err.message}`);
87
+ skipped.push(file);
79
88
  }
80
89
  }
81
90
  }
82
91
  } catch (err) {
83
- // Ignore directory read errors
92
+ debugLog(`Failed to read commands directory: ${err.message}`);
84
93
  }
85
94
 
86
- return { count: removed.length, files: removed };
95
+ return { count: removed.length, files: removed, skipped };
87
96
  }
88
97
 
89
98
  /**
90
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.
91
102
  */
92
103
  function removeClaudeMd() {
93
- if (!fs.existsSync(CLAUDE_MD_PATH)) {
94
- return { removed: false, reason: 'not found' };
95
- }
96
-
97
104
  try {
98
105
  const content = fs.readFileSync(CLAUDE_MD_PATH, 'utf-8');
99
106
  if (content.includes(WOGIFLOW_MARKER)) {
@@ -102,35 +109,55 @@ function removeClaudeMd() {
102
109
  }
103
110
  return { removed: false, reason: 'not a WogiFlow file' };
104
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}`);
105
116
  return { removed: false, reason: err.message };
106
117
  }
107
118
  }
108
119
 
109
120
  /**
110
121
  * Clean up empty .claude directory if nothing left
122
+ * Returns info about what was preserved (for user visibility)
111
123
  */
112
124
  function cleanupClaudeDir() {
113
125
  const claudeDir = path.join(PROJECT_ROOT, '.claude');
114
- if (!fs.existsSync(claudeDir)) {
115
- return;
116
- }
126
+ const result = { removed: false, preserved: [] };
117
127
 
118
128
  try {
119
129
  const remaining = fs.readdirSync(claudeDir);
130
+
120
131
  // Only remove if empty or only contains 'commands' with no files
121
132
  if (remaining.length === 0) {
122
133
  fs.rmdirSync(claudeDir);
134
+ result.removed = true;
123
135
  } else if (remaining.length === 1 && remaining[0] === 'commands') {
124
136
  const commandsDir = path.join(claudeDir, 'commands');
125
137
  const commandFiles = fs.readdirSync(commandsDir);
126
138
  if (commandFiles.length === 0) {
127
139
  fs.rmdirSync(commandsDir);
128
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
+ }
129
148
  }
149
+ } else {
150
+ // Other content in .claude - log what's being preserved
151
+ result.preserved = remaining;
152
+ debugLog(`Preserving .claude contents: ${remaining.join(', ')}`);
130
153
  }
131
154
  } catch (err) {
132
- // Ignore cleanup errors
155
+ if (err.code !== 'ENOENT') {
156
+ debugLog(`Cleanup error: ${err.message}`);
157
+ }
133
158
  }
159
+
160
+ return result;
134
161
  }
135
162
 
136
163
  /**
@@ -165,7 +192,7 @@ function main() {
165
192
  results.claudeMd = removeClaudeMd();
166
193
 
167
194
  // Clean up empty .claude directory
168
- cleanupClaudeDir();
195
+ results.claudeDir = cleanupClaudeDir();
169
196
 
170
197
  // Output summary
171
198
  if (!silent) {
@@ -187,6 +214,11 @@ function main() {
187
214
  process.stderr.write(` \x1b[31m✗\x1b[0m Removed CLAUDE.md\n`);
188
215
  }
189
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
+
190
222
  process.stderr.write('\n\x1b[2mWogiFlow has been uninstalled. Your git history is preserved.\x1b[0m\n\n');
191
223
  } else {
192
224
  process.stderr.write('\x1b[36mWogiFlow:\x1b[0m No files to clean up.\n');