@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
|
-
|
|
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,
|