@pushary/agent-hooks 1.6.2 → 1.6.3

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.
Files changed (81) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/bin/pushary-bell-hook.js +18 -18
  3. package/dist/bin/pushary-bell.js +6 -6
  4. package/dist/bin/pushary-claude.js +18 -18
  5. package/dist/bin/pushary-clean.js +19 -19
  6. package/dist/bin/pushary-codex-bridge.js +10 -10
  7. package/dist/bin/pushary-codex-hook.js +23 -23
  8. package/dist/bin/pushary-codex.js +6 -6
  9. package/dist/bin/pushary-connect.js +6 -6
  10. package/dist/bin/pushary-cowork.js +3 -3
  11. package/dist/bin/pushary-daemon.js +23 -23
  12. package/dist/bin/pushary-disconnect.js +10 -10
  13. package/dist/bin/pushary-doctor.js +22 -22
  14. package/dist/bin/pushary-elicitation-hook.js +17 -17
  15. package/dist/bin/pushary-gemini-bridge.js +9 -9
  16. package/dist/bin/pushary-gemini-hook.js +20 -20
  17. package/dist/bin/pushary-hook.js +23 -23
  18. package/dist/bin/pushary-login.js +7 -7
  19. package/dist/bin/pushary-logout.js +4 -4
  20. package/dist/bin/pushary-mode.js +3 -3
  21. package/dist/bin/pushary-notification-hook.js +20 -20
  22. package/dist/bin/pushary-opencode-hook.js +19 -19
  23. package/dist/bin/pushary-permission-denied-hook.js +24 -24
  24. package/dist/bin/pushary-permission-hook.js +23 -23
  25. package/dist/bin/pushary-post-hook.js +20 -20
  26. package/dist/bin/pushary-prompt-hook.js +20 -20
  27. package/dist/bin/pushary-session-end-hook.js +20 -20
  28. package/dist/bin/pushary-session-start-hook.js +24 -24
  29. package/dist/bin/pushary-setup.js +151 -64
  30. package/dist/bin/pushary-stats.js +2 -2
  31. package/dist/bin/pushary-status.js +10 -10
  32. package/dist/bin/pushary-stop-hook.js +20 -20
  33. package/dist/bin/pushary-stopfailure-hook.js +20 -20
  34. package/dist/bin/pushary-transcript-register.js +16 -16
  35. package/dist/bin/pushary-transcripts.js +4 -4
  36. package/dist/bin/pushary-upgrade.js +16 -16
  37. package/dist/bin/pushary-wait.js +3 -3
  38. package/dist/{chunk-ON7VIYOQ.js → chunk-3BJQYXTL.js} +1 -1
  39. package/dist/{chunk-TDXQQB55.js → chunk-3UOC3GRO.js} +1 -1
  40. package/dist/{chunk-CH4QMWBM.js → chunk-4KSTLHWY.js} +1 -1
  41. package/dist/{chunk-HW2M7XAU.js → chunk-57DDP4TB.js} +3 -3
  42. package/dist/{chunk-A6BENRKI.js → chunk-57YDFAPP.js} +6 -6
  43. package/dist/{chunk-XINNQCPW.js → chunk-BEHGVU4W.js} +1 -1
  44. package/dist/{chunk-572FZF7T.js → chunk-BG6OCZ4N.js} +5 -5
  45. package/dist/{chunk-E72R2MHO.js → chunk-COGHCL6K.js} +2 -2
  46. package/dist/{chunk-HYN2BILS.js → chunk-CTOK3AYA.js} +1 -1
  47. package/dist/{chunk-RKNA2L2J.js → chunk-CWIARY6F.js} +1 -1
  48. package/dist/{chunk-55AT5DJD.js → chunk-DX5FOQSO.js} +2 -2
  49. package/dist/{chunk-OXFWJIW4.js → chunk-EJ7ADMNM.js} +1 -1
  50. package/dist/{chunk-A5ODW52C.js → chunk-GHOB245Q.js} +16 -1
  51. package/dist/{chunk-3PDQE66Q.js → chunk-GQPCPEG2.js} +1 -1
  52. package/dist/{chunk-RK2MUM6Q.js → chunk-H3FEVIQD.js} +3 -3
  53. package/dist/{chunk-NEUYPY3I.js → chunk-HCVAMXHT.js} +7 -6
  54. package/dist/{chunk-ZRLB3N37.js → chunk-HHYVBHHC.js} +2 -2
  55. package/dist/{chunk-VQIINJ45.js → chunk-ICGAIM2R.js} +1 -1
  56. package/dist/{chunk-TCT4WUDP.js → chunk-ILGL4L3J.js} +4 -4
  57. package/dist/{chunk-5KREBDUT.js → chunk-JBU7XKY2.js} +1 -1
  58. package/dist/{chunk-GKO7T4JM.js → chunk-JBXUKGZS.js} +4 -4
  59. package/dist/{chunk-2J63MNXV.js → chunk-JX67DVMY.js} +2 -2
  60. package/dist/{chunk-7REOI7BC.js → chunk-KNIIFNNQ.js} +1 -1
  61. package/dist/{chunk-M543MAUN.js → chunk-LDS4ERW4.js} +6 -6
  62. package/dist/{chunk-LH2N6VAN.js → chunk-LM2IOEDK.js} +1 -1
  63. package/dist/{chunk-F5ENKWKY.js → chunk-NKR4YDRP.js} +1 -1
  64. package/dist/{chunk-N6AMKPDW.js → chunk-NMRH3VX4.js} +1 -1
  65. package/dist/{chunk-NSG2Q4PI.js → chunk-NPGOQQCV.js} +1 -1
  66. package/dist/{chunk-LN3FETAC.js → chunk-P35IUFFR.js} +3 -3
  67. package/dist/{chunk-KUQF2VO6.js → chunk-QKOVVL7I.js} +3 -3
  68. package/dist/{chunk-KKZ5TDTB.js → chunk-REYWOCQJ.js} +4 -4
  69. package/dist/{chunk-RKSBBEGT.js → chunk-RJUHSFYE.js} +1 -1
  70. package/dist/{chunk-D5PQGC5V.js → chunk-SND3C2AV.js} +3 -3
  71. package/dist/{chunk-SB2CRLFK.js → chunk-STOMNX4S.js} +1 -1
  72. package/dist/{chunk-HXKY6DFD.js → chunk-TZ4KUNZG.js} +1 -1
  73. package/dist/{chunk-SD6SAIEV.js → chunk-UAV5MNKY.js} +3 -3
  74. package/dist/{chunk-3HUDBDO7.js → chunk-VDMX5EMU.js} +1 -1
  75. package/dist/{chunk-D5ORNUHK.js → chunk-WA7SQX6S.js} +6 -6
  76. package/dist/{chunk-HLY5W2P4.js → chunk-WD6W7QDI.js} +1 -1
  77. package/dist/{chunk-ND43S2N4.js → chunk-YOCXPNQ5.js} +1 -1
  78. package/dist/{reapply-KV6RTOQL.js → reapply-IB7YE7BU.js} +9 -9
  79. package/dist/src/index.d.ts +2 -2
  80. package/dist/src/index.js +12 -12
  81. package/package.json +1 -1
