@pushary/agent-hooks 1.7.3 → 1.8.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 (102) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +13 -1
  3. package/data/cursor-plugin/scripts/pushary-gate.mjs +2 -21
  4. package/data/cursor-plugin/scripts/redaction.mjs +51 -0
  5. package/data/vscode-plugin/scripts/pushary-gate.mjs +1 -21
  6. package/data/vscode-plugin/scripts/redaction.mjs +51 -0
  7. package/dist/bin/pushary-bell-hook.js +23 -23
  8. package/dist/bin/pushary-bell.js +9 -9
  9. package/dist/bin/pushary-claude.js +26 -26
  10. package/dist/bin/pushary-clean.js +91 -107
  11. package/dist/bin/pushary-codex-bridge.js +18 -18
  12. package/dist/bin/pushary-codex-hook.js +42 -43
  13. package/dist/bin/pushary-codex.js +13 -13
  14. package/dist/bin/pushary-connect.js +13 -13
  15. package/dist/bin/pushary-cowork.js +5 -5
  16. package/dist/bin/pushary-daemon.js +27 -27
  17. package/dist/bin/pushary-disconnect.js +18 -18
  18. package/dist/bin/pushary-doctor.js +85 -79
  19. package/dist/bin/pushary-elicitation-hook.js +25 -25
  20. package/dist/bin/pushary-gemini-bridge.js +12 -12
  21. package/dist/bin/pushary-gemini-hook.js +29 -30
  22. package/dist/bin/pushary-hook.js +32 -32
  23. package/dist/bin/pushary-login.js +12 -12
  24. package/dist/bin/pushary-logout.js +7 -7
  25. package/dist/bin/pushary-mcp.js +85 -28
  26. package/dist/bin/pushary-mode.js +9 -9
  27. package/dist/bin/pushary-notification-hook.js +28 -28
  28. package/dist/bin/pushary-opencode-hook.js +28 -29
  29. package/dist/bin/pushary-permission-denied-hook.js +32 -32
  30. package/dist/bin/pushary-permission-hook.js +31 -31
  31. package/dist/bin/pushary-post-hook.js +28 -28
  32. package/dist/bin/pushary-prompt-hook.js +28 -28
  33. package/dist/bin/pushary-session-end-hook.js +28 -28
  34. package/dist/bin/pushary-session-start-hook.js +32 -32
  35. package/dist/bin/pushary-setup.js +60 -127
  36. package/dist/bin/pushary-stats.js +5 -5
  37. package/dist/bin/pushary-status.js +15 -15
  38. package/dist/bin/pushary-stop-hook.js +28 -28
  39. package/dist/bin/pushary-stopfailure-hook.js +28 -28
  40. package/dist/bin/pushary-suggestions.js +4 -4
  41. package/dist/bin/pushary-transcript-register.js +19 -19
  42. package/dist/bin/pushary-transcripts.js +7 -7
  43. package/dist/bin/pushary-upgrade.js +231 -105
  44. package/dist/bin/pushary-wait.js +9 -9
  45. package/dist/bin/pushary.js +6 -6
  46. package/dist/{chunk-EEEJ2JIL.js → chunk-2ABTSGFT.js} +3 -3
  47. package/dist/{chunk-DUQO4C4I.js → chunk-2OY3ZZ5N.js} +3 -3
  48. package/dist/{chunk-MIXWMA73.js → chunk-3EVPNIBE.js} +3 -3
  49. package/dist/{chunk-WTJM7PSL.js → chunk-6J2JC2RT.js} +3 -3
  50. package/dist/{chunk-EADXTSHE.js → chunk-7Z7Q4GGS.js} +2 -2
  51. package/dist/{chunk-MZBRL5H5.js → chunk-A2A2YTMG.js} +108 -25
  52. package/dist/{chunk-KEL5MXRL.js → chunk-AHV4LNB5.js} +1 -1
  53. package/dist/{chunk-G3OMOTJ4.js → chunk-AXPCESYO.js} +3 -3
  54. package/dist/{chunk-3EUBQARL.js → chunk-C2WCPBF7.js} +1 -1
  55. package/dist/chunk-CJVVKOSR.js +73 -0
  56. package/dist/{chunk-U6RVDUJ5.js → chunk-CULUZTWQ.js} +283 -41
  57. package/dist/{chunk-N5MZH5A6.js → chunk-CVQYGMSR.js} +4 -4
  58. package/dist/{chunk-VKVSRCBO.js → chunk-D2FX3EPW.js} +1 -1
  59. package/dist/{chunk-62CVUUNU.js → chunk-DB3ONZB4.js} +2 -2
  60. package/dist/{chunk-WGMW7OXW.js → chunk-DE4Y6TCC.js} +6 -6
  61. package/dist/{chunk-YYCTF4Q5.js → chunk-E4FJTUH4.js} +1 -1
  62. package/dist/{chunk-EUGNVLMG.js → chunk-EPCXUP3P.js} +3 -1
  63. package/dist/{chunk-PRNFSORD.js → chunk-EX3GAPA4.js} +1 -1
  64. package/dist/{chunk-TCVMK6GI.js → chunk-EYK3GSRH.js} +4 -4
  65. package/dist/{chunk-R6OYCUNK.js → chunk-GPEGOGRJ.js} +1 -1
  66. package/dist/chunk-GU3EJCVV.js +43 -0
  67. package/dist/{chunk-Y4ZH64UK.js → chunk-HQ6G3B5R.js} +2 -2
  68. package/dist/{chunk-5S2VBSJI.js → chunk-HZVVNGEW.js} +2 -2
  69. package/dist/{chunk-IWJKSIB4.js → chunk-IPVKH2ST.js} +1 -1
  70. package/dist/{chunk-UOQRM7JQ.js → chunk-J5TIV3J6.js} +5 -5
  71. package/dist/{chunk-IRZG3HEU.js → chunk-JU6W3XAU.js} +1 -1
  72. package/dist/{chunk-G62JL2NT.js → chunk-JYG4B33G.js} +1 -1
  73. package/dist/{chunk-OTNOANMX.js → chunk-JZTHGAPA.js} +8 -8
  74. package/dist/{chunk-7RUJKCR4.js → chunk-KGDWDSNL.js} +2 -2
  75. package/dist/{chunk-6JQFIHZC.js → chunk-KVQBWI5T.js} +3 -3
  76. package/dist/{chunk-OVC5QXN5.js → chunk-LXQ5FBBD.js} +1 -1
  77. package/dist/{chunk-VE7TXLR4.js → chunk-M5ICYGHT.js} +3 -3
  78. package/dist/{chunk-YPUBA2FL.js → chunk-M5JDZ45W.js} +4 -4
  79. package/dist/{chunk-O3JDWNLU.js → chunk-MDEPU45E.js} +183 -28
  80. package/dist/{chunk-P2VIBGXA.js → chunk-MPWXGONV.js} +1 -1
  81. package/dist/{chunk-YC27PROF.js → chunk-NGDD6TXY.js} +20 -5
  82. package/dist/{chunk-G4GLCLKK.js → chunk-NQTHFF4W.js} +138 -17
  83. package/dist/{chunk-NOI3XTCY.js → chunk-OKXS7WDZ.js} +1 -1
  84. package/dist/{chunk-LPNJLKBQ.js → chunk-OLQRRFBX.js} +1 -1
  85. package/dist/{chunk-D6OODZCM.js → chunk-P7WQEVWA.js} +2 -2
  86. package/dist/{chunk-62VT3BPH.js → chunk-Q7E4I6UA.js} +28 -16
  87. package/dist/{chunk-BIH2Y2HP.js → chunk-R7437YI3.js} +2 -2
  88. package/dist/{chunk-RLW3JWDY.js → chunk-RHR6NARM.js} +2 -2
  89. package/dist/{chunk-WPX67AKT.js → chunk-SAXBC4AZ.js} +1 -1
  90. package/dist/{chunk-IPSRMLCJ.js → chunk-SIFVFP6T.js} +1 -1
  91. package/dist/{chunk-7OA34PNW.js → chunk-SLFABHW3.js} +40 -10
  92. package/dist/{chunk-AWVNAYGD.js → chunk-TY4JT7W3.js} +1 -1
  93. package/dist/{chunk-KJXUIPS4.js → chunk-UI36QSBI.js} +28 -16
  94. package/dist/{chunk-G6RRVJOG.js → chunk-VQKRG3AC.js} +6 -6
  95. package/dist/{chunk-ZKJ34T2F.js → chunk-WE2J62NC.js} +31 -17
  96. package/dist/{chunk-LHC45YUC.js → chunk-ZSZSSJCV.js} +1 -1
  97. package/dist/{chunk-BGBLLHZ4.js → chunk-ZVSKMPBZ.js} +1 -1
  98. package/dist/{reapply-PH5T4BGR.js → reapply-CW3MA66V.js} +9 -9
  99. package/dist/src/index.js +20 -20
  100. package/package.json +1 -1
  101. package/dist/chunk-5GB22QYL.js +0 -255
  102. package/dist/chunk-VYPJHGG6.js +0 -92
