pushary 1.9.135 → 1.9.136

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 (133) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/{api-WEDLFKUE.js → api-5H25QRNM.js} +11 -11
  3. package/dist/bin/pushary-audit.js +3 -3
  4. package/dist/bin/pushary-bell-hook.js +28 -28
  5. package/dist/bin/pushary-bell.js +10 -10
  6. package/dist/bin/pushary-claude.js +27 -27
  7. package/dist/bin/pushary-clean.js +35 -35
  8. package/dist/bin/pushary-codex-bridge.js +23 -23
  9. package/dist/bin/pushary-codex-hook.js +58 -42
  10. package/dist/bin/pushary-codex-session.js +8 -8
  11. package/dist/bin/pushary-codex.js +16 -16
  12. package/dist/bin/pushary-connect.js +29 -29
  13. package/dist/bin/pushary-cowork.js +5 -5
  14. package/dist/bin/pushary-daemon.js +43 -43
  15. package/dist/bin/pushary-disconnect.js +28 -28
  16. package/dist/bin/pushary-display-hook.js +21 -7
  17. package/dist/bin/pushary-doctor.js +43 -43
  18. package/dist/bin/pushary-elicitation-hook.js +28 -28
  19. package/dist/bin/pushary-gemini-bridge.js +17 -17
  20. package/dist/bin/pushary-gemini-hook.js +32 -32
  21. package/dist/bin/pushary-hook.js +35 -34
  22. package/dist/bin/pushary-login.js +21 -21
  23. package/dist/bin/pushary-logout.js +27 -27
  24. package/dist/bin/pushary-mcp.js +12 -12
  25. package/dist/bin/pushary-mode.js +15 -15
  26. package/dist/bin/pushary-notification-hook.js +27 -27
  27. package/dist/bin/pushary-opencode-hook.js +31 -31
  28. package/dist/bin/pushary-permission-denied-hook.js +35 -34
  29. package/dist/bin/pushary-permission-hook.js +39 -36
  30. package/dist/bin/pushary-post-hook.js +33 -28
  31. package/dist/bin/pushary-prompt-hook.js +27 -27
  32. package/dist/bin/pushary-session-end-hook.js +27 -27
  33. package/dist/bin/pushary-session-start-hook.js +36 -36
  34. package/dist/bin/pushary-setup.js +50 -50
  35. package/dist/bin/pushary-stats.js +5 -5
  36. package/dist/bin/pushary-status.js +33 -33
  37. package/dist/bin/pushary-stop-hook.js +27 -27
  38. package/dist/bin/pushary-stopfailure-hook.js +27 -27
  39. package/dist/bin/pushary-suggestions.js +15 -15
  40. package/dist/bin/pushary-transcript-register.js +17 -17
  41. package/dist/bin/pushary-transcripts.js +25 -25
  42. package/dist/bin/pushary-upgrade.js +41 -41
  43. package/dist/bin/pushary-wait.js +15 -15
  44. package/dist/bin/pushary.js +7 -7
  45. package/dist/{chunk-LIXCHEDJ.js → chunk-2E46RALI.js} +6 -6
  46. package/dist/{chunk-4YBDKFU2.js → chunk-2MVKT7KH.js} +2 -2
  47. package/dist/{chunk-7JXYR4TC.js → chunk-2R4OVJHS.js} +5 -5
  48. package/dist/{chunk-WPPTHRBO.js → chunk-2XDVEBHI.js} +5 -5
  49. package/dist/{chunk-5GQLZ46V.js → chunk-3HXOR6E5.js} +8 -8
  50. package/dist/{chunk-VND6LN6X.js → chunk-3QBI5C6P.js} +2 -2
  51. package/dist/{chunk-7ASHS5VR.js → chunk-43DT3QWZ.js} +18 -5
  52. package/dist/{chunk-AEOITMCS.js → chunk-4T72AHIA.js} +4 -4
  53. package/dist/{chunk-V7KBG7XH.js → chunk-54TZGPZP.js} +3 -3
  54. package/dist/{chunk-WVOMK2HW.js → chunk-5XDFQ6E3.js} +1 -1
  55. package/dist/{chunk-JDAX2HVS.js → chunk-62GD26OE.js} +2 -2
  56. package/dist/{chunk-VCMJLNEP.js → chunk-6SWFS4GU.js} +2 -2
  57. package/dist/{chunk-UXPRMNH2.js → chunk-A2YJ2FBR.js} +3 -2
  58. package/dist/{chunk-QUMPSMZN.js → chunk-A4YOXS24.js} +3 -3
  59. package/dist/{chunk-MGTMXF3T.js → chunk-A7R43KOX.js} +3 -3
  60. package/dist/{chunk-RGRPDJG3.js → chunk-D7AAAD6W.js} +163 -108
  61. package/dist/{chunk-6RSAOA2P.js → chunk-DBIPNY7J.js} +3 -3
  62. package/dist/{chunk-H4226UC7.js → chunk-DL67HX3D.js} +32 -9
  63. package/dist/{chunk-SULQKUPJ.js → chunk-EJHD44ZN.js} +2 -2
  64. package/dist/{chunk-MYMADZRU.js → chunk-EQZB5P6I.js} +2 -2
  65. package/dist/{chunk-RCZ5ZER4.js → chunk-FAF5RDWT.js} +6 -6
  66. package/dist/{chunk-OUMH4UTT.js → chunk-G73ACPR2.js} +2 -2
  67. package/dist/{chunk-N2DYYXQI.js → chunk-GACQSKNG.js} +2 -2
  68. package/dist/{chunk-ACI4PZ5N.js → chunk-GS5FH3C2.js} +3 -3
  69. package/dist/{chunk-64QLX4ZC.js → chunk-H2RE3IPK.js} +1 -1
  70. package/dist/{chunk-KUAS2DGZ.js → chunk-HKJLPVPZ.js} +5 -5
  71. package/dist/{chunk-7DWERNHQ.js → chunk-HY4ATVCT.js} +3 -3
  72. package/dist/{chunk-UDSJKRRI.js → chunk-ICCM3DLT.js} +2 -2
  73. package/dist/{chunk-AXQFLLOB.js → chunk-IHAKBLW2.js} +4 -4
  74. package/dist/{chunk-FP6ZVMF2.js → chunk-IKBTG3OT.js} +1 -1
  75. package/dist/{chunk-DMK3U7GG.js → chunk-IRIXOH4U.js} +1 -1
  76. package/dist/{chunk-U5W3MKPU.js → chunk-JZJ5CM6X.js} +5 -5
  77. package/dist/{chunk-4VVDRMVE.js → chunk-K7YJBVR3.js} +1 -1
  78. package/dist/{chunk-GLAGHQPB.js → chunk-KLV2NQVT.js} +4 -4
  79. package/dist/{chunk-FSLV5FIE.js → chunk-KTVMIG32.js} +4 -4
  80. package/dist/{chunk-Q5GPXYDG.js → chunk-KYD3LHFB.js} +1 -1
  81. package/dist/{chunk-XRO6NRBO.js → chunk-L2GADKFL.js} +6 -6
  82. package/dist/{chunk-65ZWYA5L.js → chunk-L7Q57R4J.js} +10 -10
  83. package/dist/{chunk-IOUCIJ56.js → chunk-LAWI6NQK.js} +1 -1
  84. package/dist/{chunk-IABPEGAA.js → chunk-LNF36PTF.js} +2 -2
  85. package/dist/{chunk-E4RMOK4A.js → chunk-MENTZJHA.js} +1 -1
  86. package/dist/{chunk-TKOALSA5.js → chunk-MQ3I5OIC.js} +8 -8
  87. package/dist/{chunk-BGXXWLS5.js → chunk-MQMVJDII.js} +1 -1
  88. package/dist/{chunk-WTLQMJZ3.js → chunk-N3VCBXI6.js} +3 -3
  89. package/dist/{chunk-EWJXECUK.js → chunk-NN43KGTN.js} +4 -4
  90. package/dist/{chunk-WNPZGHHU.js → chunk-NZD6ISCL.js} +3 -3
  91. package/dist/{chunk-3KPPXZCO.js → chunk-O5T53LZ5.js} +42 -25
  92. package/dist/{chunk-6UARD3WA.js → chunk-PHA6AFOR.js} +3 -3
  93. package/dist/{chunk-LTY5DSWT.js → chunk-PNVTPEO5.js} +3 -3
  94. package/dist/{chunk-G3YIGTFS.js → chunk-POV2TBFA.js} +11 -11
  95. package/dist/{chunk-SFN72Q7W.js → chunk-Q2VV77IY.js} +3 -3
  96. package/dist/{chunk-GRCX2FGD.js → chunk-QXATIKHQ.js} +1 -1
  97. package/dist/{chunk-6QZGKKQS.js → chunk-R7CQF2P3.js} +1 -1
  98. package/dist/{chunk-ZJKWDM3S.js → chunk-R7KC57PC.js} +2 -2
  99. package/dist/{chunk-UCGWTMQD.js → chunk-RPFSVNH6.js} +3 -3
  100. package/dist/{chunk-VXYGYCNR.js → chunk-RRUP72V6.js} +1 -1
  101. package/dist/{chunk-ORZ7H3AQ.js → chunk-TLK5YLIE.js} +4 -4
  102. package/dist/{chunk-NBMK6T6R.js → chunk-U3OLXV5Z.js} +2 -2
  103. package/dist/chunk-UP5QXEUU.js +31 -0
  104. package/dist/{chunk-X3NYMHLG.js → chunk-V7ZY7P2X.js} +6 -6
  105. package/dist/{chunk-CGROOSWT.js → chunk-VBWJ756P.js} +5 -5
  106. package/dist/{chunk-OEIU6BNH.js → chunk-VO77WHK4.js} +6 -6
  107. package/dist/{chunk-NWNUS2ET.js → chunk-VV7WRIQT.js} +4 -4
  108. package/dist/{chunk-2K7MZRPH.js → chunk-VVN3RPV6.js} +1 -1
  109. package/dist/{chunk-35RCY4LB.js → chunk-WM7OY63L.js} +1 -1
  110. package/dist/{chunk-RLNJNRYP.js → chunk-WNT4JHK3.js} +1 -1
  111. package/dist/{chunk-ZNST34QH.js → chunk-WXUEOHYY.js} +5 -5
  112. package/dist/{chunk-XB75IJ3G.js → chunk-Y47BMZUR.js} +1 -1
  113. package/dist/{chunk-4XTB74D3.js → chunk-YHX5YF77.js} +4 -4
  114. package/dist/{chunk-4PPSXQQ6.js → chunk-YOV3LHOL.js} +3 -3
  115. package/dist/{chunk-7KWOR2T2.js → chunk-YQQGIDBC.js} +1 -1
  116. package/dist/{chunk-7GEMAKQL.js → chunk-YURIU333.js} +5 -5
  117. package/dist/{chunk-QLIG4PMT.js → chunk-ZWIJJYN3.js} +4 -4
  118. package/dist/{chunk-UCDPJHZT.js → chunk-ZWLSXECG.js} +2 -2
  119. package/dist/{chunk-UQCVVN7K.js → chunk-ZWURBNA3.js} +1 -1
  120. package/dist/{codex-app-cards-switch-C6DXLVAM.js → codex-app-cards-switch-Z7TMF2OR.js} +11 -11
  121. package/dist/{codex-card-routing-ZMMS4RIR.js → codex-card-routing-LQJEJNTS.js} +2 -2
  122. package/dist/{codex-desktop-launch-DIUFMA45.js → codex-desktop-launch-HKXGKL3T.js} +1 -1
  123. package/dist/{codex-session-launch-S4WTGKRY.js → codex-session-launch-DTGH7ZKM.js} +20 -20
  124. package/dist/{config-BV5FQ536.js → config-34VUNHK6.js} +3 -3
  125. package/dist/{global-upgrade-JZWB67EU.js → global-upgrade-5UAH5DCG.js} +9 -9
  126. package/dist/{identity-G6FQTONT.js → identity-UFJEWGEU.js} +4 -4
  127. package/dist/{live-capabilities-YHMOXY5E.js → live-capabilities-BL3SHFWX.js} +4 -4
  128. package/dist/{paths-XTEJ5LI2.js → paths-YA5ROXGC.js} +3 -3
  129. package/dist/{reapply-MVZKPXIQ.js → reapply-OPQF4DPQ.js} +29 -29
  130. package/dist/src/index.js +34 -33
  131. package/dist/{upgrade-lock-YPAQEEJA.js → upgrade-lock-AZLOOGKV.js} +4 -4
  132. package/dist/{usage-R6PZTIEH.js → usage-ZSV4LFDL.js} +3 -3
  133. package/package.json +1 -1
