qualia-framework 2.5.1 → 2.6.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/bin/cli.js CHANGED
@@ -167,6 +167,94 @@ function prompt(question) {
167
167
  });
168
168
  }
169
169
 
170
+ // ── Uninstall ──
171
+ async function runUninstall() {
172
+ log('');
173
+ log(`${c.red}\u2554${'═'.repeat(54)}\u2557${c.reset}`);
174
+ log(`${c.red}\u2551${c.reset}${c.bold} QUALIA FRAMEWORK \u2014 UNINSTALLER ${c.reset}${c.red}\u2551${c.reset}`);
175
+ log(`${c.red}\u255A${'═'.repeat(54)}\u255D${c.reset}`);
176
+ log('');
177
+
178
+ if (!fs.existsSync(CLAUDE_DIR)) {
179
+ warn('Nothing to uninstall \u2014 ~/.claude/ does not exist.');
180
+ return;
181
+ }
182
+
183
+ // Count everything in ~/.claude/
184
+ const totalFiles = countFilesRecursive(CLAUDE_DIR);
185
+
186
+ log(`${c.bold} NUCLEAR UNINSTALL \u2014 deleting EVERYTHING in ~/.claude/${c.reset}`);
187
+ log('');
188
+ log(` ${c.red}\u2022${c.reset} ${totalFiles} files will be permanently deleted`);
189
+ log(` ${c.red}\u2022${c.reset} settings.json will be reset to {}`);
190
+ log(` ${c.red}\u2022${c.reset} All skills, agents, hooks, rules, knowledge \u2014 gone`);
191
+ log(` ${c.red}\u2022${c.reset} All memory, projects, plans, cache \u2014 gone`);
192
+ log(` ${c.red}\u2022${c.reset} CLAUDE.md, .env.claude, all config \u2014 gone`);
193
+ log('');
194
+
195
+ // Confirmation
196
+ const force = process.argv.includes('--force');
197
+ if (!force) {
198
+ log(`${c.red} \u26A0 THIS CANNOT BE UNDONE.${c.reset}`);
199
+ log(`${c.red} \u26A0 ~/.claude/ will be wiped clean. Nothing survives.${c.reset}`);
200
+ log('');
201
+ const answer = await prompt(` Type 'UNINSTALL' to confirm: `);
202
+ if (answer !== 'UNINSTALL') {
203
+ log('');
204
+ ok('Cancelled. Nothing was deleted.');
205
+ return;
206
+ }
207
+ log('');
208
+ }
209
+
210
+ // Step 1: Nuke everything in ~/.claude/ except settings.json (we handle that separately)
211
+ step(1, 2, 'Nuking ~/.claude/ ...');
212
+
213
+ for (const entry of fs.readdirSync(CLAUDE_DIR, { withFileTypes: true })) {
214
+ const p = path.join(CLAUDE_DIR, entry.name);
215
+
216
+ // Skip settings.json — we reset it in step 2
217
+ if (entry.name === 'settings.json') continue;
218
+
219
+ try {
220
+ if (entry.isDirectory()) {
221
+ fs.rmSync(p, { recursive: true, force: true });
222
+ ok(`${entry.name}/`);
223
+ } else if (isSymlink(p)) {
224
+ fs.unlinkSync(p);
225
+ ok(`${entry.name} (symlink)`);
226
+ } else {
227
+ fs.unlinkSync(p);
228
+ ok(entry.name);
229
+ }
230
+ } catch (e) {
231
+ fail(`${entry.name}: ${e.message}`);
232
+ }
233
+ }
234
+
235
+ // Step 2: Reset settings.json to empty
236
+ step(2, 2, 'Resetting settings.json ...');
237
+ const settingsPath = path.join(CLAUDE_DIR, 'settings.json');
238
+ if (fs.existsSync(settingsPath)) {
239
+ fs.writeFileSync(settingsPath, '{}\n');
240
+ ok('settings.json reset to {}');
241
+ } else {
242
+ ok('No settings.json found');
243
+ }
244
+
245
+ log('');
246
+ log(`${c.green}\u2554${'═'.repeat(54)}\u2557${c.reset}`);
247
+ log(`${c.green}\u2551${c.reset}${c.bold} \u2713 NUKED \u2014 ~/.claude/ is clean ${c.reset}${c.green}\u2551${c.reset}`);
248
+ log(`${c.green}\u255A${'═'.repeat(54)}\u255D${c.reset}`);
249
+ log('');
250
+ log(` ${c.dim}Claude Code will use default behavior on next launch.${c.reset}`);
251
+ log('');
252
+ }
253
+
254
+ function isSymlink(p) {
255
+ try { fs.lstatSync(p); return fs.lstatSync(p).isSymbolicLink(); } catch { return false; }
256
+ }
257
+
170
258
  // ── Main ──