@@ -9,22 +9,22 @@ import {
9
9
  import {
10
10
  coworkOutput,
11
11
  coworkSelection
12
- } from "../chunk-55AT5DJD.js";
12
+ } from "../chunk-DX5FOQSO.js";
13
13
  import "../chunk-PUZZELE6.js";
14
14
  import {
15
15
  detectClaudeVersion
16
- } from "../chunk-HLY5W2P4.js";
16
+ } from "../chunk-WD6W7QDI.js";
17
17
  import {
18
18
  describeVersionManagerPin,
19
19
  versionManagerOf
20
20
  } from "../chunk-GU3EJCVV.js";
21
21
  import {
22
22
  ensureCodexTrustsPusharyHooks
23
- } from "../chunk-ND43S2N4.js";
23
+ } from "../chunk-YOCXPNQ5.js";
24
24
  import {
25
25
  readManagedControlEvidence,
26
26
  waitForMachineReadiness
27
- } from "../chunk-TCT4WUDP.js";
27
+ } from "../chunk-ILGL4L3J.js";
28
28
  import {
29
29
  HERMES_CONFIG_SCRIPT,
30
30
  HERMES_PIP_PACKAGE,
@@ -34,7 +34,7 @@ import {
34
34
  isHermesConfigReceipt,
35
35
  resolveHermesPython,
36
36
  runHermesPythonScript
37
- } from "../chunk-RKSBBEGT.js";
37
+ } from "../chunk-RJUHSFYE.js";
38
38
  import {
39
39
  describeDetection,
40
40
  detectAllAgents,
@@ -46,7 +46,7 @@ import {
46
46
  shortenHome,
47
47
  vscodeSettingsTargets,
48
48
  writeInstructionBlock
49
- } from "../chunk-LN3FETAC.js";
49
+ } from "../chunk-P35IUFFR.js";
50
50
  import {
51
51
  OPENCODE_HOOK_BINARY,
52
52
  addOpenCodeMcpServer,
@@ -57,7 +57,7 @@ import {
57
57
  openCodePluginDir,
58
58
  openCodePluginFile,
59
59
  openCodeWired
60
- } from "../chunk-SB2CRLFK.js";
60
+ } from "../chunk-STOMNX4S.js";
61
61
  import {
62
62
  addCompatibleHooks,
63
63
  addCompatibleMcpServer,
@@ -68,7 +68,7 @@ import {
68
68
  compatibleMcpFile,
69
69
  compatiblePermissionRuleFile,
70
70
  hasCompatibleHooks
71
- } from "../chunk-572FZF7T.js";
71
+ } from "../chunk-BG6OCZ4N.js";
72
72
  import {
73
73
  addClaudeMcpServer,
74
74
  addPusharyHooks,
@@ -76,16 +76,16 @@ import {
76
76
  captureClaudeMcpServer,
77
77
  isClaudeMcpSnapshot,
78
78
  updateClaudeMcpSnapshot
79
- } from "../chunk-RK2MUM6Q.js";
79
+ } from "../chunk-H3FEVIQD.js";
80
80
  import {
81
81
  detectProviderLiveCapabilities,
82
82
  hasSpawnProvider,
83
83
  resolveControlPolicy
84
- } from "../chunk-E72R2MHO.js";
84
+ } from "../chunk-COGHCL6K.js";
85
85
  import {
86
86
  describeAutoUpdateAnnouncement,
87
87
  takeAutoUpdateAnnouncement
88
- } from "../chunk-HYN2BILS.js";
88
+ } from "../chunk-CTOK3AYA.js";
89
89
  import {
90
90
  KEEP_HINT,
91
91
  captureHookTakeover,
@@ -95,23 +95,23 @@ import {
95
95
  hookOwnerOf,
96
96
  mcpBearerKey,
97
97
  planHooks
98
- } from "../chunk-KKZ5TDTB.js";
98
+ } from "../chunk-REYWOCQJ.js";
99
99
  import {
100
100
  AGENT_CHOICES,
101
101
  effectiveControlMode,
102
102
  effectiveVerify,
103
103
  parseSetupOptions
104
- } from "../chunk-NEUYPY3I.js";
104
+ } from "../chunk-HCVAMXHT.js";
105
105
  import {
106
106
  liveBridgeProbe,
107
107
  resolveBridgeStub
108
- } from "../chunk-3PDQE66Q.js";
108
+ } from "../chunk-GQPCPEG2.js";
109
109
  import {
110
110
  claudeWired,
111
111
  codexWired,
112
112
  geminiWired,
113
113
  pusharyHookExecutable
114
- } from "../chunk-D5PQGC5V.js";
114
+ } from "../chunk-SND3C2AV.js";
115
115
  import {
116
116
  clearDaemonNeedsLogin,
117
117
  daemonHasRemoteProof,
@@ -124,25 +124,25 @@ import {
124
124
  replaceDaemonService,
125
125
  stopDaemonService,
126
126
  waitForDaemonRemoteProof
127
- } from "../chunk-KUQF2VO6.js";
127
+ } from "../chunk-QKOVVL7I.js";
128
128
  import {
129
129
  GEMINI_HOOK_BINARY,
130
130
  addGeminiHooks,
131
131
  addGeminiMcpServer,
132
132
  compareVersion,
133
133
  parseVersion
134
- } from "../chunk-HW2M7XAU.js";
135
- import "../chunk-3HUDBDO7.js";
134
+ } from "../chunk-57DDP4TB.js";
135
+ import "../chunk-VDMX5EMU.js";
136
136
  import {
137
137
  transcriptPreferenceForSetup
138
- } from "../chunk-5KREBDUT.js";
138
+ } from "../chunk-JBU7XKY2.js";
139
139
  import "../chunk-XHKBHWLX.js";