@@ -27,11 +27,11 @@ import {
27
27
  toolResultErrorText,
28
28
  transcriptTokensIn,
29
29
  transcriptUsageRequest
30
- } from "./chunk-UXPRMNH2.js";
30
+ } from "./chunk-A2YJ2FBR.js";
31
31
  import {
32
32
  branchFor,
33
33
  repoKeyFor
34
- } from "./chunk-DMK3U7GG.js";
34
+ } from "./chunk-IRIXOH4U.js";
35
35
  import {
36
36
  cancelQuestion,
37
37
  clientErrorKindOf,
@@ -39,40 +39,39 @@ import {
39
39
  reportClientError,
40
40
  sendNotification,
41
41
  waitForAnswer
42
- } from "./chunk-XRO6NRBO.js";
42
+ } from "./chunk-L2GADKFL.js";
43
43
  import {
44
44
  RETRY_ACK,
45
45
  readCommandAck,
46
46
  refusedReceiptMessage
47
- } from "./chunk-XB75IJ3G.js";
47
+ } from "./chunk-Y47BMZUR.js";
48
48
  import {
49
49
  isRetryable,
50
50
  withRetry
51
- } from "./chunk-ZNST34QH.js";
51
+ } from "./chunk-WXUEOHYY.js";
52
52
  import {
53
53
  fetchAsCredential
54
- } from "./chunk-2K7MZRPH.js";
54
+ } from "./chunk-VVN3RPV6.js";
55
55
  import {
56
56
  getMachineId
57
- } from "./chunk-RLNJNRYP.js";
57
+ } from "./chunk-WNT4JHK3.js";
58
58
  import {
59
59
  reportedInstallSource
60
- } from "./chunk-IABPEGAA.js";
60
+ } from "./chunk-LNF36PTF.js";
61
61
  import {
62
62
  IDLE_PROMPT_NOTIFICATION,
63
63
  NOTIFICATION_PUSH_TYPES,
64
64
  POSTTOOLUSE_MIRROR_ONLY_TOOLS,
65
- canonicalJson,
66
65
  claudeConfigDir
67
- } from "./chunk-ZJKWDM3S.js";
66
+ } from "./chunk-R7KC57PC.js";
68
67
  import {
69
68
  compareVersion,
70
69
  parseVersion
71
- } from "./chunk-ACI4PZ5N.js";
70
+ } from "./chunk-GS5FH3C2.js";
72
71
  import {
73
72
  getApiKey,
74
73
  getBaseUrl
75
- } from "./chunk-FP6ZVMF2.js";
74
+ } from "./chunk-IKBTG3OT.js";
76
75
  import {
77
76
  writeFileAtomic,
78
77
  writeJsonAtomicDurable
@@ -101,7 +100,7 @@ import {
101
100
  resolveAutoResolveOrigin,
102
101
  resolvePolicy,
103
102
  unansweredRefusalReason
104
- } from "./chunk-H4226UC7.js";
103
+ } from "./chunk-DL67HX3D.js";
105
104
 
