@pushary/agent-hooks 1.9.14 → 1.9.16

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 (100) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/bin/pushary-bell-hook.js +25 -25
  3. package/dist/bin/pushary-bell.js +10 -10
  4. package/dist/bin/pushary-claude.js +24 -24
  5. package/dist/bin/pushary-clean.js +29 -29
  6. package/dist/bin/pushary-codex-bridge.js +17 -17
  7. package/dist/bin/pushary-codex-hook.js +72 -48
  8. package/dist/bin/pushary-codex.js +12 -12
  9. package/dist/bin/pushary-connect.js +25 -25
  10. package/dist/bin/pushary-cowork.js +5 -5
  11. package/dist/bin/pushary-daemon.js +31 -31
  12. package/dist/bin/pushary-disconnect.js +24 -24
  13. package/dist/bin/pushary-doctor.js +34 -34
  14. package/dist/bin/pushary-elicitation-hook.js +25 -25
  15. package/dist/bin/pushary-gemini-bridge.js +13 -13
  16. package/dist/bin/pushary-gemini-hook.js +27 -27
  17. package/dist/bin/pushary-hook.js +29 -29
  18. package/dist/bin/pushary-login.js +13 -13
  19. package/dist/bin/pushary-logout.js +11 -11
  20. package/dist/bin/pushary-mcp.js +9 -9
  21. package/dist/bin/pushary-mode.js +13 -13
  22. package/dist/bin/pushary-notification-hook.js +24 -24
  23. package/dist/bin/pushary-opencode-hook.js +26 -26
  24. package/dist/bin/pushary-permission-denied-hook.js +29 -29
  25. package/dist/bin/pushary-permission-hook.js +28 -28
  26. package/dist/bin/pushary-post-hook.js +24 -24
  27. package/dist/bin/pushary-prompt-hook.js +24 -24
  28. package/dist/bin/pushary-session-end-hook.js +24 -24
  29. package/dist/bin/pushary-session-start-hook.js +28 -28
  30. package/dist/bin/pushary-setup.js +443 -117
  31. package/dist/bin/pushary-stats.js +5 -5
  32. package/dist/bin/pushary-status.js +27 -27
  33. package/dist/bin/pushary-stop-hook.js +24 -24
  34. package/dist/bin/pushary-stopfailure-hook.js +24 -24
  35. package/dist/bin/pushary-suggestions.js +13 -13
  36. package/dist/bin/pushary-transcript-register.js +17 -17
  37. package/dist/bin/pushary-transcripts.js +7 -7
  38. package/dist/bin/pushary-upgrade.js +30 -30
  39. package/dist/bin/pushary-wait.js +13 -13
  40. package/dist/bin/pushary.js +10 -7
  41. package/dist/{chunk-EB6LH3U6.js → chunk-3DZG5EXY.js} +3 -3
  42. package/dist/{chunk-RMWV3MYN.js → chunk-4MOOSU5Y.js} +36 -25
  43. package/dist/{chunk-NNCK2PUR.js → chunk-4PQGFWPO.js} +2 -2
  44. package/dist/{chunk-VYXXAFIA.js → chunk-52JA2WTH.js} +1 -1
  45. package/dist/{chunk-2WWHZTI5.js → chunk-5ETPCIG4.js} +23 -4
  46. package/dist/{chunk-XJKM6NQS.js → chunk-65OI53N7.js} +6 -6
  47. package/dist/{chunk-42WYKVHL.js → chunk-7BNU5AVD.js} +2 -2
  48. package/dist/{chunk-3KHQWC4F.js → chunk-7DE5BZMB.js} +6 -6
  49. package/dist/{chunk-PWO6T7JG.js → chunk-7EBZRHIH.js} +5 -5
  50. package/dist/{chunk-NAROM5IR.js → chunk-AYV2NRYJ.js} +93 -2
  51. package/dist/{chunk-3U4R475X.js → chunk-BARUIIUR.js} +3 -3
  52. package/dist/{chunk-QD6GQDYW.js → chunk-COGQIULO.js} +1 -1
  53. package/dist/{chunk-Y6IKUCVF.js → chunk-CXXYHPN7.js} +2 -2
  54. package/dist/{chunk-2Q6IT5PR.js → chunk-DMJPRZVJ.js} +1 -1
  55. package/dist/{chunk-NMDGIMDV.js → chunk-DUDI3Z7F.js} +2 -2
  56. package/dist/{chunk-RV4U3LYL.js → chunk-EDEIIKCV.js} +3 -3
  57. package/dist/{chunk-H7MTFFNI.js → chunk-EDXJEQCK.js} +4 -4
  58. package/dist/{chunk-U4TMAANR.js → chunk-FO3MDD26.js} +4 -4
  59. package/dist/{chunk-5RONPCMH.js → chunk-HBDZYQZX.js} +5 -5
  60. package/dist/{chunk-4BXVGCPE.js → chunk-HDQAN2C3.js} +27 -8
  61. package/dist/{chunk-Q7JWY33N.js → chunk-HKSH4KWI.js} +3 -3
  62. package/dist/{chunk-OMR3P7PJ.js → chunk-ICEMM4H2.js} +14 -14
  63. package/dist/{chunk-WYPQKDKX.js → chunk-IHPSFUL2.js} +13 -18
  64. package/dist/{chunk-YSVCBUT3.js → chunk-ISJ5ROXM.js} +2 -2
  65. package/dist/{chunk-JHDHC2M7.js → chunk-J36EWRVL.js} +5 -5
  66. package/dist/{chunk-7MGNY7S3.js → chunk-JF2XRQR2.js} +1 -1
  67. package/dist/{chunk-2Z56BRTF.js → chunk-JNZU2F5B.js} +2 -2
  68. package/dist/{chunk-5UYAJVAQ.js → chunk-JQC7ZFHM.js} +1 -1
  69. package/dist/{chunk-LRZMGU7T.js → chunk-L52HDK35.js} +4 -4
  70. package/dist/{chunk-ZECHTK3K.js → chunk-LJJLMU5B.js} +3 -3
  71. package/dist/{chunk-34PUBGLS.js → chunk-LYEXTD64.js} +2 -2
  72. package/dist/{chunk-ARM4DMIL.js → chunk-MN2QJA7K.js} +1 -1
  73. package/dist/{chunk-5VP72OOI.js → chunk-NM6IHHRO.js} +8 -8
  74. package/dist/{chunk-CT4BJEU7.js → chunk-OEMDXBV6.js} +1 -1
  75. package/dist/{chunk-FKQMH2DW.js → chunk-OIAZ2QAC.js} +3 -2
  76. package/dist/{chunk-MSEUUAJ7.js → chunk-OLJ6YZME.js} +5 -5
  77. package/dist/{chunk-AJRT3JGE.js → chunk-PJNZJPPX.js} +1 -1
  78. package/dist/{chunk-POJUUEGO.js → chunk-PVOOKOKX.js} +4 -4
  79. package/dist/{chunk-J5RQW52I.js → chunk-PYPZ3MYC.js} +2 -2
  80. package/dist/{chunk-7SIZISYH.js → chunk-PZ33VQ54.js} +5 -5
  81. package/dist/{chunk-LETLRKSY.js → chunk-QINDG6HO.js} +1 -1
  82. package/dist/{chunk-DVTXGXXL.js → chunk-QIOWXUFH.js} +1 -1
  83. package/dist/{chunk-NXJNYAP7.js → chunk-QJYBHKHO.js} +1 -1
  84. package/dist/{chunk-2A234H3F.js → chunk-R2FHKTD3.js} +3 -3
  85. package/dist/{chunk-CIZQARGJ.js → chunk-S2LU6HIZ.js} +3 -3
  86. package/dist/{chunk-ZSL7B7NF.js → chunk-VKYDON4A.js} +2 -2
  87. package/dist/{chunk-ECU2Y7D2.js → chunk-W2AUU35K.js} +2 -2
  88. package/dist/{chunk-2QASSTM5.js → chunk-WVSECXIM.js} +2 -2
  89. package/dist/{chunk-3XAUHY35.js → chunk-WWTB4DAE.js} +1 -1
  90. package/dist/{chunk-ZVFKNSRX.js → chunk-XIJMMY6M.js} +1 -1
  91. package/dist/{chunk-2NIBBM3N.js → chunk-YHHUYJQN.js} +2 -2
  92. package/dist/{chunk-K2IUMMZJ.js → chunk-YKYFFCB5.js} +1 -1
  93. package/dist/{chunk-APG7IAUK.js → chunk-ZH74RRGM.js} +1 -1
  94. package/dist/{chunk-SEQSZYLW.js → chunk-ZOMVMLMU.js} +10 -15
  95. package/dist/{global-upgrade-P5CJ22AW.js → global-upgrade-4XWM5RXK.js} +6 -6
  96. package/dist/{paths-XZE2MPTP.js → paths-2RE6MBKF.js} +2 -2
  97. package/dist/{reapply-V4GMKCGP.js → reapply-Y5PSM7U7.js} +20 -20
  98. package/dist/src/index.js +19 -19
  99. package/dist/{upgrade-lock-DQF62B6X.js → upgrade-lock-HVWZN4BZ.js} +3 -3
  100. package/package.json +1 -1
