@pushary/agent-hooks 0.89.13 → 0.90.0

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 (78) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/data/SKILL.md +1 -1
  3. package/data/cursor-plugin/skills/pushary/SKILL.md +1 -1
  4. package/data/vscode-plugin/skills/pushary/SKILL.md +1 -1
  5. package/dist/bin/pushary-bell-hook.js +4 -4
  6. package/dist/bin/pushary-bell.js +8 -8
  7. package/dist/bin/pushary-claude.js +72 -21
  8. package/dist/bin/pushary-clean.js +16 -42
  9. package/dist/bin/pushary-codex-bridge.js +37 -12
  10. package/dist/bin/pushary-codex-hook.js +45 -12
  11. package/dist/bin/pushary-codex.js +7 -7
  12. package/dist/bin/pushary-connect.js +11 -10
  13. package/dist/bin/pushary-daemon.js +186 -62
  14. package/dist/bin/pushary-disconnect.js +8 -8
  15. package/dist/bin/pushary-doctor.js +108 -25
  16. package/dist/bin/pushary-elicitation-hook.js +4 -4
  17. package/dist/bin/pushary-gemini-bridge.js +33 -11
  18. package/dist/bin/pushary-gemini-hook.js +21 -10
  19. package/dist/bin/pushary-hook.js +13 -13
  20. package/dist/bin/pushary-login.js +18 -7
  21. package/dist/bin/pushary-logout.js +6 -6
  22. package/dist/bin/pushary-mode.js +28 -21
  23. package/dist/bin/pushary-notification-hook.js +7 -7
  24. package/dist/bin/pushary-opencode-hook.js +8 -8
  25. package/dist/bin/pushary-permission-denied-hook.js +11 -11
  26. package/dist/bin/pushary-permission-hook.js +11 -11
  27. package/dist/bin/pushary-post-hook.js +14 -8
  28. package/dist/bin/pushary-prompt-hook.js +7 -7
  29. package/dist/bin/pushary-session-end-hook.js +7 -7
  30. package/dist/bin/pushary-session-start-hook.js +7 -7
  31. package/dist/bin/pushary-setup.js +168 -45
  32. package/dist/bin/pushary-stats.js +4 -4
  33. package/dist/bin/pushary-status.js +11 -10
  34. package/dist/bin/pushary-stop-hook.js +14 -8
  35. package/dist/bin/pushary-stopfailure-hook.js +7 -7
  36. package/dist/bin/pushary-suggestions.js +2 -2
  37. package/dist/bin/pushary-transcripts.js +6 -6
  38. package/dist/bin/pushary-upgrade.js +15 -15
  39. package/dist/bin/pushary-wait.js +5 -5
  40. package/dist/bin/pushary.js +1 -1
  41. package/dist/{chunk-B2HND22S.js → chunk-2LAHXHBR.js} +1 -1
  42. package/dist/{chunk-GMJDQDXU.js → chunk-43GMYSS4.js} +1 -0
  43. package/dist/{chunk-JTBDBKHU.js → chunk-54ELC7D7.js} +1 -1
  44. package/dist/{chunk-C56VHSXU.js → chunk-5NAZ7SFS.js} +1 -1
  45. package/dist/{chunk-4IPSMEGT.js → chunk-7FE2KABY.js} +12 -2
  46. package/dist/{chunk-RAEPAUNJ.js → chunk-7TPQEWUZ.js} +1 -1
  47. package/dist/{chunk-ZO43JTT3.js → chunk-AJYV3VGU.js} +1 -1
  48. package/dist/{chunk-QFJZHVVL.js → chunk-AZPIQG4G.js} +35 -1
  49. package/dist/{chunk-5MNTWAAJ.js → chunk-B7UZHEBL.js} +29 -22
  50. package/dist/{chunk-MNTZKFZI.js → chunk-BQBEH6TV.js} +5 -5
  51. package/dist/{chunk-WHDSJ6PD.js → chunk-BVBEURWJ.js} +1 -1
  52. package/dist/{chunk-ZWEKONU6.js → chunk-CELX75MW.js} +1 -1
  53. package/dist/{chunk-ZP3SNUP7.js → chunk-CNPAT3HL.js} +3 -2
  54. package/dist/{chunk-YXT55PYF.js → chunk-DYP6SMOR.js} +1 -1
  55. package/dist/chunk-DZDI62LY.js +145 -0
  56. package/dist/{chunk-VF3RTVWY.js → chunk-EZIEXHYM.js} +15 -7
  57. package/dist/{chunk-7JZCADBR.js → chunk-F2ICEWZL.js} +101 -19
  58. package/dist/{chunk-VASZ6TWW.js → chunk-FQL5E6NG.js} +2 -2
  59. package/dist/{chunk-JHJHCMAF.js → chunk-FXEVRLHC.js} +20 -2
  60. package/dist/{chunk-JVLB5CAJ.js → chunk-GL3FFM7A.js} +7 -4
  61. package/dist/{chunk-5YEF55AX.js → chunk-H2QZRQR2.js} +1 -1
  62. package/dist/{chunk-S4BLNILH.js → chunk-I463AEG3.js} +1 -1
  63. package/dist/{chunk-ANMHIZZY.js → chunk-JW4KO5AF.js} +1 -1
  64. package/dist/{chunk-3YGGEDJK.js → chunk-KUZWXPUS.js} +3 -2
  65. package/dist/{chunk-N4QJ3CLX.js → chunk-L4E2BIJ2.js} +80 -7
  66. package/dist/{chunk-NBDU3R3G.js → chunk-OSALSIUF.js} +1 -1
  67. package/dist/{chunk-KNLKHJZR.js → chunk-PYA4FLKI.js} +32 -21
  68. package/dist/chunk-QCGNGEGE.js +15 -0
  69. package/dist/chunk-S6LYP7QA.js +127 -0
  70. package/dist/{chunk-OX35BSPV.js → chunk-TDZFPMSZ.js} +70 -11
  71. package/dist/{chunk-M3UABYRT.js → chunk-UZNKVRLE.js} +1 -1
  72. package/dist/{chunk-FOGW6O2Y.js → chunk-VHWCVD42.js} +1 -1
  73. package/dist/{chunk-QINYXLA5.js → chunk-VNMKIJZB.js} +15 -2
  74. package/dist/{chunk-CBGGUEKE.js → chunk-Y6BWPERV.js} +90 -7
  75. package/dist/src/index.d.ts +3 -0
  76. package/dist/src/index.js +11 -11
  77. package/package.json +1 -1
  78. package/dist/chunk-MSTHT2M7.js +0 -72