140
140
  import {
141
141
  reportEvent
142
- } from "../chunk-GKO7T4JM.js";
143
- import "../chunk-XINNQCPW.js";
142
+ } from "../chunk-JBXUKGZS.js";
143
+ import "../chunk-BEHGVU4W.js";
144
144
  import "../chunk-LVHGSD5E.js";
145
- import "../chunk-LH2N6VAN.js";
145
+ import "../chunk-LM2IOEDK.js";
146
146
  import {
147
147
  addCodexHookTrust,
148
148
  addCodexHooks,
@@ -181,7 +181,7 @@ import {
181
181
  resolveGlobalBinary,
182
182
  vscodePluginDir,
183
183
  vscodePluginMcp
184
- } from "../chunk-ON7VIYOQ.js";
184
+ } from "../chunk-3BJQYXTL.js";
185
185
  import {
186
186
  BROWSER_CONNECT_COMMAND,
187
187
  confirmAppConnection,
@@ -192,13 +192,13 @@ import {
192
192
  printConnectInstructions,
193
193
  roundTripEvidence,
194
194
  verifyRoundTrip
195
- } from "../chunk-ZRLB3N37.js";
195
+ } from "../chunk-HHYVBHHC.js";
196
196
  import "../chunk-3EGEA4KH.js";
197
197
  import {
198
198
  checkApiKey,
199
199
  describeKeyCheck,
200
200
  samePusharyAccount
201
- } from "../chunk-HXKY6DFD.js";
201
+ } from "../chunk-TZ4KUNZG.js";
202
202
  import {
203
203
  setHumanStream
204
204
  } from "../chunk-QCGNGEGE.js";
@@ -216,7 +216,7 @@ import {
216
216
  readKeySource,
217
217
  resolveShellRc,
218
218
  writeKey
219
- } from "../chunk-RKNA2L2J.js";
219
+ } from "../chunk-CWIARY6F.js";
220
220
  import "../chunk-HETOKNIL.js";
221
221
  import "../chunk-SAF6HGAA.js";