@@ -11,22 +11,22 @@ import {
11
11
  clipToRow,
12
12
  terminalColumns,
13
13
  useColor
14
- } from "./chunk-U4TMAANR.js";
14
+ } from "./chunk-FO3MDD26.js";
15
15
  import {
16
16
  callMcpTool
17
- } from "./chunk-CIZQARGJ.js";
17
+ } from "./chunk-S2LU6HIZ.js";
18
18
  import {
19
19
  reportedInstallSource
20
- } from "./chunk-ZSL7B7NF.js";
20
+ } from "./chunk-VKYDON4A.js";
21
21
  import {
22
22
  NPX_LATEST_COMMAND
23
- } from "./chunk-FKQMH2DW.js";
23
+ } from "./chunk-OIAZ2QAC.js";
24
24
  import {
25
25
  NO_PAIRING_COMPUTER,
26
26
  PAIR_TTL_SECONDS,
27
27
  classifyConfirmResponse,
28
28
  isAnswerSource
29
- } from "./chunk-NAROM5IR.js";
29
+ } from "./chunk-AYV2NRYJ.js";
30
30
 
31
31
  // src/reach.ts
32
32
  var reachVerdict = (channels) => {
@@ -282,9 +282,9 @@ var describeAnswerSource = (source) => {
282
282
  switch (source) {
283
283
  case "mobile_app":
284
284
  case "mobile_background":
285
- return "A phone answered this synthetic test.";
285
+ return "Answered on your phone.";
286
286
  case "mac_app":
287
- return "A Mac answered this synthetic test.";
287
+ return "Answered on your Mac.";
288
288
  case "sandbox":
289
289
  return "This was a simulated sandbox answer.";
290
290
  default:
@@ -357,6 +357,7 @@ var yellow = paint("\x1B[33m");
357
357
  var check = green("\u2713");
358
358
  var apiBase = () => process.env.PUSHARY_API_URL?.trim() || process.env.PUSHARY_BASE_URL?.trim() || "https://pushary.com";
359
359
  var EXIT_ABORTED = 130;
360
+ var EXIT_TERMINATED = 143;
360
361
  var CONNECT_POLL_INTERVAL_MS = 2500;
361
362
  var CONNECT_TIMEOUT_MS = 18e4;
362
363
  var EMPTY_CHANNELS = {
@@ -491,10 +492,11 @@ var startSpinner = (getLabel) => {
491
492
  writeStatusLine(`${finalGlyph} ${finalLabel}`);
492
493
  };
493
494
  };
495
+ var qrRows = (qr) => qr.replace(/\n+$/, "").split("\n");
494
496
  var printQr = (url) => new Promise((resolve, reject) => {
495
497
  try {
496
498
  qrcodeTerminal.generate(url, { small: true }, (qr) => {
497
- writeHuman("\n" + qr.split("\n").map((line) => " " + line).join("\n") + "\n");
499
+ writeHuman("\n" + qrRows(qr).map((line) => " " + line).join("\n") + "\n");
498
500
  resolve();
499
501
  });
500
502
  } catch (err) {
@@ -737,7 +739,17 @@ var PAIR_TIMEOUT_MS = PAIR_TTL_SECONDS * 1e3 - PAIR_STOP_BEFORE_EXPIRY_MS;
737
739
  var PAIR_HINT_AFTER_MS = 45e3;
738
740
  var PAIR_BROWSER_FALLBACK_AFTER_MS = 6e4;
739
741
  var BROWSER_CONNECT_COMMAND = `${NPX_LATEST_COMMAND} setup --connect browser`;
740
- var PAIR_BROWSER_FALLBACK_LINE = `Still waiting? Sign in with a browser instead: Ctrl-C, then ${BROWSER_CONNECT_COMMAND}`;
742
+ var PAIR_BROWSER_FALLBACK_LINE = `Still waiting? Ctrl-C, then: ${BROWSER_CONNECT_COMMAND}`;
743
+ var PAIR_INSTALL_HINT = "No app yet? Install it, sign in, then scan the code above. Ctrl-C to stop.";
744
+ var PAIR_GET_APP_LINE = "No app yet? Get it at pushary.com/download. Setup keeps waiting.";
745
+ var describePairingScreen = (screen) => [
746
+ bold("Connect your phone"),
747
+ "Scan this with your phone's camera or the Pushary app.",
748
+ `${dim("Or open on your phone:")} ${cyan(screen.universalLink)}`,
749
+ `Your phone will show ${cyan(screen.fingerprint)}. Check it matches.`,
750
+ `${dim("Already have the app and it opened a browser? Use")} ${cyan(screen.deepLink)}`,
751
+ dim(PAIR_GET_APP_LINE)
752
+ ];
741
753
  var SYSTEM_PAIR_CLOCK = { now: () => Date.now(), sleep };
742
754
  var startPairing = async (cliPublicKey, computer) => {
743
755
  try {
@@ -841,15 +853,10 @@ var connectViaAppPairing = async (options = {}) => {
841
853
  }
842
854
  const { pairId, code } = started;
843
855
  const { qrLink, universalLink, deepLink } = buildPairLinks(pairId, keypair.publicKeyB64, apiBase(), code);
844
- console.log();
845
- console.log(` ${bold("Connect your Pushary app")}`);
846
- console.log(` ${dim("Scan this with your phone camera:")}`);
856
+ for (const line of describePairingScreen({ universalLink, fingerprint: publicKeyFingerprint(keypair.publicKeyB64), deepLink })) {
857
+ console.log(` ${line}`);
858
+ }
847
859
  await printQr(qrLink);
848
- console.log(` ${dim("No camera handy? Open this on the phone instead:")}`);
849
- console.log(` ${cyan(universalLink)}`);
850
- console.log(` ${dim("Confirm the app shows fingerprint")} ${cyan(publicKeyFingerprint(keypair.publicKeyB64))}`);
851
- console.log(` ${dim("Already have the app and it opened a browser? Use")} ${cyan(deepLink)}`);
852
- console.log();
853
860
  const startedAt = clock.now();
854
861
  const deadline = requestedAt + PAIR_TIMEOUT_MS;
855
862
  let hintShown = false;
@@ -861,20 +868,22 @@ var connectViaAppPairing = async (options = {}) => {
861
868
  }
862
869
  if (!hintShown) {
863
870
  hintShown = true;
864
- writeStatusLine(
865
- `${dim("No app yet? Install it, sign in with this account, then scan. Ctrl-C to stop.")}`
866
- );
871
+ writeStatusLine(dim(PAIR_INSTALL_HINT));
867
872
  }
868
873
  return `Waiting for the app ${dim(`(${left}m left)`)}`;
869
874
  });
870
875
  let cancelled = false;
871
- const onInterrupt = () => {
876
+ const cancelOnSignal = (exitCode) => () => {
877
+ if (cancelled) return;
872
878
  cancelled = true;
873
879
  stop(yellow("!"), "Cancelled");
874
- const flushed = options.onCancelled?.();
875
- void Promise.allSettled([Promise.resolve(flushed), cancelPairing(pairId)]).finally(() => process.exit(EXIT_ABORTED));
880
+ const flushed = options.onCancelled?.(exitCode);
881
+ void Promise.allSettled([Promise.resolve(flushed), cancelPairing(pairId)]).finally(() => process.exit(exitCode));
876
882
  };
883
+ const onInterrupt = cancelOnSignal(EXIT_ABORTED);
884
+ const onTerminate = cancelOnSignal(EXIT_TERMINATED);
877
885
  process.once("SIGINT", onInterrupt);
886
+ process.once("SIGTERM", onTerminate);
878
887
  let consecutiveFailures = 0;
879
888
  try {
880
889
  while (clock.now() < deadline) {
@@ -900,7 +909,7 @@ var connectViaAppPairing = async (options = {}) => {
900
909
  try {
901
910
  apiKey = openSealedKey(claim.sealed, keypair);
902
911
  } catch {
903
- stop(yellow("!"), "Pairing failed to decrypt \u2014 re-run setup to try again");
912
+ stop(yellow("!"), "Pairing failed to decrypt. Re-run setup to try again.");
904
913
  await cancelPairing(pairId);
905
914
  return pairFailed("decrypt");
906
915
  }
@@ -909,7 +918,7 @@ var connectViaAppPairing = async (options = {}) => {
909
918
  return { kind: "paired", apiKey, handle: claim.siteSlug };
910
919
  }
911
920
  if (claim?.status === "expired") {
912
- stop(yellow("!"), "Pairing expired \u2014 re-run setup to try again");
921
+ stop(yellow("!"), "Pairing expired. Re-run setup to try again.");
913
922
  return pairFailed("expired");
914
923
  }
915
924
  if (claim?.status === "failed") {
@@ -927,6 +936,7 @@ var connectViaAppPairing = async (options = {}) => {
927
936
  return pairFailed("unreachable");
928
937
  } finally {
929
938
  process.off("SIGINT", onInterrupt);
939
+ process.off("SIGTERM", onTerminate);
930
940
  }
931
941
  };
932
942
 
@@ -934,6 +944,7 @@ export {
934
944
  reachVerdict,
935
945
  describeReach,
936
946
  verifyRoundTrip,
947
+ describeRoundTripOutcome,
937
948
  describeRoundTrip,
938
949
  roundTripEvidence,
939
950
  fetchChannels,
@@ -3,10 +3,10 @@ import {
3
3
  } from "./chunk-KZERVKTD.js";
4
4
  import {
5
5
  renderCommandHelp
6
- } from "./chunk-FKQMH2DW.js";
6
+ } from "./chunk-OIAZ2QAC.js";
7
7
  import {
8
8
  getPackageVersion
9
- } from "./chunk-NAROM5IR.js";
9
+ } from "./chunk-AYV2NRYJ.js";
10
10
 
11
11
  // src/cli/usage.ts
12
12
  var exitOnHelpFlag = (command) => {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  PRETOOLUSE_GATED_TOOLS
3
- } from "./chunk-NAROM5IR.js";
3
+ } from "./chunk-AYV2NRYJ.js";
4
4
 
5
5
  // src/claude-tools.ts
6
6
  var POSTTOOLUSE_MIRROR_ONLY_TOOLS = ["TodoWrite", "Task", "WebFetch", "WebSearch"];
@@ -13,7 +13,7 @@ import {
13
13
  isReleaseVersion,
14
14
  ownPackageName,
15
15
  withHookHoldBudget
16
- } from "./chunk-NAROM5IR.js";
16
+ } from "./chunk-AYV2NRYJ.js";
17
17
 
18
18
  // src/setup/paths.ts
19
19
  import { homedir as homedir2 } from "os";
@@ -168,6 +168,23 @@ var NpmMissingError = class extends Error {
168
168
  this.name = "NpmMissingError";
169
169
  }
170
170
  };
171
+ var NpmPermissionError = class extends Error {
172
+ constructor(detail) {
173
+ super(detail);
174
+ this.name = "NpmPermissionError";
175
+ }
176
+ };
177
+ var NPM_PERMISSION_CODE = /\bE(?:ACCES|PERM)\b/;
178
+ var ERROR_TEXT_FIELDS = ["code", "stderr", "stdout", "message"];
179
+ var errorTextOf = (err) => {
180
+ if (typeof err !== "object" || err === null) return [String(err)];
181
+ return ERROR_TEXT_FIELDS.flatMap((field) => {
182
+ const value = Reflect.get(err, field);
183
+ return typeof value === "string" || Buffer.isBuffer(value) ? [value.toString()] : [];
184
+ });
185
+ };
186
+ var isNpmPermissionFailure = (err) => errorTextOf(err).some((text) => NPM_PERMISSION_CODE.test(text));
187
+ var npmInstallFailure = (err) => isNpmPermissionFailure(err) ? new NpmPermissionError(npmErrorMessage(err)) : new Error(npmErrorMessage(err));
171
188
  var resolveBinary = (name) => resolveGlobalBinary(name) ?? resolvePathBinary(name);
172
189
  var resolvePackageVersionFromBinary = (binary, packageName) => {
173
190
  try {
@@ -365,9 +382,9 @@ var installGlobally = (options) => {
365
382
  }
366
383
  const started = (async () => {
367
384
  if (!npmIsOnPath()) throw new NpmMissingError();
368
- const { withUpgradeLock } = await import("./global-upgrade-P5CJ22AW.js");
369
- const { installWithUpgradeLock, ownsUpgradeLock } = await import("./upgrade-lock-DQF62B6X.js");
370
- const { autoUpdateLock: autoUpdateLock2 } = await import("./paths-XZE2MPTP.js");
385
+ const { withUpgradeLock } = await import("./global-upgrade-4XWM5RXK.js");
386
+ const { installWithUpgradeLock, ownsUpgradeLock } = await import("./upgrade-lock-HVWZN4BZ.js");
387
+ const { autoUpdateLock: autoUpdateLock2 } = await import("./paths-2RE6MBKF.js");
371
388
  let result = "skipped";
372
389
  const install = async () => {
373
390
  const platform = process.platform;
@@ -848,6 +865,8 @@ export {
848
865
  npmIsOnPath,
849
866
  globalPackageState,
850
867
  NpmMissingError,
868
+ NpmPermissionError,
869
+ npmInstallFailure,
851
870
  resolveBinary,
852
871
  resolvePackageVersionFromBinary,
853
872
  resolveGlobalPackageVersion,
@@ -3,27 +3,27 @@ import {
3
3
  expectedLaunchCapabilities,
4
4
  hasSpawnProvider,
5
5
  resolveControlPolicy
6
- } from "./chunk-ECU2Y7D2.js";
6
+ } from "./chunk-W2AUU35K.js";
7
7
  import {
8
8
  daemonHasRemoteProof,
9
9
  daemonServiceManagerAvailable,
10
10
  hasDaemonServiceDefinition,
11
11
  readDaemonNeedsLogin,
12
12
  readDaemonStatus
13
- } from "./chunk-7SIZISYH.js";
13
+ } from "./chunk-PZ33VQ54.js";
14
14
  import {
15
15
  readControlMode,
16
16
  readKeySource
17
- } from "./chunk-NMDGIMDV.js";
17
+ } from "./chunk-DUDI3Z7F.js";
18
18
  import {
19
19
  getMachineId
20
- } from "./chunk-ZVFKNSRX.js";
20
+ } from "./chunk-XIJMMY6M.js";
21
21
  import {
22
22
  getBaseUrl
23
- } from "./chunk-AJRT3JGE.js";
23
+ } from "./chunk-PJNZJPPX.js";
24
24
  import {
25
25
  getPackageVersion
26
- } from "./chunk-NAROM5IR.js";
26
+ } from "./chunk-AYV2NRYJ.js";
27
27
 
28
28
  // src/machines.ts
29
29
  import { hostname } from "os";
@@ -6,12 +6,12 @@ import {
6
6
  permissionDeniedAction,
7
7
  releaseThrottle,
8
8
  reportEvent
9
- } from "./chunk-WYPQKDKX.js";
9
+ } from "./chunk-IHPSFUL2.js";
10
10
  import {
11
11
  machineDecisionFor,
12
12
  shouldDeferToNativeMode,
13
13
  wireVerdictFor
14
- } from "./chunk-NAROM5IR.js";
14
+ } from "./chunk-AYV2NRYJ.js";
15
15
 
16
16
  // src/machine-decision-audit.ts
17
17
  import { basename } from "path";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ensureCodexTrustsPusharyHooks
3
- } from "./chunk-YSVCBUT3.js";
3
+ } from "./chunk-ISJ5ROXM.js";
4
4
  import {
5
5
  detectClaudeVersion
6
6
  } from "./chunk-RIVNNBEK.js";
@@ -12,12 +12,12 @@ import {
12
12
  openCodeHookArgv,
13
13
  openCodePluginDir,
14
14
  openCodeWired
15
- } from "./chunk-5RONPCMH.js";
15
+ } from "./chunk-HBDZYQZX.js";
16
16
  import {
17
17
  addClaudeMcpServer,
18
18
  addPusharyHooks,
19
19
  addPusharyToolPermissions
20
- } from "./chunk-POJUUEGO.js";
20
+ } from "./chunk-PVOOKOKX.js";
21
21
  import {
22
22
  claudeUnprovenHolds,
23
23
  claudeWired,
@@ -25,7 +25,7 @@ import {
25
25
  codexWired,
26
26
  geminiWired,
27
27
  planHooks
28
- } from "./chunk-SEQSZYLW.js";
28
+ } from "./chunk-ZOMVMLMU.js";
29
29
  import {
30
30
  CLAUDE_HOOK_BINARY,
31
31
  CLAUDE_HOOK_EVENTS,
@@ -36,7 +36,7 @@ import {
36
36
  needsReregistration,
37
37
  registrationSignatures,
38
38
  supportedClaudeEvents
39
- } from "./chunk-RV4U3LYL.js";
39
+ } from "./chunk-EDEIIKCV.js";
40
40
  import {
41
41
  formatVersion
42
42
  } from "./chunk-6ICPEJY5.js";