171
259
  async function main() {
172
260
  const command = process.argv[2];
@@ -175,6 +263,8 @@ async function main() {
175
263
  await runUpdate();
176
264
  } else if (command === 'verify') {
177
265
  runVerify();
266
+ } else if (command === 'uninstall') {
267
+ await runUninstall();
178
268
  } else {
179
269
  await runInstall();
180
270
  }
@@ -1 +1 @@
1
- 2.5.1
1
+ 2.6.0
package/package.json CHANGED
@@ -1,15 +1,19 @@
1
1
  {
2
2
  "name": "qualia-framework",
3
- "version": "2.5.1",
3
+ "version": "2.6.0",
4
4
  "description": "Qualia Solutions — Claude Code Framework",
5
5
  "bin": {
6
6
  "qualia-framework": "./bin/cli.js"
7
7
  },
8
+ "scripts": {
9
+ "preuninstall": "node bin/cli.js uninstall --force"
10
+ },
8
11
  "files": [
9
12
  "bin/",
10
13
  "framework/",
11
14
  "profiles/",
12
- "templates/"
15
+ "templates/",
16
+ "uninstall.sh"
13
17
  ],
14
18
  "engines": {
15
19
  "node": ">=18.0.0"
package/uninstall.sh ADDED
@@ -0,0 +1,90 @@
1
+ #!/bin/bash
2
+ # Qualia Framework — Nuclear Uninstaller
3
+ # Wipes EVERYTHING in ~/.claude/ — nothing survives
4
+ #
5
+ # Usage: ./uninstall.sh
6
+ # ./uninstall.sh --force (skip confirmation)
7
+
8
+ set -euo pipefail
9
+
10
+ # Colors
11
+ RED='\033[38;2;239;68;68m'
12
+ GREEN='\033[38;2;52;211;153m'
13
+ YELLOW='\033[38;2;234;179;8m'
14
+ WHITE='\033[38;2;220;225;230m'
15
+ DIM='\033[38;2;70;78;88m'
16
+ RESET='\033[0m'
17
+
18
+ CLAUDE_DIR="$HOME/.claude"
19
+
20
+ printf "\n"
21
+ printf "${RED}━━━${RESET} ${WHITE}QUALIA FRAMEWORK — NUCLEAR UNINSTALLER${RESET}\n"
22
+ printf "\n"
23
+
24
+ if [ ! -d "$CLAUDE_DIR" ]; then
25
+ printf "${YELLOW} Nothing to uninstall — $CLAUDE_DIR does not exist.${RESET}\n\n"
26
+ exit 0
27
+ fi
28
+
29
+ # Count everything
30
+ TOTAL=$(find "$CLAUDE_DIR" -type f 2>/dev/null | wc -l | tr -d ' ')
31
+
32
+ printf "${WHITE} NUCLEAR UNINSTALL — deleting EVERYTHING in ~/.claude/${RESET}\n\n"
33
+ printf " ${RED}*${RESET} ${TOTAL} files will be permanently deleted\n"
34
+ printf " ${RED}*${RESET} settings.json will be reset to {}\n"
35
+ printf " ${RED}*${RESET} All skills, agents, hooks, rules, knowledge — gone\n"
36
+ printf " ${RED}*${RESET} All memory, projects, plans, cache — gone\n"
37
+ printf " ${RED}*${RESET} CLAUDE.md, .env.claude, all config — gone\n\n"
38
+
39
+ # ─── Confirmation ───
40
+ if [ "${1:-}" != "--force" ]; then
41
+ printf "${RED} WARNING: THIS CANNOT BE UNDONE.${RESET}\n"
42
+ printf "${RED} ~/.claude/ will be wiped clean. Nothing survives.${RESET}\n\n"
43
+ read -rp " Type 'UNINSTALL' to confirm: " CONFIRM </dev/tty
44
+ if [ "$CONFIRM" != "UNINSTALL" ]; then
45
+ printf "\n${GREEN} Cancelled. Nothing was deleted.${RESET}\n\n"
46
+ exit 0
47
+ fi
48
+ printf "\n"
49
+ fi
50
+
51
+ # ─── Step 1: Nuke everything except settings.json ───
52
+ printf "${YELLOW}[1/2] Nuking ~/.claude/ ...${RESET}\n"
53
+
54
+ for entry in "$CLAUDE_DIR"/* "$CLAUDE_DIR"/.*; do
55
+ [ ! -e "$entry" ] && [ ! -L "$entry" ] && continue
56
+ name=$(basename "$entry")
57
+
58
+ # Skip . and ..
59
+ [ "$name" = "." ] || [ "$name" = ".." ] && continue
60
+
61
+ # Skip settings.json — we reset it in step 2
62
+ [ "$name" = "settings.json" ] && continue
63
+
64
+ if [ -L "$entry" ]; then
65
+ rm -f "$entry"
66
+ printf "${GREEN} ✓ ${name} (symlink)${RESET}\n"
67
+ elif [ -d "$entry" ]; then
68
+ rm -rf "$entry"
69
+ printf "${GREEN} ✓ ${name}/${RESET}\n"
70
+ elif [ -f "$entry" ]; then
71
+ rm -f "$entry"
72
+ printf "${GREEN} ✓ ${name}${RESET}\n"
73
+ fi
74
+ done
75
+
76
+ # ─── Step 2: Reset settings.json ───
77
+ printf "${YELLOW}[2/2] Resetting settings.json ...${RESET}\n"
78
+
79
+ if [ -f "$CLAUDE_DIR/settings.json" ]; then
80
+ echo '{}' > "$CLAUDE_DIR/settings.json"
81
+ printf "${GREEN} ✓ settings.json reset to {}${RESET}\n"
82
+ else
83
+ printf "${GREEN} ✓ No settings.json found${RESET}\n"
84
+ fi
85
+
86
+ # ─── Done ───
87
+ printf "\n"
88
+ printf "${GREEN}━━━${RESET} ${WHITE}NUKED${RESET}\n\n"
89
+ printf " ${WHITE}~/.claude/ is clean. Nothing survived.${RESET}\n"
90
+ printf " ${DIM}Claude Code will use default behavior on next launch.${RESET}\n\n"