@@ -455,7 +455,7 @@ var compatibleTargetFiles = (profile) => {
455
455
  };
456
456
 
457
457
  // ../contracts/src/redaction.ts
458
- var CREDENTIAL_NAME = String.raw`(?:secret|token|password|passwd|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)["']?`;
458
+ var CREDENTIAL_NAME = String.raw`(?:authorization|secret|token|password|passwd|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)["']?`;
459
459
  var CREDENTIAL_KEY = String.raw`${CREDENTIAL_NAME}\s*[=:]\s*`;
460
460
  var DISPLAYED_CREDENTIAL_KEY = String.raw`${CREDENTIAL_NAME}(?:[ \t]*:[ \t]*|[ \t]+=[ \t]*|=)`;
461
461
  var SHELL_INERT_UNIT = String.raw`(?:[A-Za-z0-9_\-./+=:@%^!#]|\\[^\s'"])`;
@@ -659,9 +659,13 @@ var INSTALL_SOURCES = [
659
659
  "framework_adapter",
660
660
  /** The browser onboarding wizard. */
661
661
  "dashboard",
662
- /** Reported nothing, or reported something we do not recognise. */
663
662
  /** The macOS app pairing a phone from its own onboarding. */
664
663
  "mac_app",
664
+ /** The phone app's own sign-up, which provisions the agent site before any web step. */
665
+ "mobile_app",
666
+ /** The CLI's device-code sign-in page (`/cli/authorize`), which provisions a site before any web step. */
667
+ "cli_login",
668
+ /** Reported nothing, or reported something we do not recognise. */
665
669
  "unknown"
666
670
  ];
667
671
  var isInstallSource = (value) => typeof value === "string" && INSTALL_SOURCES.includes(value);
@@ -1535,6 +1539,16 @@ var API_KEY_PATTERN = /^pk_[a-f0-9]+\.[a-f0-9]+$/;
1535
1539
  var isValidApiKey = (value) => API_KEY_PATTERN.test(value);
1536
1540
  var ACTION_BODY_MAX = 4e3;
1537
1541
  var DECISION_LINE_MAX = 500;