@@ -59,7 +59,7 @@ import {
59
59
  registrationHolderOf,
60
60
  resolveGlobalBinary,
61
61
  vscodePluginMcp
62
- } from "./chunk-2WWHZTI5.js";
62
+ } from "./chunk-5ETPCIG4.js";
63
63
  import {
64
64
  readJsonSafe,
65
65
  writeFileAtomic,
@@ -5,18 +5,18 @@ import {
5
5
  import {
6
6
  SubscriptionRequiredError,
7
7
  callMcpTool
8
- } from "./chunk-CIZQARGJ.js";
8
+ } from "./chunk-S2LU6HIZ.js";
9
9
  import {
10
10
  installNetworkDefaults,
11
11
  isNetworkFailure
12
- } from "./chunk-EB6LH3U6.js";
12
+ } from "./chunk-3DZG5EXY.js";
13
13
  import {
14
14
  clientReportClaims
15
- } from "./chunk-2WWHZTI5.js";
15
+ } from "./chunk-5ETPCIG4.js";
16
16
  import {
17
17
  getApiKey,
18
18
  getBaseUrl
19
- } from "./chunk-AJRT3JGE.js";
19
+ } from "./chunk-PJNZJPPX.js";
20
20
  import {
21
21
  ASK_AGENT_NAME_MAX,
22
22
  ASK_QUESTION_MAX,
@@ -24,7 +24,7 @@ import {
24
24
  DECISION_LINE_MAX,
25
25
  degradedLine,
26
26
  truncateLine
27
- } from "./chunk-NAROM5IR.js";
27
+ } from "./chunk-AYV2NRYJ.js";
28
28
 