@@ -6,10 +6,14 @@ import {
6
6
  var HOOK_SHELL = "/bin/sh -c";
7
7
  var LOCATE = 'B=$(command -v "$0") || exit 0; [ -f "$B" ] || exit 0; [ -x "$B" ] || exit 0';
8
8
  var NODE_PRESENT = "command -v node >/dev/null 2>&1 || exit 0";
9
+ var CURSOR_NO_OPINION = { permission: "ask" };
10
+ var shellDoubleQuoted = (text) => `"${text.replace(/(["\\$`])/g, "\\$1")}"`;
11
+ var CURSOR_MISS = `{ printf %s ${shellDoubleQuoted(JSON.stringify(CURSOR_NO_OPINION))}; exit 0; }`;
9
12
  var HOOK_GUARD_SCRIPTS = {
10
13
  native_binary: `${LOCATE}; exec "$B" "$@"`,
11
14
  node_binary: `${LOCATE}; ${NODE_PRESENT}; exec "$B" "$@"`,
12
- node_script: `[ -f "$0" ] || exit 0; ${NODE_PRESENT}; exec node "$0" "$@"`
15
+ node_script: `[ -f "$0" ] || exit 0; ${NODE_PRESENT}; exec node "$0" "$@"`,
16
+ cursor_gate_script: `[ -f "$0" ] || ${CURSOR_MISS}; command -v node >/dev/null 2>&1 || ${CURSOR_MISS}; exec node "$0" "$@"`
13
17
  };
14
18
  var BINARY_GUARDS = {
15
19
  native: "native_binary",
@@ -19,21 +23,25 @@ var guardKindOf = (target) => {
19
23
  switch (target.kind) {
20
24
  case "node":
21
25
  return "node_script";
26
+ case "cursor_gate":
27
+ return "cursor_gate_script";
22
28
  case "binary":
23
29
  return BINARY_GUARDS[target.runtime];
24
30
  }
25
31
  };
32
+ var targetPath = (target) => target.kind === "binary" ? target.path : target.script;
33
+ var runsThroughNode = (target) => target.kind !== "binary";
26
34
  var guardHookCommand = (target, platform = process.platform) => {
27
- const path = quoteIfNeeded(target.kind === "node" ? target.script : target.path);
28
- if (platform === "win32") return target.kind === "node" ? `node ${path}` : path;
35
+ const path = quoteIfNeeded(targetPath(target));
36
+ if (platform === "win32") return runsThroughNode(target) ? `node ${path}` : path;
29
37
  return `${HOOK_SHELL} '${HOOK_GUARD_SCRIPTS[guardKindOf(target)]}' ${path}`;
30
38
  };
31
39
  var guardBinary = (path, platform) => guardHookCommand({ kind: "binary", path, runtime: "node" }, platform);
32
- var guardNodeScript = (script, platform) => guardHookCommand({ kind: "node", script }, platform);
40
+ var guardCursorGate = (script, platform) => guardHookCommand({ kind: "cursor_gate", script }, platform);
33
41
  var guardedArgv = (target, args = [], platform = process.platform) => {
34
- const path = target.kind === "node" ? target.script : target.path;
42
+ const path = targetPath(target);
35
43
  if (platform === "win32") {
36
- return target.kind === "node" ? ["node", path, ...args] : [path, ...args];
44
+ return runsThroughNode(target) ? ["node", path, ...args] : [path, ...args];
37
45
  }
38
46
  const [shell, ...shellArgs] = HOOK_SHELL.split(/\s+/);
39
47
  return [shell, ...shellArgs, HOOK_GUARD_SCRIPTS[guardKindOf(target)], path, ...args];
@@ -41,6 +49,6 @@ var guardedArgv = (target, args = [], platform = process.platform) => {
41
49
 
42
50
  export {
43
51
  guardBinary,
44
- guardNodeScript,
52
+ guardCursorGate,
45
53
  guardedArgv
46
54
  };
@@ -7,10 +7,10 @@ import {
7
7
  } from "./chunk-L4ZCFMWW.js";
8
8
  import {
9
9
  getMachineId
10
- } from "./chunk-JTBDBKHU.js";
10
+ } from "./chunk-54ELC7D7.js";
11
11
  import {
12
12
  pusharyDir
13
- } from "./chunk-3YGGEDJK.js";
13
+ } from "./chunk-KUZWXPUS.js";
14
14
  import {
15
15
  getPackageVersion
16
16
  } from "./chunk-DINDL2CF.js";
@@ -383,18 +383,32 @@ var manageDaemonService = (action, options = {}) => {
383
383
  }
384
384
  return applyDaemonService(action, definition, { run: options.run });
385
385
  };
