@ghl-ai/aw 0.1.35-beta.13 → 0.1.35-beta.14

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/ecc.mjs +57 -12
  2. package/package.json +1 -1
package/ecc.mjs CHANGED
@@ -1,5 +1,8 @@
1
1
  import { execSync } from "node:child_process";
2
- import { existsSync, readFileSync, readdirSync, rmSync } from "node:fs";
2
+ import {
3
+ existsSync, mkdirSync, readFileSync, readdirSync,
4
+ renameSync, rmSync, writeFileSync,
5
+ } from "node:fs";
3
6
  import { dirname, join } from "node:path";
4
7
  import { homedir } from "node:os";
5
8
  import * as fmt from "./fmt.mjs";
@@ -9,6 +12,12 @@ const AW_ECC_REPO_HTTPS = "https://github.com/shreyansh-ghl/aw-ecc.git";
9
12
  const AW_ECC_TAG = "v1.0.0";
10
13
  const TMP_DIR = "/tmp/aw-ecc";
11
14
 
15
+ const TARGET_STATE = {
16
+ cursor: { state: ".cursor/ecc-install-state.json" },
17
+ claude: { state: ".claude/ecc/install-state.json" },
18
+ codex: { state: ".codex/ecc-install-state.json" },
19
+ };
20
+
12
21
  function run(cmd, opts = {}) {
13
22
  return execSync(cmd, { stdio: "pipe", ...opts });
14
23
  }
@@ -21,6 +30,44 @@ function cloneRepo(tag, dest) {
21
30
  }
22
31
  }
23
32
 
33
+ function namespaceCommands(target) {
34
+ const HOME = homedir();
35
+ const cfg = TARGET_STATE[target];
36
+ if (!cfg) return;
37
+
38
+ const statePath = join(HOME, cfg.state);
39
+ if (!existsSync(statePath)) return;
40
+
41
+ try {
42
+ const state = JSON.parse(readFileSync(statePath, "utf8"));
43
+ let moved = false;
44
+
45
+ for (const op of state.operations) {
46
+ const dest = op.destinationPath;
47
+ // Match top-level command files only (e.g. /commands/plan.md)
48
+ // Skip files already in subdirs (e.g. /commands/aw/plan.md)
49
+ // Skip .opencode paths (different command structure)
50
+ if (dest.includes(".opencode/")) continue;
51
+ const match = dest.match(/^(.+\/commands)\/([^/]+\.md)$/);
52
+ if (!match) continue;
53
+ if (match[1].endsWith("/aw")) continue;
54
+
55
+ const cmdDir = match[1];
56
+ const filename = match[2];
57
+ const awDir = join(cmdDir, "aw");
58
+ const newDest = join(awDir, filename);
59
+
60
+ if (!existsSync(dest)) continue;
61
+ mkdirSync(awDir, { recursive: true });
62
+ renameSync(dest, newDest);
63
+ op.destinationPath = newDest;
64
+ moved = true;
65
+ }
66
+
67
+ if (moved) writeFileSync(statePath, JSON.stringify(state, null, 2));
68
+ } catch { /* best effort */ }
69
+ }
70
+
24
71
  export async function installAwEcc(
25
72
  cwd,
26
73
  { targets = ["cursor", "claude", "codex"], silent = false } = {},
@@ -39,6 +86,7 @@ export async function installAwEcc(
39
86
  `node ${join(TMP_DIR, "scripts/install-apply.js")} --target ${target} --profile full`,
40
87
  { cwd },
41
88
  );
89
+ namespaceCommands(target);
42
90
  } catch {
43
91
  // Target not supported on this system — skip silently
44
92
  }
@@ -54,27 +102,24 @@ export async function installAwEcc(
54
102
 
55
103
  export function uninstallAwEcc({ silent = false } = {}) {
56
104
  const HOME = homedir();
57
- const statePaths = [
58
- { dir: join(HOME, ".cursor"), state: join(HOME, ".cursor", "ecc-install-state.json") },
59
- { dir: join(HOME, ".claude"), state: join(HOME, ".claude", "ecc", "install-state.json") },
60
- { dir: join(HOME, ".codex"), state: join(HOME, ".codex", "ecc-install-state.json") },
61
- ];
62
105
  let removed = 0;
63
106
 
64
- for (const { dir, state } of statePaths) {
65
- if (!existsSync(state)) continue;
107
+ for (const cfg of Object.values(TARGET_STATE)) {
108
+ const statePath = join(HOME, cfg.state);
109
+ const ideDir = join(HOME, cfg.state.split("/")[0]); // e.g. ~/.cursor, ~/.claude, ~/.codex
110
+ if (!existsSync(statePath)) continue;
66
111
 
67
112
  try {
68
- const data = JSON.parse(readFileSync(state, "utf8"));
113
+ const data = JSON.parse(readFileSync(statePath, "utf8"));
69
114
  for (const op of data.operations || []) {
70
115
  if (op.destinationPath && existsSync(op.destinationPath)) {
71
116
  rmSync(op.destinationPath, { recursive: true, force: true });
72
117
  removed++;
73
- pruneEmptyParents(op.destinationPath, dir);
118
+ pruneEmptyParents(op.destinationPath, ideDir);
74
119
  }
75
120
  }
76
- rmSync(state, { force: true });
77
- pruneEmptyParents(state, dir);
121
+ rmSync(statePath, { force: true });
122
+ pruneEmptyParents(statePath, ideDir);
78
123
  } catch { /* corrupted state — skip */ }
79
124
  }
80
125
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghl-ai/aw",
3
- "version": "0.1.35-beta.13",
3
+ "version": "0.1.35-beta.14",
4
4
  "description": "Agentic Workspace CLI — pull, push & manage agents, skills and commands from the registry",
5
5
  "type": "module",
6
6
  "bin": {