@pushary/agent-hooks 0.64.1 → 0.64.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.64.2
4
+
5
+ ### A run that gave up reported nothing, and said it stopped at the start
6
+
7
+ `agent_setup_completed` was wired to one of setup's fifteen exits: the last line
8
+ of a run that finished. Every other way out returned before it. A key the server
9
+ refused, a cancelled pairing, no terminal to sign in from, an installer that
10
+ threw, a Ctrl-C at the agent checkbox: all silent. The beacon was added so failed
11
+ and abandoned runs would stop being invisible, and the runs it could see were
12
+ still only the ones that already worked.
13
+
14
+ Every early exit reports now, and each says why it stopped: `key-refused`,
15
+ `pairing-cancelled`, `no-key`, `login-rejected`, `no-agents-detected`,
16
+ `invalid-key`, `interrupted`, `crashed`.
17
+
18
+ Argv-time exits stay silent, along with `--help` and `--dry-run`. A flag typo is
19
+ not an abandoned run: nothing was attempted and nothing was written. It is also
20
+ the fastest-failing path there is, and waiting on a beacon took `setup --bogus`
21
+ from 60ms to two seconds against an unreachable server. A dry run stays silent
22
+ for the other reason: counting it as a completed setup would be its own lie.
23
+
24
+ `abandonedAt` said where. It was always `start`, because `markStep` had no call
25
+ site outside its own test, so the field that was supposed to locate a failure was
26
+ a constant. It now moves through the run, per agent inside the configure loop, so
27
+ an installer that hangs is named rather than grouped.
28
+
29
+ Ctrl-C at the pairing QR reports before the process leaves. The cancel and the
30
+ beacon run concurrently and the exit waits for both, so this adds nothing to the
31
+ worst case a cancel already had.
32
+
33
+ The beacon authenticates with the key the run resolved rather than the one
34
+ already installed. Most of these exits happen before the key is written to disk,
35
+ so without that they posted as nobody, which meant the window holding the
36
+ interesting failures was exactly the window that could not report.
37
+
3
38
  ## 0.64.1
4
39
 
5
40
  ### Ctrl-C at the pairing QR printed nothing
@@ -17,7 +17,7 @@ import {
17
17
  reportEvent,
18
18
  resolvePolicy,
19
19
  waitForAnswer
20
- } from "../chunk-5ZDYDU2Q.js";
20
+ } from "../chunk-XOUYM27W.js";
21
21
  import "../chunk-BSZYIAZL.js";
22
22
  import "../chunk-SAF6HGAA.js";
23
23
  import "../chunk-7QLSKOSU.js";
@@ -31,7 +31,7 @@ import {
31
31
  toCodexWire,
32
32
  toPolicyLookup,
33
33
  waitForAnswer
34
- } from "../chunk-5ZDYDU2Q.js";
34
+ } from "../chunk-XOUYM27W.js";
35
35
  import {
36
36
  isGatingMoment,
37
37
  recordKeylessMoment
@@ -3,7 +3,7 @@ import {
3
3
  askUser,
4
4
  reportEvent,
5
5
  waitForAnswer
6
- } from "../chunk-5ZDYDU2Q.js";
6
+ } from "../chunk-XOUYM27W.js";
7
7
  import "../chunk-BSZYIAZL.js";
8
8
  import "../chunk-SAF6HGAA.js";
9
9
  import "../chunk-7QLSKOSU.js";
@@ -6,7 +6,7 @@ import {
6
6
  confirmAppConnection,
7
7
  connectDevice,
8
8
  printConnectInstructions
9
- } from "../chunk-RASBS2CC.js";
9
+ } from "../chunk-GFHQ26ST.js";
10
10
  import "../chunk-3EGEA4KH.js";
11
11
  import {
12
12
  readKeySource
@@ -34,7 +34,7 @@ import {
34
34
  describeReach,
35
35
  fetchChannels,
36
36
  reachVerdict
37
- } from "../chunk-RASBS2CC.js";
37
+ } from "../chunk-GFHQ26ST.js";
38
38
  import "../chunk-3EGEA4KH.js";