386
+ var nominalDaemonService = (options) => buildDaemonService({
387
+ platform: options.platform ?? process.platform,
388
+ homeDir: options.homeDir ?? homedir(),
389
+ stateDir: options.stateDir ?? pusharyDir(),
390
+ execPath: options.execPath ?? process.execPath,
391
+ daemonEntry: options.daemonEntry ?? process.execPath,
392
+ pathEnv: options.pathEnv ?? process.env.PATH ?? "",
393
+ uid: options.uid ?? process.getuid?.()
394
+ });
386
395
  var hasDaemonServiceDefinition = (options = {}) => {
387
- const definition = buildDaemonService({
388
- platform: options.platform ?? process.platform,
389
- homeDir: options.homeDir ?? homedir(),
390
- stateDir: options.stateDir ?? pusharyDir(),
391
- execPath: options.execPath ?? process.execPath,
392
- daemonEntry: options.daemonEntry ?? process.execPath,
393
- pathEnv: options.pathEnv ?? process.env.PATH ?? "",
394
- uid: options.uid ?? process.getuid?.()
395
- });
396
+ const definition = nominalDaemonService(options);
396
397
  return definition !== null && existsSync(definition.definitionPath);
397
398
  };
399
+ var daemonServiceDefinitionPath = (options = {}) => nominalDaemonService(options)?.definitionPath ?? null;
400
+ var readInstalledDaemonService = (options = {}) => {
401
+ const definition = nominalDaemonService(options);
402
+ if (!definition) return null;
403
+ try {
404
+ return {
405
+ path: definition.definitionPath,
406
+ contents: readFileSync(definition.definitionPath, definition.encoding ?? "utf-8")
407
+ };
408
+ } catch {
409
+ return null;
410
+ }
411
+ };
398
412
  var spawnDetachedDaemon = (plan, options = {}) => {
399
413
  const spawnImpl = options.spawnImpl ?? spawnClaude;
400
414
  const child = spawnImpl(plan.command, plan.args, {
@@ -418,13 +432,19 @@ var processIsAlive = (pid) => {
418
432
  };
419
433
  var isString = (value) => typeof value === "string" && value.length > 0;
420
434
  var isTimestamp = (value) => isString(value) && Number.isFinite(Date.parse(value));
435
+ var daemonConfigurationId = (apiKey) => createHash("sha256").update(apiKey).digest("hex").slice(0, 16);
421
436
  var currentConfigurationId = () => {
422
437
  try {
423
- return createHash("sha256").update(getApiKey()).digest("hex").slice(0, 16);
438
+ return daemonConfigurationId(getApiKey());
424
439
  } catch {
425
440
  return null;
426
441
  }
427
442
  };
443
+ var parseDaemonLastError = (value) => {
444
+ if (typeof value !== "object" || value === null) return null;
445
+ const error = value;
446
+ return isString(error.message) && isTimestamp(error.at) ? { message: error.message, at: error.at } : null;
447
+ };
428
448
  var parseDaemonState = (value) => {
429
449
  if (typeof value !== "object" || value === null) return null;
430
450
  const state = value;
@@ -438,7 +458,8 @@ var parseDaemonState = (value) => {
438
458
  startedAt: state.startedAt,
439
459
  updatedAt: state.updatedAt,
440
460
  lastSuccessfulHeartbeatAt: state.lastSuccessfulHeartbeatAt,
441
- lastSuccessfulControlAt: state.lastSuccessfulControlAt ?? null
461
+ lastSuccessfulControlAt: state.lastSuccessfulControlAt ?? null,
462
+ lastError: parseDaemonLastError(state.lastError)
442
463
  };
443
464
  };
444
465
  var parseLockOwner = (value) => {
@@ -461,16 +482,17 @@ var readDaemonStatus = (options = {}) => {
461
482
  startedAt: null,
462
483
  updatedAt: null,
463
484
  lastSuccessfulHeartbeatAt: null,
464
- lastSuccessfulControlAt: null
485
+ lastSuccessfulControlAt: null,
486
+ lastError: null
465
487
  };
466
488
  }
467
489
  const value = state.kind === "ok" ? parseDaemonState(state.value) : null;
468
490
  if (value) {
469
491
  const alive = (options.isProcessAlive ?? processIsAlive)(value.pid);
470
492
  const fresh = (options.now ?? Date.now)() - Date.parse(value.updatedAt) <= LOCAL_LEASE_TIMEOUT_MS;
471
- const expectedConfigurationId = options.configurationId === void 0 ? currentConfigurationId() : options.configurationId;
493
+ const expectedConfigurationId2 = options.configurationId === void 0 ? currentConfigurationId() : options.configurationId;
472
494
  return {
473
- kind: !alive || !fresh ? "unresponsive" : value.version !== installedVersion ? "version-mismatch" : expectedConfigurationId !== null && value.configurationId !== null && value.configurationId !== expectedConfigurationId ? "configuration-mismatch" : "running",
495
+ kind: !alive || !fresh ? "unresponsive" : value.version !== installedVersion ? "version-mismatch" : expectedConfigurationId2 !== null && value.configurationId !== null && value.configurationId !== expectedConfigurationId2 ? "configuration-mismatch" : "running",
474
496
  installedVersion,
475
497
  machineId: value.machineId,
476
498
  pid: value.pid,
@@ -479,7 +501,8 @@ var readDaemonStatus = (options = {}) => {
479
501
  startedAt: value.startedAt,
480
502
  updatedAt: value.updatedAt,
481
503
  lastSuccessfulHeartbeatAt: value.lastSuccessfulHeartbeatAt,
482
- lastSuccessfulControlAt: value.lastSuccessfulControlAt
504
+ lastSuccessfulControlAt: value.lastSuccessfulControlAt,
505
+ lastError: value.lastError
483
506
  };
484
507
  }
485
508
  return {
@@ -492,7 +515,8 @@ var readDaemonStatus = (options = {}) => {
492
515
  startedAt: null,
493
516
  updatedAt: null,
494
517
  lastSuccessfulHeartbeatAt: null,
495
- lastSuccessfulControlAt: null
518
+ lastSuccessfulControlAt: null,
519
+ lastError: null
496
520
  };
497
521
  };
498
522
  var safeUnlink = (path) => {
@@ -561,7 +585,8 @@ var acquireDaemonLease = (options = {}) => {
561
585
  startedAt,
562
586
  updatedAt: startedAt,
563
587
  lastSuccessfulHeartbeatAt: null,
564
- lastSuccessfulControlAt: null
588
+ lastSuccessfulControlAt: null,
589
+ lastError: null
565
590
  };
566
591
  try {
567
592
  writeJsonAtomic(statePath(dir), state, 384);
@@ -605,6 +630,14 @@ var acquireDaemonLease = (options = {}) => {
605
630
  lastSuccessfulControlAt: timestamp
606
631
  });
607
632
  },
633
+ recordError: (message, at = now()) => {
634
+ const timestamp = new Date(at).toISOString();
635
+ updateState({
636
+ ...currentState,
637
+ updatedAt: timestamp,
638
+ lastError: { message: message.slice(0, 240), at: timestamp }
639
+ });
640
+ },
608
641
  shouldYield: () => {
609
642
  if (!isOwner()) return true;
610
643
  const target = readJsonSafe(targetPath(dir));
@@ -670,6 +703,44 @@ var stopDaemonRunning = async (options = {}) => {
670
703
  safeUnlink(lockPath(dir));
671
704
  return { kind: "stopped" };
672
705
  };
706
+ var needsLoginPath = (dir) => join(dir, "daemon-needs-login.json");
707
+ var isLoginReason = (value) => value === "key_rejected" || value === "plan_inactive";
708
+ var parseDaemonNeedsLogin = (value) => {
709
+ if (typeof value !== "object" || value === null) return null;
710
+ const record = value;
711
+ if (!isLoginReason(record.reason) || !isTimestamp(record.at)) return null;
712
+ if (!(record.configurationId === null || isString(record.configurationId))) return null;
713
+ return { reason: record.reason, at: record.at, configurationId: record.configurationId };
714
+ };
715
+ var expectedConfigurationId = (options) => options.configurationId === void 0 ? currentConfigurationId() : options.configurationId;
716
+ var writeDaemonNeedsLogin = (reason, options = {}) => {
717
+ const record = {
718
+ reason,
719
+ at: new Date((options.now ?? Date.now)()).toISOString(),
720
+ configurationId: expectedConfigurationId(options)
721
+ };
722
+ writeJsonAtomic(needsLoginPath(options.dir ?? pusharyDir()), record, 384);
723
+ return record;
724
+ };
725
+ var readDaemonNeedsLogin = (options = {}) => {
726
+ const stored = readJsonSafe(needsLoginPath(options.dir ?? pusharyDir()));
727
+ const record = stored.kind === "ok" ? parseDaemonNeedsLogin(stored.value) : null;
728
+ if (!record) return { kind: "none" };
729
+ return record.configurationId === expectedConfigurationId(options) ? { kind: "blocked", record } : { kind: "stale", record };
730
+ };
731
+ var clearDaemonNeedsLogin = (options = {}) => {
732
+ const path = needsLoginPath(options.dir ?? pusharyDir());
733
+ if (!existsSync(path)) return false;
734
+ safeUnlink(path);
735
+ return true;
736
+ };
737
+ var describeDaemonLoginBlock = (record) => record.reason === "key_rejected" ? `this machine's key was rejected at ${record.at}; run \`pushary login\` to sign in again` : `this workspace had no active plan at ${record.at}; pick one at pushary.com/dashboard/settings?tab=billing, then run \`pushary login\``;
738
+ var recoverDaemonAfterLogin = (options = {}) => {
739
+ const cleared = clearDaemonNeedsLogin(options);
740
+ if (!cleared || !hasDaemonServiceDefinition(options)) return { cleared, restarted: false, detail: null };
741
+ const started = manageDaemonService("start", options);
742
+ return started.kind === "ok" ? { cleared, restarted: true, detail: null } : { cleared, restarted: false, detail: started.detail };
743
+ };
673
744
  var deactivateDaemonService = async (action, options) => {
674
745
  const platform = options.platform ?? process.platform;
675
746
  const supported = ["darwin", "linux", "win32"].includes(platform);
@@ -966,6 +1037,10 @@ var ensureDaemonRunning = async (options = {}) => {
966
1037
  return { kind: "not-configured", status: initial, detail: "Pushary is not configured on this machine" };
967
1038
  }
968
1039
  if (initial.kind === "running") return { kind: "running", status: initial };
1040
+ const loginBlock = readDaemonNeedsLogin(options);
1041
+ if (loginBlock.kind === "blocked") {
1042
+ return { kind: "unavailable", status: initial, detail: describeDaemonLoginBlock(loginBlock.record) };
1043
+ }
969
1044
  let handoffStatus;
970
1045
  try {
971
1046
  handoffStatus = await requestDaemonHandoff(initial, options);
@@ -1020,10 +1095,17 @@ export {
1020
1095
  parseDaemonAction,
1021
1096
  manageDaemonService,
1022
1097
  hasDaemonServiceDefinition,
1098
+ daemonServiceDefinitionPath,
1099
+ readInstalledDaemonService,
1023
1100
  readDaemonStatus,
1024
1101
  acquireDaemonLease,
1025
1102
  requestDaemonHandoff,
1026
1103
  stopDaemonRunning,
1104
+ writeDaemonNeedsLogin,
1105
+ readDaemonNeedsLogin,
1106
+ clearDaemonNeedsLogin,
1107
+ describeDaemonLoginBlock,
1108
+ recoverDaemonAfterLogin,
1027
1109
  stopDaemonService,
1028
1110
  disableDaemonService,
1029
1111
  replaceDaemonService,
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  openCodeConfigDirFrom
3
- } from "./chunk-ZWEKONU6.js";
3
+ } from "./chunk-CELX75MW.js";
4
4
  import {
5
5
  codexHomeFrom
6
- } from "./chunk-3YGGEDJK.js";
6
+ } from "./chunk-KUZWXPUS.js";
7
7
 
8
8
  // src/vscode-config.ts
9
9
  import { homedir } from "os";
@@ -189,10 +189,27 @@ var removePendingCommand = (sessionId, id, namespace = "") => {
189
189
  }
190
190
  };
191
191
  var isDefaultSession = (sessionId) => sanitize(sessionId) === DEFAULT_SESSION;
192
- var savePendingQuestion = (sessionId, correlationId) => {
192
+ var savePendingQuestion = (sessionId, correlationId, toolUseId) => {
193
193
  const dir = dirFor(sessionId);
194
194
  if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
195
- writeFileSync(join(dir, correlationId), "", "utf-8");
195
+ writeFileSync(join(dir, correlationId), toolUseId ?? "", "utf-8");
196
+ };
197
+ var listPendingQuestionsForToolUse = (sessionId, toolUseId) => {
198
+ if (!toolUseId) return [];
199
+ const dir = dirFor(sessionId);
200
+ let files;
201
+ try {
202
+ files = readdirSync(dir);
203
+ } catch {
204
+ return [];
205
+ }
206
+ return files.filter((name) => {
207
+ try {
208
+ return readFileSync(join(dir, name), "utf-8") === toolUseId;
209
+ } catch {
210
+ return false;
211
+ }
212
+ });
196
213
  };
197
214
  var listPendingQuestions = (sessionId) => {
198
215
  const dir = dirFor(sessionId);
@@ -241,6 +258,7 @@ export {
241
258
  removePendingCommand,
242
259
  isDefaultSession,
243
260
  savePendingQuestion,
261
+ listPendingQuestionsForToolUse,
244
262
  listPendingQuestions,
245
263
  removePendingQuestion,
246
264
  removePendingSession
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  PRETOOLUSE_GATED_TOOLS,
3
3
  PRETOOLUSE_PHONE_ANSWERED_TOOLS
4
- } from "./chunk-B2HND22S.js";
4
+ } from "./chunk-2LAHXHBR.js";
5
5
  import {
6
6
  guardBinary
7
- } from "./chunk-VF3RTVWY.js";
7
+ } from "./chunk-EZIEXHYM.js";
8
8
  import {
9
9
  isProtectedByScope
10
- } from "./chunk-3YGGEDJK.js";
10
+ } from "./chunk-KUZWXPUS.js";
11
11
  import {
12
12
  HOOK_BUDGETS,
13
13
  HOOK_LOCATOR_BINARY
14
- } from "./chunk-QINYXLA5.js";
14
+ } from "./chunk-VNMKIJZB.js";
15
15
 
16
16
  // src/claude-config.ts
17
17
  import { join } from "path";
@@ -234,6 +234,7 @@ var GEMINI_HOOK_EVENTS = [
234
234
  { event: "BeforeTool", matcher: "run_shell_command|write_file|replace", delivery: "approval", timeoutMs: HOOK_BUDGETS.gemini.budgetSeconds * 1e3 },
235
235
  { event: "AfterTool", matcher: "run_shell_command|write_file|replace", delivery: "telemetry", timeoutMs: 1e4 },
236
236
  { event: "BeforeAgent", delivery: "telemetry", timeoutMs: 1e4 },
237
+ { event: "AfterAgent", delivery: "telemetry", timeoutMs: 1e4 },
237
238
  { event: "SessionStart", delivery: "telemetry", timeoutMs: 1e4 },
238
239
  { event: "SessionEnd", delivery: "telemetry", timeoutMs: 1e4 }
239
240
  ];
@@ -330,6 +331,7 @@ var missingGeminiHookEvents = (settings) => {
330
331
  export {
331
332
  parseVersion,
332
333
  compareVersion,
334
+ CLAUDE_HOOK_EVENTS,
333
335
  addClaudeMcpServer,
334
336
  isClaudeMcpSnapshot,
335
337
  captureClaudeMcpServer,
@@ -340,6 +342,7 @@ export {
340
342
  addPusharyHooks,
341
343
  removePusharySettings,
342
344
  GEMINI_HOOK_BINARY,
345
+ GEMINI_HOOK_EVENTS,
343
346
  addGeminiMcpServer,
344
347
  addGeminiHooks,
345
348
  removeGeminiSettings,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseVersion
3
- } from "./chunk-JVLB5CAJ.js";
3
+ } from "./chunk-GL3FFM7A.js";
4
4
 
5
5
  // src/setup/agent-probe.ts
6
6
  import { execSync } from "child_process";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  shouldDeferToNativeMode
3
- } from "./chunk-QINYXLA5.js";
3
+ } from "./chunk-VNMKIJZB.js";
4
4
 
5
5
  // src/native-defer.ts
6
6
  var nativeDeferOptions = () => {
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-2UMNXADU.js";
4
4
  import {
5
5
  normalizeInstallSource
6
- } from "./chunk-QINYXLA5.js";
6
+ } from "./chunk-VNMKIJZB.js";
7
7
 
8
8
  // src/install-source.ts
9
9
  import { readFileSync } from "fs";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  HOOK_BUDGETS,
3
3
  HOOK_LOCATOR_BINARY
4
- } from "./chunk-QINYXLA5.js";
4
+ } from "./chunk-VNMKIJZB.js";
5
5
 
