@ghl-ai/aw 0.1.72 → 0.1.73-beta.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/c4/templates/scripts/aw-c4-bootstrap.sh +14 -13
- package/commands/c4.mjs +9 -13
- package/commands/init.mjs +6 -0
- package/ecc.mjs +1 -1
- package/git.mjs +2 -1
- package/hooks/aw-usage/lib/aw-usage-telemetry.js +5 -0
- package/package.json +3 -3
- package/startup.mjs +26 -5
|
@@ -129,29 +129,30 @@ aw_c4_exit=$?
|
|
|
129
129
|
|
|
130
130
|
# Defense-in-depth: `aw c4` delegates registry sync to `aw init --silent`,
|
|
131
131
|
# which can fail to fetch in silent mode without surfacing an error. When
|
|
132
|
-
# that happens, the registry (~/.aw/.aw_registry) may be empty or incomplete
|
|
133
|
-
#
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
# that happens, the registry (~/.aw/.aw_registry) may be empty or incomplete
|
|
133
|
+
# and only the 10 hardcoded stage commands get linked. Re-run `aw pull`
|
|
134
|
+
# post-c4 if the command count looks low.
|
|
135
|
+
verify_registry_commands() {
|
|
136
|
+
local aw_cmd_dir="$HOME/.aw/.aw_registry"
|
|
137
|
+
if [ ! -d "$aw_cmd_dir" ]; then
|
|
137
138
|
echo "[aw-c4-bootstrap] registry dir missing — running aw init + pull"
|
|
138
139
|
aw init --no-integrations --silent 2>&1 | tail -3 || true
|
|
139
140
|
aw pull 2>&1 | tail -5 || true
|
|
140
141
|
return
|
|
141
142
|
fi
|
|
142
143
|
|
|
143
|
-
local
|
|
144
|
-
|
|
145
|
-
if [ "${
|
|
146
|
-
echo "[aw-c4-bootstrap] only ${
|
|
144
|
+
local cmd_count
|
|
145
|
+
cmd_count=$(find "$aw_cmd_dir" -name '*.md' -path '*/commands/*' ! -path '*/evals/*' 2>/dev/null | wc -l | tr -d ' ')
|
|
146
|
+
if [ "${cmd_count:-0}" -lt 20 ]; then
|
|
147
|
+
echo "[aw-c4-bootstrap] only ${cmd_count} registry commands found — running aw pull"
|
|
147
148
|
aw pull 2>&1 | tail -5 || true
|
|
148
149
|
local new_count
|
|
149
|
-
new_count=$(find "$
|
|
150
|
-
echo "[aw-c4-bootstrap] registry
|
|
150
|
+
new_count=$(find "$aw_cmd_dir" -name '*.md' -path '*/commands/*' ! -path '*/evals/*' 2>/dev/null | wc -l | tr -d ' ')
|
|
151
|
+
echo "[aw-c4-bootstrap] registry commands: ${cmd_count} → ${new_count}"
|
|
151
152
|
else
|
|
152
|
-
echo "[aw-c4-bootstrap] registry: ${
|
|
153
|
+
echo "[aw-c4-bootstrap] registry: ${cmd_count} commands OK"
|
|
153
154
|
fi
|
|
154
155
|
}
|
|
155
|
-
|
|
156
|
+
verify_registry_commands || true
|
|
156
157
|
|
|
157
158
|
exit "$aw_c4_exit"
|
package/commands/c4.mjs
CHANGED
|
@@ -110,11 +110,6 @@ function safeListNamespaceDirs(dir) {
|
|
|
110
110
|
} catch { return []; }
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
function hasRegistrySkillSurface(registryDir, existsSync = fsExistsSync) {
|
|
114
|
-
if (existsSync(join(registryDir, 'platform', 'core', 'skills'))) return true;
|
|
115
|
-
return safeListNamespaceDirs(registryDir).length > 0;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
113
|
async function safeAsync(label, fn, writer) {
|
|
119
114
|
try {
|
|
120
115
|
return { ok: true, value: await fn() };
|
|
@@ -410,17 +405,18 @@ export async function c4Command(rawArgs, overrides = {}) {
|
|
|
410
405
|
return exit(1);
|
|
411
406
|
}
|
|
412
407
|
|
|
413
|
-
// Step 9a — verify registry has
|
|
408
|
+
// Step 9a — verify registry has namespace directories. `aw init --silent`
|
|
414
409
|
// can exit 0 but fail to fetch (fetchAndMerge swallows the error in silent
|
|
415
410
|
// mode). Metadata-only artifacts (AW-PROTOCOL.md) pass a simple non-empty
|
|
416
|
-
// check, so we specifically look for
|
|
417
|
-
// the registry content was actually pulled.
|
|
411
|
+
// check, so we specifically look for directories (namespaces like
|
|
412
|
+
// "platform") to confirm the registry content was actually pulled.
|
|
418
413
|
{
|
|
419
|
-
|
|
420
|
-
|
|
414
|
+
const registryNamespaces = safeListNamespaceDirs(awRegistry);
|
|
415
|
+
if (registryNamespaces.length === 0) {
|
|
416
|
+
writer.stderr('[aw-c4] registry has no namespace directories after init — retrying with aw pull\n');
|
|
421
417
|
const pullRes = spawnSync('aw', ['pull'], { stdio: 'pipe' });
|
|
422
|
-
if (pullRes?.status !== 0 ||
|
|
423
|
-
writer.stderr('[aw-c4] FATAL: registry
|
|
418
|
+
if (pullRes?.status !== 0 || safeListNamespaceDirs(awRegistry).length === 0) {
|
|
419
|
+
writer.stderr('[aw-c4] FATAL: registry commands were not fetched\n');
|
|
424
420
|
return exit(1);
|
|
425
421
|
}
|
|
426
422
|
}
|
|
@@ -443,7 +439,7 @@ export async function c4Command(rawArgs, overrides = {}) {
|
|
|
443
439
|
writer.stdout('[aw-c4] MCP disabled; skipping registerGhlAiMcp\n');
|
|
444
440
|
}
|
|
445
441
|
|
|
446
|
-
// Step 12 —
|
|
442
|
+
// Step 12 — slash command surface (10 stage commands from ECC).
|
|
447
443
|
safe('ensureCommandSurface', () => c4.ensureCommandSurface({ harness, home, eccHome }), writer);
|
|
448
444
|
|
|
449
445
|
// Step 12a — full registry command surface.
|
package/commands/init.mjs
CHANGED
|
@@ -25,6 +25,7 @@ import * as fmt from '../fmt.mjs';
|
|
|
25
25
|
import { chalk, setSilent } from '../fmt.mjs';
|
|
26
26
|
import { linkWorkspace } from '../link.mjs';
|
|
27
27
|
import { generateCommands, copyInstructions, initAwDocs, syncHomeHarnessInstructions } from '../integrate.mjs';
|
|
28
|
+
import { renderRules } from '../render-rules.mjs';
|
|
28
29
|
import { setupMcp } from '../mcp.mjs';
|
|
29
30
|
import { isContextModeRequested } from '../integrations/context-mode.mjs';
|
|
30
31
|
import { applyStoredStartupPreferences, ensureAwRuntimeHook, isDefaultRoutingEnabled } from '../startup.mjs';
|
|
@@ -150,6 +151,11 @@ function syncHomeAndProjectInstructions(cwd, namespace) {
|
|
|
150
151
|
initAwDocs(HOME);
|
|
151
152
|
if (cwd !== HOME) {
|
|
152
153
|
syncInstructionsAndAwDocs(cwd, namespace);
|
|
154
|
+
} else {
|
|
155
|
+
// Running from $HOME (fresh-laptop flow): render global IDE rules directly.
|
|
156
|
+
// The project branch above is otherwise the only renderRules call site, so
|
|
157
|
+
// init from $HOME used to leave ~/.claude/rules and ~/.cursor/rules empty.
|
|
158
|
+
renderRules(HOME, { homeDir: HOME });
|
|
153
159
|
}
|
|
154
160
|
}
|
|
155
161
|
|
package/ecc.mjs
CHANGED
|
@@ -12,7 +12,7 @@ import { applyStoredStartupPreferences } from "./startup.mjs";
|
|
|
12
12
|
|
|
13
13
|
const AW_ECC_REPO_SSH = "git@github.com:shreyansh-ghl/aw-ecc.git";
|
|
14
14
|
const AW_ECC_REPO_HTTPS = "https://github.com/shreyansh-ghl/aw-ecc.git";
|
|
15
|
-
export const AW_ECC_TAG = "v1.4.
|
|
15
|
+
export const AW_ECC_TAG = "v1.4.66";
|
|
16
16
|
const REQUIRED_ECC_FILES = [
|
|
17
17
|
"package.json",
|
|
18
18
|
"scripts/install-apply.js",
|
package/git.mjs
CHANGED
|
@@ -390,7 +390,8 @@ export async function fetchAndMerge(awHome, { silent = true } = {}) {
|
|
|
390
390
|
// drops bare-name patterns (e.g. "content", "CODEOWNERS") when HEAD advances.
|
|
391
391
|
//
|
|
392
392
|
// --autostash: AW writes into the registry working tree from external
|
|
393
|
-
// sources (
|
|
393
|
+
// sources (ensureAwRuntimeHook copies ~/.aw-ecc/.../session-start.sh into a
|
|
394
|
+
// tracked path; transformCursorAwRefs rewrites /aw: → /aw- through Cursor
|
|
394
395
|
// skill directory symlinks that resolve into .aw_registry/). When those
|
|
395
396
|
// versions drift, the working tree is dirty at rebase time and rebase
|
|
396
397
|
// refuses to run, silently aborting the entire pull. Autostash stashes the
|
|
@@ -119,6 +119,11 @@ function getAwCliVersionDetails() {
|
|
|
119
119
|
const candidates = [
|
|
120
120
|
path.join(AW_HOME, 'node_modules', '@ghl-ai', 'aw', 'package.json'),
|
|
121
121
|
];
|
|
122
|
+
// Derive global npm prefix from the running node binary (no shell needed)
|
|
123
|
+
try {
|
|
124
|
+
const nodeDir = path.dirname(process.execPath);
|
|
125
|
+
candidates.push(path.join(nodeDir, '..', 'lib', 'node_modules', '@ghl-ai', 'aw', 'package.json'));
|
|
126
|
+
} catch { /* ignore */ }
|
|
122
127
|
try {
|
|
123
128
|
const globalPrefix = execSync('npm prefix -g', { encoding: 'utf8', timeout: 3000 }).trim();
|
|
124
129
|
candidates.push(path.join(globalPrefix, 'lib', 'node_modules', '@ghl-ai', 'aw', 'package.json'));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghl-ai/aw",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Agentic Workspace CLI
|
|
3
|
+
"version": "0.1.73-beta.0",
|
|
4
|
+
"description": "Agentic Workspace CLI \u2014 pull, push & manage agents, skills and commands from the registry",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"aw": "bin.js"
|
|
@@ -74,4 +74,4 @@
|
|
|
74
74
|
"devDependencies": {
|
|
75
75
|
"vitest": "^4.1.2"
|
|
76
76
|
}
|
|
77
|
-
}
|
|
77
|
+
}
|
package/startup.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
1
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { randomBytes } from 'node:crypto';
|
|
@@ -83,6 +83,10 @@ function resolveRegistryRoot(homeDir = homedir()) {
|
|
|
83
83
|
].find(existsSync) || null;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
function awRuntimeHookSourcePath(homeDir = homedir()) {
|
|
87
|
+
return join(homeDir, '.aw-ecc', 'skills', 'using-aw-skills', 'hooks', 'session-start.sh');
|
|
88
|
+
}
|
|
89
|
+
|
|
86
90
|
function readJson(filePath, fallback = {}) {
|
|
87
91
|
if (!existsSync(filePath)) return fallback;
|
|
88
92
|
try {
|
|
@@ -389,10 +393,27 @@ function hasCodexSessionStartScript(homeDir = homedir()) {
|
|
|
389
393
|
}
|
|
390
394
|
|
|
391
395
|
export function ensureAwRuntimeHook(homeDir = homedir()) {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
+
const sourcePath = awRuntimeHookSourcePath(homeDir);
|
|
397
|
+
const registryRoot = resolveRegistryRoot(homeDir);
|
|
398
|
+
if (!existsSync(sourcePath) || !registryRoot) return [];
|
|
399
|
+
|
|
400
|
+
const destinationPath = join(
|
|
401
|
+
registryRoot,
|
|
402
|
+
'platform',
|
|
403
|
+
'core',
|
|
404
|
+
'skills',
|
|
405
|
+
'using-aw-skills',
|
|
406
|
+
'hooks',
|
|
407
|
+
'session-start.sh',
|
|
408
|
+
);
|
|
409
|
+
const sourceContent = readFileSync(sourcePath, 'utf8');
|
|
410
|
+
const existingContent = existsSync(destinationPath) ? readFileSync(destinationPath, 'utf8') : null;
|
|
411
|
+
if (existingContent === sourceContent) return [];
|
|
412
|
+
|
|
413
|
+
mkdirSync(dirname(destinationPath), { recursive: true });
|
|
414
|
+
writeFileSync(destinationPath, sourceContent);
|
|
415
|
+
try { chmodSync(destinationPath, 0o755); } catch { /* best effort */ }
|
|
416
|
+
return [destinationPath];
|
|
396
417
|
}
|
|
397
418
|
|
|
398
419
|
function hasCodexHooksEnabled(homeDir = homedir()) {
|