1542
+ var ASK_QUESTION_MAX = 500;
1543
+ var ASK_AGENT_NAME_MAX = 100;
1544
+ var TRUNCATION_MARK = "\u2026";
1545
+ var isHighSurrogate = (code) => code >= 55296 && code <= 56319;
1546
+ var truncateLine = (text, max, mark = TRUNCATION_MARK) => {
1547
+ if (text.length <= max) return text;
1548
+ const end = max - mark.length;
1549
+ const keep = isHighSurrogate(text.charCodeAt(end - 1)) ? end - 1 : end;
1550
+ return `${text.slice(0, keep)}${mark}`;
1551
+ };
1538
1552
  var APPROVAL_FATIGUE_FLAG_PATTERNS = [
1539
1553
  /\brm\s+-[a-z]*r/i,
1540
1554
  /\brmdir\b/i,
@@ -2539,40 +2553,126 @@ var hookActivationResult = (report) => {
2539
2553
  return report && !report.truncated && report.evidence.length === 1 ? report.evidence[0].result : "unverified";
2540
2554
  };
2541
2555
 
2556
+ // src/cli-package-name.ts
2557
+ var CANONICAL_PACKAGE = "pushary";
2558
+ var LEGACY_PACKAGE = "@pushary/agent-hooks";
2559
+ var CLI_PACKAGE_NAMES = [CANONICAL_PACKAGE, LEGACY_PACKAGE];
2560
+ var isCliPackageName = (value) => typeof value === "string" && CLI_PACKAGE_NAMES.some((name) => name === value);
2561
+ var cliPackagePathSegments = (name) => name.split("/");
2562
+
2563
+ // src/global-package.ts
2564
+ import { posix, win32 } from "path";
2565
+ var OWNERSHIP_PROBE_COMMAND = "pushary-hook";
2566
+ var pathApiFor = (platform) => platform === "win32" ? win32 : posix;
2567
+ var POSIX_GLOBAL_ROOT_SEGMENTS = ["lib", "node_modules"];
2568
+ var UPGRADE_ENTRY_SEGMENTS = ["dist", "bin", "pushary-upgrade.js"];
2569
+ var globalRootFor = (prefix, platform) => platform === "win32" ? win32.join(prefix, "node_modules") : posix.join(prefix, ...POSIX_GLOBAL_ROOT_SEGMENTS);
2570
+ var globalPackageFolder = (root, name, platform) => pathApiFor(platform).join(root, ...cliPackagePathSegments(name));
2571
+ var globalUpgradeEntry = (prefix, name, platform) => pathApiFor(platform).join(globalPackageFolder(globalRootFor(prefix, platform), name, platform), ...UPGRADE_ENTRY_SEGMENTS);
2572
+ var isInsideFolder = (target, folder, platform) => {
2573
+ const pathApi = pathApiFor(platform);
2574
+ const relativePath = pathApi.relative(folder, target);
2575
+ return relativePath !== "" && !relativePath.startsWith("..") && !pathApi.isAbsolute(relativePath);
2576
+ };
2577
+ var linkPointsInto = (evidence, targets, name) => evidence.globalRoots.some((root) => {
2578
+ const folder = globalPackageFolder(root, name, evidence.platform);
2579
+ return targets.some((target) => isInsideFolder(target, folder, evidence.platform));
2580
+ });
2581
+ var ownerFromInstalled = (installed, whenNone) => {
2582
+ const [only, ...others] = installed;
2583
+ if (only === void 0) return whenNone;
2584
+ if (others.length > 0) return { kind: "unknown", reason: "both_installed" };
2585
+ return { kind: "owned", name: only };
2586
+ };
2587
+ var decideCommandOwner = (evidence) => {
2588
+ const { link } = evidence;
2589
+ if (link.kind === "resolved") {
2590
+ const name = CLI_PACKAGE_NAMES.find((candidate) => linkPointsInto(evidence, link.targets, candidate));
2591
+ return name === void 0 ? { kind: "unknown", reason: "foreign_command" } : { kind: "owned", name };
2592
+ }
2593
+ const whenNone = link.kind === "absent" ? { kind: "none" } : { kind: "unknown", reason: "unreadable_command" };
2594
+ return ownerFromInstalled(evidence.installed, whenNone);
2595
+ };
2596
+ var CMD_SHIM_TARGET = /"%(?:~dp0|dp0%)\\([^"]+?)"\s+%[*]/;
2597
+ var cmdShimTarget = (shimDir, contents) => {
2598
+ const relativeTarget = CMD_SHIM_TARGET.exec(contents)?.[1];
2599
+ return relativeTarget === void 0 ? void 0 : win32.resolve(shimDir, relativeTarget);
2600
+ };
2601
+ var launchedPackage = (ownName) => ownName ?? LEGACY_PACKAGE;
2602
+ var globalInstallTarget = (owner, ownName) => {
2603
+ switch (owner.kind) {
2604
+ case "owned":
2605
+ return owner.name;
2606
+ case "none":
2607
+ return launchedPackage(ownName);
2608
+ case "unknown":
2609
+ return LEGACY_PACKAGE;
2610
+ }
2611
+ };
2612
+ var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2613
+ var declaresOwnershipProbe = (bin) => isRecord2(bin) && typeof bin[OWNERSHIP_PROBE_COMMAND] === "string";
2614
+ var cliManifestName = (manifest) => {
2615
+ if (!isRecord2(manifest) || !isCliPackageName(manifest.name) || !declaresOwnershipProbe(manifest.bin)) return void 0;
2616
+ return manifest.name;
2617
+ };
2618
+ var classifyGlobalFolder = (name, read) => {
2619
+ if (read.kind === "unreadable") return { kind: "unseen" };
2620
+ const { manifest } = read;
2621
+ if (!isRecord2(manifest) || cliManifestName(manifest) !== name) return { kind: "foreign" };
2622
+ return { kind: "ours", installed: { name, version: typeof manifest.version === "string" ? manifest.version : void 0 } };
2623
+ };
2624
+ var classifyGlobalInstall = (installed, owner) => {
2625
+ const [only, ...others] = installed;
2626
+ if (only === void 0) return { kind: "absent" };
2627
+ if (others.length === 0) return { kind: "single", installed: only };
2628
+ return { kind: "both", installed, owner };
2629
+ };
2630
+ var isUninstallable = (evidence) => evidence.listing !== "absent" && evidence.folder !== "foreign";
2631
+ var globalPackagesToUninstall = (evidence) => evidence.filter(isUninstallable).map((entry) => entry.name);
2632
+ var commandsPackage = (install) => {
2633
+ if (install.kind === "single") return install.installed;
2634
+ if (install.kind !== "both" || install.owner.kind !== "owned") return void 0;
2635
+ const ownerName = install.owner.name;
2636
+ return install.installed.find((installed) => installed.name === ownerName);
2637
+ };
2638
+
2542
2639
  // src/cli/version.ts
