@ghl-ai/aw 0.1.73-beta.4 → 0.1.73
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 +20 -17
- package/constants.mjs +1 -1
- package/ecc.mjs +1 -1
- package/hooks/aw-usage/hooks/aw-usage-commit-created.js +4 -13
- package/hooks/aw-usage/hooks/aw-usage-post-tool-use.js +0 -65
- package/hooks/aw-usage/hooks/aw-usage-prompt-submit.js +1 -3
- package/hooks/aw-usage/hooks/aw-usage-telemetry-send.js +1 -1
- package/hooks/aw-usage/lib/aw-usage-telemetry.js +1 -85
- package/hooks.mjs +2 -2
- package/package.json +3 -3
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';
|
|
@@ -77,19 +78,6 @@ function writeHookManifestBestEffort(manifest, context) {
|
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
|
|
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
|
-
|
|
93
81
|
function formatIntegrationStatusSummary(statuses, installedNow = []) {
|
|
94
82
|
if (!statuses || statuses.length === 0) return null;
|
|
95
83
|
|
|
@@ -163,6 +151,11 @@ function syncHomeAndProjectInstructions(cwd, namespace) {
|
|
|
163
151
|
initAwDocs(HOME);
|
|
164
152
|
if (cwd !== HOME) {
|
|
165
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 });
|
|
166
159
|
}
|
|
167
160
|
}
|
|
168
161
|
|
|
@@ -519,8 +512,6 @@ export async function initCommand(args) {
|
|
|
519
512
|
if (cwd !== HOME) installLocalCommitHook(cwd);
|
|
520
513
|
if (!silent) fmt.logStep(`IDE wired — ${chalk.bold(symlinks)} symlinks · ${chalk.bold(commands)} commands`);
|
|
521
514
|
|
|
522
|
-
const awUsageHooksReport = installAwUsageHooksBestEffort({ silent });
|
|
523
|
-
|
|
524
515
|
// Write hook manifest after all hook installation is complete
|
|
525
516
|
writeHookManifestBestEffort({ eccVersion: AW_ECC_TAG, awVersion: VERSION });
|
|
526
517
|
|
|
@@ -548,7 +539,6 @@ export async function initCommand(args) {
|
|
|
548
539
|
'',
|
|
549
540
|
` ${chalk.green('✓')} Registry synced`,
|
|
550
541
|
` ${chalk.green('✓')} IDE refreshed — ${chalk.bold(symlinks)} symlinks · ${chalk.bold(commands)} commands`,
|
|
551
|
-
awUsageHooksReport ? ` ${chalk.green('✓')} ${awUsageHooksReport}` : null,
|
|
552
542
|
removedLegacyStartupFiles.length > 0
|
|
553
543
|
? ` ${chalk.green('✓')} Removed ${removedLegacyStartupFiles.length} legacy repo startup file${removedLegacyStartupFiles.length > 1 ? 's' : ''}`
|
|
554
544
|
: null,
|
|
@@ -696,12 +686,25 @@ export async function initCommand(args) {
|
|
|
696
686
|
];
|
|
697
687
|
if (!silent) fmt.logStep(`IDE wired — ${chalk.bold(symlinks)} symlinks · ${chalk.bold(commands)} commands`);
|
|
698
688
|
|
|
689
|
+
// Ensure telemetry config exists (generates machine_id on first run)
|
|
690
|
+
ensureTelemetryConfig();
|
|
691
|
+
|
|
699
692
|
// Install bundled aw-usage producer hooks into ~/.claude.
|
|
700
693
|
// Copies the scripts + lib files and non-destructively merges 5 hook phases
|
|
701
694
|
// (SessionStart, UserPromptSubmit, PostToolUse, PostToolUseFailure, Stop)
|
|
702
695
|
// into ~/.claude/settings.json. Idempotent. After this, every Claude Code
|
|
703
696
|
// session emits usage_events to the live telemetry API automatically.
|
|
704
|
-
|
|
697
|
+
let awUsageHooksReport = null;
|
|
698
|
+
try {
|
|
699
|
+
if (isDefaultRoutingEnabled(HOME, process.env)) {
|
|
700
|
+
const result = installAwUsageHooks();
|
|
701
|
+
awUsageHooksReport = formatAwUsageHooksInstallReport(result);
|
|
702
|
+
}
|
|
703
|
+
} catch (e) {
|
|
704
|
+
// Non-fatal — telemetry is observational. Surface the error in silent mode
|
|
705
|
+
// logs but don't block the install.
|
|
706
|
+
if (!silent) fmt.note(`aw-usage hooks install: ${e.message}`, 'Telemetry');
|
|
707
|
+
}
|
|
705
708
|
|
|
706
709
|
// Write hook manifest after all hook installation is complete, including
|
|
707
710
|
// bundled usage hooks, so `aw nuke` can prune AW-managed settings entries.
|
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://
|
|
108
|
+
export const TELEMETRY_URL = process.env.AW_TELEMETRY_URL || 'https://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.
|
|
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",
|
|
@@ -11,23 +11,14 @@
|
|
|
11
11
|
|
|
12
12
|
'use strict';
|
|
13
13
|
|
|
14
|
-
const {
|
|
15
|
-
buildEvent,
|
|
16
|
-
sendAsync,
|
|
17
|
-
isDisabled,
|
|
18
|
-
findRecentSdlcSessionForProject,
|
|
19
|
-
} = require('../lib/aw-usage-telemetry');
|
|
14
|
+
const { buildEvent, sendAsync, isDisabled } = require('../lib/aw-usage-telemetry');
|
|
20
15
|
|
|
21
16
|
function buildCommitCreatedEvent({ commitHash = 'unknown', branch = 'unknown', cwd = process.cwd() } = {}) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
...(linkedSession?.session_id ? { session_id: linkedSession.session_id } : {}),
|
|
26
|
-
}, 'commit_created', {
|
|
17
|
+
// Git hooks have no harness session context, but cwd lets buildEvent derive
|
|
18
|
+
// project_hash so the dashboard can correlate commits back to /aw:* sessions.
|
|
19
|
+
const event = buildEvent({ cwd }, 'commit_created', {
|
|
27
20
|
commit_hash: commitHash,
|
|
28
|
-
commit_sha: commitHash,
|
|
29
21
|
branch,
|
|
30
|
-
...(linkedSession?.session_id ? { linked_session_source: 'project_recent_sdlc_session' } : {}),
|
|
31
22
|
});
|
|
32
23
|
|
|
33
24
|
// Override harness to 'git' since this fires from a git hook, not a harness.
|
|
@@ -112,44 +112,6 @@ 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
|
-
|
|
153
115
|
function normalizeToolResult(input) {
|
|
154
116
|
const rawToolResponse = parseMaybeJsonObject(input?.tool_response);
|
|
155
117
|
const rawToolOutput = parseMaybeJsonObject(input?.tool_output);
|
|
@@ -270,32 +232,6 @@ function collectPostToolUseEvents(input, options = {}) {
|
|
|
270
232
|
|
|
271
233
|
if (toolName === 'Shell' || toolName === 'Bash') {
|
|
272
234
|
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
|
-
|
|
299
235
|
// Codex skill detection: Bash commands that read SKILL.md files.
|
|
300
236
|
if (!promptSkillOverride) {
|
|
301
237
|
const skillCmdMatch = cmd.match(/\/skills\/([^/]+)\/SKILL\.md/i);
|
|
@@ -426,7 +362,6 @@ if (require.main === module) {
|
|
|
426
362
|
|
|
427
363
|
module.exports = {
|
|
428
364
|
collectPostToolUseEvents,
|
|
429
|
-
detectDeployCommand,
|
|
430
365
|
detectSdlcArtifact,
|
|
431
366
|
detectTestFramework,
|
|
432
367
|
inferShellFailureFromMessage,
|
|
@@ -109,9 +109,7 @@ function processPromptSubmitInput(input, deps = {}) {
|
|
|
109
109
|
|
|
110
110
|
if (slash) {
|
|
111
111
|
persistSkill(getSessionId(input), input?.turn_id || null, slash);
|
|
112
|
-
persistSlashCmd(getSessionId(input), slash
|
|
113
|
-
cwd: input?.cwd || (input?.workspace_roots && input.workspace_roots[0]) || null,
|
|
114
|
-
});
|
|
112
|
+
persistSlashCmd(getSessionId(input), slash);
|
|
115
113
|
events.push({
|
|
116
114
|
eventType: 'skill_invoked',
|
|
117
115
|
payload: {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
const https = require('https');
|
|
13
13
|
const http = require('http');
|
|
14
14
|
|
|
15
|
-
const DEFAULT_URL = 'https://
|
|
15
|
+
const DEFAULT_URL = 'https://services.leadconnectorhq.com/agentic-workspace/api/telemetry/usage-events';
|
|
16
16
|
const TIMEOUT_MS = 10_000;
|
|
17
17
|
|
|
18
18
|
function post(url, body) {
|
|
@@ -21,7 +21,6 @@ const SENDER_SCRIPT = path.join(__dirname, '..', 'hooks', 'aw-usage-telemetry-se
|
|
|
21
21
|
const AW_HOME = path.join(os.homedir(), '.aw');
|
|
22
22
|
const CONFIG_PATH = path.join(AW_HOME, 'telemetry', 'config.json');
|
|
23
23
|
const SESSION_DIR = path.join(AW_HOME, 'telemetry', 'sessions');
|
|
24
|
-
const SESSION_PROJECT_DIR = path.join(SESSION_DIR, 'by-project');
|
|
25
24
|
const DEDUPE_DIR = path.join(os.tmpdir(), 'aw-usage-telemetry-dedupe');
|
|
26
25
|
|
|
27
26
|
// ── Git config cache (once per process) ──────────────────────────────
|
|
@@ -158,16 +157,6 @@ function computeProjectHash(cwd) {
|
|
|
158
157
|
return crypto.createHash('sha256').update(cwd).digest('hex').slice(0, 16);
|
|
159
158
|
}
|
|
160
159
|
|
|
161
|
-
function normalizeProjectHash(value) {
|
|
162
|
-
return typeof value === 'string' && /^[a-f0-9]{16}$/i.test(value) ? value.toLowerCase() : null;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function resolveProjectHash(context) {
|
|
166
|
-
if (!context || typeof context !== 'object') return null;
|
|
167
|
-
return normalizeProjectHash(context.project_hash || context.projectHash)
|
|
168
|
-
|| computeProjectHash(context.cwd);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
160
|
// ── Session file cleanup ─────────────────────────────────────────────
|
|
172
161
|
// Prune session files older than SESSION_MAX_AGE_MS to prevent unbounded growth.
|
|
173
162
|
// Called once per session start — best-effort, never blocks.
|
|
@@ -252,40 +241,21 @@ function readSessionSkill(sessionId, turnId) {
|
|
|
252
241
|
// to the originating /aw:* invocation. Separate from `last_skill` because
|
|
253
242
|
// the source is the prompt, not the tool, and the lifetime is the whole
|
|
254
243
|
// session (not just one turn).
|
|
255
|
-
function
|
|
256
|
-
if (!projectHash || !sessionId || !slashCommand?.is_sdlc_stage) return;
|
|
257
|
-
try {
|
|
258
|
-
fs.mkdirSync(SESSION_PROJECT_DIR, { recursive: true });
|
|
259
|
-
fs.writeFileSync(path.join(SESSION_PROJECT_DIR, `${projectHash}.json`), JSON.stringify({
|
|
260
|
-
project_hash: projectHash,
|
|
261
|
-
session_id: sessionId,
|
|
262
|
-
command_namespace: slashCommand.command_namespace || null,
|
|
263
|
-
command_name: slashCommand.command_name,
|
|
264
|
-
is_sdlc_stage: Boolean(slashCommand.is_sdlc_stage),
|
|
265
|
-
updated_at: new Date().toISOString(),
|
|
266
|
-
}));
|
|
267
|
-
} catch { /* ignore */ }
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
function persistSessionSlashCommand(sessionId, slashCommand, context = {}) {
|
|
244
|
+
function persistSessionSlashCommand(sessionId, slashCommand) {
|
|
271
245
|
if (!sessionId || !slashCommand?.command_name) return;
|
|
272
246
|
try {
|
|
273
247
|
fs.mkdirSync(SESSION_DIR, { recursive: true });
|
|
274
248
|
const state = readSessionState(sessionId);
|
|
275
|
-
const projectHash = resolveProjectHash(context) || state.project_hash || null;
|
|
276
249
|
fs.writeFileSync(path.join(SESSION_DIR, sessionId + '.json'), JSON.stringify({
|
|
277
250
|
...state,
|
|
278
|
-
...(projectHash ? { project_hash: projectHash } : {}),
|
|
279
251
|
last_slash_command: {
|
|
280
252
|
command_namespace: slashCommand.command_namespace || null,
|
|
281
253
|
command_name: slashCommand.command_name,
|
|
282
254
|
command_args: slashCommand.command_args || '',
|
|
283
255
|
is_sdlc_stage: Boolean(slashCommand.is_sdlc_stage),
|
|
284
|
-
...(projectHash ? { project_hash: projectHash } : {}),
|
|
285
256
|
updated_at: new Date().toISOString(),
|
|
286
257
|
},
|
|
287
258
|
}));
|
|
288
|
-
writeProjectSessionIndex(projectHash, sessionId, slashCommand);
|
|
289
259
|
} catch { /* ignore */ }
|
|
290
260
|
}
|
|
291
261
|
|
|
@@ -295,59 +265,6 @@ function readSessionLastSlashCommand(sessionId) {
|
|
|
295
265
|
return cmd;
|
|
296
266
|
}
|
|
297
267
|
|
|
298
|
-
function parseUpdatedAt(value) {
|
|
299
|
-
const millis = Date.parse(value || '');
|
|
300
|
-
return Number.isFinite(millis) ? millis : 0;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
function isRecentSdlcSessionCandidate(candidate, projectHash, maxAgeMs) {
|
|
304
|
-
if (!candidate?.session_id) return false;
|
|
305
|
-
if (!candidate?.is_sdlc_stage) return false;
|
|
306
|
-
if (candidate.project_hash !== projectHash) return false;
|
|
307
|
-
const updatedAt = parseUpdatedAt(candidate.updated_at);
|
|
308
|
-
if (!updatedAt) return false;
|
|
309
|
-
return Date.now() - updatedAt <= maxAgeMs;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
function readProjectSessionIndex(projectHash, maxAgeMs) {
|
|
313
|
-
try {
|
|
314
|
-
const candidate = JSON.parse(fs.readFileSync(path.join(SESSION_PROJECT_DIR, `${projectHash}.json`), 'utf8'));
|
|
315
|
-
return isRecentSdlcSessionCandidate(candidate, projectHash, maxAgeMs) ? candidate : null;
|
|
316
|
-
} catch {
|
|
317
|
-
return null;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
function findRecentSdlcSessionForProject(cwd, maxAgeMs = SESSION_MAX_AGE_MS) {
|
|
322
|
-
const projectHash = computeProjectHash(cwd);
|
|
323
|
-
if (!projectHash) return null;
|
|
324
|
-
|
|
325
|
-
const indexed = readProjectSessionIndex(projectHash, maxAgeMs);
|
|
326
|
-
if (indexed) return indexed;
|
|
327
|
-
|
|
328
|
-
let best = null;
|
|
329
|
-
try {
|
|
330
|
-
const entries = fs.readdirSync(SESSION_DIR);
|
|
331
|
-
for (const entry of entries) {
|
|
332
|
-
if (!entry.endsWith('.json')) continue;
|
|
333
|
-
const sessionId = entry.slice(0, -'.json'.length);
|
|
334
|
-
const state = readSessionState(sessionId);
|
|
335
|
-
const cmd = state.last_slash_command;
|
|
336
|
-
const candidate = {
|
|
337
|
-
session_id: sessionId,
|
|
338
|
-
project_hash: cmd?.project_hash || state.project_hash || null,
|
|
339
|
-
is_sdlc_stage: Boolean(cmd?.is_sdlc_stage),
|
|
340
|
-
updated_at: cmd?.updated_at || state.updated_at || null,
|
|
341
|
-
};
|
|
342
|
-
if (!isRecentSdlcSessionCandidate(candidate, projectHash, maxAgeMs)) continue;
|
|
343
|
-
if (!best || parseUpdatedAt(candidate.updated_at) > parseUpdatedAt(best.updated_at)) {
|
|
344
|
-
best = candidate;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
} catch { /* ignore */ }
|
|
348
|
-
return best;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
268
|
// ── Short-TTL dedupe guards ──────────────────────────────────────────
|
|
352
269
|
|
|
353
270
|
function normalizeDedupePart(value) {
|
|
@@ -586,7 +503,6 @@ module.exports = {
|
|
|
586
503
|
readSessionSkill,
|
|
587
504
|
persistSessionSlashCommand,
|
|
588
505
|
readSessionLastSlashCommand,
|
|
589
|
-
findRecentSdlcSessionForProject,
|
|
590
506
|
readLastAssistantFromTranscript,
|
|
591
507
|
resolvePromptText,
|
|
592
508
|
getAwCliVersionDetails,
|
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 HEAD 2>/dev/null || echo unknown)"
|
|
105
|
+
COMMIT_HASH="$(git rev-parse --short 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 HEAD 2>/dev/null || echo unknown)"
|
|
289
|
+
COMMIT_HASH="$(git rev-parse --short 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,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghl-ai/aw",
|
|
3
|
-
"version": "0.1.73
|
|
4
|
-
"description": "Agentic Workspace CLI
|
|
3
|
+
"version": "0.1.73",
|
|
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
|
+
}
|