222
222
  import {
@@ -225,7 +225,7 @@ import {
225
225
  import {
226
226
  EXIT
227
227
  } from "../chunk-KZERVKTD.js";
228
- import "../chunk-NSG2Q4PI.js";
228
+ import "../chunk-NPGOQQCV.js";
229
229
  import {
230
230
  backupFile,
231
231
  readJsonSafe,
@@ -241,7 +241,7 @@ import {
241
241
  compatibleTargetFiles,
242
242
  hookCompatibleProfile,
243
243
  isValidApiKey
244
- } from "../chunk-A5ODW52C.js";
244
+ } from "../chunk-GHOB245Q.js";
245
245
  import {
246
246
  NPX_LATEST_COMMAND,
247
247
  renderCommandHelp
@@ -278,6 +278,35 @@ var planPhoneCheck = (context) => {
278
278
  return "connect";
279
279
  };
280
280
 
281
+ // src/setup/agent-failure.ts
282
+ var AgentConfigError = class extends Error {
283
+ kind;
284
+ filePath;
285
+ constructor(kind, filePath, message) {
286
+ super(message);
287
+ this.name = "AgentConfigError";
288
+ this.kind = kind;
289
+ this.filePath = filePath;
290
+ }
291
+ };
292
+ var configFailureKind = (readFailure) => readFailure === "unparseable" ? "config-unparseable" : "config-unreadable";
293
+ var AGENT_FAILURE_DETAILS = {
294
+ "not-wired": "reported success but its config is not there.",
295
+ "app-account-mismatch": "Mac app hooks kept, but their Pushary account could not be matched to this setup."
296
+ };
297
+ var describedAgentFailure = (agent, kind) => ({
298
+ agent,
299
+ kind,
300
+ detail: AGENT_FAILURE_DETAILS[kind]
301
+ });
302
+ var agentFailureFromError = (agent, error, describeError) => ({
303
+ agent,
304
+ kind: error instanceof AgentConfigError ? error.kind : "installer-error",
305
+ detail: describeError(error)
306
+ });
307
+ var retryAgentCommand = (agent) => `${NPX_LATEST_COMMAND} setup --agents ${agent}`;
308
+ var agentFailureWire = (failures) => failures.map(({ agent, kind }) => ({ agent, kind }));
309
+
281
310
  // src/setup/closing.ts
282
311
  var ACTIVITY_URL = "pushary.com/dashboard/agent/activity";
283
312
  var COMMAND_SURFACE = [
@@ -318,7 +347,8 @@ var describeClosing = (facts) => {
318
347
  ok: false,
319
348
  headline: "Setup failed.",
320
349
  next: ["Nothing was configured. Run pushary doctor to see why."],
321
- exitCode: EXIT.FAILED
350
+ exitCode: EXIT.FAILED,
351
+ reason: "configured-nothing"
322
352
  };
323
353
  }
324
354
  if (facts.failed.length > 0) {
@@ -331,7 +361,8 @@ var describeClosing = (facts) => {
331
361
  "",
332
362
  `Approvals: ${ACTIVITY_URL}`
333
363
  ],
334
- exitCode: EXIT.PROBLEMS_FOUND
364
+ exitCode: EXIT.PROBLEMS_FOUND,
365
+ reason: "agents-failed"
335
366
  };
336
367
  }
337
368
  if (facts.staleEnvironmentKey) {
@@ -339,7 +370,8 @@ var describeClosing = (facts) => {
339
370
  ok: false,
340
371
  headline: "Agents configured. This terminal still selects the previous key.",
341
372
  next: nextSteps(facts, reachable),
342
- exitCode: EXIT.PROBLEMS_FOUND
373
+ exitCode: EXIT.PROBLEMS_FOUND,
374
+ reason: "stale-environment-key"
343
375
  };
344
376
  }
345
377
  if (facts.daemonReady === false) {
@@ -351,7 +383,8 @@ var describeClosing = (facts) => {
351
383
  "pushary daemon install install or repair the background service",
352
384
  "pushary doctor verify it became reachable"
353
385
  ],
354
- exitCode: EXIT.PROBLEMS_FOUND
386
+ exitCode: EXIT.PROBLEMS_FOUND,
387
+ reason: "control-unready"
355
388
  };
356
389
  }
357
390
  if (facts.roundTripAnswered === true) {
@@ -359,7 +392,8 @@ var describeClosing = (facts) => {
359
392
  ok: true,
360
393
  headline: "Agents configured. Synthetic answer returned.",
361
394
  next: ["Agent hook activation remains unverified.", ...nextSteps(facts, reachable), "", `Approvals: ${ACTIVITY_URL}`],
362
- exitCode: EXIT.OK
395
+ exitCode: EXIT.OK,
396
+ reason: "synthetic-answer"
363
397
  };
364
398
  }
365
399
  if (facts.reachChecked && !facts.reachesYou) {
@@ -371,7 +405,8 @@ var describeClosing = (facts) => {
371
405
  "",
372
406
  ...nextSteps(facts, false)
373
407
  ],
374
- exitCode: EXIT.NO_DEVICE
408
+ exitCode: EXIT.NO_DEVICE,
409
+ reason: "phone-unverified"
375
410
  };
376
411
  }
