@ghl-ai/aw 0.1.73-beta.2 → 0.1.73-beta.4

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 CHANGED
@@ -77,6 +77,19 @@ function writeHookManifestBestEffort(manifest, context) {
77
77
  }
78
78
  }
79
79
 
80
+ function installAwUsageHooksBestEffort({ silent = false } = {}) {
81
+ ensureTelemetryConfig();
82
+
83
+ try {
84
+ if (!isDefaultRoutingEnabled(HOME, process.env)) return null;
85
+ const result = installAwUsageHooks();
86
+ return formatAwUsageHooksInstallReport(result);
87
+ } catch (e) {
88
+ if (!silent) fmt.note(`aw-usage hooks install: ${e.message}`, 'Telemetry');
89
+ return null;
90
+ }
91
+ }
92
+
80
93
  function formatIntegrationStatusSummary(statuses, installedNow = []) {
81
94
  if (!statuses || statuses.length === 0) return null;
82
95
 
@@ -506,6 +519,8 @@ export async function initCommand(args) {
506
519
  if (cwd !== HOME) installLocalCommitHook(cwd);
507
520
  if (!silent) fmt.logStep(`IDE wired — ${chalk.bold(symlinks)} symlinks · ${chalk.bold(commands)} commands`);
508
521
 
522
+ const awUsageHooksReport = installAwUsageHooksBestEffort({ silent });
523
+
509
524
  // Write hook manifest after all hook installation is complete
510
525
  writeHookManifestBestEffort({ eccVersion: AW_ECC_TAG, awVersion: VERSION });
511
526
 
@@ -533,6 +548,7 @@ export async function initCommand(args) {
533
548
  '',
534
549
  ` ${chalk.green('✓')} Registry synced`,
535
550
  ` ${chalk.green('✓')} IDE refreshed — ${chalk.bold(symlinks)} symlinks · ${chalk.bold(commands)} commands`,
551
+ awUsageHooksReport ? ` ${chalk.green('✓')} ${awUsageHooksReport}` : null,
536
552
  removedLegacyStartupFiles.length > 0
537
553
  ? ` ${chalk.green('✓')} Removed ${removedLegacyStartupFiles.length} legacy repo startup file${removedLegacyStartupFiles.length > 1 ? 's' : ''}`
538
554
  : null,
@@ -680,25 +696,12 @@ export async function initCommand(args) {
680
696
  ];
681
697
  if (!silent) fmt.logStep(`IDE wired — ${chalk.bold(symlinks)} symlinks · ${chalk.bold(commands)} commands`);
682
698
 
683
- // Ensure telemetry config exists (generates machine_id on first run)
684
- ensureTelemetryConfig();
685
-
686
699
  // Install bundled aw-usage producer hooks into ~/.claude.
687
700
  // Copies the scripts + lib files and non-destructively merges 5 hook phases
688
701
  // (SessionStart, UserPromptSubmit, PostToolUse, PostToolUseFailure, Stop)
689
702
  // into ~/.claude/settings.json. Idempotent. After this, every Claude Code
690
703
  // session emits usage_events to the live telemetry API automatically.
691
- let awUsageHooksReport = null;
692
- try {
693
- if (isDefaultRoutingEnabled(HOME, process.env)) {
694
- const result = installAwUsageHooks();
695
- awUsageHooksReport = formatAwUsageHooksInstallReport(result);
696
- }
697
- } catch (e) {
698
- // Non-fatal — telemetry is observational. Surface the error in silent mode
699
- // logs but don't block the install.
700
- if (!silent) fmt.note(`aw-usage hooks install: ${e.message}`, 'Telemetry');
701
- }
704
+ const awUsageHooksReport = installAwUsageHooksBestEffort({ silent });
702
705
 
703
706
  // Write hook manifest after all hook installation is complete, including
704
707
  // bundled usage hooks, so `aw nuke` can prune AW-managed settings entries.
@@ -112,6 +112,44 @@ function getCommand(input) {
112
112
  );
113
113
  }
114
114
 
115
+ function commandSegments(command) {
116
+ return String(command || '')
117
+ .split(/\n|&&|\|\||;/)
118
+ .map(segment => segment.trim())
119
+ .filter(Boolean)
120
+ .map(segment => segment.replace(/^(?:[A-Za-z_][A-Za-z0-9_]*=(?:"[^"]*"|'[^']*'|\S+)\s+)*/, ''))
121
+ .filter(segment => !segment.startsWith('#'));
122
+ }
123
+
124
+ function detectDeployCommand(command) {
125
+ const patterns = [
126
+ { regex: /^(?:npx\s+)?aw\s+deploy\b/i, tool: 'aw', provider: 'aw' },
127
+ { regex: /^(?:npm|yarn|pnpm|bun)\s+(?:run\s+)?deploy(?::[a-z0-9_-]+)?\b/i, tool: 'package-script', provider: 'package-script' },
128
+ { regex: /^gcloud\s+run\s+deploy\b/i, tool: 'gcloud', provider: 'cloud-run' },
129
+ { regex: /^firebase\s+deploy\b/i, tool: 'firebase', provider: 'firebase' },
130
+ { regex: /^vercel\s+(?:deploy\b|--prod\b)/i, tool: 'vercel', provider: 'vercel' },
131
+ { regex: /^wrangler\s+(?:deploy|pages\s+deploy)\b/i, tool: 'wrangler', provider: 'cloudflare' },
132
+ { regex: /^helm\s+upgrade\b/i, tool: 'helm', provider: 'kubernetes' },
133
+ { regex: /^kubectl\s+(?:rollout\s+restart|set\s+image)\b/i, tool: 'kubectl', provider: 'kubernetes' },
134
+ { regex: /^gh\s+workflow\s+run\b.*\b(?:deploy|release|staging|production|prod)\b/i, tool: 'gh', provider: 'github-actions' },
135
+ { regex: /^aws\s+(?:ecs\s+update-service|lambda\s+update-function-code)\b/i, tool: 'aws', provider: 'aws' },
136
+ { regex: /^(?:sam|serverless|sls)\s+deploy\b/i, tool: 'serverless', provider: 'serverless' },
137
+ ];
138
+
139
+ for (const segment of commandSegments(command)) {
140
+ for (const pattern of patterns) {
141
+ if (pattern.regex.test(segment)) {
142
+ return {
143
+ deploy_tool: pattern.tool,
144
+ deploy_provider: pattern.provider,
145
+ };
146
+ }
147
+ }
148
+ }
149
+
150
+ return null;
151
+ }
152
+
115
153
  function normalizeToolResult(input) {
116
154
  const rawToolResponse = parseMaybeJsonObject(input?.tool_response);
117
155
  const rawToolOutput = parseMaybeJsonObject(input?.tool_output);
@@ -232,6 +270,32 @@ function collectPostToolUseEvents(input, options = {}) {
232
270
 
233
271
  if (toolName === 'Shell' || toolName === 'Bash') {
234
272
  const cmd = getCommand(input);
273
+ const deploy = detectDeployCommand(cmd);
274
+ if (deploy) {
275
+ const deployPayload = {
276
+ ...deploy,
277
+ tool_name: toolName,
278
+ sdlc_correlated_command: slashCmd ? slashCmd.command_name : null,
279
+ sdlc_correlated_namespace: slashCmd ? slashCmd.command_namespace : null,
280
+ sdlc_correlated_is_sdlc_stage: slashCmd ? Boolean(slashCmd.is_sdlc_stage) : false,
281
+ };
282
+ const failed = isExplicitFailureExitCode(toolResult.exitCode)
283
+ || inferShellFailureFromMessage(toolName, toolResult.rawErrorMessage);
284
+
285
+ events.push({
286
+ eventType: 'deploy_triggered',
287
+ payload: deployPayload,
288
+ });
289
+ events.push({
290
+ eventType: failed ? 'deploy_failed' : 'deploy_success',
291
+ payload: {
292
+ ...deployPayload,
293
+ status: failed ? 'failed' : 'success',
294
+ ...(isExplicitFailureExitCode(toolResult.exitCode) ? { exit_code: toolResult.exitCode } : {}),
295
+ },
296
+ });
297
+ }
298
+
235
299
  // Codex skill detection: Bash commands that read SKILL.md files.
236
300
  if (!promptSkillOverride) {
237
301
  const skillCmdMatch = cmd.match(/\/skills\/([^/]+)\/SKILL\.md/i);
@@ -362,6 +426,7 @@ if (require.main === module) {
362
426
 
363
427
  module.exports = {
364
428
  collectPostToolUseEvents,
429
+ detectDeployCommand,
365
430
  detectSdlcArtifact,
366
431
  detectTestFramework,
367
432
  inferShellFailureFromMessage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghl-ai/aw",
3
- "version": "0.1.73-beta.2",
3
+ "version": "0.1.73-beta.4",
4
4
  "description": "Agentic Workspace CLI — pull, push & manage agents, skills and commands from the registry",
5
5
  "type": "module",
6
6
  "bin": {