29
29
  // src/client-report-claim.ts
30
30
  import { createHash } from "crypto";
@@ -1716,6 +1716,8 @@ var DESTRUCTIVE_SUBCOMMANDS = /* @__PURE__ */ new Set([
1716
1716
  "wipe",
1717
1717
  "reset"
1718
1718
  ]);
1719
+ var SUBCOMMAND_WORD_SEPARATOR = /[-:]/;
1720
+ var subcommandWordDestroys = (word) => word.split(SUBCOMMAND_WORD_SEPARATOR).some((part) => DESTRUCTIVE_SUBCOMMANDS.has(part));
1719
1721
  var DATA_LOSS_COMMAND_PATTERNS = [
1720
1722
  "Bash(git branch -D:*)",
1721
1723
  "Bash(git branch --delete:*)",
@@ -1810,7 +1812,7 @@ var normalizedCommand = (command) => {
1810
1812
  const segments = readableCommandSegments(command);
1811
1813
  return segments === null ? null : segments.map((segment) => normalizedInvocation(invocationOf(segment))).join("; ");
1812
1814
  };
1813
- var subcommandDestroys = ({ program, args }) => program !== void 0 && SUBCOMMAND_CLIS.has(basenameOf(program.text)) && subcommandWordsOf(argsAfterHarmlessGlobalFlags(args)).some((word) => DESTRUCTIVE_SUBCOMMANDS.has(word.text));
1815
+ var subcommandDestroys = ({ program, args }) => program !== void 0 && SUBCOMMAND_CLIS.has(basenameOf(program.text)) && subcommandWordsOf(argsAfterHarmlessGlobalFlags(args)).some((word) => subcommandWordDestroys(word.text));
1814
1816
  var segmentNeedsAPerson = (toolName, segment) => {
1815
1817
  const invocation = invocationOf(segment);
1816
1818
  const normalized = normalizedInvocation(invocation);
@@ -1826,7 +1828,79 @@ var withoutSessionToolGrants = (config) => ({
1826
1828
  policies: config.policies.filter((policy) => !isSessionToolGrant(policy))
1827
1829
  });
1828
1830
  var SESSION_TOOL_GRANT_TOOLS = /* @__PURE__ */ new Set(["Bash"]);
1829
- var isSessionToolGrant = (policy) => Boolean(policy.sessionId) && SESSION_TOOL_GRANT_TOOLS.has(policy.tool) && isAutoApprove(policy);
1831
+ var MCP_TOOL_PREFIX = "mcp__";
1832
+ var parseMcpToolName = (toolName) => {
1833
+ if (!toolName.startsWith(MCP_TOOL_PREFIX)) return void 0;
1834
+ const rest = toolName.slice(MCP_TOOL_PREFIX.length);
1835
+ const split = rest.indexOf("__");
1836
+ if (split <= 0 || split + 2 >= rest.length) return void 0;
1837
+ return { server: rest.slice(0, split), tool: rest.slice(split + 2) };
1838
+ };
1839
+ var CAMEL_CASE_BOUNDARY = /([a-z0-9])([A-Z])/g;
1840
+ var MCP_TOOL_NAME_WORD_SEPARATOR = /[\s_.:-]+/;
1841
+ var wordsOfMcpToolName = (toolName) => toolName.replace(CAMEL_CASE_BOUNDARY, "$1 $2").toLowerCase().split(MCP_TOOL_NAME_WORD_SEPARATOR).filter((word) => word.length > 0);
1842
+ var MCP_TOOL_WORDS_THAT_MOVE_MONEY = /* @__PURE__ */ new Set([
1843
+ "pay",
1844
+ "payment",
1845
+ "payout",
1846
+ "refund",
1847
+ "charge",
1848
+ "transfer",
1849
+ "withdraw",
1850
+ "money",
1851
+ "purchase",
1852
+ "buy",
1853
+ "wire",
1854
+ "transaction",
1855
+ "invoice",
1856
+ "subscription"
1857
+ ]);
1858
+ var MCP_TOOL_WORDS_THAT_RUN_CODE = /* @__PURE__ */ new Set([
1859
+ "exec",
1860
+ "execute",
1861
+ "eval",
1862
+ "run",
1863
+ "shell",
1864
+ "command",
1865
+ "cmd",
1866
+ "script",
1867
+ "sql",
1868
+ "repl",
1869
+ "js",
1870
+ "python",
1871
+ "terminal"
1872
+ ]);
1873
+ var MCP_TOOL_WORDS_THAT_REACH_OTHERS = /* @__PURE__ */ new Set([
1874
+ "send",
1875
+ "email",
1876
+ "post",
1877
+ "publish",
1878
+ "merge",
1879
+ "deploy",
1880
+ "promote",
1881
+ "release",
1882
+ "push",
1883
+ "force",
1884
+ "cancel",
1885
+ "revoke",
1886
+ "kill",
1887
+ "truncate",
1888
+ "write",
1889
+ "overwrite",
1890
+ "move",
1891
+ "rename",
1892
+ "upload",
1893
+ "invite",
1894
+ "share"
1895
+ ]);
1896
+ var mcpToolWordNeedsAPerson = (word) => DESTRUCTIVE_SUBCOMMANDS.has(word) || MCP_TOOL_WORDS_THAT_MOVE_MONEY.has(word) || MCP_TOOL_WORDS_THAT_RUN_CODE.has(word) || MCP_TOOL_WORDS_THAT_REACH_OTHERS.has(word);
1897
+ var mcpToolNameNeedsAPerson = (toolName) => {
1898
+ const words = wordsOfMcpToolName(toolName);
1899
+ const phrase = words.join(" ");
1900
+ return words.some(mcpToolWordNeedsAPerson) || classifyDecisionRisk(phrase, phrase) !== "standard";
1901
+ };
1902
+ var allowsSessionToolGrant = (toolName) => SESSION_TOOL_GRANT_TOOLS.has(toolName) || parseMcpToolName(toolName) !== void 0 && !isPusharyOwnTool(toolName.toLowerCase()) && !mcpToolNameNeedsAPerson(toolName);
1903
+ var isSessionToolGrant = (policy) => Boolean(policy.sessionId) && allowsSessionToolGrant(policy.tool) && isAutoApprove(policy);
1830
1904
  var API_KEY_PATTERN = /^pk_[a-f0-9]+\.[a-f0-9]+$/;
1831
1905
  var isValidApiKey = (value) => API_KEY_PATTERN.test(value);
1832
1906
  var ACTION_BODY_MAX = 4e3;
@@ -2509,6 +2583,17 @@ var agentPromptsBeforeAnEdit = ({ source, event, permissionMode }) => {
2509
2583
  return event === "PreToolUse" && runsTheClaudeHook(source) && claudePromptsBeforeAnEdit(permissionMode);
2510
2584
  };
2511
2585
  var editGoesToTheAgentsPrompt = (call, input, verdict) => agentPromptsBeforeAnEdit(call) && editAsksAtTheAgentsPrompt(input, verdict);
2586
+ var SCOPE_BATCH_REASON = "This patch exceeds the agreed scope. Split it into single-file edits so each additional path can be approved.";
2587
+ var unapprovedScopeReason = (scopeReason) => `${scopeReason}. Nobody approved this path, so the change was refused.`;
2588
+ var codexRaisesItsOwnPrompts = (permissionMode) => permissionMode !== "bypassPermissions";
2589
+ var isScopeReason = (scopeReason) => typeof scopeReason === "string" && scopeReason.length > 0;
2590
+ var scopeBreachReasonOf = (verdict) => verdict.kind === "gate" && isScopeReason(verdict.scopeReason) ? verdict.scopeReason : void 0;
2591
+ var onlyCodexPreToolUseCanAsk = (verdict, permissionMode) => verdict.kind === "gate" && (scopeBreachReasonOf(verdict) !== void 0 || !codexRaisesItsOwnPrompts(permissionMode));
2592
+ var runsACommandThatNeedsAPerson = ({ toolName, toolInputs }) => toolName === "Bash" && toolInputs.some((toolInput) => {
2593
+ const command = extractPolicyArg(toolName, toolInput);
2594
+ return command !== void 0 && commandNeedsAPerson(toolName, command);
2595
+ });
2596
+ var codexCallNeedsAPerson = (input, verdict, call) => onlyCodexPreToolUseCanAsk(verdict, call.permissionMode) || verdict.kind === "gate" && (aChosenRuleGoverns(input) || call.deletesFiles || runsACommandThatNeedsAPerson(input));
2512
2597
  var MAX_AGENT_PERMISSION_RULES_PER_KIND = 256;
2513
2598
  var MAX_AGENT_PERMISSION_RULE_LENGTH = 512;
2514
2599
  var isAgentPermissionRule = (value) => typeof value === "string" && value.length > 0 && value.length <= MAX_AGENT_PERMISSION_RULE_LENGTH;
@@ -3105,6 +3190,7 @@ export {
3105
3190
  isSafeReadOnlyCommand,
3106
3191
  isAutoApprove,
3107
3192
  FILE_TARGET_TOOLS,
3193
+ parseMcpToolName,
3108
3194
  isValidApiKey,
3109
3195
  ACTION_BODY_MAX,
3110
3196
  DECISION_LINE_MAX,
@@ -3131,6 +3217,11 @@ export {
3131
3217
  CLAUDE_PRETOOLUSE_MATCHER,
3132
3218
  resolveGate,
3133
3219
  editGoesToTheAgentsPrompt,
3220
+ SCOPE_BATCH_REASON,
3221
+ unapprovedScopeReason,
3222
+ scopeBreachReasonOf,
3223
+ onlyCodexPreToolUseCanAsk,
3224
+ codexCallNeedsAPerson,
3134
3225
  claudePermissionRulesFromSettings,
3135
3226
  claudeConsultsItsAllowlist,
3136
3227
  agentRulesAllowEveryInput,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pusharyFetch
3
- } from "./chunk-EB6LH3U6.js";
3
+ } from "./chunk-3DZG5EXY.js";
4
4
  import {
5
5
  NetworkError
6
6
  } from "./chunk-7QLSKOSU.js";
@@ -9,11 +9,11 @@ import {
9
9
  } from "./chunk-KZERVKTD.js";
10
10
  import {
11
11
  getBaseUrl
12
- } from "./chunk-AJRT3JGE.js";
12
+ } from "./chunk-PJNZJPPX.js";
13
13
  import {
14
14
  isValidApiKey,
15
15
  normalizeKeyScope
16
- } from "./chunk-NAROM5IR.js";
16
+ } from "./chunk-AYV2NRYJ.js";
17
17
 