2543
2640
  import { readFileSync } from "fs";
2544
2641
  import { dirname, join, parse } from "path";
2545
2642
  import { fileURLToPath } from "url";
2546
- var PACKAGE_NAME = "@pushary/agent-hooks";
2547
2643
  var UNKNOWN_VERSION = "0.0.0";
2548
- var findOwnPackageJson = (start) => {
2644
+ var cliManifestNameAt = (manifestPath) => {
2645
+ try {
2646
+ return cliManifestName(JSON.parse(readFileSync(manifestPath, "utf-8")));
2647
+ } catch {
2648
+ return void 0;
2649
+ }
2650
+ };
2651
+ var findOwnPackage = (start) => {
2549
2652
  const { root } = parse(start);
2550
2653
  let dir = start;
2551
2654
  while (true) {
2552
- const candidate = join(dir, "package.json");
2553
- try {
2554
- const pkg = JSON.parse(readFileSync(candidate, "utf-8"));
2555
- if (pkg.name === PACKAGE_NAME) return candidate;
2556
- } catch {
2557
- }
2655
+ const name = cliManifestNameAt(join(dir, "package.json"));
2656
+ if (name !== void 0) return { root: dir, name };
2558
2657
  if (dir === root) return void 0;
2559
2658
  const parent = dirname(dir);
2560
2659
  if (parent === dir) return void 0;
2561
2660
  dir = parent;
2562
2661
  }
2563
2662
  };
2564
- var getPackageVersion = () => {
2565
- const root = ownPackageRoot();
2566
- return (root === void 0 ? void 0 : packageVersionAt(root)) ?? UNKNOWN_VERSION;
2567
- };
2568
- var ownPackageRoot = () => {
2663
+ var runningPackage = () => {
2569
2664
  try {
2570
- const found = findOwnPackageJson(dirname(fileURLToPath(import.meta.url)));
2571
- return found ? dirname(found) : void 0;
2665
+ return findOwnPackage(dirname(fileURLToPath(import.meta.url)));
2572
2666
  } catch {
2573
2667
  return void 0;
2574
2668
  }
2575
2669
  };
2670
+ var getPackageVersion = () => {
2671
+ const root = ownPackageRoot();
2672
+ return (root === void 0 ? void 0 : packageVersionAt(root)) ?? UNKNOWN_VERSION;
2673
+ };
2674
+ var ownPackageRoot = () => runningPackage()?.root;
2675
+ var ownPackageName = () => runningPackage()?.name;
2576
2676
  var packageVersionAt = (packageRoot) => {
2577
2677
  try {
2578
2678
  const manifest = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf-8"));
@@ -2657,6 +2757,9 @@ export {
2657
2757
  isValidApiKey,
2658
2758
  ACTION_BODY_MAX,
2659
2759
  DECISION_LINE_MAX,
2760
+ ASK_QUESTION_MAX,
2761
+ ASK_AGENT_NAME_MAX,
2762
+ truncateLine,
2660
2763
  isAnswerSource,
2661
2764
  buildDecisionEpisodeFeatures,
2662
2765
  resolveAutoResolveOrigin,
@@ -2700,8 +2803,26 @@ export {
2700
2803
  planElicitationAsk,
2701
2804
  elicitationContent,
2702
2805
  elicitationContentFromAnswers,
2806
+ CANONICAL_PACKAGE,
2807
+ LEGACY_PACKAGE,
2808
+ CLI_PACKAGE_NAMES,
2809
+ cliPackagePathSegments,
2810
+ OWNERSHIP_PROBE_COMMAND,
2811
+ POSIX_GLOBAL_ROOT_SEGMENTS,
2812
+ globalRootFor,
2813
+ globalPackageFolder,
2814
+ globalUpgradeEntry,
2815
+ decideCommandOwner,
2816
+ cmdShimTarget,
2817
+ launchedPackage,
2818
+ globalInstallTarget,
2819
+ classifyGlobalFolder,
2820
+ classifyGlobalInstall,
2821
+ globalPackagesToUninstall,
2822
+ commandsPackage,
2703
2823
  getPackageVersion,
2704
2824
  ownPackageRoot,
2825
+ ownPackageName,
2705
2826
  packageVersionAt,
2706
2827
  isNewerVersion,
2707
2828
  isReleaseVersion,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  guardBinary
3
- } from "./chunk-MZBRL5H5.js";
3
+ } from "./chunk-A2A2YTMG.js";
4
4
 
5
5
  // src/bell/install.ts
6
6
  import { join } from "path";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  readTranscriptPreference
3
- } from "./chunk-D6OODZCM.js";
3
+ } from "./chunk-P7WQEVWA.js";
4
4
 
5
5
  // src/transcript-setting.ts
6
6
  var transcriptEnvironmentPreference = () => {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveInstallSourceFor
3
- } from "./chunk-62CVUUNU.js";
3
+ } from "./chunk-DB3ONZB4.js";
4
4
  import {
5
5
  backupFile,
6
6
  readJsonSafe,
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-T7E75EKA.js";
10
10
  import {
11
11
  configFilePath
12
- } from "./chunk-R6OYCUNK.js";
12
+ } from "./chunk-GPEGOGRJ.js";
13
13
 
14
14
  // src/shell-alias.ts
15
15
  import { homedir } from "os";
@@ -1,19 +1,15 @@
1
1
  import {
2
2
  activeHookSource,
3
3
  activeIdentity
4
- } from "./chunk-UOQRM7JQ.js";
4
+ } from "./chunk-J5TIV3J6.js";
5
5
  import {
6
- blockedActionFingerprint,
7
6
  defersToNativeMode,
8
- forgetBlockedActionHint,
9
- hasBlockedActionHint,
10
- recordBlockedActionHint,
11
7
  reportMachineDenial
12
- } from "./chunk-5GB22QYL.js";
8
+ } from "./chunk-CJVVKOSR.js";
13
9
  import {
14
10
  isGatingMoment,
15
11
  recordKeylessMoment
16
- } from "./chunk-IRZG3HEU.js";
12
+ } from "./chunk-JU6W3XAU.js";
17
13
  import {
18
14
  announceSubscriptionRequired,
19
15
  denyReasonFrom,
@@ -22,6 +18,8 @@ import {
22
18
  } from "./chunk-5OP5MQI7.js";
23
19
  import {
24
20
  UNNAMED_ACTION,
21
+ approvalAwaitingRetry,
22
+ blockedActionFingerprint,
25
23
  claimThrottle,
26
24
  deriveAction,
27
25
  deriveActionBody,
@@ -29,15 +27,19 @@ import {
29
27
  deriveToolTarget,
30
28
  describeToolCall,
31
29
  fetchModeState,
30
+ forgetBlockedActionHint,
32
31
  getPolicy,
32
+ hasBlockedActionHint,
33
+ markApprovalReminded,
33
34
  permissionDeniedAction,
34
35
  readLastPrompt,
35
36
  readLastUserPrompt,
37
+ recordBlockedActionHint,
36
38
  repoKeyFor,
37
39
  reportEvent,
38
40
  scopePathFor,
39
41
  settleQuestionsForToolUse
40
- } from "./chunk-U6RVDUJ5.js";
42
+ } from "./chunk-CULUZTWQ.js";
41
43
  import {
42
44
  DEFAULT_SESSION
43
45
  } from "./chunk-N6IOSZOE.js";
@@ -53,17 +55,17 @@ import {
53
55
  requestGate,
54
56
  sendNotification,
55
57
  waitForQuestion
56
- } from "./chunk-YC27PROF.js";
58
+ } from "./chunk-NGDD6TXY.js";
57
59
  import {
58
60
  SubscriptionRequiredError
59
- } from "./chunk-VE7TXLR4.js";
61
+ } from "./chunk-M5ICYGHT.js";
60
62
  import {
61
63
  getMachineId
62
- } from "./chunk-OVC5QXN5.js";
64
+ } from "./chunk-LXQ5FBBD.js";
63
65
  import {
64
66
  getApiKey,
65
67
  getBaseUrl
66
- } from "./chunk-R6OYCUNK.js";
68
+ } from "./chunk-GPEGOGRJ.js";
67
69
  import {
68
70
  AGENT_QUESTION_STRATEGY,
69
71
  GATE_BLOCK_REASON_MAX_LENGTH,
@@ -91,7 +93,7 @@ import {
91
93
  parseAgentQuestions,
92
94
  resolveGate,
93
95
  stoppedOutput
94
- } from "./chunk-G4GLCLKK.js";
96
+ } from "./chunk-NQTHFF4W.js";
95
97
 