39
39
  import {
40
40
  keyPrefix,
@@ -23,7 +23,7 @@ import {
23
23
  savePendingQuestion,
24
24
  sendNotification,
25
25
  waitForAnswer
26
- } from "../chunk-5ZDYDU2Q.js";
26
+ } from "../chunk-XOUYM27W.js";
27
27
  import {
28
28
  isGatingMoment,
29
29
  recordKeylessMoment
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePreToolUse
4
- } from "../chunk-SDXF5I46.js";
4
+ } from "../chunk-SONXGCZY.js";
5
5
  import "../chunk-CAJZAFVS.js";
6
6
  import {
7
7
  exitOnHelpFlag
8
8
  } from "../chunk-ATP6UQPH.js";
9
9
  import "../chunk-JGH37QRB.js";
10
10
  import "../chunk-YHG74UFF.js";
11
- import "../chunk-5ZDYDU2Q.js";
11
+ import "../chunk-XOUYM27W.js";
12
12
  import "../chunk-WLGEY4UX.js";
13
13
  import "../chunk-BSZYIAZL.js";
14
14
  import "../chunk-SAF6HGAA.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleNotification
4
- } from "../chunk-5ZDYDU2Q.js";
4
+ } from "../chunk-XOUYM27W.js";
5
5
  import "../chunk-BSZYIAZL.js";
6
6
  import "../chunk-SAF6HGAA.js";
7
7
  import "../chunk-7QLSKOSU.js";
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePermissionDenied
4
- } from "../chunk-SDXF5I46.js";
4
+ } from "../chunk-SONXGCZY.js";
5
5
  import "../chunk-CAJZAFVS.js";
6
6
  import "../chunk-YHG74UFF.js";
7
- import "../chunk-5ZDYDU2Q.js";
7
+ import "../chunk-XOUYM27W.js";
8
8
  import "../chunk-WLGEY4UX.js";
9
9
  import "../chunk-BSZYIAZL.js";
10
10
  import "../chunk-SAF6HGAA.js";
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePermissionRequest
4
- } from "../chunk-SDXF5I46.js";
4
+ } from "../chunk-SONXGCZY.js";
5
5
  import "../chunk-CAJZAFVS.js";
6
6
  import "../chunk-YHG74UFF.js";
7
- import "../chunk-5ZDYDU2Q.js";
7
+ import "../chunk-XOUYM27W.js";
8
8
  import "../chunk-WLGEY4UX.js";
9
9
  import "../chunk-BSZYIAZL.js";
10
10
  import "../chunk-SAF6HGAA.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePostToolUse
4
- } from "../chunk-5ZDYDU2Q.js";
4
+ } from "../chunk-XOUYM27W.js";
5
5
  import "../chunk-BSZYIAZL.js";
6
6
  import "../chunk-SAF6HGAA.js";
7
7
  import "../chunk-7QLSKOSU.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleUserPrompt
4
- } from "../chunk-5ZDYDU2Q.js";
4
+ } from "../chunk-XOUYM27W.js";
5
5
  import "../chunk-BSZYIAZL.js";
6
6
  import "../chunk-SAF6HGAA.js";
7
7
  import "../chunk-7QLSKOSU.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleSessionEnd
4
- } from "../chunk-5ZDYDU2Q.js";
4
+ } from "../chunk-XOUYM27W.js";
5
5
  import "../chunk-BSZYIAZL.js";
6
6
  import "../chunk-SAF6HGAA.js";
7
7
  import "../chunk-7QLSKOSU.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleSessionStart
4
- } from "../chunk-5ZDYDU2Q.js";
4
+ } from "../chunk-XOUYM27W.js";
5
5
  import "../chunk-BSZYIAZL.js";
6
6
  import "../chunk-SAF6HGAA.js";
7
7
  import "../chunk-7QLSKOSU.js";