18
18
  // src/session.ts
19
19
  var samePusharyAccount = (left, right) => left.kind === "ok" && right.kind === "ok" && left.identity.workspaceId !== "" && left.identity.workspaceId === right.identity.workspaceId && left.identity.siteId === right.identity.siteId;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  readConfigFileKey
3
- } from "./chunk-NMDGIMDV.js";
3
+ } from "./chunk-DUDI3Z7F.js";
4
4
 
5
5
  // src/bell/fleet.ts
6
6
  import { closeSync, constants, futimesSync, lstatSync, mkdirSync, openSync, readdirSync, unlinkSync } from "fs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pusharyDir
3
- } from "./chunk-2WWHZTI5.js";
3
+ } from "./chunk-5ETPCIG4.js";
4
4
  import {
5
5
  readJsonSafe,
6
6
  writeFileAtomic
@@ -13,7 +13,7 @@ import {
13
13
  serializeDeclinedAgents,
14
14
  withDeclinedAgent,
15
15
  withoutDeclinedAgent
16
- } from "./chunk-NAROM5IR.js";
16
+ } from "./chunk-AYV2NRYJ.js";
17
17
 
18
18
  // src/declined-agents-file.ts
19
19
  import { join } from "path";
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-3EGEA4KH.js";
10
10
  import {
11
11
  getBaseUrl
12
- } from "./chunk-AJRT3JGE.js";
12
+ } from "./chunk-PJNZJPPX.js";
13
13
 