96
98
  // src/claude-permission-rules.ts
97
99
  import { readFileSync, statSync } from "fs";
@@ -530,6 +532,7 @@ var batchScopeReason = "This patch exceeds the agreed scope. Split it into singl
530
532
  var BLOCKED_ACTION_GATE_TIMEOUT_MS = 15e3;
531
533
  var BLOCKED_ACTION_CLAIM_TIMEOUT_MS = 4e3;
532
534
  var BLOCKED_ACTION_ALLOW_REASON = "Approved from Pushary after auto mode blocked it";
535
+ var BLOCKED_ACTION_CHANGED_RETRY_REASON = "This is not the call the person allowed from Pushary, so their approval does not cover it. Send the call auto mode blocked again, exactly as it was with nothing changed, to use their approval.";
533
536
  var blockReasonOf = (reason) => typeof reason === "string" ? reason.trim().slice(0, GATE_BLOCK_REASON_MAX_LENGTH).trim() || void 0 : void 0;
534
537
  var blockedActionFingerprintFor = (input) => blockedActionFingerprint({
535
538
  sessionId: input.session_id,
@@ -566,6 +569,13 @@ var claimedBlockedActionRetry = async (apiKey, input) => {
566
569
  return false;
567
570
  }
568
571
  };
572
+ var remindedOfApprovedRetry = (input) => {
573
+ const approval = approvalAwaitingRetry(input.session_id);
574
+ if (!approval || approval.reminded || approval.toolName !== input.tool_name) return false;
575
+ if (approval.fingerprint === blockedActionFingerprintFor(input)) return false;
576
+ markApprovalReminded(approval);
577
+ return true;
578
+ };
569
579
  var handlePreToolUse = async (input, canonical) => {
570
580
  if (isPusharyOwnTool(input.tool_name)) return void 0;
571
581
  let apiKey;
@@ -597,6 +607,7 @@ var handlePreToolUse = async (input, canonical) => {
597
607
  return handleExitPlanMode(apiKey, input);
598
608
  }
599
609
  if (await claimedBlockedActionRetry(apiKey, input)) return allow(BLOCKED_ACTION_ALLOW_REASON);
610
+ if (remindedOfApprovedRetry(input)) return deny(BLOCKED_ACTION_CHANGED_RETRY_REASON);
600
611
  if (!(verdict.kind === "gate" && verdict.scopeReason) && shouldDeferToNativeMode(input.permission_mode, input.tool_name)) {
601
612
  return void 0;
602
613
  }
@@ -709,11 +720,12 @@ var isRetryOutput = (output) => {
709
720
  return false;
710
721
  }
711
722
  };
712
- var retryOnce = (fingerprint) => recordBlockedActionHint(fingerprint) ? claudePermissionDeniedOutput("allow") : void 0;
723
+ var approvedCallOf = (input) => input.session_id ? { sessionId: input.session_id, toolName: input.tool_name } : void 0;
724
+ var retryOnce = (fingerprint, input) => recordBlockedActionHint(fingerprint, approvedCallOf(input)) ? claudePermissionDeniedOutput("allow") : void 0;
713
725
  var askAboutBlockedAction = async (apiKey, input, fingerprint, holdEndsAt) => {
714
726
  const reply = await requestGate(apiKey, blockedActionGateRequest(input, "PermissionDenied"), BLOCKED_ACTION_GATE_TIMEOUT_MS);
715
727
  if (!reply) return void 0;
716
- if (reply.kind === "no_opinion") return isRetryOutput(reply.output) ? retryOnce(fingerprint) : void 0;
728
+ if (reply.kind === "no_opinion") return isRetryOutput(reply.output) ? retryOnce(fingerprint, input) : void 0;
717
729
  if (reply.kind !== "ask" || !reply.correlationId || reply.deadlineSeconds === void 0) return void 0;
718
730
  if (reply.noDevices) {
719
731
  await cancelQuestion(apiKey, reply.correlationId, AbortSignal.timeout(4e3)).catch(() => void 0);
@@ -721,7 +733,7 @@ var askAboutBlockedAction = async (apiKey, input, fingerprint, holdEndsAt) => {
721
733
  }
722
734
  const deadline = Math.min(hookWaitDeadline(START_MS, reply.deadlineSeconds, "claude", Date.now()), holdEndsAt);
723
735
  const answer = await pollForAnswer(apiKey, reply.correlationId, deadline);
724
- return isAffirmativeAnswer(answer) ? retryOnce(fingerprint) : void 0;
736
+ return isAffirmativeAnswer(answer) ? retryOnce(fingerprint, input) : void 0;
725
737
  };
726
738
  var handlePermissionDenied = async (input, holdBudgetSeconds) => {
727
739
  await reportPermissionDenied(input);
@@ -3,11 +3,11 @@ import {
3
3
  decodePublicKey,
4
4
  generateSessionKey,
5
5
  wrapSessionKey
6
- } from "./chunk-P2VIBGXA.js";
6
+ } from "./chunk-MPWXGONV.js";
7
7
  import {
8
8
  fetchTranscriptRecipients,
9
9
  uploadTranscriptRecords
10
- } from "./chunk-WPX67AKT.js";
10
+ } from "./chunk-SAXBC4AZ.js";
11
11
 
12
12
  // src/live-session.ts
13
13
  var MAX_TRANSCRIPT_QUEUE = 100;
@@ -6,10 +6,10 @@ import {
6
6
  codexHooksJsonIn,
7
7
  isPusharyCodexCommand,
8
8
  resolvePathBinary
9
- } from "./chunk-MZBRL5H5.js";
9
+ } from "./chunk-A2A2YTMG.js";
10
10
  import {
11
11
  getPackageVersion
12
- } from "./chunk-G4GLCLKK.js";
12
+ } from "./chunk-NQTHFF4W.js";
13
13
 