@@ -45,7 +45,7 @@ import {
45
45
  connectViaAppPairing,
46
46
  printConnectInstructions,
47
47
  setHumanStream
48
- } from "../chunk-RASBS2CC.js";
48
+ } from "../chunk-GFHQ26ST.js";
49
49
  import "../chunk-3EGEA4KH.js";
50
50
  import {
51
51
  KEY_FILE_MODE,
@@ -86,7 +86,7 @@ import {
86
86
  } from "../chunk-JGH37QRB.js";
87
87
  import {
88
88
  reportEvent
89
- } from "../chunk-5ZDYDU2Q.js";
89
+ } from "../chunk-XOUYM27W.js";
90
90
  import "../chunk-BSZYIAZL.js";
91
91
  import "../chunk-SAF6HGAA.js";
92
92
  import {
@@ -206,32 +206,60 @@ var installSkillViaSkillsCli = (agent) => {
206
206
 
207
207
  // src/setup/telemetry.ts
208
208
  var currentStep = "start";
209
+ var markStep = (step) => {
210
+ currentStep = step;
211
+ };
212
+ var recordedOptions = null;
213
+ var recordSetupOptions = (options) => {
214
+ recordedOptions = options;
215
+ };
216
+ var recordedKey = null;
217
+ var recordSetupKey = (apiKey) => {
218
+ recordedKey = apiKey;
219
+ };
209
220
  var emitted = false;
210
- var reportSetupOutcome = async (outcome) => {
221
+ var defaultDeps = { report: reportEvent };
222
+ var emit = async (deps, props) => {
211
223
  if (emitted) return;
212
224
  emitted = true;
213
225
  try {
214
- await reportEvent(
215
- {
216
- event: "agent_setup_completed",
217
- agentType: "setup",
218
- agents: outcome.completed,
219
- connectMode: outcome.options.connectMode,
220
- connectOutcome: outcome.connectOutcome,
221
- failedAgents: outcome.failed.length,
222
- skippedAgents: outcome.skipped,
223
- nonInteractive: outcome.options.nonInteractive,
224
- keyCheck: outcome.keyCheck,
225
- exitCode: outcome.exitCode,
226
- // Where the run stopped. On a completed run this is the closing step, so
227
- // the interesting values are the ones that are not.
228
- abandonedAt: outcome.exitCode === 0 ? null : currentStep
229
- },
230
- { maxAttempts: 1, timeoutMs: 2e3 }
226
+ await deps.report(
227
+ { event: "agent_setup_completed", agentType: "setup", ...props },
228
+ { maxAttempts: 1, timeoutMs: 2e3, ...recordedKey ? { apiKey: recordedKey } : {} }
231
229
  );
232
230
  } catch {
233
231
  }
234
232
  };
233
+ var reportSetupOutcomeWith = async (deps, outcome) => emit(deps, {
234
+ agents: outcome.completed,
235
+ connectMode: outcome.options.connectMode,
236
+ connectOutcome: outcome.connectOutcome,
237
+ failedAgents: outcome.failed.length,
238
+ skippedAgents: outcome.skipped,
239
+ nonInteractive: outcome.options.nonInteractive,
240
+ keyCheck: outcome.keyCheck,
241
+ exitCode: outcome.exitCode,
242
+ // Where the run stopped. On a completed run this is the closing step, so the
243
+ // interesting values are the ones that are not.
244
+ abandonedAt: outcome.exitCode === 0 ? null : currentStep,
245
+ // Always present, so a query can separate "ended" from "gave up" on the
246
+ // property rather than on the absence of one.
247
+ abortReason: null
248
+ });
249
+ var reportSetupOutcome = (outcome) => reportSetupOutcomeWith(defaultDeps, outcome);
250
+ var reportSetupAbortWith = async (deps, reason, exitCode, keyCheck = "unknown") => emit(deps, {
251
+ agents: [],
252
+ connectMode: recordedOptions?.connectMode ?? null,
253
+ connectOutcome: "skipped",
254
+ failedAgents: 0,
255
+ skippedAgents: [],
256
+ nonInteractive: recordedOptions?.nonInteractive ?? null,
257
+ keyCheck,
258
+ exitCode,
259
+ abandonedAt: currentStep,
260
+ abortReason: reason
261
+ });
262
+ var reportSetupAbort = (reason, exitCode, keyCheck) => reportSetupAbortWith(defaultDeps, reason, exitCode, keyCheck);
235
263
 
236
264
  // src/setup/options.ts
237
265
  var AGENT_CHOICES = ["claude_code", "codex", "gemini_cli", "hermes", "cursor", "custom"];
@@ -333,6 +361,10 @@ var green = (s) => `\x1B[32m${s}\x1B[0m`;
333
361
  var cyan = (s) => `\x1B[36m${s}\x1B[0m`;
334
362
  var yellow = (s) => `\x1B[33m${s}\x1B[0m`;
335
363
  var check = green("\u2713");
364
+ var abortWith = async (reason, code, keyCheck) => {
365
+ await reportSetupAbort(reason, code, keyCheck);
366
+ return code;
367
+ };
336
368
  var readKeyFromStdin = async (options) => {
337
369
  if (!options.keyStdin) return void 0;
338
370
  const chunks = [];
@@ -341,14 +373,14 @@ var readKeyFromStdin = async (options) => {
341
373
  if (!first) {
342
374
  console.log(`
343
375
  ${yellow("!")} --key-stdin was passed but stdin was empty.`);
344
- process.exit(2);
376
+ process.exit(EXIT.USAGE);
345
377
  }
346
378
  if (!isValidApiKey(first)) {
347
379
  console.log(`
348
380
  ${yellow("!")} The key on stdin is not a valid Pushary key. Expected: ${dim("pk_xxx.xxx")}`);
349
381
  console.log(` ${dim("Copy your key from")} ${cyan("https://pushary.com/dashboard/agent/settings")}
350
382
  `);
351
- process.exit(2);
383
+ process.exit(EXIT.USAGE);
352
384
  }
353
385
  return first;
354
386
  };
@@ -971,7 +1003,7 @@ var verifyKeyOrExit = async (apiKey, options, precomputed) => {
971
1003
  console.log(` ${yellow("!")} ${report.message}`);
972
1004
  for (const line of report.next) console.log(` ${dim(line)}`);
973
1005
  console.log();
974
- process.exit(report.exitCode);
1006
+ process.exit(await abortWith("key-refused", report.exitCode, result.kind));
975
1007
  }
976
1008
  if (result.kind === "ok") {
977
1009
  const { siteSlug, siteName, plan } = result.identity;
@@ -1054,7 +1086,7 @@ var resolveAgents = async (options) => {
1054
1086
  console.log(` ${yellow("!")} No agents detected, so nothing was configured. Your key is saved.`);
1055
1087
  console.log(` ${dim("Install an agent and re-run, name one with --agents <id>, or pass --agents none to accept this.")}`);
1056
1088
  console.log();
1057
- process.exit(EXIT.PROBLEMS_FOUND);
1089
+ process.exit(await abortWith("no-agents-detected", EXIT.PROBLEMS_FOUND));
1058
1090
  }
1059
1091
  console.log(` ${check} Selected automatically: ${picked.map((a) => AGENT_NAMES[a]).join(", ")} ${dim("(--agents to choose)")}`);
1060
1092
  return picked;
@@ -1125,6 +1157,7 @@ var main = async () => {
1125
1157
  `);
1126
1158
  process.exit(EXIT.OK);
1127
1159
  }
1160
+ recordSetupOptions(options);
1128
1161
  if (options.json) {
1129
1162
  humanStream = process.stderr;
1130
1163
  setHumanStream(process.stderr);
@@ -1139,6 +1172,7 @@ var main = async () => {
1139
1172
  console.log(` ${dim("Push notifications for AI agents")}`);
1140
1173
  console.log();
1141
1174
  await checkForUpdates(version);
1175
+ markStep("resolve-key");
1142
1176
  const connectMode = options.connectMode;
1143
1177
  const flagKey = await readKeyFromStdin(options) ?? options.key ?? void 0;
1144
1178
  const envKey = process.env.PUSHARY_API_KEY?.trim();
@@ -1174,11 +1208,17 @@ var main = async () => {
1174
1208
  } else if (connectMode === "app" && canRunBrowserLogin() && !options.skipPhone) {
1175
1209
  console.log(` ${dim("Pairing with your Pushary app.")}`);
1176
1210
  console.log(` ${dim("No app? Ctrl-C, then:")} ${cyan("npx @pushary/agent-hooks setup --connect browser")}`);
1211
+ markStep("pair");
1177
1212
  const previous = readKeySource();
1178
- const paired = await connectViaAppPairing({ onCancelled: printPairingEscape });
1213
+ const paired = await connectViaAppPairing({
1214
+ onCancelled: async () => {
1215
+ printPairingEscape();
1216
+ await reportSetupAbort("pairing-cancelled", 130);
1217
+ }
1218
+ });
1179
1219
  if (!paired) {
1180
1220
  printPairingEscape();
1181
- process.exit(EXIT.NOT_CONFIGURED);
1221
+ process.exit(await abortWith("pairing-cancelled", EXIT.NOT_CONFIGURED));
1182
1222
  }
1183
1223
  trimmedKey = paired.apiKey;
1184
1224
  keyFromPairing = true;
@@ -1195,8 +1235,9 @@ var main = async () => {
1195
1235
  console.log(` ${dim("Pass --key <pk_xxx.xxx>, or --key-stdin, or export PUSHARY_API_KEY.")}`);
1196
1236
  console.log(` ${dim("On a machine with a terminal, run")} ${cyan("pushary login")} ${dim("once and re-run this.")}`);
1197
1237
  console.log();
1198
- process.exit(EXIT.NOT_CONFIGURED);
1238
+ process.exit(await abortWith("no-key", EXIT.NOT_CONFIGURED));
1199
1239
  } else {
1240
+ markStep("browser-login");
1200
1241
  const outcome = await runBrowserLogin(
1201
1242
  { say: (line) => console.log(line), bold, dim, cyan, yellow },
1202
1243
  { cliVersion: version }
@@ -1210,7 +1251,7 @@ var main = async () => {
1210
1251
  console.log();
1211
1252
  console.log(` ${yellow("!")} That request was rejected in the browser. Nothing was written.`);
1212
1253
  console.log();
1213
- process.exit(EXIT.NOT_CONFIGURED);
1254
+ process.exit(await abortWith("login-rejected", EXIT.NOT_CONFIGURED));
1214
1255
  } else {
1215
1256
  console.log();
1216
1257
  if (outcome.kind === "unavailable") {
@@ -1231,15 +1272,19 @@ var main = async () => {
1231
1272
  console.log(` ${dim("Copy your key from")} ${cyan("https://pushary.com/dashboard/agent/settings")}`);
1232
1273
  console.log(` ${dim("Or sign up at")} ${cyan("https://pushary.com/sign-up?from=ai-coding")}
1233
1274
  `);
1234
- process.exit(EXIT.USAGE);
1275
+ process.exit(await abortWith("invalid-key", EXIT.USAGE));
1235
1276
  }
1277
+ recordSetupKey(trimmedKey);
1278
+ markStep("verify-key");
1236
1279
  const keyCheck = keyFromPairing ? null : await verifyKeyOrExit(trimmedKey, options, storedKeyCheck ?? void 0);
1280
+ markStep("resolve-agents");
1237
1281
  const agents = await resolveAgents(options);
1238
1282
  if (options.dryRun) {
1239
1283
  reportDryRun(trimmedKey, agents, keyCheck);
1240
1284
  emitJson(options, { ok: true, dryRun: true, agents, keyCheck: keyCheck?.kind ?? "skipped" });
1241
1285
  process.exit(EXIT.OK);
1242
1286
  }
1287
+ markStep("save-key");
1243
1288
  const rc = await saveApiKey(trimmedKey);
1244
1289
  const context = { rc };
1245
1290
  const failed = [];
@@ -1251,6 +1296,7 @@ var main = async () => {
1251
1296
  console.log(` ${dim("Run setup again with --agents <id> when you want one wired up.")}`);
1252
1297
  } else {
1253
1298
  for (const agent of agents) {
1299
+ markStep(`configure:${agent}`);
1254
1300
  try {
1255
1301
  const outcome = await AGENT_SETUP[agent](trimmedKey, context);
1256
1302
  if (outcome === "skipped") skipped.push(agent);
@@ -1269,11 +1315,13 @@ var main = async () => {
1269
1315
  console.log();
1270
1316
  console.log(` ${yellow("!")} Failed: ${failed.join(", ")} ${dim("(others completed successfully)")}`);
1271
1317
  }
1318
+ markStep("project-instructions");
1272
1319
  await offerProjectInstructions(agents, options);
1273
1320
  if (completed.includes("claude_code")) {
1274
1321
  await offerClaudeAlias(options);
1275
1322
  }
1276
1323
  }
1324
+ markStep("connect-phone");
1277
1325
  const skipPhone = options.skipPhone;
1278
1326
  let phone = null;
1279
1327
  if (keyCheck?.kind === "locked") {
@@ -1311,6 +1359,15 @@ var main = async () => {
1311
1359
  rc: rc.kind,
1312
1360
  exitCode: report.exitCode
1313
1361
  });
1362
+ await reportSetupOutcome({
1363
+ options,
1364
+ completed,
1365
+ skipped,
1366
+ failed,
1367
+ connectOutcome: "skipped",
1368
+ keyCheck: "locked",
1369
+ exitCode: report.exitCode
1370
+ });
1314
1371
  process.exit(report.exitCode);
1315
1372
  }
1316
1373
  printManualSteps();
@@ -1318,6 +1375,7 @@ var main = async () => {
1318
1375
  const agentsOk = failed.length === 0 && !configuredNothing;
1319
1376
  const reachChecked = phone !== null;
1320
1377
  const reachesYou = phone?.reachesYou ?? true;
1378
+ markStep("closing");
1321
1379
  const closing = describeClosing({
1322
1380
  agentsOk,
1323
1381
  configuredNothing,
@@ -1372,7 +1430,7 @@ var main = async () => {
1372
1430
  process.exit(exitCode);
1373
1431
  }
1374
1432
  };
1375
- main().catch((err) => {
1433
+ main().catch(async (err) => {
1376
1434
  if (err instanceof UsageError) {
1377
1435
  console.log();
1378
1436
  console.log(` ${yellow("!")} ${err.message}`);
@@ -1384,11 +1442,11 @@ main().catch((err) => {
1384
1442
  console.log();
1385
1443
  console.log(` ${dim("Cancelled. Nothing further was changed.")}`);
1386
1444
  console.log();
1387
- process.exit(130);
1445
+ process.exit(await abortWith("interrupted", 130));
1388
1446
  }
1389
1447
  console.log();
1390
1448
  console.log(` ${yellow("!")} Setup failed: ${formatError(err)}`);
1391
1449
  console.log(` ${dim("Run")} ${cyan("npx @pushary/agent-hooks doctor")} ${dim("after fixing the issue, then rerun setup.")}`);
1392
1450
  console.log();
1393
- process.exit(1);
1451
+ process.exit(await abortWith("crashed", EXIT.FAILED));
1394
1452
  });
@@ -7,7 +7,7 @@ import {
7
7
  describeReach,
8
8
  fetchChannels,
9
9
  reachVerdict
10
- } from "../chunk-RASBS2CC.js";
10
+ } from "../chunk-GFHQ26ST.js";
11
11
  import "../chunk-3EGEA4KH.js";
12
12
  import {
13
13
  readKeySource
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleStop
4
- } from "../chunk-5ZDYDU2Q.js";
4
+ } from "../chunk-XOUYM27W.js";
5
5
  import "../chunk-BSZYIAZL.js";
6
6
  import "../chunk-SAF6HGAA.js";
7
7
  import "../chunk-7QLSKOSU.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleStopFailure
4
- } from "../chunk-5ZDYDU2Q.js";
4
+ } from "../chunk-XOUYM27W.js";
5
5
  import "../chunk-BSZYIAZL.js";
6
6
  import "../chunk-SAF6HGAA.js";
7
7
  import "../chunk-7QLSKOSU.js";
@@ -520,8 +520,8 @@ var connectViaAppPairing = async (options = {}) => {
520
520
  const onInterrupt = () => {
521
521
  cancelled = true;
522
522
  stop(yellow("!"), "Cancelled");
523
- options.onCancelled?.();
524
- void cancelPairing(pairId).finally(() => process.exit(EXIT_ABORTED));
523
+ const flushed = options.onCancelled?.();
524
+ void Promise.allSettled([Promise.resolve(flushed), cancelPairing(pairId)]).finally(() => process.exit(EXIT_ABORTED));
525
525
  };
526
526
  process.once("SIGINT", onInterrupt);
527
527
  try {
@@ -25,7 +25,7 @@ import {
25
25
  sendNotification,
26
26
  throttlePass,
27
27
  waitForAnswer
28
- } from "./chunk-5ZDYDU2Q.js";
28
+ } from "./chunk-XOUYM27W.js";
29
29
  import {
30
30
  isGatingMoment,
31
31
  recordKeylessMoment
@@ -928,7 +928,7 @@ ${injected}` : injected;
928
928
  };
929
929
  var detectInstallMode = () => (process.argv[1] ?? "").includes("_npx") ? "npx" : "cli";
930
930
  var reportEvent = async (event, options = {}) => {
931
- const apiKey = getApiKey();
931
+ const apiKey = options.apiKey ?? getApiKey();
932
932
  const baseUrl = getBaseUrl();
933
933
  return withRetry(async () => {
934
934
  const res = await fetch(`${baseUrl}/api/agent/event`, {
@@ -73,6 +73,16 @@ interface AgentEvent {
73
73
  interface ReportEventOptions {
74
74
  maxAttempts?: number;
75
75
  timeoutMs?: number;
76
+ /**
77
+ * Authenticate with this key instead of the ambient one.
78
+ *
79
+ * getApiKey() reads the environment and ~/.pushary/config.json, so it can only
80
+ * ever speak for a key that is already installed. setup resolves a key minutes
81
+ * before it writes one, and its abort beacons run inside that window: without
82
+ * an override they post as nobody, so the runs that fail before saveApiKey are
83
+ * exactly the runs that cannot report failing.
84
+ */
85
+ apiKey?: string;
76
86
  }
77
87
  interface EventResponse {
78
88
  readonly ok?: boolean;
package/dist/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  handlePreToolUse
3
- } from "../chunk-SDXF5I46.js";
3
+ } from "../chunk-SONXGCZY.js";
4
4
  import "../chunk-CAJZAFVS.js";
5
5
  import "../chunk-YHG74UFF.js";
6
6
  import {
@@ -15,7 +15,7 @@ import {
15
15
  reportEvent,
16
16
  resolvePolicy,
17
17
  waitForAnswer
18
- } from "../chunk-5ZDYDU2Q.js";
18
+ } from "../chunk-XOUYM27W.js";
19
19
  import "../chunk-WLGEY4UX.js";
20
20
  import "../chunk-BSZYIAZL.js";
21
21
  import "../chunk-SAF6HGAA.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushary/agent-hooks",
3
- "version": "0.64.1",
3
+ "version": "0.64.2",
4
4
  "description": "Permission hooks for AI coding agents: route tool approvals through Pushary push notifications",
5
5
  "keywords": [
6
6
  "pushary",