@pushary/agent-hooks 1.7.2 → 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 (105) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +13 -1
  3. package/data/cursor-plugin/CHANGELOG.md +1 -0
  4. package/data/cursor-plugin/scripts/pushary-gate.mjs +2 -21
  5. package/data/cursor-plugin/scripts/pushary-gate.test.mjs +23 -1
  6. package/data/cursor-plugin/scripts/redaction.mjs +51 -0
  7. package/data/vscode-plugin/CHANGELOG.md +1 -0
  8. package/data/vscode-plugin/scripts/pushary-gate.mjs +1 -21
  9. package/data/vscode-plugin/scripts/redaction.mjs +51 -0
  10. package/dist/bin/pushary-bell-hook.js +23 -23
  11. package/dist/bin/pushary-bell.js +9 -9
  12. package/dist/bin/pushary-claude.js +28 -28
  13. package/dist/bin/pushary-clean.js +91 -107
  14. package/dist/bin/pushary-codex-bridge.js +18 -18
  15. package/dist/bin/pushary-codex-hook.js +42 -43
  16. package/dist/bin/pushary-codex.js +13 -13
  17. package/dist/bin/pushary-connect.js +13 -13
  18. package/dist/bin/pushary-cowork.js +5 -5
  19. package/dist/bin/pushary-daemon.js +27 -27
  20. package/dist/bin/pushary-disconnect.js +18 -18
  21. package/dist/bin/pushary-doctor.js +85 -79
  22. package/dist/bin/pushary-elicitation-hook.js +25 -25
  23. package/dist/bin/pushary-gemini-bridge.js +12 -12
  24. package/dist/bin/pushary-gemini-hook.js +29 -30
  25. package/dist/bin/pushary-hook.js +32 -32
  26. package/dist/bin/pushary-login.js +12 -12
  27. package/dist/bin/pushary-logout.js +7 -7
  28. package/dist/bin/pushary-mcp.js +85 -28
  29. package/dist/bin/pushary-mode.js +9 -9
  30. package/dist/bin/pushary-notification-hook.js +28 -28
  31. package/dist/bin/pushary-opencode-hook.js +28 -29
  32. package/dist/bin/pushary-permission-denied-hook.js +32 -32
  33. package/dist/bin/pushary-permission-hook.js +31 -31
  34. package/dist/bin/pushary-post-hook.js +28 -28
  35. package/dist/bin/pushary-prompt-hook.js +28 -28
  36. package/dist/bin/pushary-session-end-hook.js +28 -28
  37. package/dist/bin/pushary-session-start-hook.js +32 -32
  38. package/dist/bin/pushary-setup.js +60 -127
  39. package/dist/bin/pushary-stats.js +5 -5
  40. package/dist/bin/pushary-status.js +15 -15
  41. package/dist/bin/pushary-stop-hook.js +28 -28
  42. package/dist/bin/pushary-stopfailure-hook.js +28 -28
  43. package/dist/bin/pushary-suggestions.js +4 -4
  44. package/dist/bin/pushary-transcript-register.js +19 -19
  45. package/dist/bin/pushary-transcripts.js +7 -7
  46. package/dist/bin/pushary-upgrade.js +231 -105
  47. package/dist/bin/pushary-wait.js +9 -9
  48. package/dist/bin/pushary.js +6 -6
  49. package/dist/{chunk-VQDJ6KB3.js → chunk-2ABTSGFT.js} +3 -3
  50. package/dist/{chunk-UFNBKYWT.js → chunk-2OY3ZZ5N.js} +3 -3
  51. package/dist/{chunk-A6WQF7FQ.js → chunk-3EVPNIBE.js} +3 -3
  52. package/dist/{chunk-L6IF4JOF.js → chunk-6J2JC2RT.js} +3 -3
  53. package/dist/{chunk-3NSRL5E7.js → chunk-7Z7Q4GGS.js} +2 -2
  54. package/dist/{chunk-NYBZJ44G.js → chunk-A2A2YTMG.js} +108 -25
  55. package/dist/{chunk-SKEW3TQX.js → chunk-AHV4LNB5.js} +1 -1
  56. package/dist/{chunk-KAJT6HPI.js → chunk-AXPCESYO.js} +3 -3
  57. package/dist/{chunk-JMSB6CJT.js → chunk-C2WCPBF7.js} +1 -1
  58. package/dist/chunk-CJVVKOSR.js +73 -0
  59. package/dist/{chunk-2B4XCMH6.js → chunk-CULUZTWQ.js} +283 -41
  60. package/dist/{chunk-6QZK4O36.js → chunk-CVQYGMSR.js} +4 -4
  61. package/dist/{chunk-SEIZQZEE.js → chunk-D2FX3EPW.js} +1 -1
  62. package/dist/{chunk-LI3C2IQY.js → chunk-DB3ONZB4.js} +2 -2
  63. package/dist/{chunk-YU54LNC6.js → chunk-DE4Y6TCC.js} +6 -6
  64. package/dist/{chunk-65RN6ZCO.js → chunk-E4FJTUH4.js} +1 -1
  65. package/dist/{chunk-RLRDPZG4.js → chunk-EPCXUP3P.js} +3 -1
  66. package/dist/{chunk-OXEF6JHD.js → chunk-EX3GAPA4.js} +1 -1
  67. package/dist/{chunk-E3PLF7YB.js → chunk-EYK3GSRH.js} +4 -4
  68. package/dist/{chunk-SJN64NJX.js → chunk-GPEGOGRJ.js} +1 -1
  69. package/dist/chunk-GU3EJCVV.js +43 -0
  70. package/dist/{chunk-YNJ2H2FD.js → chunk-HQ6G3B5R.js} +2 -2
  71. package/dist/{chunk-6NHXKTQU.js → chunk-HZVVNGEW.js} +2 -2
  72. package/dist/{chunk-ZUKZJQGR.js → chunk-IPVKH2ST.js} +1 -1
  73. package/dist/{chunk-T3PRPFDY.js → chunk-J5TIV3J6.js} +5 -5
  74. package/dist/{chunk-F6BMJOSW.js → chunk-JU6W3XAU.js} +1 -1
  75. package/dist/{chunk-AWZNDM3B.js → chunk-JYG4B33G.js} +1 -1
  76. package/dist/{chunk-ZMWX5SDA.js → chunk-JZTHGAPA.js} +8 -8
  77. package/dist/{chunk-3RO2UWJQ.js → chunk-KGDWDSNL.js} +2 -2
  78. package/dist/{chunk-MY3UZO5U.js → chunk-KVQBWI5T.js} +3 -3
  79. package/dist/{chunk-HOIGXMI7.js → chunk-LXQ5FBBD.js} +1 -1
  80. package/dist/{chunk-D4OGEWLH.js → chunk-M5ICYGHT.js} +3 -3
  81. package/dist/{chunk-YLCSKVQQ.js → chunk-M5JDZ45W.js} +4 -4
  82. package/dist/{chunk-SKMWPXGV.js → chunk-MDEPU45E.js} +183 -28
  83. package/dist/{chunk-R7ZETVNR.js → chunk-MPWXGONV.js} +3 -3
  84. package/dist/{chunk-2XOHXZRC.js → chunk-NGDD6TXY.js} +20 -5
  85. package/dist/{chunk-WWTLAZQA.js → chunk-NQTHFF4W.js} +178 -39
  86. package/dist/{chunk-KLXYMPTM.js → chunk-OKXS7WDZ.js} +1 -1
  87. package/dist/{chunk-Q7CDBJXU.js → chunk-OLQRRFBX.js} +1 -1
  88. package/dist/{chunk-VSGKQ3HI.js → chunk-P7WQEVWA.js} +2 -2
  89. package/dist/{chunk-UUTWHVSV.js → chunk-Q7E4I6UA.js} +28 -16
  90. package/dist/{chunk-WXIVUIXA.js → chunk-R7437YI3.js} +2 -2
  91. package/dist/{chunk-5GIBNUBD.js → chunk-RHR6NARM.js} +2 -2
  92. package/dist/{chunk-QSZ37ROP.js → chunk-SAXBC4AZ.js} +1 -1
  93. package/dist/{chunk-U3MS6D5X.js → chunk-SIFVFP6T.js} +1 -1
  94. package/dist/{chunk-TVJYGZXB.js → chunk-SLFABHW3.js} +40 -10
  95. package/dist/{chunk-M2JGLFFS.js → chunk-TY4JT7W3.js} +1 -1
  96. package/dist/{chunk-YU4222G2.js → chunk-UI36QSBI.js} +28 -16
  97. package/dist/{chunk-OJRB5QKN.js → chunk-VQKRG3AC.js} +6 -6
  98. package/dist/{chunk-4S7CCOXB.js → chunk-WE2J62NC.js} +31 -17
  99. package/dist/{chunk-PWNQGITG.js → chunk-ZSZSSJCV.js} +1 -1
  100. package/dist/{chunk-I7B2DNVU.js → chunk-ZVSKMPBZ.js} +1 -1
  101. package/dist/{reapply-D6RSDYCK.js → reapply-CW3MA66V.js} +9 -9
  102. package/dist/src/index.js +20 -20
  103. package/package.json +1 -1
  104. package/dist/chunk-INR3RVQ3.js +0 -92
  105. package/dist/chunk-IZVAVXHQ.js +0 -255