14
14
  // src/codex-app-server.ts
15
15
  import { existsSync, realpathSync } from "fs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getBaseUrl
3
- } from "./chunk-R6OYCUNK.js";
3
+ } from "./chunk-GPEGOGRJ.js";
4
4
 
5
5
  // src/transcript-api.ts
6
6
  var fetchTranscriptRecipients = async (apiKey, baseUrl = getBaseUrl()) => {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseVersion
3
- } from "./chunk-MIXWMA73.js";
3
+ } from "./chunk-3EVPNIBE.js";
4
4
 
5
5
  // src/setup/agent-probe.ts
6
6
  import { execSync } from "child_process";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  parseSseMessages
3
- } from "./chunk-VE7TXLR4.js";
3
+ } from "./chunk-M5ICYGHT.js";
4
4
  import {
5
5
  NPX_LATEST_COMMAND
6
- } from "./chunk-YYCTF4Q5.js";
6
+ } from "./chunk-E4FJTUH4.js";
7
7
 
8
8
  // src/mcp-stdio-bridge.ts
9
9
  var MCP_BRIDGE_BINARY = "pushary-mcp";
@@ -11,6 +11,7 @@ var MCP_BRIDGE_PATH = "/api/mcp/mcp";
11
11
  var MCP_BRIDGE_REQUEST_TIMEOUT_MS = 9e4;
12
12
  var JSON_RPC_PARSE_ERROR = -32700;
13
13
  var MCP_BRIDGE_ERROR = -32e3;
14
+ var MCP_MAX_RESPONSE_BYTES = 1024 * 1024;
14
15
  var MCP_SESSION_HEADER = "mcp-session-id";