14
14
  // src/cli/login-ui.ts
15
15
  import { hostname } from "os";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveInstallSourceFor
3
- } from "./chunk-ZSL7B7NF.js";
3
+ } from "./chunk-VKYDON4A.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-AJRT3JGE.js";
12
+ } from "./chunk-PJNZJPPX.js";
13
13
 
14
14
  // src/shell-alias.ts
15
15
  import { homedir } from "os";
@@ -5,16 +5,16 @@ import {
5
5
  import {
6
6
  NOTIFICATION_MATCHED_TYPES,
7
7
  POSTTOOLUSE_MIRRORED_TOOLS
8
- } from "./chunk-VYXXAFIA.js";
8
+ } from "./chunk-52JA2WTH.js";
9
9
  import {
10
10
  isProtectedByScope,
11
11
  registerHookEntry
12
- } from "./chunk-2WWHZTI5.js";
12
+ } from "./chunk-5ETPCIG4.js";
13
13
  import {
14
14
  CLAUDE_PRETOOLUSE_MATCHER,
15
15
  HOOK_BUDGETS,
16
16
  HOOK_LOCATOR_BINARY
17
- } from "./chunk-NAROM5IR.js";
17
+ } from "./chunk-AYV2NRYJ.js";
18
18
 
19
19
  // src/gemini-config.ts