377
412
  if (facts.roundTripAnswered === false) {
@@ -386,7 +421,8 @@ var describeClosing = (facts) => {
386
421
  "",
387
422
  "If you simply were not looking, re-run setup or pass --verify push to skip this check."
388
423
  ],
389
- exitCode: EXIT.PROBLEMS_FOUND
424
+ exitCode: EXIT.PROBLEMS_FOUND,
425
+ reason: "roundtrip-unanswered"
390
426
  };
391
427
  }
392
428
  if (!facts.reachChecked) {
@@ -398,16 +434,28 @@ var describeClosing = (facts) => {
398
434
  "",
399
435
  ...nextSteps(facts, false)
400
436
  ],
401
- exitCode: EXIT.OK
437
+ exitCode: EXIT.OK,
438
+ reason: "phone-skipped"
402
439
  };
403
440
  }
404
441
  return {
405
442
  ok: true,
406
443
  headline: "Setup complete.",
407
444
  next: [...nextSteps(facts, true), "", `Approvals: ${ACTIVITY_URL}`],
408
- exitCode: EXIT.OK
445
+ exitCode: EXIT.OK,
446
+ reason: "complete"
409
447
  };
410
448
  };
449
+ var RETRY_AGENT_LABEL = "Retry just this agent:";
450
+ var describeAgentFailures = (failures, agentName) => failures.map((failure) => ({
451
+ summary: `${agentName(failure.agent)}: ${failure.detail}`,
452
+ retryCommand: retryAgentCommand(failure.agent)
453
+ }));
454
+ var unverifiedKeyClosingReason = (facts) => {
455
+ if (facts.failedCount > 0) return "agents-failed";
456
+ if (facts.controlLifecycleFailed) return "control-unready";
457
+ return facts.keyCheck === "locked" ? "plan-inactive" : "key-unverified";
458
+ };
411
459
 
412
460
  // src/setup/codex-version.ts
413
461
  import { dirname, join } from "path";
@@ -547,13 +595,20 @@ var recordCodexTrust = (outcome) => {
547
595
  recordedCodexTrust = outcome;
548
596
  };
549
597
  var emitted = false;
598
+ var SETUP_COMPLETED_EVENT = "agent_setup_completed";
599
+ var SETUP_AGENT_TYPE = "setup";
550
600
  var defaultDeps = { report: reportEvent };
