@ghl-ai/aw 0.1.35-beta.1 → 0.1.35-beta.12
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/commands/init.mjs +3 -4
- package/commands/nuke.mjs +12 -11
- package/commands/push.mjs +1 -30
- package/constants.mjs +1 -1
- package/ecc.mjs +94 -0
- package/package.json +3 -2
package/commands/init.mjs
CHANGED
|
@@ -19,7 +19,7 @@ import { generateCommands, copyInstructions, initAwDocs } from '../integrate.mjs
|
|
|
19
19
|
import { setupMcp } from '../mcp.mjs';
|
|
20
20
|
import { autoUpdate, promptUpdate } from '../update.mjs';
|
|
21
21
|
import { installGlobalHooks } from '../hooks.mjs';
|
|
22
|
-
import {
|
|
22
|
+
import { installAwEcc } from '../ecc.mjs';
|
|
23
23
|
|
|
24
24
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
25
25
|
const VERSION = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8')).version;
|
|
@@ -201,13 +201,13 @@ export async function initCommand(args) {
|
|
|
201
201
|
|
|
202
202
|
// Re-link IDE dirs + hooks (idempotent)
|
|
203
203
|
linkWorkspace(HOME);
|
|
204
|
+
await installAwEcc(cwd, { silent });
|
|
204
205
|
generateCommands(HOME);
|
|
205
206
|
copyInstructions(HOME, null, freshCfg?.namespace || team) || [];
|
|
206
207
|
initAwDocs(HOME);
|
|
207
208
|
setupMcp(HOME, freshCfg?.namespace || team) || [];
|
|
208
209
|
if (cwd !== HOME) setupMcp(cwd, freshCfg?.namespace || team);
|
|
209
210
|
installGlobalHooks();
|
|
210
|
-
const ideHookFiles = installIdeHooks(HOME);
|
|
211
211
|
|
|
212
212
|
// Link current project if needed
|
|
213
213
|
if (cwd !== HOME && !existsSync(join(cwd, '.aw_registry'))) {
|
|
@@ -282,13 +282,13 @@ export async function initCommand(args) {
|
|
|
282
282
|
// Step 3: Link IDE dirs + setup tasks
|
|
283
283
|
fmt.logStep('Linking IDE symlinks...');
|
|
284
284
|
linkWorkspace(HOME);
|
|
285
|
+
await installAwEcc(cwd, { silent });
|
|
285
286
|
generateCommands(HOME);
|
|
286
287
|
const instructionFiles = copyInstructions(HOME, null, team) || [];
|
|
287
288
|
initAwDocs(HOME);
|
|
288
289
|
const mcpFiles = setupMcp(HOME, team) || [];
|
|
289
290
|
if (cwd !== HOME) setupMcp(cwd, team);
|
|
290
291
|
const hooksInstalled = installGlobalHooks();
|
|
291
|
-
const ideHookFilesInit = installIdeHooks(HOME);
|
|
292
292
|
installIdeTasks();
|
|
293
293
|
|
|
294
294
|
// Step 4: Symlink in current directory if it's a git repo
|
|
@@ -307,7 +307,6 @@ export async function initCommand(args) {
|
|
|
307
307
|
createdFiles: [
|
|
308
308
|
...instructionFiles.map(p => p.startsWith(HOME) ? p.slice(HOME.length + 1) : p),
|
|
309
309
|
...mcpFiles.map(p => p.startsWith(HOME) ? p.slice(HOME.length + 1) : p),
|
|
310
|
-
...(ideHookFilesInit || []).map(p => p.startsWith(HOME) ? p.slice(HOME.length + 1) : p),
|
|
311
310
|
],
|
|
312
311
|
globalHooksDir: hooksInstalled ? join(HOME, '.aw', 'hooks') : null,
|
|
313
312
|
};
|
package/commands/nuke.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import { execSync } from 'node:child_process';
|
|
|
9
9
|
import * as fmt from '../fmt.mjs';
|
|
10
10
|
import { chalk } from '../fmt.mjs';
|
|
11
11
|
import { removeGlobalHooks } from '../hooks.mjs';
|
|
12
|
-
import {
|
|
12
|
+
import { uninstallAwEcc } from '../ecc.mjs';
|
|
13
13
|
|
|
14
14
|
const HOME = homedir();
|
|
15
15
|
const GLOBAL_AW_DIR = join(HOME, '.aw_registry');
|
|
@@ -244,31 +244,31 @@ export function nukeCommand(args) {
|
|
|
244
244
|
// 2. Remove IDE symlinks (only those pointing to .aw_registry)
|
|
245
245
|
removeIdeSymlinks();
|
|
246
246
|
|
|
247
|
-
// 3. Remove
|
|
247
|
+
// 3. Remove aw-ecc installed files (agents, commands, rules, skills, hooks)
|
|
248
|
+
uninstallAwEcc();
|
|
249
|
+
|
|
250
|
+
// 4. Remove .aw_registry symlinks from ALL project directories
|
|
248
251
|
removeProjectSymlinks();
|
|
249
252
|
|
|
250
|
-
//
|
|
253
|
+
// 5. Remove git hooks (core.hooksPath + legacy template)
|
|
251
254
|
removeGitHooks(manifest);
|
|
252
255
|
|
|
253
|
-
// 5. Remove IDE session hooks (superpowers bootstrap)
|
|
254
|
-
removeIdeHooks(HOME);
|
|
255
|
-
|
|
256
256
|
// 6. Remove IDE auto-init tasks
|
|
257
257
|
removeIdeTasks();
|
|
258
258
|
|
|
259
|
-
//
|
|
259
|
+
// Remove upgrade lock/log (inside .aw_registry, must happen before dir removal)
|
|
260
260
|
for (const p of [join(GLOBAL_AW_DIR, '.aw-upgrade.lock'), join(GLOBAL_AW_DIR, '.aw-upgrade.log')]) {
|
|
261
261
|
try { if (existsSync(p)) rmSync(p, { recursive: true, force: true }); } catch { /* best effort */ }
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
//
|
|
264
|
+
// 7. Remove ~/.aw_docs/
|
|
265
265
|
const awDocs = join(HOME, '.aw_docs');
|
|
266
266
|
if (existsSync(awDocs)) {
|
|
267
267
|
rmSync(awDocs, { recursive: true, force: true });
|
|
268
268
|
fmt.logStep('Removed ~/.aw_docs/');
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
-
//
|
|
271
|
+
// 8. Remove any manual `aw` symlinks (e.g. ~/.local/bin/aw)
|
|
272
272
|
const manualBins = [
|
|
273
273
|
join(HOME, '.local', 'bin', 'aw'),
|
|
274
274
|
join(HOME, 'bin', 'aw'),
|
|
@@ -282,7 +282,7 @@ export function nukeCommand(args) {
|
|
|
282
282
|
} catch { /* doesn't exist */ }
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
-
//
|
|
285
|
+
// 9. Uninstall npm global package (skip if already in npm uninstall lifecycle)
|
|
286
286
|
if (!process.env.npm_lifecycle_event) {
|
|
287
287
|
try {
|
|
288
288
|
execSync('npm uninstall -g @ghl-ai/aw', { stdio: 'pipe', timeout: 15000 });
|
|
@@ -290,7 +290,7 @@ export function nukeCommand(args) {
|
|
|
290
290
|
} catch { /* not installed via npm or no permissions */ }
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
-
//
|
|
293
|
+
// 10. Remove ~/.aw_registry/ itself (source of truth — last!)
|
|
294
294
|
rmSync(GLOBAL_AW_DIR, { recursive: true, force: true });
|
|
295
295
|
fmt.logStep('Removed ~/.aw_registry/');
|
|
296
296
|
|
|
@@ -299,6 +299,7 @@ export function nukeCommand(args) {
|
|
|
299
299
|
'',
|
|
300
300
|
` ${chalk.green('✓')} Generated files cleaned`,
|
|
301
301
|
` ${chalk.green('✓')} IDE symlinks cleaned`,
|
|
302
|
+
` ${chalk.green('✓')} aw-ecc engine removed`,
|
|
302
303
|
` ${chalk.green('✓')} Project symlinks cleaned`,
|
|
303
304
|
` ${chalk.green('✓')} Git hooks removed`,
|
|
304
305
|
` ${chalk.green('✓')} IDE auto-sync tasks removed`,
|
package/commands/push.mjs
CHANGED
|
@@ -73,17 +73,12 @@ function collectBatchFiles(folderAbsPath, workspaceDir) {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
-
* Collect all modified
|
|
77
|
-
* 1. Manifest-tracked files that are modified or template-derived (never pushed).
|
|
78
|
-
* 2. Filesystem files not in the manifest at all (newly added by user).
|
|
76
|
+
* Collect all modified files from manifest (for no-args push).
|
|
79
77
|
* Returns array of { absPath, registryTarget, type, namespace, slug, isDir }.
|
|
80
78
|
*/
|
|
81
79
|
function collectModifiedFiles(workspaceDir) {
|
|
82
80
|
const manifest = loadManifest(workspaceDir);
|
|
83
|
-
const manifestKeys = new Set(Object.keys(manifest.files || {}));
|
|
84
81
|
const files = [];
|
|
85
|
-
|
|
86
|
-
// 1. Manifest-tracked: modified or never-pushed
|
|
87
82
|
for (const [key, entry] of Object.entries(manifest.files || {})) {
|
|
88
83
|
const filePath = join(workspaceDir, key);
|
|
89
84
|
if (!existsSync(filePath)) continue;
|
|
@@ -104,30 +99,6 @@ function collectModifiedFiles(workspaceDir) {
|
|
|
104
99
|
}
|
|
105
100
|
}
|
|
106
101
|
}
|
|
107
|
-
|
|
108
|
-
// 2. Untracked: files on disk but not in manifest (e.g. manually added)
|
|
109
|
-
for (const name of readdirSync(workspaceDir, { withFileTypes: true })) {
|
|
110
|
-
if (!name.isDirectory() || name.name.startsWith('.')) continue;
|
|
111
|
-
const nsDir = join(workspaceDir, name.name);
|
|
112
|
-
const entries = walkRegistryTree(nsDir, name.name);
|
|
113
|
-
for (const entry of entries) {
|
|
114
|
-
// Build the manifest key for this file
|
|
115
|
-
const manifestKey = (entry.type === 'skills' || entry.type === 'evals')
|
|
116
|
-
? `${entry.namespacePath}/${entry.type}/${entry.slug}/${entry.skillRelPath || entry.filename}`
|
|
117
|
-
: `${entry.namespacePath}/${entry.type}/${entry.filename}`;
|
|
118
|
-
if (manifestKeys.has(manifestKey)) continue; // Already handled above
|
|
119
|
-
const registryTarget = `${REGISTRY_DIR}/${manifestKey}`;
|
|
120
|
-
files.push({
|
|
121
|
-
absPath: entry.sourcePath,
|
|
122
|
-
registryTarget,
|
|
123
|
-
type: entry.type,
|
|
124
|
-
namespace: entry.namespacePath,
|
|
125
|
-
slug: entry.slug,
|
|
126
|
-
isDir: false,
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
102
|
return files;
|
|
132
103
|
}
|
|
133
104
|
|
package/constants.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// constants.mjs — Single source of truth for registry settings.
|
|
2
2
|
|
|
3
3
|
/** Base branch for PRs and sync checkout */
|
|
4
|
-
export const REGISTRY_BASE_BRANCH = '
|
|
4
|
+
export const REGISTRY_BASE_BRANCH = 'main';
|
|
5
5
|
|
|
6
6
|
/** Default registry repository */
|
|
7
7
|
export const REGISTRY_REPO = 'GoHighLevel/platform-docs';
|
package/ecc.mjs
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readFileSync, readdirSync, rmSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import * as fmt from "./fmt.mjs";
|
|
6
|
+
|
|
7
|
+
const AW_ECC_REPO_SSH = "git@github.com:shreyansh-ghl/aw-ecc.git";
|
|
8
|
+
const AW_ECC_REPO_HTTPS = "https://github.com/shreyansh-ghl/aw-ecc.git";
|
|
9
|
+
const AW_ECC_TAG = "v1.0.0";
|
|
10
|
+
const TMP_DIR = "/tmp/aw-ecc";
|
|
11
|
+
const STATE_FILE = "ecc-install-state.json";
|
|
12
|
+
|
|
13
|
+
function run(cmd, opts = {}) {
|
|
14
|
+
return execSync(cmd, { stdio: "pipe", ...opts });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function cloneRepo(tag, dest) {
|
|
18
|
+
try {
|
|
19
|
+
run(`git clone --quiet --depth 1 --branch ${tag} ${AW_ECC_REPO_SSH} ${dest}`);
|
|
20
|
+
} catch {
|
|
21
|
+
run(`git clone --quiet --depth 1 --branch ${tag} ${AW_ECC_REPO_HTTPS} ${dest}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function installAwEcc(
|
|
26
|
+
cwd,
|
|
27
|
+
{ targets = ["cursor", "claude", "codex"], silent = false } = {},
|
|
28
|
+
) {
|
|
29
|
+
if (!silent) fmt.logStep("Installing aw-ecc engine...");
|
|
30
|
+
|
|
31
|
+
if (existsSync(TMP_DIR)) rmSync(TMP_DIR, { recursive: true, force: true });
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
cloneRepo(AW_ECC_TAG, TMP_DIR);
|
|
35
|
+
run("npm install --no-audit --no-fund --ignore-scripts --loglevel=error", { cwd: TMP_DIR });
|
|
36
|
+
|
|
37
|
+
for (const target of targets) {
|
|
38
|
+
try {
|
|
39
|
+
run(
|
|
40
|
+
`node ${join(TMP_DIR, "scripts/install-apply.js")} --target ${target} --profile full`,
|
|
41
|
+
{ cwd },
|
|
42
|
+
);
|
|
43
|
+
} catch {
|
|
44
|
+
// Target not supported on this system — skip silently
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!silent) fmt.logSuccess("aw-ecc engine installed");
|
|
49
|
+
} catch (err) {
|
|
50
|
+
if (!silent) fmt.logWarn(`aw-ecc install failed: ${err.message}`);
|
|
51
|
+
} finally {
|
|
52
|
+
if (existsSync(TMP_DIR)) rmSync(TMP_DIR, { recursive: true, force: true });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function uninstallAwEcc({ silent = false } = {}) {
|
|
57
|
+
const HOME = homedir();
|
|
58
|
+
const ideDirs = [".cursor", ".claude", ".codex"].map((d) => join(HOME, d));
|
|
59
|
+
let removed = 0;
|
|
60
|
+
|
|
61
|
+
for (const ideDir of ideDirs) {
|
|
62
|
+
const statePath = join(ideDir, STATE_FILE);
|
|
63
|
+
if (!existsSync(statePath)) continue;
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const state = JSON.parse(readFileSync(statePath, "utf8"));
|
|
67
|
+
for (const op of state.operations || []) {
|
|
68
|
+
if (op.destinationPath && existsSync(op.destinationPath)) {
|
|
69
|
+
rmSync(op.destinationPath, { recursive: true, force: true });
|
|
70
|
+
removed++;
|
|
71
|
+
pruneEmptyParents(op.destinationPath, ideDir);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
rmSync(statePath, { force: true });
|
|
75
|
+
} catch { /* corrupted state — skip */ }
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!silent && removed > 0) fmt.logStep(`Removed ${removed} aw-ecc file${removed > 1 ? "s" : ""}`);
|
|
79
|
+
return removed;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function pruneEmptyParents(filePath, stopAt) {
|
|
83
|
+
let dir = dirname(filePath);
|
|
84
|
+
while (dir !== stopAt && dir.startsWith(stopAt)) {
|
|
85
|
+
try {
|
|
86
|
+
if (readdirSync(dir).length === 0) {
|
|
87
|
+
rmSync(dir);
|
|
88
|
+
dir = dirname(dir);
|
|
89
|
+
} else {
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
} catch { break; }
|
|
93
|
+
}
|
|
94
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghl-ai/aw",
|
|
3
|
-
"version": "0.1.35-beta.
|
|
3
|
+
"version": "0.1.35-beta.12",
|
|
4
4
|
"description": "Agentic Workspace CLI — pull, push & manage agents, skills and commands from the registry",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"registry.mjs",
|
|
25
25
|
"apply.mjs",
|
|
26
26
|
"update.mjs",
|
|
27
|
-
"hooks.mjs"
|
|
27
|
+
"hooks.mjs",
|
|
28
|
+
"ecc.mjs"
|
|
28
29
|
],
|
|
29
30
|
"engines": {
|
|
30
31
|
"node": ">=18.0.0"
|