20
20
  var GEMINI_HOOK_BINARY = "pushary-gemini-hook";
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  macAppBridgeAvailable
3
- } from "./chunk-5RONPCMH.js";
3
+ } from "./chunk-HBDZYQZX.js";
4
4
  import {
5
5
  keyPrefix
6
- } from "./chunk-NMDGIMDV.js";
6
+ } from "./chunk-DUDI3Z7F.js";
7
7
  import {
8
8
  bridgeAgentKey
9
- } from "./chunk-2WWHZTI5.js";
9
+ } from "./chunk-5ETPCIG4.js";
10
10
  import {
11
11
  readJsonSafe
12
12
  } from "./chunk-T7E75EKA.js";
13
13
  import {
14
14
  isValidApiKey
15
- } from "./chunk-NAROM5IR.js";
15
+ } from "./chunk-AYV2NRYJ.js";
16
16
 
17
17
  // src/shared-mcp-key.ts
18
18
  var asRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
@@ -72,11 +72,11 @@ var createIo = (stream = process.stdout, context = {}) => {
72
72
  process.stderr.write(`${yellow("!")} ${s}
73
73
  `);
74
74
  };
75
+ const finishedLine = (label, end) => end ? ` ${end.ok ? check() : yellow("!")} ${end.label}` : ` ${check()} ${label}`;
75
76
  const spinner = async (label, fn, options = {}) => {
76
77
  if (stream.isTTY !== true) {
77
78
  try {
78
- await fn();
79
- line(` ${check()} ${label}`);
79
+ line(finishedLine(label, await fn()));
80
80
  } catch (err) {
81
81
  line(` ${yellow("!")} ${label} ${dim(`(${describeError(err)})`)}`);
82
82
  if (!options.optional) throw err;
@@ -88,9 +88,9 @@ var createIo = (stream = process.stdout, context = {}) => {
88
88
  stream.write(`\r ${dim(SPINNER_FRAMES[frame++ % SPINNER_FRAMES.length])} ${clipToRow(label, terminalColumns(stream) - SPINNER_FRAME_WIDTH)}\x1B[K`);
89
89
  }, SPINNER_INTERVAL_MS);
90
90
  try {
91
- await fn();
91
+ const end = await fn();
92
92
  clearInterval(timer);
93
- stream.write(`\r ${check()} ${label}\x1B[K
93
+ stream.write(`\r${finishedLine(label, end)}\x1B[K
94
94
  `);
95
95
  } catch (err) {
96
96
  clearInterval(timer);