15
16
  var MCP_PROTOCOL_HEADER = "mcp-protocol-version";
16
17
  var INITIALIZE_METHOD = "initialize";
@@ -63,6 +64,25 @@ var negotiatedProtocolOf = (messages, initializeIds) => {
63
64
  }
64
65
  return void 0;
65
66
  };
67
+ var readBoundedResponse = async (response) => {
68
+ if (!response.body) return "";
69
+ const reader = response.body.getReader();
70
+ const chunks = [];
71
+ let size = 0;
72
+ try {
73
+ for (; ; ) {
74
+ const { done, value } = await reader.read();
75
+ if (done) break;
76
+ size += value.byteLength;
77
+ if (size > MCP_MAX_RESPONSE_BYTES) throw new Error("MCP response exceeds the 1 MiB limit.");
78
+ chunks.push(value);
79
+ }
80
+ return Buffer.concat(chunks).toString("utf8");
81
+ } finally {
82
+ await reader.cancel().catch(() => void 0);
83
+ reader.releaseLock();
84
+ }
85
+ };
66
86
  var createMcpStdioBridge = (deps) => {
67
87
  let sessionId = null;
68
88
  let protocolVersion = null;
@@ -73,9 +93,9 @@ var createMcpStdioBridge = (deps) => {
73
93
  ...sessionId ? { [MCP_SESSION_HEADER]: sessionId } : {},
74
94
  ...protocolVersion ? { [MCP_PROTOCOL_HEADER]: protocolVersion } : {}
75
95
  });