6
6
  // src/removal-scope.ts
7
7
  var namesAppLocator = (command) => command.includes(HOOK_LOCATOR_BINARY);
@@ -29,7 +29,7 @@ var codexHooksJson = () => join(codexHome(), "hooks.json");
29
29
  var codexAgentsMd = () => join(codexHome(), "AGENTS.md");
30
30
  var codexSkillDir = () => join(codexHome(), "skills", "pushary");
31
31
  var CODEX_HOOK_EVENTS = [
32
- { event: "PermissionRequest", matcher: "Bash|apply_patch", delivery: "approval", timeout: HOOK_BUDGETS.codex.budgetSeconds, statusMessage: "Waiting for your phone" },
32
+ { event: "PermissionRequest", delivery: "approval", timeout: HOOK_BUDGETS.codex.budgetSeconds, statusMessage: "Waiting for your phone" },
33
33
  { event: "PreToolUse", matcher: "Bash|apply_patch", delivery: "approval", timeout: HOOK_BUDGETS.codex.budgetSeconds, statusMessage: "Checking Pushary policy" },
34
34
  { event: "PostToolUse", matcher: "Bash|apply_patch", delivery: "telemetry", timeout: 10 },
35
35
  { event: "UserPromptSubmit", delivery: "telemetry", timeout: 10 },
@@ -286,6 +286,7 @@ export {
286
286
  codexHooksJson,
287
287
  codexAgentsMd,
288
288
  codexSkillDir,
289
+ CODEX_HOOK_EVENTS,
289
290
  addCodexMcpServer,
290
291
  readCodexMcpAuth,
291
292
  addCodexHooks,
@@ -5,7 +5,7 @@ import {
5
5
  FILE_TARGET_TOOLS,
6
6
  redactSecrets,
7
7
  redactSecretsDeep
8
- } from "./chunk-QINYXLA5.js";
8
+ } from "./chunk-VNMKIJZB.js";
9
9
 
10
10
  // ../hook-mapping/src/describe.ts
11
11
  import { isAbsolute, relative, resolve } from "path";
@@ -44,6 +44,48 @@ var eventPrefixes = {
44
44
  Read: (input) => `read: ${input.file_path ?? "unknown"}`,
45
45
  TodoWrite: (input) => describeTodoProgress(input.todos)
46
46
  };
47
+ var MCP_TOOL_PREFIX = "mcp__";
48
+ var parseMcpToolName = (toolName) => {
49
+ if (!toolName.startsWith(MCP_TOOL_PREFIX)) return void 0;
50
+ const rest = toolName.slice(MCP_TOOL_PREFIX.length);
51
+ const split = rest.indexOf("__");
52
+ if (split <= 0 || split + 2 >= rest.length) return void 0;
53
+ return { server: rest.slice(0, split), tool: rest.slice(split + 2) };
54
+ };
55
+ var NETWORK_TARGET_KEYS = ["url", "urls", "href", "host", "hosts", "hostname", "domain", "domains"];
56
+ var ABSOLUTE_HTTP_URL = /^https?:\/\//i;
57
+ var HOSTNAME = /^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+(?::\d{1,5})?$/i;
58
+ var hostOfUrl = (value) => {
59
+ try {
60
+ return new URL(value).host || void 0;
61
+ } catch {
62
+ return void 0;
63
+ }
64
+ };
65
+ var hostOf = (value, bareHostnames) => {
66
+ if (typeof value !== "string") return void 0;
67
+ const trimmed = value.trim();
68
+ if (ABSOLUTE_HTTP_URL.test(trimmed)) return hostOfUrl(trimmed);
69
+ return bareHostnames && HOSTNAME.test(trimmed) ? trimmed : void 0;
70
+ };
71
+ var firstHost = (value, bareHostnames) => Array.isArray(value) ? value.map((entry) => hostOf(entry, bareHostnames)).find((host) => host !== void 0) : hostOf(value, bareHostnames);
72
+ var deriveNetworkTarget = (toolInput) => {
73
+ for (const key of NETWORK_TARGET_KEYS) {
74
+ const host = firstHost(toolInput[key], true);
75
+ if (host) return host;
76
+ }
77
+ return Object.values(toolInput).map((value) => firstHost(value, false)).find((host) => host !== void 0);
78
+ };
79
+ var describeUnbuiltCall = (toolName, toolInput, format) => {
80
+ const mcp = parseMcpToolName(toolName);
81
+ const host = deriveNetworkTarget(toolInput);
82
+ if (mcp) {
83
+ if (format === "event") return `called ${mcp.tool} on ${mcp.server}`;
84
+ return host ? `call ${mcp.tool} on ${mcp.server} to reach ${host}` : `call ${mcp.tool} on ${mcp.server}`;
85
+ }
86
+ if (host) return format === "event" ? `accessed ${host}` : `network access to ${host}`;
87
+ return void 0;
88
+ };
47
89
  var EVENT_ACTION_MAX = 120;
48
90
  var HOOK_FALLBACK_MAX = 200;
49
91
  var UNNAMED_ACTION = "this request";
@@ -51,11 +93,12 @@ var describeToolCall = (toolName, toolInput, format = "hook") => {
51
93
  if (!toolName) return "";
52
94
  const prefixes = format === "hook" ? hookPrefixes : eventPrefixes;
53
95
  const builder = prefixes[toolName];
96
+ const unbuilt = builder ? void 0 : describeUnbuiltCall(toolName, toolInput ?? {}, format);
54
97
  const detail = JSON.stringify(toolInput ?? {});
55
- const raw = builder ? builder(toolInput) : format === "hook" ? detail === "{}" || detail === void 0 ? toolName : `${toolName}: ${detail}` : `${toolName}: done`;
98
+ const raw = builder ? builder(toolInput) : unbuilt ?? (format === "hook" ? detail === "{}" || detail === void 0 ? toolName : `${toolName}: ${detail}` : `${toolName}: done`);
56
99
  const redacted = redactSecrets(raw);
57
100
  if (format === "event") return redacted.slice(0, EVENT_ACTION_MAX);
58
- return builder ? redacted : redacted.slice(0, HOOK_FALLBACK_MAX);
101
+ return builder || unbuilt ? redacted : redacted.slice(0, HOOK_FALLBACK_MAX);
59
102
  };
60
103
  var TOOL_TARGET_MAX_LENGTH = 80;
61
104
  var deriveCommandHead = (command) => {
@@ -76,7 +119,9 @@ var deriveToolTarget = (toolName, toolInput) => {
76
119
  if (dot <= 0) return void 0;
77
120
  return base.slice(dot).slice(0, TOOL_TARGET_MAX_LENGTH);
78
121
  }
79
- return void 0;
122
+ const mcp = parseMcpToolName(toolName);
123
+ if (mcp) return mcp.server.slice(0, TOOL_TARGET_MAX_LENGTH);
124
+ return deriveNetworkTarget(toolInput)?.slice(0, TOOL_TARGET_MAX_LENGTH);
80
125
  };
81
126
  var SCRIPT_RUNNERS = /* @__PURE__ */ new Set(["npm", "pnpm", "yarn", "bun", "npx", "deno", "rake", "make", "just", "task", "turbo"]);
82
127
  var RUN_SUBCOMMANDS = /* @__PURE__ */ new Set(["run", "run-script", "exec", "task"]);
@@ -210,7 +255,7 @@ var rawActionBody = (toolName, toolInput) => {
210
255
  if (toolName === "Bash" || toolName === "PowerShell" || toolName === "Monitor" || toolName === "run_shell_command" || toolName === "shell" || toolName === "apply_patch") {
211
256
  return firstString(toolInput.command);
212
257
  }
213
- return void 0;
258
+ return firstString(toolInput.url, toolInput.href);
214
259
  };
215
260
  var deriveActionBody = (toolName, toolInput) => {
216
261
  try {
@@ -264,11 +309,36 @@ var summarizeStop = (input) => {
264
309
  if (running > 0) return `Paused with ${running} background task${running === 1 ? "" : "s"} still running`;
265
310
  const crons = countArray(input.session_crons);
266
311
  if (crons > 0) return `Idle until a scheduled task wakes it (${crons} pending)`;
267
- return summarizeFinalMessage(input.last_assistant_message);
312
+ return summarizeFinalMessage(input.last_assistant_message ?? input.prompt_response);
313
+ };
314
+ var subagentStopAction = (agentType) => {
315
+ const name = typeof agentType === "string" ? agentType.replace(/\s+/g, " ").trim() : "";
316
+ return name ? `${name} subagent finished` : "Subagent finished";
317
+ };
318
+ var subagentStopSummary = (input) => {
319
+ const message = input.last_assistant_message ?? input.prompt_response;
320
+ if (typeof message === "string" && message.trim()) return summarizeStop(input);
321
+ return subagentStopAction(input.agent_type);
322
+ };
323
+ var COMPACTION_TRIGGERS = {
324
+ manual: "on request",
325
+ auto: "automatically"
326
+ };
327
+ var compactionAction = (hookEvent, trigger) => {
328
+ const how = typeof trigger === "string" ? COMPACTION_TRIGGERS[trigger] : void 0;
329
+ const base = hookEvent === "PostCompact" ? "Compacted context" : "Compacting context";
330
+ return how ? `${base} ${how}` : base;
268
331
  };
269
332
  var sessionStartAction = (source) => source === "resume" ? "Session resumed" : "Session started";
270
333
  var sessionEndAction = (reason) => typeof reason === "string" && SESSION_END_ACTIONS[reason] || "Session ended";
271
334
  var taskTitleFrom = (prompt) => typeof prompt === "string" ? prompt.replace(/\s+/g, " ").trim().slice(0, TASK_TITLE_MAX_LENGTH) || void 0 : void 0;
335
+ var asString = (value) => typeof value === "string" && value.length > 0 ? value : void 0;
336
+ var sessionIdentityOf = (payload) => {
337
+ const sessionId = asString(payload.session_id);
338
+ const agentId = asString(payload.agent_id);
339
+ if (!agentId) return { sessionId };
340
+ return { sessionId: agentId, parentSessionId: sessionId };
341
+ };
272
342
 
273
343
  export {
274
344
  HOOK_FALLBACK_MAX,
@@ -287,7 +357,10 @@ export {
287
357
  deriveBlocker,
288
358
  AGENT_IDENTITIES,
289
359
  summarizeStop,
360
+ subagentStopSummary,
361
+ compactionAction,
290
362
  sessionStartAction,
291
363
  sessionEndAction,
292
- taskTitleFrom
364
+ taskTitleFrom,
365
+ sessionIdentityOf
293
366
  };
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-BC3VCZ3E.js";
4
4
  import {
5
5
  resolveInstallSourceFor
6
- } from "./chunk-ANMHIZZY.js";
6
+ } from "./chunk-JW4KO5AF.js";
7
7
  import {
8
8
  backupFile,
9
9
  readJsonSafe,