@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.
- package/ecc.mjs +57 -12
- package/package.json +1 -1
package/ecc.mjs
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { execSync } from "node:child_process";
|
|
2
|
-
import {
|
|
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
|
|
65
|
-
|
|
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(
|
|
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,
|
|
118
|
+
pruneEmptyParents(op.destinationPath, ideDir);
|
|
74
119
|
}
|
|
75
120
|
}
|
|
76
|
-
rmSync(
|
|
77
|
-
pruneEmptyParents(
|
|
121
|
+
rmSync(statePath, { force: true });
|
|
122
|
+
pruneEmptyParents(statePath, ideDir);
|
|
78
123
|
} catch { /* corrupted state — skip */ }
|
|
79
124
|
}
|
|
80
125
|
|