106
105
  // src/pending.ts
107
106
  import { join } from "path";
@@ -796,12 +795,48 @@ var permissionTimeoutDecision = (timeoutAction, paused) => {
796
795
  return codexPass();
797
796
  };
798
797
 
799
- // src/codex-call-decision.ts
800
- import { createHash as createHash4 } from "crypto";
801
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync4, readdirSync as readdirSync3, rmSync as rmSync2, statSync as statSync3, writeFileSync as writeFileSync4 } from "fs";
802
- import { tmpdir as tmpdir4, userInfo } from "os";
798
+ // src/driver.ts
799
+ var DRIVER_ENV = "PUSHARY_DRIVER";
800
+ var PHONE_DRIVER = "phone";
801
+ var driverFromEnv = (env) => env[DRIVER_ENV] === PHONE_DRIVER ? PHONE_DRIVER : void 0;
802
+ var phoneDrivenEnv = (base) => ({
803
+ ...base,
804
+ [DRIVER_ENV]: PHONE_DRIVER
805
+ });
806
+
807
+ // src/throttle.ts
803
808
  import { join as join4 } from "path";
804
- var CODEX_DECISION_TTL_MS = 60 * 1e3;
809
+ import { tmpdir as tmpdir4 } from "os";
810
+ import { createHash as createHash4 } from "crypto";
811
+ import { existsSync as existsSync3, mkdirSync as mkdirSync3, statSync as statSync3, writeFileSync as writeFileSync4, rmSync as rmSync2 } from "fs";
812
+ var THROTTLE_DIR = join4(tmpdir4(), "pushary-throttle");
813
+ var markerPath = (key) => join4(THROTTLE_DIR, createHash4("sha256").update(key).digest("hex").slice(0, 16));
814
+ var claimThrottle = (key, windowMs) => {
815
+ try {
816
+ const path = markerPath(key);
817
+ if (existsSync3(path) && Date.now() - statSync3(path).mtimeMs < windowMs) return "throttled";
818
+ mkdirSync3(THROTTLE_DIR, { recursive: true });
819
+ writeFileSync4(path, "", "utf-8");
820
+ return "passed";
821
+ } catch {
822
+ return "unavailable";
823
+ }
824
+ };
825
+ var releaseThrottle = (key) => {
826
+ rmSync2(markerPath(key), { force: true });
827
+ };
828
+
829
+ // src/blocked-action-hint.ts
830
+ import { createHash as createHash5 } from "crypto";
831
+ import { existsSync as existsSync4, mkdirSync as mkdirSync5, readFileSync as readFileSync5, readdirSync as readdirSync4, rmSync as rmSync4, statSync as statSync4, utimesSync as utimesSync2 } from "fs";
832
+ import { tmpdir as tmpdir6 } from "os";
833
+ import { join as join6 } from "path";
834
+
835
+ // src/call-decision-store.ts
836
+ import { randomUUID } from "crypto";
837
+ import { lstatSync as lstatSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync4, readdirSync as readdirSync3, renameSync, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "fs";
838
+ import { tmpdir as tmpdir5, userInfo } from "os";
839
+ import { join as join5 } from "path";
805
840
  var userScope = () => {
806
841
  try {
807
842
  const info = userInfo();
@@ -811,8 +846,6 @@ var userScope = () => {
811
846
  return "default";
812
847
  }
813
848
  };
814
- var decisionDir = () => join4(tmpdir4(), `pushary-codex-decisions-${userScope()}`);
815
- var decisionFile = (key) => join4(decisionDir(), key);
816
849
  var PRESENTATION_ONLY_INPUT_KEYS = ["description"];
817
850
  var identifyingToolInput = (toolInput) => {
818
851
  if (!toolInput) return {};
@@ -823,105 +856,128 @@ var identifyingToolInput = (toolInput) => {
823
856
  }
824
857
  return identifying;
825
858
  };
826
- var codexCallKey = (identity) => {
827
- if (!identity.sessionId || !identity.turnId || !identity.toolName) return null;
828
- const material = canonicalJson([
829
- identity.sessionId,
830
- identity.turnId,
831
- identity.toolName,
832
- identifyingToolInput(identity.toolInput)
833
- ]);
834
- return createHash4("sha256").update(material, "utf-8").digest("hex").slice(0, 32);
859
+ var PRIVATE_FOLDER_MODE = 448;
860
+ var PRIVATE_FILE_MODE = 384;
861
+ var GROUP_OR_OTHER_PERMISSIONS = 63;
862
+ var isPrivateFolder = (path) => {
863
+ try {
864
+ const folder = lstatSync3(path);
865
+ if (!folder.isDirectory()) return false;
866
+ if (typeof process.getuid !== "function") return true;
867
+ return folder.uid === process.getuid() && (folder.mode & GROUP_OR_OTHER_PERMISSIONS) === 0;
868
+ } catch {
869
+ return false;
870
+ }
835
871
  };
836
- var parseDecision = (raw) => {
872
+ var privateFolderAt = (path) => {
837
873
  try {
838
- const parsed = JSON.parse(raw);
839
- if (parsed.kind === "approved") {
840
- return typeof parsed.toolUseId === "string" && parsed.toolUseId ? { kind: "approved", toolUseId: parsed.toolUseId } : null;
841
- }
842
- if (parsed.kind === "handled") return { kind: "handled" };
843
- if (parsed.kind === "denied") {
844
- return { kind: "denied", reason: typeof parsed.reason === "string" ? parsed.reason : "" };
845
- }
846
- return null;
874
+ mkdirSync4(path, { recursive: true, mode: PRIVATE_FOLDER_MODE });
847
875
  } catch {
848
876
  return null;
849
877
  }
878
+ return isPrivateFolder(path) ? path : null;
850
879
  };
851
- var sweepExpired = (dir, nowMs) => {
880
+ var removeQuietly = (path) => {
852
881
  try {
853
- for (const name of readdirSync3(dir)) {
854
- const path = join4(dir, name);
855
- try {
856
- if (nowMs - statSync3(path).mtimeMs >= CODEX_DECISION_TTL_MS) rmSync2(path, { force: true });
857
- } catch {
858
- continue;
859
- }
860
- }
882
+ rmSync3(path, { force: true });
861
883
  } catch {
862
884
  return;
863
885
  }
864
886
  };
865
- var recordCodexCallDecision = (key, decision) => {
866
- if (!key) return;
887
+ var reportedUnrecordedDecision = false;
888
+ var reportUnrecordedDecision = (reason) => {
889
+ if (reportedUnrecordedDecision) return;
890
+ reportedUnrecordedDecision = true;
867
891
  try {
868
- const dir = decisionDir();
869
- if (!existsSync3(dir)) mkdirSync3(dir, { recursive: true, mode: 448 });
870
- else sweepExpired(dir, Date.now());
871
- writeFileSync4(decisionFile(key), JSON.stringify(decision), { encoding: "utf-8", mode: 384 });
892
+ process.stderr.write(`[pushary] Could not record this decision for the agent's next hook: ${reason}
893
+ `);
872
894
  } catch {
873
895
  return;
874
896
  }
875
897
  };
876
- var consumeCodexCallDecision = (key) => {
877
- if (!key) return null;
878
- const path = decisionFile(key);
898
+ var parseDecision = (raw) => {
899
+ let parsed;
879
900
  try {
880
- const fresh = Date.now() - statSync3(path).mtimeMs < CODEX_DECISION_TTL_MS;
881
- const raw = readFileSync4(path, "utf-8");
882
- rmSync2(path, { force: true });
883
- return fresh ? parseDecision(raw) : null;
901
+ parsed = JSON.parse(raw);
884
902
  } catch {
885
903
  return null;
886
904
  }
905
+ if (!isRecord(parsed)) return null;
906
+ if (parsed.kind === "approved") {
907
+ return typeof parsed.toolUseId === "string" && parsed.toolUseId ? { kind: "approved", toolUseId: parsed.toolUseId } : null;
908
+ }
909
+ if (parsed.kind === "handled") return { kind: "handled" };
910
+ if (parsed.kind === "denied") {
911
+ return { kind: "denied", reason: typeof parsed.reason === "string" ? parsed.reason : "" };
912
+ }
913
+ return null;
887
914
  };
888
-
889
- // src/driver.ts
890
- var DRIVER_ENV = "PUSHARY_DRIVER";
891
- var PHONE_DRIVER = "phone";
892
- var driverFromEnv = (env) => env[DRIVER_ENV] === PHONE_DRIVER ? PHONE_DRIVER : void 0;
893
- var phoneDrivenEnv = (base) => ({
894
- ...base,
895
- [DRIVER_ENV]: PHONE_DRIVER
896
- });
897
-
898
- // src/throttle.ts
899
- import { join as join5 } from "path";
900
- import { tmpdir as tmpdir5 } from "os";
901
- import { createHash as createHash5 } from "crypto";
902
- import { existsSync as existsSync4, mkdirSync as mkdirSync4, statSync as statSync4, writeFileSync as writeFileSync5, rmSync as rmSync3 } from "fs";
903
- var THROTTLE_DIR = join5(tmpdir5(), "pushary-throttle");
904
- var markerPath = (key) => join5(THROTTLE_DIR, createHash5("sha256").update(key).digest("hex").slice(0, 16));
905
- var claimThrottle = (key, windowMs) => {
915
+ var sweepExpired = (dir, nowMs, ttlMs) => {
906
916
  try {
907
- const path = markerPath(key);
908
- if (existsSync4(path) && Date.now() - statSync4(path).mtimeMs < windowMs) return "throttled";
909
- mkdirSync4(THROTTLE_DIR, { recursive: true });
910
- writeFileSync5(path, "", "utf-8");
911
- return "passed";
917
+ for (const name of readdirSync3(dir)) {
918
+ const path = join5(dir, name);
919
+ try {
920
+ if (nowMs - lstatSync3(path).mtimeMs >= ttlMs) rmSync3(path, { force: true });
921
+ } catch {
922
+ continue;
923
+ }
924
+ }
912
925
  } catch {
913
- return "unavailable";
926
+ return;
914
927
  }
915
928
  };
916
- var releaseThrottle = (key) => {
917
- rmSync3(markerPath(key), { force: true });
929
+ var readClaimed = (claimed, ttlMs) => {
930
+ try {
931
+ const record = lstatSync3(claimed);
932
+ if (!record.isFile() || Date.now() - record.mtimeMs >= ttlMs) return null;
933
+ return parseDecision(readFileSync4(claimed, "utf-8"));
934
+ } catch {
935
+ return null;
936
+ } finally {
937
+ removeQuietly(claimed);
938
+ }
939
+ };
940
+ var callDecisionStore = (name, ttlMs) => {
941
+ const decisionDir = () => join5(tmpdir5(), `pushary-${name}-decisions-${userScope()}`);
942
+ return {
943
+ record: (key, decision) => {
944
+ if (!key) return;
945
+ const dir = privateFolderAt(decisionDir());
946
+ if (!dir) {
947
+ reportUnrecordedDecision(`${decisionDir()} is not a folder only this user can open`);
948
+ return;
949
+ }
950
+ sweepExpired(dir, Date.now(), ttlMs);
951
+ const pending = join5(dir, `${key}.${randomUUID()}.pending`);
952
+ try {
953
+ writeFileSync5(pending, JSON.stringify(decision), { encoding: "utf-8", mode: PRIVATE_FILE_MODE, flag: "wx" });
954
+ renameSync(pending, join5(dir, key));
955
+ } catch (error) {
956
+ removeQuietly(pending);
957
+ reportUnrecordedDecision(error instanceof Error ? error.message : String(error));
958
+ }
959
+ },
960
+ consume: (key) => {
961
+ if (!key) return null;
962
+ const dir = decisionDir();
963
+ if (!isPrivateFolder(dir)) return null;
964
+ const claimed = join5(dir, `${key}.${randomUUID()}.claimed`);
965
+ try {
966
+ renameSync(join5(dir, key), claimed);
967
+ } catch {
968
+ return null;
969
+ }
970
+ return readClaimed(claimed, ttlMs);
971
+ },
972
+ forget: (key) => {
973
+ if (!key) return;
974
+ const dir = decisionDir();
975
+ if (isPrivateFolder(dir)) removeQuietly(join5(dir, key));
976
+ }
977
+ };
918
978
  };
919
979
 
920
980
  // src/blocked-action-hint.ts
921
- import { createHash as createHash6 } from "crypto";
922
- import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync5, readdirSync as readdirSync4, rmSync as rmSync4, statSync as statSync5, utimesSync as utimesSync2 } from "fs";
923
- import { tmpdir as tmpdir6 } from "os";
924
- import { join as join6 } from "path";
925
981
  var BLOCKED_ACTION_HINT_TTL_MS = BLOCKED_ACTION_GRANT_TTL_SECONDS * 1e3;
926
982
  var FINGERPRINT = /^[0-9a-f]{64}$/;
927
983
  var isFingerprint = (value) => typeof value === "string" && FINGERPRINT.test(value);
@@ -936,7 +992,7 @@ var blockedActionFingerprint = ({ source = "claude", sessionId, toolName, toolIn
936
992
  const [canonicalInput] = canonical.toolInputs;
937
993
  if (!canonicalInput) return null;
938
994
  const subject = blockedActionSubject(source, sessionId, canonical.toolName, canonicalInput, cwd);
939
- return subject ? createHash6("sha256").update(blockedActionIdentity(subject), "utf8").digest("hex") : null;
995
+ return subject ? createHash5("sha256").update(blockedActionIdentity(subject), "utf8").digest("hex") : null;
940
996
  };
941
997
  var hintDir = () => join6(tmpdir6(), `pushary-blocked-action-hints-${userScope()}`);
942
998
  var hintFile = (fingerprint) => join6(hintDir(), fingerprint);
@@ -946,7 +1002,7 @@ var sweepFilesOlderThan = (dir, ttlMs, nowMs) => {
946
1002
  for (const name of readdirSync4(dir)) {
947
1003
  const path = join6(dir, name);
948
1004
  try {
949
- if (nowMs - statSync5(path).mtimeMs >= ttlMs) rmSync4(path, { force: true });
1005
+ if (nowMs - statSync4(path).mtimeMs >= ttlMs) rmSync4(path, { force: true });
950
1006
  } catch {
951
1007
  continue;
952
1008
  }
@@ -959,7 +1015,7 @@ var recordBlockedActionHint = (fingerprint, approved) => {
959
1015
  if (!isFingerprint(fingerprint)) return false;
960
1016
  try {
961
1017
  const dir = hintDir();
962
- if (!existsSync5(dir)) mkdirSync5(dir, { recursive: true, mode: 448 });
1018
+ if (!existsSync4(dir)) mkdirSync5(dir, { recursive: true, mode: 448 });
963
1019
  else sweepFilesOlderThan(dir, BLOCKED_ACTION_HINT_TTL_MS, Date.now());
964
1020
  writeFileAtomic(hintFile(fingerprint), JSON.stringify({ fingerprint, ...approved }), 384);
965
1021
  return true;
@@ -970,7 +1026,7 @@ var recordBlockedActionHint = (fingerprint, approved) => {
970
1026
  var readLiveHint = (fingerprint) => {
971
1027
  const path = hintFile(fingerprint);
972
1028
  try {
973
- const stat = statSync5(path);
1029
+ const stat = statSync4(path);
974
1030
  if (!stat.isFile()) return null;
975
1031
  if (isExpired(stat.mtimeMs, Date.now())) {
976
1032
  rmSync4(path, { force: true });
@@ -1003,7 +1059,7 @@ var approvalAwaitingRetry = (sessionId) => {
1003
1059
  var markApprovalReminded = (approval) => {
1004
1060
  const path = hintFile(approval.fingerprint);
1005
1061
  try {
1006
- const { atime, mtime } = statSync5(path);
1062
+ const { atime, mtime } = statSync4(path);
1007
1063
  const { fingerprint, sessionId, toolName } = approval;
1008
1064
  writeFileAtomic(path, JSON.stringify({ fingerprint, sessionId, toolName, reminded: true }), 384);
1009
1065
  utimesSync2(path, atime, mtime);
@@ -1021,7 +1077,7 @@ var forgetBlockedActionHint = (fingerprint) => {
1021
1077
  };
1022
1078
 
1023
1079
  // src/claude-session-record.ts
1024
- import { readFileSync as readFileSync6, readdirSync as readdirSync5, statSync as statSync6 } from "fs";
1080
+ import { readFileSync as readFileSync6, readdirSync as readdirSync5, statSync as statSync5 } from "fs";
1025
1081
  import { join as join7 } from "path";
1026
1082
  var UNREADABLE = { kind: "unreadable" };
1027
1083
  var OTHER_SESSION = { kind: "other_session" };
@@ -1038,7 +1094,7 @@ var isRunning = (pid) => {
1038
1094
  };
1039
1095
  var isSmallRegularFile = (path) => {
1040
1096
  try {
1041
- const stats = statSync6(path);
1097
+ const stats = statSync5(path);
1042
1098
  return stats.isFile() && stats.size <= SESSION_FILE_MAX_BYTES;
1043
1099
  } catch {
1044
1100
  return false;
@@ -1085,13 +1141,13 @@ var claudeSessionVersion = (sessionId, environment = process.env) => {
1085
1141
  };
1086
1142
 
1087
1143
  // src/background-work.ts
1088
- import { createHash as createHash7 } from "crypto";
1089
- import { mkdirSync as mkdirSync6, rmSync as rmSync5, statSync as statSync7, writeFileSync as writeFileSync6 } from "fs";
1144
+ import { createHash as createHash6 } from "crypto";
1145
+ import { mkdirSync as mkdirSync6, rmSync as rmSync5, statSync as statSync6, writeFileSync as writeFileSync6 } from "fs";
1090
1146
  import { tmpdir as tmpdir7 } from "os";
1091
1147
  import { join as join8 } from "path";
1092
1148
  var BACKGROUND_WORK_TTL_MS = 60 * 60 * 1e3;
1093
1149
  var backgroundWorkDir = () => join8(tmpdir7(), "pushary-background-work");
1094
- var markerFor = (sessionKey) => join8(backgroundWorkDir(), createHash7("sha256").update(sessionKey).digest("hex"));
1150
+ var markerFor = (sessionKey) => join8(backgroundWorkDir(), createHash6("sha256").update(sessionKey).digest("hex"));
1095
1151
  var hasRunningBackgroundTasks = (backgroundTasks) => Array.isArray(backgroundTasks) && backgroundTasks.length > 0;
1096
1152
  var noteBackgroundWork = (sessionKey, running) => {
1097
1153
  try {
@@ -1107,7 +1163,7 @@ var noteBackgroundWork = (sessionKey, running) => {
1107
1163
  };
1108
1164
  var isWaitingOnBackgroundWork = (sessionKey, nowMs = Date.now()) => {
1109
1165
  try {
1110
- return nowMs - statSync7(markerFor(sessionKey)).mtimeMs < BACKGROUND_WORK_TTL_MS;
1166
+ return nowMs - statSync6(markerFor(sessionKey)).mtimeMs < BACKGROUND_WORK_TTL_MS;
1111
1167
  } catch {
1112
1168
  return false;
1113
1169
  }
@@ -1115,7 +1171,7 @@ var isWaitingOnBackgroundWork = (sessionKey, nowMs = Date.now()) => {
1115
1171
 
1116
1172
  // src/events.ts
1117
1173
  import { basename, join as join9 } from "path";
1118
- import { existsSync as existsSync6, mkdirSync as mkdirSync7, readFileSync as readFileSync7, statSync as statSync8, writeFileSync as writeFileSync7 } from "fs";
1174
+ import { existsSync as existsSync5, mkdirSync as mkdirSync7, readFileSync as readFileSync7, statSync as statSync7, writeFileSync as writeFileSync7 } from "fs";
1119
1175
  import { tmpdir as tmpdir8 } from "os";
1120
1176
  var INTENT_DIR = join9(tmpdir8(), "pushary-intent");
1121
1177
  var INTENT_MAX_BYTES = 2048;
@@ -1134,7 +1190,7 @@ var saveLastPrompt = (sessionId, prompt) => {
1134
1190
  var readLastPrompt = (sessionId) => {
1135
1191
  try {
1136
1192
  const path = intentFile(sessionId);
1137
- if (isDefaultSession(sessionId) && statSync8(path).mtimeMs < Date.now() - INTENT_GRACE_MS) return void 0;
1193
+ if (isDefaultSession(sessionId) && statSync7(path).mtimeMs < Date.now() - INTENT_GRACE_MS) return void 0;
1138
1194
  const value = readFileSync7(path, "utf-8").trim();
1139
1195
  return value.length > 0 ? value : void 0;
1140
1196
  } catch {
@@ -1199,7 +1255,7 @@ var POLICY_CACHE_TTL_MS = 5 * 60 * 1e3;
1199
1255
  var readFreshCachedPolicy = (apiKey, agentType, sessionId) => {
1200
1256
  const request = policyRequestFor(agentType);
1201
1257
  const path = policyCacheFile(apiKey, request.agent, request.repoAware, sessionId);
1202
- if (!existsSync6(path)) return null;
1258
+ if (!existsSync5(path)) return null;
1203
1259
  const cached = JSON.parse(readFileSync7(path, "utf-8"));
1204
1260
  if (!isCachedPolicyRead(cached)) return null;
1205
1261
  if ((cached._sessionId ?? null) !== (sessionId ?? null)) return null;
@@ -1776,9 +1832,8 @@ export {
1776
1832
  codexQuestionLimitDecision,
1777
1833
  permissionTimeoutDecision,
1778
1834
  userScope,
1779
- codexCallKey,
1780
- recordCodexCallDecision,
1781
- consumeCodexCallDecision,
1835
+ identifyingToolInput,
1836
+ callDecisionStore,
1782
1837
  blockedActionFingerprint,
1783
1838
  sweepFilesOlderThan,
1784
1839
  recordBlockedActionHint,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  realpath
3
- } from "./chunk-SULQKUPJ.js";
3
+ } from "./chunk-EJHD44ZN.js";
4
4
  import {
5
5
  findNativeClaudeInstall
6
6
  } from "./chunk-CYTPQDQY.js";
@@ -13,10 +13,10 @@ import {
13
13
  resolvePackageVersionFromBinary,
14
14
  resolvePathBinary,
15
15
  resolvePathBinaryAsync
16
- } from "./chunk-ACI4PZ5N.js";
16
+ } from "./chunk-GS5FH3C2.js";
17
17
  import {
18
18
  MANAGED_PROVIDERS
19
- } from "./chunk-H4226UC7.js";
19
+ } from "./chunk-DL67HX3D.js";
20
20
 
21
21
  // src/live-capabilities.ts
22
22
  import { homedir } from "os";
@@ -623,6 +623,13 @@ var firstString = (record4, keys2) => {
623
623
  }
624
624
  return void 0;
625
625
  };
626
+ var pathsNamedIn = (record4, keys2) => keys2.flatMap((key) => {
627
+ const value = record4[key];
628
+ return typeof value === "string" && value.length > 0 ? [value] : [];
629
+ });
630
+ var namesOneFile = (paths, resolvePath) => new Set(paths.map(resolvePath)).size === 1;
631
+ var filePathKeysOf = (profile) => [...profile.pathInputKeys, ...CANONICAL_PATH_KEYS];
632
+ var namesAFilePath = (profile, toolInput) => pathsNamedIn(toolInput, filePathKeysOf(profile)).length > 0;
626
633
  var withCanonicalInputKeys = (profile, toolInput) => {
627
634
  const renamed = Object.entries(profile.inputKeyAliases).flatMap(([agentKey, canonicalKey]) => toolInput[agentKey] === void 0 || toolInput[canonicalKey] !== void 0 ? [] : [[canonicalKey, toolInput[agentKey]]]);
628
635
  return renamed.length === 0 ? toolInput : { ...toolInput, ...Object.fromEntries(renamed) };
@@ -666,8 +673,9 @@ var toToolLookup = (profile, toolName, toolInput, resolvePath = (path) => path)
666
673
  return { tool, input: { command, ...context }, unreadable: false };
667
674
  }
668
675
  if (!PATH_TOOLS.has(tool)) return { tool, input: toolInput, unreadable: false };
669
- const filePath = firstString(toolInput, [...profile.pathInputKeys, ...CANONICAL_PATH_KEYS]);
670
- if (!filePath) return { tool, input: toolInput, unreadable: true };
676
+ const paths = pathsNamedIn(toolInput, filePathKeysOf(profile));
677
+ const [filePath] = paths;
678
+ if (!filePath || !namesOneFile(paths, resolvePath)) return { tool, input: toolInput, unreadable: true };
671
679
  return { tool, input: { ...withCanonicalInputKeys(profile, toolInput), file_path: resolvePath(filePath) }, unreadable: false };
672
680
  };
673
681
  var NO_AGENT_PROMPT_REASON = "Pushary needs an answer from the phone before this can run, and this agent has no approval prompt of its own here, so nothing ran. Ask the user, then try again.";
@@ -797,7 +805,9 @@ var QWEN_CODE = {
797
805
  permissionRuleFile: null,
798
806
  configDirIsShared: false,
799
807
  soleGate: null,
800
- taskControl: null
808
+ taskControl: null,
809
+ promptFollowsPreToolUseAllow: true,
810
+ permissionRequestPaths: "shell_escaped"
801
811
  };
802
812
  var CODEBUDDY = {
803
813
  agentType: "codebuddy",
@@ -821,7 +831,9 @@ var CODEBUDDY = {
821
831
  permissionRuleFile: homeJson(".codebuddy", "settings.json"),
822
832
  configDirIsShared: false,
823
833
  soleGate: null,
824
- taskControl: null
834
+ taskControl: null,
835
+ promptFollowsPreToolUseAllow: false,
836
+ permissionRequestPaths: "as_pre_tool_use"
825
837
  };
826
838
  var QODER = {
827
839
  agentType: "qoder",
@@ -845,7 +857,9 @@ var QODER = {
845
857
  permissionRuleFile: null,
846
858
  configDirIsShared: false,
847
859
  soleGate: null,
848
- taskControl: null
860
+ taskControl: null,
861
+ promptFollowsPreToolUseAllow: false,
862
+ permissionRequestPaths: "as_pre_tool_use"
849
863
  };
850
864
  var DROID = {
851
865
  agentType: "droid",
@@ -874,7 +888,9 @@ var DROID = {
874
888
  permissionRuleFile: null,
875
889
  configDirIsShared: false,
876
890
  soleGate: null,
877
- taskControl: null
891
+ taskControl: null,
892
+ promptFollowsPreToolUseAllow: false,
893
+ permissionRequestPaths: "as_pre_tool_use"
878
894
  };
879
895
  var DEVIN = {
880
896
  agentType: "devin",
@@ -908,7 +924,9 @@ var DEVIN = {
908
924
  permissionRuleFile: null,
909
925
  configDirIsShared: false,
910
926
  soleGate: null,
911
- taskControl: null
927
+ taskControl: null,
928
+ promptFollowsPreToolUseAllow: false,
929
+ permissionRequestPaths: "as_pre_tool_use"
912
930
  };
913
931
  var ANTIGRAVITY_TASK_CONTROL = {
914
932
  name: "manage_task",
@@ -959,7 +977,9 @@ var ANTIGRAVITY_CLI = {
959
977
  receipt: [".pushary", "setup", "antigravity-tool-permission.json"],
960
978
  coveredTools: [ANTIGRAVITY_TASK_CONTROL.name]
961
979
  },
962
- taskControl: ANTIGRAVITY_TASK_CONTROL
980
+ taskControl: ANTIGRAVITY_TASK_CONTROL,
981
+ promptFollowsPreToolUseAllow: false,
982
+ permissionRequestPaths: "as_pre_tool_use"
963
983
  };
964
984
  var GROK = {
965
985
  agentType: "grok",
@@ -993,7 +1013,9 @@ var GROK = {
993
1013
  permissionRuleFile: null,
994
1014
  configDirIsShared: false,
995
1015
  soleGate: null,
996
- taskControl: null
1016
+ taskControl: null,
1017
+ promptFollowsPreToolUseAllow: false,
1018
+ permissionRequestPaths: "as_pre_tool_use"
997
1019
  };
998
1020
  var HOOK_COMPATIBLE_PROFILES = Object.freeze([QWEN_CODE, CODEBUDDY, QODER, DROID, DEVIN, ANTIGRAVITY_CLI, GROK]);
999
1021
  var hookCompatibleProfile = (agentType) => HOOK_COMPATIBLE_PROFILES.find((profile) => profile.agentType === agentType);
@@ -9525,6 +9547,7 @@ export {
9525
9547
  isGrokSessionEndStop,
9526
9548
  isCompatibleAgentType,
9527
9549
  PHONE_ANSWERED_TOOLS,
9550
+ namesAFilePath,
9528
9551
  canonicalToolName,
9529
9552
  TASK_OUTPUT_TOOL,
9530
9553
  TASK_STOP_TOOL,
@@ -3,10 +3,10 @@ import {
3
3
  } from "./chunk-CYTPQDQY.js";
4
4
  import {
5
5
  parseVersion
6
- } from "./chunk-ACI4PZ5N.js";
6
+ } from "./chunk-GS5FH3C2.js";
7
7
  import {
8
8
  isRecord
9
- } from "./chunk-H4226UC7.js";
9
+ } from "./chunk-DL67HX3D.js";
10
10
 
11
11
  // src/setup/agent-probe.ts
12
12
  import { execSync } from "child_process";
@@ -9,13 +9,13 @@ import {
9
9
  installedCodexApp,
10
10
  readCodexAppRuntime,
11
11
  shellQuoted
12
- } from "./chunk-UCGWTMQD.js";
12
+ } from "./chunk-RPFSVNH6.js";
13
13
  import {
14
14
  writeHuman
15
15
  } from "./chunk-QCGNGEGE.js";
16
16
  import {
17
17
  xml
18
- } from "./chunk-RCZ5ZER4.js";
18
+ } from "./chunk-FAF5RDWT.js";
19
19
  import {
20
20
  writeFileAtomic
21
21
  } from "./chunk-TODDEIYG.js";
@@ -4,19 +4,19 @@ import {
4
4
  } from "./chunk-H6CL3T2S.js";
5
5
  import {
6
6
  getMachineId
7
- } from "./chunk-RLNJNRYP.js";
7
+ } from "./chunk-WNT4JHK3.js";
8
8
  import {
9
9
  readControlMode
10
- } from "./chunk-LTY5DSWT.js";
10
+ } from "./chunk-PNVTPEO5.js";
11
11
  import {
12
12
  pusharyDir
13
- } from "./chunk-ZJKWDM3S.js";
13
+ } from "./chunk-R7KC57PC.js";
14
14
  import {
15
15
  resolveGlobalBinary
16
- } from "./chunk-ACI4PZ5N.js";
16
+ } from "./chunk-GS5FH3C2.js";
17
17
  import {
18
18
  getApiKey
19
- } from "./chunk-FP6ZVMF2.js";
19
+ } from "./chunk-IKBTG3OT.js";
20
20
  import {
21
21
  readJsonSafe,
22
22
  writeFileAtomic,
@@ -32,7 +32,7 @@ import {
32
32
  } from "./chunk-WIIMW5YO.js";
33
33
  import {
34
34
  isRecord
35
- } from "./chunk-H4226UC7.js";
35
+ } from "./chunk-DL67HX3D.js";
36
36
 
37
37
  // src/daemon-lifecycle.ts
38
38
  import { dirname, join, win32 as win32Path } from "path";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  claudeConfigDir
3
- } from "./chunk-ZJKWDM3S.js";
3
+ } from "./chunk-R7KC57PC.js";
4
4
  import {
5
5
  claudePermissionRulesFromSettings
6
- } from "./chunk-H4226UC7.js";
6
+ } from "./chunk-DL67HX3D.js";
7
7
 
8
8
  // src/claude-permission-rules.ts
9
9
  import { readFileSync, statSync } from "fs";