76
- const failRequests = (requests, message, answered = /* @__PURE__ */ new Set()) => {
96
+ const failRequests = async (requests, message, answered = /* @__PURE__ */ new Set()) => {
77
97
  for (const request of requests) {
78
- if (!answered.has(request.id)) deps.emit(bridgeError(request.id, message));
98
+ if (!answered.has(request.id)) await deps.emit(bridgeError(request.id, message));
79
99
  }
80
100
  };
81
101
  const post = async (line, apiKey) => deps.fetchImpl(deps.endpoint, {
@@ -87,7 +107,7 @@ var createMcpStdioBridge = (deps) => {
87
107
  const forward = async (line) => {
88
108
  const parsed = parseBridgeLine(line);
89
109
  if (!parsed.ok) {
90
- deps.emit(bridgeError(null, PARSE_ERROR_MESSAGE, JSON_RPC_PARSE_ERROR));
110
+ await deps.emit(bridgeError(null, PARSE_ERROR_MESSAGE, JSON_RPC_PARSE_ERROR));
91
111
  return;
92
112
  }
93
113
  const requests = requestsIn(parsed.payload);
@@ -96,25 +116,35 @@ var createMcpStdioBridge = (deps) => {
96
116
  let body;
97
117
  try {
98
118
  response = await post(line, apiKey);
99
- body = await response.text();
119
+ body = await readBoundedResponse(response);
100
120
  } catch (err) {
101
- failRequests(requests, unreachableMessage(err));
121
+ await failRequests(requests, unreachableMessage(err));
102
122
  return;
103
123
  }
104
124
  sessionId = response.headers.get(MCP_SESSION_HEADER) ?? sessionId;
105
125
  const messages = parseMcpMessages(body, response.headers.get("content-type")).filter(isJsonRpcMessage);
106
126
  const initializeIds = new Set(requests.filter((request) => request.method === INITIALIZE_METHOD).map((request) => request.id));
107
127
  protocolVersion = negotiatedProtocolOf(messages, initializeIds) ?? protocolVersion;
108
- for (const message of messages) deps.emit(message);
128
+ for (const message of messages) await deps.emit(message);
109
129
  const answered = new Set(messages.map(responseIdOf).filter(isJsonRpcId));
110
130
  const failure = response.ok ? NO_RESPONSE_MESSAGE : httpFailureMessage(response.status, apiKey !== null, body);
111
- failRequests(requests, failure, answered);
131
+ await failRequests(requests, failure, answered);
132
+ };
133
+ const reject = async (line, message) => {
134
+ const parsed = parseBridgeLine(line);
135
+ if (!parsed.ok) {
136
+ await deps.emit(bridgeError(null, PARSE_ERROR_MESSAGE, JSON_RPC_PARSE_ERROR));
137
+ return;
138
+ }
139
+ await failRequests(requestsIn(parsed.payload), message);
112
140
  };
113
- return { forward };
141
+ return { forward, reject };
114
142
  };
115
143
 
116
144
  export {
117
145
  MCP_BRIDGE_BINARY,
118
146
  MCP_BRIDGE_PATH,
147
+ bridgeError,
148
+ parseBridgeLine,
119
149
  createMcpStdioBridge
120
150
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  NPX_LATEST_COMMAND
3
- } from "./chunk-YYCTF4Q5.js";
3
+ } from "./chunk-E4FJTUH4.js";
4
4
 
5
5
  // src/setup/codex-trust.ts
6
6
  var CODEX_TRUST_TELEMETRY = {
@@ -3,23 +3,25 @@ import {
3
3
  } from "./chunk-POFBE6ZY.js";
4
4
  import {
5
5
  autoUpdateState
6
- } from "./chunk-MZBRL5H5.js";
6
+ } from "./chunk-A2A2YTMG.js";
7
7
  import {
8
8
  readJsonSafe,
9
9
  writeJsonAtomic
10
10
  } from "./chunk-T7E75EKA.js";
11
11
  import {
12
+ CLI_PACKAGE_NAMES,
13
+ POSIX_GLOBAL_ROOT_SEGMENTS,
14
+ cliPackagePathSegments,
15
+ globalUpgradeEntry,
12
16
  ownPackageRoot
13
- } from "./chunk-G4GLCLKK.js";
17
+ } from "./chunk-NQTHFF4W.js";
14
18
 
15
19
  // src/auto-update.ts
16
20
  import { spawn } from "child_process";
17
- import { dirname, join } from "path";
21
+ import { dirname } from "path";
18
22
  var AUTO_UPDATE_DISABLE_ENV = "PUSHARY_DISABLE_AUTOUPDATE";
19
23
  var AUTO_UPDATE_INTERVAL_MS = 24 * 60 * 60 * 1e3;
20
24
  var AUTO_UPDATE_FLAG = "--auto";
21
- var GLOBAL_PACKAGE_SUBPATH = "/lib/node_modules/@pushary/agent-hooks";
22
- var UPGRADE_ENTRY_SUBPATH = ["dist", "bin", "pushary-upgrade.js"];
23
25
  var NON_GLOBAL_INSTALL_SEGMENTS = ["/_npx/", "/.volta/"];
24
26
  var AUTO_UPDATE_RESULTS = ["updated", "current", "needs_manual", "failed", "finish_pending"];
25
27
  var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -55,14 +57,24 @@ var autoUpdateOffReason = (input) => {
55
57
  if (input.platform === "linux") return "linux";
56
58
  return null;
57
59
  };
58
- var globalInstallPrefix = (packageRoot) => {
59
- const root = packageRoot.replace(/\/+$/, "");
60
- if (!root.endsWith(GLOBAL_PACKAGE_SUBPATH)) return null;
61
- if (NON_GLOBAL_INSTALL_SEGMENTS.some((segment) => root.includes(segment))) return null;
62
- const prefix = root.slice(0, -GLOBAL_PACKAGE_SUBPATH.length);
60
+ var globalPackageSubpath = (name) => `/${[...POSIX_GLOBAL_ROOT_SEGMENTS, ...cliPackagePathSegments(name)].join("/")}`;
61
+ var prefixOfGlobalPackage = (root, name) => {
62
+ const subpath = globalPackageSubpath(name);
63
+ if (!root.endsWith(subpath)) return null;
64
+ const prefix = root.slice(0, -subpath.length);
63
65
  return prefix.startsWith("/") ? prefix : null;
64
66
  };
65
- var upgradeEntryFor = (prefix) => join(prefix, GLOBAL_PACKAGE_SUBPATH, ...UPGRADE_ENTRY_SUBPATH);
67
+ var isNonGlobalInstall = (root) => NON_GLOBAL_INSTALL_SEGMENTS.some((segment) => root.includes(segment));
68
+ var globalInstallLocation = (packageRoot) => {
69
+ const root = packageRoot.replace(/\/+$/, "");
70
+ if (isNonGlobalInstall(root)) return null;
71
+ for (const packageName of CLI_PACKAGE_NAMES) {
72
+ const prefix = prefixOfGlobalPackage(root, packageName);
73
+ if (prefix !== null) return { prefix, packageName };
74
+ }
75
+ return null;
76
+ };
77
+ var upgradeEntryFor = (location, platform = process.platform) => globalUpgradeEntry(location.prefix, location.packageName, platform);
66
78
  var checkedWithinInterval = (lastCheckAt, now) => {
67
79
  const last = lastCheckAt === void 0 ? Number.NaN : Date.parse(lastCheckAt);
68
80
  if (Number.isNaN(last)) return false;
@@ -73,10 +85,10 @@ var autoUpdateDecision = (input) => {
73
85
  if (input.isSubagentStart) return { kind: "skip", reason: "subagent_start" };
74
86
  const offReason = autoUpdateOffReason(input);
75
87
  if (offReason !== null) return { kind: "skip", reason: offReason };
76
- const prefix = input.packageRoot === void 0 ? null : globalInstallPrefix(input.packageRoot);
77
- if (prefix === null) return { kind: "skip", reason: "not_global_install" };
88
+ const location = input.packageRoot === void 0 ? null : globalInstallLocation(input.packageRoot);
89
+ if (location === null) return { kind: "skip", reason: "not_global_install" };
78
90
  if (checkedWithinInterval(input.state.lastCheckAt, input.now)) return { kind: "skip", reason: "checked_recently" };
79
- return { kind: "check", prefix };
91
+ return { kind: "check", ...location };
80
92
  };
81
93
  var parseAutoUpdateFlag = (args) => {
82
94
  const token = args.find((arg) => arg === AUTO_UPDATE_FLAG || arg.startsWith(`${AUTO_UPDATE_FLAG}=`));
@@ -141,7 +153,7 @@ var triggerAutoUpdate = (trigger) => {
141
153
  if (decision.kind === "skip") return decision;
142
154
  updateAutoUpdateState(statePath, { lastCheckAt: new Date(now).toISOString() });
143
155
  const spawnUpgrade = trigger.spawn ?? spawnDetached;
144
- spawnUpgrade(trigger.execPath ?? process.execPath, [upgradeEntryFor(decision.prefix), AUTO_UPDATE_FLAG], dirname(statePath));
156
+ spawnUpgrade(trigger.execPath ?? process.execPath, [upgradeEntryFor(decision), AUTO_UPDATE_FLAG], dirname(statePath));
145
157
  return decision;
146
158
  } catch {
147
159
  return null;
@@ -152,7 +164,7 @@ export {
152
164
  AUTO_UPDATE_DISABLE_ENV,
153
165
  isAutoUpdateDisabledByEnv,
154
166
  autoUpdateOffReason,
155
- globalInstallPrefix,
167
+ globalInstallLocation,
156
168
  upgradeEntryFor,
157
169
  parseAutoUpdateFlag,
158
170
  describeAutoUpdateCheck,