551
- var emit = async (deps, props) => {
601
+ var completeBeacon = (run) => ({
602
+ ...run,
603
+ codexTrust: recordedCodexTrust,
604
+ cliVersion: getPackageVersion()
605
+ });
606
+ var emit = async (deps, run) => {
552
607
  if (emitted) return;
553
608
  emitted = true;
554
609
  try {
555
610
  await deps.report(
556
- { event: "agent_setup_completed", agentType: "setup", ...props, codexTrust: recordedCodexTrust },
611
+ { event: SETUP_COMPLETED_EVENT, agentType: SETUP_AGENT_TYPE, ...completeBeacon(run) },
557
612
  { maxAttempts: 1, timeoutMs: 2e3, ...recordedKey ? { apiKey: recordedKey } : {} }
558
613
  );
559
614
  } catch {
@@ -563,7 +618,9 @@ var reportSetupOutcomeWith = async (deps, outcome) => emit(deps, {
563
618
  agents: outcome.completed,
564
619
  connectMode: outcome.options.connectMode,
565
620
  connectOutcome: outcome.connectOutcome,
566
- failedAgents: outcome.failed.length,
621
+ failedAgents: outcome.failures.length,
622
+ agentFailures: agentFailureWire(outcome.failures),
623
+ closingReason: outcome.closingReason,
567
624
  skippedAgents: outcome.skipped,
568
625
  nonInteractive: outcome.options.nonInteractive,
569
626
  keyCheck: outcome.keyCheck,
@@ -581,6 +638,8 @@ var reportSetupAbortWith = async (deps, reason, exitCode, keyCheck = "unknown")
581
638
  connectMode: recordedOptions?.connectMode ?? null,
582
639
  connectOutcome: "skipped",
583
640
  failedAgents: 0,
641
+ agentFailures: [],
642
+ closingReason: null,
584
643
  skippedAgents: [],
585
644
  nonInteractive: recordedOptions?.nonInteractive ?? null,
586
645
  keyCheck,
@@ -676,7 +735,9 @@ var readAgentJson = (filePath) => {
676
735
  if (result.kind === "missing") return {};
677
736
  const backup = backupFile(filePath);
678
737
  const reason = result.kind === "unparseable" ? "is not valid JSON" : "could not be read";
679
- throw new Error(
738
+ throw new AgentConfigError(
739
+ configFailureKind(result.kind),
740
+ filePath,
680
741
  `${filePath} ${reason}, so it was left untouched. A copy is at ${backup}. Fix or remove the original, then re-run setup.`
681
742
  );
682
743
  };
@@ -691,14 +752,16 @@ var readAgentToml = (filePath) => {
691
752
  raw = readFileSync(filePath, "utf-8");
692
753
  } catch (err) {
693
754
  if (err.code === "ENOENT") return {};
694
- throw new Error(`${filePath} could not be read, so it was left untouched.`);
755
+ throw new AgentConfigError("config-unreadable", filePath, `${filePath} could not be read, so it was left untouched.`);
695
756
  }
696
757
  if (raw.trim() === "") return {};
697
758
  try {
698
759
  return parseTOML(raw);
699
760
  } catch {
700
761
  const backup = backupFile(filePath);
701
- throw new Error(
762
+ throw new AgentConfigError(
763
+ "config-unparseable",
764
+ filePath,
702
765
  `${filePath} is not valid TOML, so it was left untouched. A copy is at ${backup}. Fix or remove the original, then re-run setup.`
703
766
  );
704
767
  }
@@ -1178,13 +1241,15 @@ var installCursorUserHooks = (gateScript) => {
1178
1241
  if (existsSync(CURSOR_USER_HOOKS)) {
1179
1242
  const result = readJsonSafe(CURSOR_USER_HOOKS);
1180
1243
  if (result.kind === "ok") userHooks = result.value;
1181
- else {
1244
+ else if (result.kind !== "missing") {
1182
1245
  let backup = "";
1183
1246
  try {
1184
1247
  backup = backupFile(CURSOR_USER_HOOKS);
1185
1248
  } catch {
1186
1249
  }
1187
- throw new Error(
1250
+ throw new AgentConfigError(
1251
+ configFailureKind(result.kind),
1252
+ CURSOR_USER_HOOKS,
1188
1253
  `Could not parse or read Cursor hooks.json; left it untouched${backup ? ` and backed it up at ${backup}` : ""}. Fix the file, then re-run setup.`
1189
1254
  );
1190
1255
  }
@@ -1810,6 +1875,13 @@ var AGENT_CAPABILITIES = {
1810
1875
  ...compatibleRecord((profile) => profile.mcp ? "MCP + native hooks" : "native hooks"),
1811
1876
  custom: "any MCP or HTTP agent (Windsurf, n8n, custom)"
1812
1877
  };
1878
+ var failedAgentNames = (failures) => failures.map((failure) => AGENT_NAMES[failure.agent]);
1879
+ var printAgentFailures = (failures) => {
1880
+ for (const failure of describeAgentFailures(failures, (agent) => AGENT_NAMES[agent])) {
1881
+ console.log(` ${yellow("!")} ${failure.summary}`);
1882
+ console.log(` ${dim(RETRY_AGENT_LABEL)} ${cyan(failure.retryCommand)}`);
1883
+ }
1884
+ };
1813
1885
  var NAME_COLUMN = Math.max(...Object.values(AGENT_NAMES).map((name) => name.length)) + 2;
1814
1886
  var AGENT_LABELS = Object.fromEntries(
1815
1887
  Object.keys(AGENT_NAMES).map((agent) => [
@@ -2138,7 +2210,7 @@ var main = async () => {
2138
2210
  `This shell still exports the previous key (${keyPrefix(envKey)}), and it wins over the one just saved. Open a new terminal before starting an agent here, or re-export PUSHARY_API_KEY.`
2139
2211
  );
2140
2212
  }
2141
- const failed = [];
2213
+ const failures = [];
2142
2214
  const completed = [];
2143
2215
  const skipped = [];
2144
2216
  const hookOwners = [];
@@ -2157,9 +2229,10 @@ var main = async () => {
2157
2229
  if (keepAppWiring) {
2158
2230
  if (!await appAccountMatches(agent)) {
2159
2231
  hookOwners.push({ agent, owner: "app", kept: true });
2160
- failed.push(AGENT_NAMES[agent]);
2232
+ const failure = describedAgentFailure(agent, "app-account-mismatch");
2233
+ failures.push(failure);
2161
2234
  console.log(`
2162
- ${yellow("!")} ${AGENT_NAMES[agent]}: Mac app hooks kept, but their Pushary account could not be matched to this setup.`);
2235
+ ${yellow("!")} ${AGENT_NAMES[agent]}: ${failure.detail}`);
2163
2236
  console.log(` ${dim("Sign the Mac app into the same account and repair this agent, then re-run setup.")}`);
2164
2237
  console.log(` ${dim("Or pass --take-over-hooks if you intentionally want the CLI to own these hooks.")}`);
2165
2238
  continue;
@@ -2178,13 +2251,15 @@ var main = async () => {
2178
2251
  completed.push(agent);
2179
2252
  hookOwners.push({ agent, owner: hookOwnerFor(agent, appBridgeAvailable), kept: false });
2180
2253
  } else {
2181
- failed.push(AGENT_NAMES[agent]);
2182
- console.log(` ${yellow("!")} ${AGENT_NAMES[agent]} reported success but its config is not there.`);
2254
+ const failure = describedAgentFailure(agent, "not-wired");
2255
+ failures.push(failure);
2256
+ console.log(` ${yellow("!")} ${AGENT_NAMES[agent]} ${failure.detail}`);
2183
2257
  console.log(` ${dim("Re-run setup, then")} ${cyan("npx @pushary/agent-hooks@latest doctor")} ${dim("to see what is missing.")}`);
2184
2258
  }
2185
2259
  } catch (err) {
2186
- failed.push(AGENT_NAMES[agent]);
2187
- console.log(` ${yellow("!")} ${AGENT_NAMES[agent]} setup failed: ${formatError(err)}`);
2260
+ const failure = agentFailureFromError(agent, err, formatError);
2261
+ failures.push(failure);
2262
+ console.log(` ${yellow("!")} ${AGENT_NAMES[agent]} setup failed: ${failure.detail}`);
2188
2263
  console.log(` ${dim("Other agents will continue. Re-run setup to retry.")}`);
2189
2264
  }
2190
2265
  }
@@ -2192,9 +2267,9 @@ var main = async () => {
2192
2267
  console.log();
2193
2268
  console.log(` ${yellow("!")} Not configured: ${skipped.map((a) => a.replace("_", " ")).join(", ")} ${dim("(not installed on this machine)")}`);
2194
2269
  }
2195
- if (failed.length > 0) {
2270
+ if (failures.length > 0) {
2196
2271
  console.log();
2197
- console.log(` ${yellow("!")} Failed: ${failed.join(", ")} ${dim("(others completed successfully)")}`);
2272
+ console.log(` ${yellow("!")} Failed: ${failedAgentNames(failures).join(", ")} ${dim("(others completed successfully)")}`);
2198
2273
  console.log(` ${dim("Run")} npx @pushary/agent-hooks@latest doctor ${dim("for the reason, or send it to")} ${SUPPORT_EMAIL}`);
2199
2274
  }
2200
2275
  markStep("project-instructions");
@@ -2283,9 +2358,13 @@ var main = async () => {
2283
2358
  if (keyCheck.kind === "locked" || keyCheck.kind === "unreachable") {
2284
2359
  const report = describeKeyCheck(keyCheck);
2285
2360
  const next = [...report.next, "Finish activation: pushary setup (reuses the saved key)."];
2286
- const exitCode2 = failed.length > 0 || controlLifecycleFailure ? EXIT.PROBLEMS_FOUND : report.exitCode;
2361
+ const exitCode2 = failures.length > 0 || controlLifecycleFailure ? EXIT.PROBLEMS_FOUND : report.exitCode;
2287
2362
  printManualSteps();
2288
2363
  console.log(` ${yellow(bold(keyCheck.kind === "locked" ? "Agents configured, approvals inactive." : "Configuration saved, activation unverified."))}`);
2364
+ if (failures.length > 0) {
2365
+ console.log();
2366
+ printAgentFailures(failures);
2367
+ }
2289
2368
  console.log();
2290
2369
  console.log(` ${report.message}`);
2291
2370
  for (const line of next) console.log(` ${dim(line)}`);
@@ -2297,7 +2376,8 @@ var main = async () => {
2297
2376
  configured: completed,
2298
2377
  skipped,
2299
2378
  manualSteps,
2300
- failed,
2379
+ failed: failedAgentNames(failures),
2380
+ agentFailures: failures,
2301
2381
  keyCheck: keyCheck.kind,
2302
2382
  rc: rc.kind,
2303
2383
  control: controlMode,
@@ -2308,7 +2388,12 @@ var main = async () => {
2308
2388
  options,
2309
2389
  completed,
2310
2390
  skipped,
2311
- failed,
2391
+ failures,
2392
+ closingReason: unverifiedKeyClosingReason({
2393
+ failedCount: failures.length,
2394
+ controlLifecycleFailed: controlLifecycleFailure !== null,
2395
+ keyCheck: keyCheck.kind
2396
+ }),
2312
2397
  connectOutcome: "skipped",
2313
2398
  keyCheck: keyCheck.kind,
2314
2399
  exitCode: exitCode2
@@ -2317,7 +2402,7 @@ var main = async () => {
2317
2402
  }
2318
2403
  printManualSteps();
2319
2404
  const configuredNothing = agents.length > 0 && completed.length === 0;
2320
- const agentsOk = failed.length === 0 && !configuredNothing;
2405
+ const agentsOk = failures.length === 0 && !configuredNothing;
2321
2406
  const reachChecked = phone !== null;
2322
2407
  const reachesYou = phone?.reachesYou ?? true;
2323
2408
  markStep("closing");
@@ -2397,7 +2482,7 @@ var main = async () => {
2397
2482
  agentsOk,
2398
2483
  configuredNothing,
2399
2484
  completed,
2400
- failed,
2485
+ failed: failedAgentNames(failures),
2401
2486
  reachChecked,
2402
2487
  reachesYou,
2403
2488
  managedControlReady: !controlLifecycleFailure && managedControl.ready,
@@ -2408,10 +2493,10 @@ var main = async () => {
2408
2493
  roundTripAnswered: roundTrip === null ? null : roundTrip.kind === "answered" ? true : roundTrip.kind === "unanswered" ? false : null
2409
2494
  });
2410
2495
  console.log(` ${closing.ok ? green(bold(closing.headline)) : yellow(bold(closing.headline))}`);
2411
- if (failed.length > 0) {
2496
+ if (failures.length > 0) {
2412
2497
  console.log();
2413
2498
  for (const agent of completed) console.log(` ${check} ${AGENT_NAMES[agent] ?? agent}`);
2414
- for (const item of failed) console.log(` ${yellow("!")} ${item}`);
2499
+ printAgentFailures(failures);
2415
2500
  }
2416
2501
  const ownershipLine = describeHookOwnership(hookOwners, AGENT_NAMES);
2417
2502
  if (ownershipLine) console.log(` ${dim(ownershipLine)}`);
@@ -2426,7 +2511,8 @@ var main = async () => {
2426
2511
  options,
2427
2512
  completed,
2428
2513
  skipped,
2429
- failed,
2514
+ failures,
2515
+ closingReason: closing.reason,
2430
2516
  // 'answered' is finally reachable. It was in the enum from the start and
2431
2517
  // nothing produced it, because setup stopped at a delivered notification, so
2432
2518
  // the one value meaning "a human tapped" was never emitted by the command
@@ -2440,7 +2526,8 @@ var main = async () => {
2440
2526
  configured: completed,
2441
2527
  skipped,
2442
2528
  manualSteps,
2443
- failed,
2529
+ failed: failedAgentNames(failures),
2530
+ agentFailures: failures,
2444
2531
  hookOwners,
2445
2532
  keyCheck: keyCheck?.kind ?? "skipped",
2446
2533
  reach: phone === null ? "skipped" : phone.reachesYou ? "yours" : phone.outcome?.kind ?? phone.detail ?? "unreachable",
@@ -2460,7 +2547,7 @@ var main = async () => {
2460
2547
  exitCode
2461
2548
  });
2462
2549
  if (exitCode !== EXIT.OK) {
2463
- if (configuredNothing && failed.length === 0) {
2550
+ if (configuredNothing && failures.length === 0) {
2464
2551
  console.log(` ${yellow("!")} Nothing was configured: none of the agents you asked for are installed here.`);
2465
2552
  console.log(` ${dim("Your key is saved. Install one and re-run, or pass --agents none to accept this.")}`);
2466
2553
  console.log();
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  readLedgerSummary
4
- } from "../chunk-CH4QMWBM.js";
4
+ } from "../chunk-4KSTLHWY.js";
5
5
  import {
6
6
  exitOnHelpFlag
7
7
  } from "../chunk-P4BNYJ5Q.js";
@@ -9,7 +9,7 @@ import "../chunk-KZERVKTD.js";
9
9
  import {
10
10
  getApiKey
11
11
  } from "../chunk-OSJEMXSR.js";
12
- import "../chunk-A5ODW52C.js";
12
+ import "../chunk-GHOB245Q.js";
13
13
  import "../chunk-EA3IELHP.js";
14
14
  import "../chunk-HWJW3CPO.js";
15
15
 
@@ -2,22 +2,22 @@
2
2
  import {
3
3
  describeLastSeen,
4
4
  listMachines
5
- } from "../chunk-TCT4WUDP.js";
6
- import "../chunk-E72R2MHO.js";
7
- import "../chunk-KUQF2VO6.js";
5
+ } from "../chunk-ILGL4L3J.js";
6
+ import "../chunk-COGHCL6K.js";
7
+ import "../chunk-QKOVVL7I.js";
8
8
  import "../chunk-XHKBHWLX.js";
9
- import "../chunk-LH2N6VAN.js";
10
- import "../chunk-ON7VIYOQ.js";
9
+ import "../chunk-LM2IOEDK.js";
10
+ import "../chunk-3BJQYXTL.js";
11
11
  import {
12
12
  describeReach,
13
13
  fetchChannels,
14
14
  reachVerdict
15
- } from "../chunk-ZRLB3N37.js";
15
+ } from "../chunk-HHYVBHHC.js";
16
16
  import "../chunk-3EGEA4KH.js";
17
17
  import {
18
18
  checkApiKey,
19
19
  describeKeyCheck
20
- } from "../chunk-HXKY6DFD.js";
20
+ } from "../chunk-TZ4KUNZG.js";
21
21
  import "../chunk-QCGNGEGE.js";
22
22
  import {
23
23
  createIo
@@ -30,7 +30,7 @@ import {
30
30
  } from "../chunk-GMXKITVA.js";
31
31
  import {
32
32
  readKeySource
33
- } from "../chunk-RKNA2L2J.js";
33
+ } from "../chunk-CWIARY6F.js";
34
34
  import "../chunk-HETOKNIL.js";
35
35
  import "../chunk-SAF6HGAA.js";
36
36
  import {
@@ -39,10 +39,10 @@ import {
39
39
  import {
40
40
  EXIT
41
41
  } from "../chunk-KZERVKTD.js";
42
- import "../chunk-NSG2Q4PI.js";
42
+ import "../chunk-NPGOQQCV.js";
43
43
  import "../chunk-T7E75EKA.js";
44
44
  import "../chunk-OSJEMXSR.js";
45
- import "../chunk-A5ODW52C.js";
45
+ import "../chunk-GHOB245Q.js";
46
46
  import "../chunk-EA3IELHP.js";
47
47
  import "../chunk-HWJW3CPO.js";
48
48