@ghl-ai/aw 0.1.14 → 0.1.16

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 (2) hide show
  1. package/commands/nuke.mjs +61 -22
  2. package/package.json +4 -1
package/commands/nuke.mjs CHANGED
@@ -13,7 +13,7 @@ const HOME = homedir();
13
13
  const GLOBAL_AW_DIR = join(HOME, '.aw_registry');
14
14
  const MANIFEST_PATH = join(GLOBAL_AW_DIR, '.aw-manifest.json');
15
15
 
16
- const IDE_DIRS = ['.claude', '.cursor', '.codex'];
16
+ const IDE_DIRS = ['.claude', '.cursor', '.codex', '.agents'];
17
17
  const CONTENT_TYPES = ['agents', 'skills', 'commands', 'blueprints', 'evals'];
18
18
 
19
19
  function loadManifest() {
@@ -35,16 +35,37 @@ function removeCreatedFiles(manifest) {
35
35
  }
36
36
 
37
37
  // 2. Remove symlinks from IDE dirs that point into .aw_registry
38
+ // Scans both ~ (global) and cwd (project-level)
38
39
  function removeIdeSymlinks() {
39
40
  let removed = 0;
41
+ const cwd = process.cwd();
42
+ const baseDirs = new Set([HOME]);
43
+ if (cwd !== HOME) baseDirs.add(cwd);
44
+
45
+ for (const base of baseDirs) {
46
+ for (const ide of IDE_DIRS) {
47
+ for (const type of [...CONTENT_TYPES, 'commands/aw', 'commands/ghl']) {
48
+ const dir = join(base, ide, type);
49
+ if (!existsSync(dir)) continue;
50
+
51
+ for (const entry of readdirSync(dir)) {
52
+ const p = join(dir, entry);
53
+ try {
54
+ if (lstatSync(p).isSymbolicLink()) {
55
+ const target = readlinkSync(p);
56
+ if (target.includes('.aw_registry') || target.includes('aw_registry')) {
57
+ unlinkSync(p); removed++;
58
+ }
59
+ }
60
+ } catch { /* best effort */ }
61
+ }
62
+ // Remove dir if now empty
63
+ try { if (readdirSync(dir).length === 0) rmSync(dir); } catch {}
64
+ }
40
65
 
41
- for (const ide of IDE_DIRS) {
42
- for (const type of [...CONTENT_TYPES, 'commands/aw', 'commands/ghl']) {
43
- const dir = join(HOME, ide, type);
44
- if (!existsSync(dir)) continue;
45
-
46
- for (const entry of readdirSync(dir)) {
47
- const p = join(dir, entry);
66
+ // Also clean CLAUDE.md / AGENTS.md if they're AW-generated
67
+ for (const file of ['CLAUDE.md', 'AGENTS.md']) {
68
+ const p = join(base, ide, file);
48
69
  try {
49
70
  if (lstatSync(p).isSymbolicLink()) {
50
71
  const target = readlinkSync(p);
@@ -52,23 +73,39 @@ function removeIdeSymlinks() {
52
73
  unlinkSync(p); removed++;
53
74
  }
54
75
  }
55
- } catch { /* best effort */ }
76
+ } catch { /* not a symlink or doesn't exist */ }
56
77
  }
57
- // Remove dir if now empty
58
- try { if (readdirSync(dir).length === 0) rmSync(dir); } catch {}
78
+
79
+ // Clean up empty IDE dirs
80
+ const ideDir = join(base, ide);
81
+ try {
82
+ for (const type of CONTENT_TYPES) {
83
+ const dir = join(ideDir, type);
84
+ if (existsSync(dir) && readdirSync(dir).length === 0) rmSync(dir);
85
+ }
86
+ if (existsSync(ideDir) && readdirSync(ideDir).length === 0) rmSync(ideDir);
87
+ } catch {}
59
88
  }
60
89
 
61
- // Also clean CLAUDE.md / AGENTS.md if they're AW-generated
90
+ // Also clean root-level CLAUDE.md / AGENTS.md if AW-generated
62
91
  for (const file of ['CLAUDE.md', 'AGENTS.md']) {
63
- const p = join(HOME, ide, file);
92
+ const p = join(base, file);
64
93
  try {
65
- if (lstatSync(p).isSymbolicLink()) {
66
- const target = readlinkSync(p);
67
- if (target.includes('.aw_registry') || target.includes('aw_registry')) {
94
+ if (existsSync(p)) {
95
+ const content = readFileSync(p, 'utf8');
96
+ // Only remove if it contains AW markers
97
+ if (content.includes('aw_registry') || content.includes('.aw_docs') || content.includes('Agentic Workspace')) {
68
98
  unlinkSync(p); removed++;
69
99
  }
70
100
  }
71
- } catch { /* not a symlink or doesn't exist */ }
101
+ } catch { /* best effort */ }
102
+ }
103
+
104
+ // Clean .aw_docs in project dir
105
+ const projectAwDocs = join(base, '.aw_docs');
106
+ if (base !== HOME && existsSync(projectAwDocs)) {
107
+ rmSync(projectAwDocs, { recursive: true, force: true });
108
+ removed++;
72
109
  }
73
110
  }
74
111
 
@@ -225,11 +262,13 @@ export function nukeCommand(args) {
225
262
  } catch { /* doesn't exist */ }
226
263
  }
227
264
 
228
- // 8. Uninstall npm global package
229
- try {
230
- execSync('npm uninstall -g @ghl-ai/aw', { stdio: 'pipe', timeout: 15000 });
231
- fmt.logStep('Uninstalled @ghl-ai/aw globally');
232
- } catch { /* not installed via npm or no permissions */ }
265
+ // 8. Uninstall npm global package (skip if already in npm uninstall lifecycle)
266
+ if (!process.env.npm_lifecycle_event) {
267
+ try {
268
+ execSync('npm uninstall -g @ghl-ai/aw', { stdio: 'pipe', timeout: 15000 });
269
+ fmt.logStep('Uninstalled @ghl-ai/aw globally');
270
+ } catch { /* not installed via npm or no permissions */ }
271
+ }
233
272
 
234
273
  // 9. Remove ~/.aw_registry/ itself (source of truth — last!)
235
274
  rmSync(GLOBAL_AW_DIR, { recursive: true, force: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghl-ai/aw",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "Agentic Workspace CLI — pull, push & manage agents, skills and commands from the registry",
5
5
  "type": "module",
6
6
  "bin": {
@@ -36,6 +36,9 @@
36
36
  ],
37
37
  "author": "GoHighLevel",
38
38
  "license": "MIT",
39
+ "scripts": {
40
+ "preuninstall": "node bin.js nuke 2>/dev/null || true"
41
+ },
39
42
  "publishConfig": {
40
43
  "access": "public"
41
44
  },