@@ -455,21 +455,42 @@ var compatibleTargetFiles = (profile) => {
455
455
  };
456
456
 
457
457
  // ../contracts/src/redaction.ts
458
- var CREDENTIAL_KEY = String.raw`(?:secret|token|password|passwd|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)["']?\s*[=:]\s*`;
459
- var CLOSED_DOUBLE_QUOTE = '"';
460
- var CLOSED_SINGLE_QUOTE = "'";
461
- var DOUBLE_QUOTE_OR_CUT_OFF = String.raw`(?:"|\\?$)`;
462
- var SINGLE_QUOTE_OR_CUT_OFF = "(?:'|$)";
463
- var credentialAssignmentRule = (doubleQuoteEnd, singleQuoteEnd) => ({
464
- pattern: new RegExp(
465
- String.raw`(${CREDENTIAL_KEY})(?:(")(?:\\[\s\S]|[^"\\])*${doubleQuoteEnd}|(')[^']*${singleQuoteEnd}|\S+)`,
466
- "gi"
467
- ),
468
- replacement: "$1$2$3[redacted]$2$3"
458
+ var CREDENTIAL_NAME = String.raw`(?:authorization|secret|token|password|passwd|api[_-]?key|access[_-]?key|client[_-]?secret|private[_-]?key)["']?`;
459
+ var CREDENTIAL_KEY = String.raw`${CREDENTIAL_NAME}\s*[=:]\s*`;
460
+ var DISPLAYED_CREDENTIAL_KEY = String.raw`${CREDENTIAL_NAME}(?:[ \t]*:[ \t]*|[ \t]+=[ \t]*|=)`;
461
+ var SHELL_INERT_UNIT = String.raw`(?:[A-Za-z0-9_\-./+=:@%^!#]|\\[^\s'"])`;
462
+ var SHELL_INERT_SINGLE_QUOTED_UNIT = String.raw`[A-Za-z0-9_\-./+=:@%^!#\\]`;
463
+ var SHELL_INERT_URL_PASSWORD_UNIT = String.raw`(?:[A-Za-z0-9_\-.+=:%^!#]|\\[^\s'"@/])`;
464
+ var PEM_LINE_BREAK = String.raw`(?:\r?\n|(?:\\r)?\\n)`;
465
+ var credentialAssignmentRule = (key, doubleQuoted, singleQuoted, bare) => ({
466
+ pattern: new RegExp(String.raw`(${key})(?:(")${doubleQuoted}|(')${singleQuoted}|(["']?)${bare})`, "gi"),
467
+ replacement: "$1$2$3$4[redacted]$2$3"
469
468
  });
470
- var PRECISE_SECRET_RULES = [
469
+ var DISPLAYED_SECRET_SHAPES = {
470
+ privateKeyBody: String.raw`${PEM_LINE_BREAK}?(?:(?:Proc-Type|DEK-Info): [A-Za-z0-9,-]+${PEM_LINE_BREAK})*(?:[A-Za-z0-9+/=\r\n]|\\[rn])*?`,
471
+ urlPassword: `${SHELL_INERT_URL_PASSWORD_UNIT}+`,
472
+ authorizationValue: `${SHELL_INERT_UNIT}+`,
473
+ credentialAssignment: credentialAssignmentRule(
474
+ DISPLAYED_CREDENTIAL_KEY,
475
+ `${SHELL_INERT_UNIT}*"`,
476
+ `${SHELL_INERT_SINGLE_QUOTED_UNIT}*'`,
477
+ `${SHELL_INERT_UNIT}+`
478
+ )
479
+ };
480
+ var CUT_OFF_SECRET_SHAPES = {
481
+ privateKeyBody: String.raw`[\s\S]*?`,
482
+ urlPassword: String.raw`[^\s@/]+`,
483
+ authorizationValue: String.raw`\S+`,
484
+ credentialAssignment: credentialAssignmentRule(
485
+ CREDENTIAL_KEY,
486
+ String.raw`(?:\\[\s\S]|[^"\\])*(?:"|\\?$)`,
487
+ "[^']*(?:'|$)",
488
+ String.raw`\S+`
489
+ )
490
+ };
491
+ var secretRedactionRules = (shapes) => [
471
492
  { pattern: /\bpk_[A-Za-z0-9_]+\.[A-Za-z0-9_]+/g, replacement: "[redacted]" },
472
- { pattern: /-----BEGIN[A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END[A-Z0-9 ]*PRIVATE KEY-----/g, replacement: "[redacted key]" },
493
+ { pattern: new RegExp(String.raw`-----BEGIN[A-Z0-9 ]*PRIVATE KEY-----${shapes.privateKeyBody}-----END[A-Z0-9 ]*PRIVATE KEY-----`, "g"), replacement: "[redacted key]" },
473
494
  { pattern: /\bsk-[A-Za-z0-9_-]{16,}\b/g, replacement: "[redacted]" },
474
495
  { pattern: /\b[spr]k_(?:live|test)_[A-Za-z0-9]{8,}\b/g, replacement: "[redacted]" },
475
496
  { pattern: /\bwhsec_[A-Za-z0-9]{16,}\b/g, replacement: "[redacted]" },
@@ -482,21 +503,17 @@ var PRECISE_SECRET_RULES = [
482
503
  { pattern: /\bnpm_[A-Za-z0-9]{36}\b/g, replacement: "[redacted]" },
483
504
  { pattern: /\bxai-[A-Za-z0-9]{16,}\b/g, replacement: "[redacted]" },
484
505
  { pattern: /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, replacement: "[redacted]" },
485
- { pattern: /\b([a-z][a-z0-9+.-]*:\/\/[^\s:/@]+:)[^\s@/]+@/gi, replacement: "$1[redacted]@" },
506
+ { pattern: new RegExp(String.raw`\b([a-z][a-z0-9+.-]*:\/\/[^\s:/@]+:)${shapes.urlPassword}@`, "gi"), replacement: "$1[redacted]@" },
486
507
  { pattern: /\bbearer\s+[A-Za-z0-9._~+/=-]+/gi, replacement: "bearer [redacted]" },
487
- { pattern: /\bauthorization:\s*\S+/gi, replacement: "authorization: [redacted]" }
488
- ];
489
- var SECRET_REDACTION_RULES = [
490
- ...PRECISE_SECRET_RULES,
491
- credentialAssignmentRule(CLOSED_DOUBLE_QUOTE, CLOSED_SINGLE_QUOTE)
492
- ];
493
- var CUT_OFF_TEXT_REDACTION_RULES = [
494
- ...PRECISE_SECRET_RULES,
495
- credentialAssignmentRule(DOUBLE_QUOTE_OR_CUT_OFF, SINGLE_QUOTE_OR_CUT_OFF)
508
+ { pattern: new RegExp(String.raw`\bauthorization:\s*${shapes.authorizationValue}`, "gi"), replacement: "authorization: [redacted]" },
509
+ shapes.credentialAssignment
496
510
  ];
511
+ var SECRET_REDACTION_RULES = secretRedactionRules(DISPLAYED_SECRET_SHAPES);
512
+ var CUT_OFF_TEXT_REDACTION_RULES = secretRedactionRules(CUT_OFF_SECRET_SHAPES);
497
513
  var HIGH_ENTROPY_RULE = { pattern: /[A-Za-z0-9+/]{40,}={0,2}/g, replacement: "[redacted]" };
498
514
  var applyRedactionRules = (rules, text) => rules.reduce((acc, rule) => acc.replace(rule.pattern, rule.replacement), text);
499
515
  var redactSecrets = (text) => applyRedactionRules(SECRET_REDACTION_RULES, text);
516
+ var redactSecretsFromContent = (text) => applyRedactionRules(CUT_OFF_TEXT_REDACTION_RULES, text);
500
517
  var redactSecretsDeep = (text) => redactSecrets(text).replace(HIGH_ENTROPY_RULE.pattern, HIGH_ENTROPY_RULE.replacement);
501
518
 
502
519
  // ../contracts/src/degraded.ts
@@ -642,9 +659,13 @@ var INSTALL_SOURCES = [
642
659
  "framework_adapter",
643
660
  /** The browser onboarding wizard. */
644
661
  "dashboard",
645
- /** Reported nothing, or reported something we do not recognise. */
646
662
  /** The macOS app pairing a phone from its own onboarding. */
647
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. */
648
669
  "unknown"
649
670
  ];
650
671
  var isInstallSource = (value) => typeof value === "string" && INSTALL_SOURCES.includes(value);
@@ -1518,6 +1539,16 @@ var API_KEY_PATTERN = /^pk_[a-f0-9]+\.[a-f0-9]+$/;
1518
1539
  var isValidApiKey = (value) => API_KEY_PATTERN.test(value);
1519
1540
  var ACTION_BODY_MAX = 4e3;
1520
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
+ };
1521
1552
  var APPROVAL_FATIGUE_FLAG_PATTERNS = [
1522
1553
  /\brm\s+-[a-z]*r/i,
1523
1554
  /\brmdir\b/i,
@@ -2522,40 +2553,126 @@ var hookActivationResult = (report) => {
2522
2553
  return report && !report.truncated && report.evidence.length === 1 ? report.evidence[0].result : "unverified";
2523
2554
  };
2524
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
+
2525
2639
  // src/cli/version.ts
2526
2640
  import { readFileSync } from "fs";
2527
2641
  import { dirname, join, parse } from "path";
2528
2642
  import { fileURLToPath } from "url";
2529
- var PACKAGE_NAME = "@pushary/agent-hooks";
2530
2643
  var UNKNOWN_VERSION = "0.0.0";
2531
- 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) => {
2532
2652
  const { root } = parse(start);
2533
2653
  let dir = start;
2534
2654
  while (true) {
2535
- const candidate = join(dir, "package.json");
2536
- try {
2537
- const pkg = JSON.parse(readFileSync(candidate, "utf-8"));
2538
- if (pkg.name === PACKAGE_NAME) return candidate;
2539
- } catch {
2540
- }
2655
+ const name = cliManifestNameAt(join(dir, "package.json"));
2656
+ if (name !== void 0) return { root: dir, name };
2541
2657
  if (dir === root) return void 0;
2542
2658
  const parent = dirname(dir);
2543
2659
  if (parent === dir) return void 0;
2544
2660
  dir = parent;
2545
2661
  }
2546
2662
  };
2547
- var getPackageVersion = () => {
2548
- const root = ownPackageRoot();
2549
- return (root === void 0 ? void 0 : packageVersionAt(root)) ?? UNKNOWN_VERSION;
2550
- };
2551
- var ownPackageRoot = () => {
2663
+ var runningPackage = () => {
2552
2664
  try {
2553
- const found = findOwnPackageJson(dirname(fileURLToPath(import.meta.url)));
2554
- return found ? dirname(found) : void 0;
2665
+ return findOwnPackage(dirname(fileURLToPath(import.meta.url)));
2555
2666
  } catch {
2556
2667
  return void 0;
2557
2668
  }
2558
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;
2559
2676
  var packageVersionAt = (packageRoot) => {
2560
2677
  try {
2561
2678
  const manifest = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf-8"));
@@ -2601,6 +2718,7 @@ export {
2601
2718
  hookCompatibleProfileBySource,
2602
2719
  compatibleTargetFiles,
2603
2720
  redactSecrets,
2721
+ redactSecretsFromContent,
2604
2722
  redactSecretsDeep,
2605
2723
  degradedLine,
2606
2724
  hookWritePath,
@@ -2639,6 +2757,9 @@ export {
2639
2757
  isValidApiKey,
2640
2758
  ACTION_BODY_MAX,
2641
2759
  DECISION_LINE_MAX,
2760
+ ASK_QUESTION_MAX,
2761
+ ASK_AGENT_NAME_MAX,
2762
+ truncateLine,
2642
2763
  isAnswerSource,
2643
2764
  buildDecisionEpisodeFeatures,
2644
2765
  resolveAutoResolveOrigin,
@@ -2682,8 +2803,26 @@ export {
2682
2803
  planElicitationAsk,
2683
2804
  elicitationContent,
2684
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,
2685
2823
  getPackageVersion,
2686
2824
  ownPackageRoot,
2825
+ ownPackageName,
2687
2826
  packageVersionAt,
2688
2827
  isNewerVersion,
2689
2828
  isReleaseVersion,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  guardBinary
3
- } from "./chunk-NYBZJ44G.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-VSGKQ3HI.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-LI3C2IQY.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-SJN64NJX.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-T3PRPFDY.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-IZVAVXHQ.js";
8
+ } from "./chunk-CJVVKOSR.js";
13
9
  import {
14
10
  isGatingMoment,
15
11
  recordKeylessMoment
16
- } from "./chunk-F6BMJOSW.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-2B4XCMH6.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-2XOHXZRC.js";
58
+ } from "./chunk-NGDD6TXY.js";
57
59
  import {
58
60
  SubscriptionRequiredError
59
- } from "./chunk-D4OGEWLH.js";
61
+ } from "./chunk-M5ICYGHT.js";
60
62
  import {
61
63
  getMachineId
62
- } from "./chunk-HOIGXMI7.js";
64
+ } from "./chunk-LXQ5FBBD.js";
63
65
  import {
64
66
  getApiKey,
65
67
  getBaseUrl
66
- } from "./chunk-SJN64NJX.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-WWTLAZQA.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-R7ZETVNR.js";
6
+ } from "./chunk-MPWXGONV.js";
7
7
  import {
8
8
  fetchTranscriptRecipients,
9
9
  uploadTranscriptRecords
10
- } from "./chunk-QSZ37ROP.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-NYBZJ44G.js";
9
+ } from "./chunk-A2A2YTMG.js";
10
10
  import {
11
11
  getPackageVersion
12
- } from "./chunk-WWTLAZQA.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-SJN64NJX.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-A6WQF7FQ.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-D4OGEWLH.js";
3
+ } from "./chunk-M5ICYGHT.js";
4
4
  import {
5
5
  NPX_LATEST_COMMAND
6
- } from "./chunk-65RN6ZCO.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-65RN6ZCO.js";
3
+ } from "./chunk-E4FJTUH4.js";
4
4
 
5
5
  // src/setup/codex-trust.ts
6
6
  var CODEX_TRUST_TELEMETRY = {