@ghl-ai/aw 0.1.72 → 0.1.73-beta.1

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.
@@ -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
- # Re-run `aw pull` post-c4 if the skill surface looks too small.
134
- verify_registry_skills() {
135
- local aw_registry_dir="$HOME/.aw/.aw_registry"
136
- if [ ! -d "$aw_registry_dir" ]; then
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 skill_count
144
- skill_count=$(find "$aw_registry_dir" -name 'SKILL.md' -path '*/skills/*' ! -path '*/evals/*' 2>/dev/null | wc -l | tr -d ' ')
145
- if [ "${skill_count:-0}" -lt 5 ]; then
146
- echo "[aw-c4-bootstrap] only ${skill_count} registry skills found — running aw pull"
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 "$aw_registry_dir" -name 'SKILL.md' -path '*/skills/*' ! -path '*/evals/*' 2>/dev/null | wc -l | tr -d ' ')
150
- echo "[aw-c4-bootstrap] registry skills: ${skill_count} → ${new_count}"
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: ${skill_count} skills OK"
153
+ echo "[aw-c4-bootstrap] registry: ${cmd_count} commands OK"
153
154
  fi
154
155
  }
155
- verify_registry_skills || true
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 the skill surface. `aw init --silent`
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 the platform skill namespace to confirm
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
- if (!hasRegistrySkillSurface(awRegistry, fs.existsSync)) {
420
- writer.stderr('[aw-c4] registry has no platform skill surface after init — retrying with aw pull\n');
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 || !hasRegistrySkillSurface(awRegistry, fs.existsSync)) {
423
- writer.stderr('[aw-c4] FATAL: registry skills were not fetched\n');
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 — legacy slash command surface, when provided by the installed ECC.
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/constants.mjs CHANGED
@@ -105,7 +105,7 @@ export const RULES_SOURCE_DIR = '.aw_rules';
105
105
  /** Runtime location exposed to harnesses and generated instructions */
106
106
  export const RULES_RUNTIME_DIR = '.aw/.aw_rules';
107
107
  /** Telemetry endpoint — override with AW_TELEMETRY_URL env var */
108
- export const TELEMETRY_URL = process.env.AW_TELEMETRY_URL || 'https://services.leadconnectorhq.com/agentic-workspace/api/telemetry/events';
108
+ export const TELEMETRY_URL = process.env.AW_TELEMETRY_URL || 'https://staging.services.leadconnectorhq.com/agentic-workspace/api/telemetry/events';
109
109
 
110
110
  /** AW bot identity for Co-Authored-By trailers */
111
111
  export const AW_BOT_NAME = 'AW';
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.67-beta.0";
15
+ export const AW_ECC_TAG = "v1.4.67";
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 (transformCursorAwRefs rewrites /aw: → /aw- through Cursor
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
@@ -18,6 +18,7 @@ function buildCommitCreatedEvent({ commitHash = 'unknown', branch = 'unknown', c
18
18
  // project_hash so the dashboard can correlate commits back to /aw:* sessions.
19
19
  const event = buildEvent({ cwd }, 'commit_created', {
20
20
  commit_hash: commitHash,
21
+ commit_sha: commitHash,
21
22
  branch,
22
23
  });
23
24
 
@@ -12,7 +12,7 @@
12
12
  const https = require('https');
13
13
  const http = require('http');
14
14
 
15
- const DEFAULT_URL = 'https://services.leadconnectorhq.com/agentic-workspace/api/telemetry/usage-events';
15
+ const DEFAULT_URL = 'https://staging.services.leadconnectorhq.com/agentic-workspace/api/telemetry/usage-events';
16
16
  const TIMEOUT_MS = 10_000;
17
17
 
18
18
  function post(url, body) {
@@ -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/hooks.mjs CHANGED
@@ -102,7 +102,7 @@ if git log -1 --format='%b' HEAD 2>/dev/null | grep -qF "Co-Authored-By: AW"; th
102
102
  TELEMETRY_HOOK="$HOME/.aw-ecc/scripts/hooks/aw-usage-commit-created.js"
103
103
  fi
104
104
  if command -v node >/dev/null 2>&1 && [ -f "$TELEMETRY_HOOK" ]; then
105
- COMMIT_HASH="$(git rev-parse --short HEAD 2>/dev/null || echo unknown)"
105
+ COMMIT_HASH="$(git rev-parse HEAD 2>/dev/null || echo unknown)"
106
106
  BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo unknown)"
107
107
  node "$TELEMETRY_HOOK" "$COMMIT_HASH" "$BRANCH" "$(pwd)" >/dev/null 2>&1
108
108
  fi
@@ -286,7 +286,7 @@ if git log -1 --format='%b' HEAD 2>/dev/null | grep -qF "Co-Authored-By: AW"; th
286
286
  TELEMETRY_HOOK="$HOME/.aw-ecc/scripts/hooks/aw-usage-commit-created.js"
287
287
  fi
288
288
  if command -v node >/dev/null 2>&1 && [ -f "$TELEMETRY_HOOK" ]; then
289
- COMMIT_HASH="$(git rev-parse --short HEAD 2>/dev/null || echo unknown)"
289
+ COMMIT_HASH="$(git rev-parse HEAD 2>/dev/null || echo unknown)"
290
290
  BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo unknown)"
291
291
  node "$TELEMETRY_HOOK" "$COMMIT_HASH" "$BRANCH" "$(pwd)" >/dev/null 2>&1
292
292
  fi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghl-ai/aw",
3
- "version": "0.1.72",
3
+ "version": "0.1.73-beta.1",
4
4
  "description": "Agentic Workspace CLI — pull, push & manage agents, skills and commands from the registry",
5
5
  "type": "module",
6
6
  "bin": {
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
- resolveRegistryRoot(homeDir);
393
- // The AW router hook is registry-owned. aw-ecc no longer ships SDLC skills
394
- // or using-aw-skills, so init/pull must not recreate it from ~/.aw-ecc.
395
- return [];
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()) {