@pushary/agent-hooks 1.5.0 → 1.6.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 (83) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +2 -1
  3. package/dist/bin/pushary-bell-hook.js +18 -18
  4. package/dist/bin/pushary-bell.js +6 -6
  5. package/dist/bin/pushary-claude.js +18 -18
  6. package/dist/bin/pushary-clean.js +19 -19
  7. package/dist/bin/pushary-codex-bridge.js +10 -10
  8. package/dist/bin/pushary-codex-hook.js +23 -23
  9. package/dist/bin/pushary-codex.js +6 -6
  10. package/dist/bin/pushary-connect.js +6 -6
  11. package/dist/bin/pushary-cowork.js +3 -3
  12. package/dist/bin/pushary-daemon.js +23 -22
  13. package/dist/bin/pushary-disconnect.js +10 -10
  14. package/dist/bin/pushary-doctor.js +52 -24
  15. package/dist/bin/pushary-elicitation-hook.js +17 -17
  16. package/dist/bin/pushary-gemini-bridge.js +9 -9
  17. package/dist/bin/pushary-gemini-hook.js +20 -20
  18. package/dist/bin/pushary-hook.js +23 -23
  19. package/dist/bin/pushary-login.js +7 -7
  20. package/dist/bin/pushary-logout.js +4 -4
  21. package/dist/bin/pushary-mode.js +3 -3
  22. package/dist/bin/pushary-notification-hook.js +20 -20
  23. package/dist/bin/pushary-opencode-hook.js +19 -19
  24. package/dist/bin/pushary-permission-denied-hook.js +24 -24
  25. package/dist/bin/pushary-permission-hook.js +23 -23
  26. package/dist/bin/pushary-post-hook.js +20 -20
  27. package/dist/bin/pushary-prompt-hook.js +20 -20
  28. package/dist/bin/pushary-session-end-hook.js +20 -20
  29. package/dist/bin/pushary-session-start-hook.js +24 -23
  30. package/dist/bin/pushary-setup.js +63 -62
  31. package/dist/bin/pushary-stats.js +2 -2
  32. package/dist/bin/pushary-status.js +10 -10
  33. package/dist/bin/pushary-stop-hook.js +20 -20
  34. package/dist/bin/pushary-stopfailure-hook.js +20 -20
  35. package/dist/bin/pushary-transcript-register.js +16 -16
  36. package/dist/bin/pushary-transcripts.js +4 -4
  37. package/dist/bin/pushary-upgrade.js +80 -32
  38. package/dist/bin/pushary-wait.js +3 -3
  39. package/dist/{chunk-KEOLNHR3.js → chunk-5MH5P366.js} +2 -2
  40. package/dist/{chunk-HVBF35GT.js → chunk-5QCZYSYR.js} +1 -1
  41. package/dist/{chunk-IYTQ4B5I.js → chunk-644CGYOB.js} +66 -12
  42. package/dist/{chunk-FDHMNT24.js → chunk-66BIMA62.js} +6 -5
  43. package/dist/{chunk-UQHUUZ5H.js → chunk-7JSE6JTZ.js} +1 -1
  44. package/dist/{chunk-NFKVRMTM.js → chunk-A2GS2ENL.js} +6 -6
  45. package/dist/{chunk-TFKBFQCE.js → chunk-A5URWZTP.js} +1 -1
  46. package/dist/{chunk-MYP4UUFH.js → chunk-ALG3IBLB.js} +1 -1
  47. package/dist/{chunk-TUXFIVOH.js → chunk-B6TYEKJR.js} +1 -1
  48. package/dist/{chunk-CQYHOHOK.js → chunk-BE4P7ERZ.js} +3 -3
  49. package/dist/{chunk-EADZPVYW.js → chunk-BK5F3FGE.js} +3 -3
  50. package/dist/{chunk-F57RGL7K.js → chunk-BW3Y2D24.js} +4 -4
  51. package/dist/chunk-BY2CRWBO.js +38 -0
  52. package/dist/{chunk-43LJSM4F.js → chunk-CSW6A2EW.js} +1 -1
  53. package/dist/{chunk-7XT76LWT.js → chunk-DZ75BJ7V.js} +3 -3
  54. package/dist/{chunk-DTQNDR7C.js → chunk-E7MJBWSR.js} +1 -1
  55. package/dist/{chunk-DYHXOXUF.js → chunk-F2OPOBRO.js} +7 -21
  56. package/dist/{chunk-43ZDACBO.js → chunk-F4KRNFDE.js} +1 -1
  57. package/dist/{chunk-ORLJNJEO.js → chunk-FDF72XHK.js} +2 -2
  58. package/dist/{chunk-JF736N4C.js → chunk-FI3LQCUH.js} +5 -5
  59. package/dist/{chunk-DLJN5XEU.js → chunk-G5LENVCZ.js} +3 -3
  60. package/dist/{chunk-K3QVDAZW.js → chunk-GDXSCXQC.js} +1 -1
  61. package/dist/{chunk-5HYNICS7.js → chunk-GOXINLDU.js} +1 -1
  62. package/dist/{chunk-2QT3GCU4.js → chunk-GP6SFVEN.js} +1 -1
  63. package/dist/{chunk-J4J45VPZ.js → chunk-HWG7X3VI.js} +3 -3
  64. package/dist/{chunk-PCGZXWGQ.js → chunk-KZBGITM4.js} +4 -4
  65. package/dist/{chunk-NTQSICPJ.js → chunk-MOQOJOMD.js} +3 -3
  66. package/dist/{chunk-3NBODGQS.js → chunk-NDS27FXU.js} +1 -1
  67. package/dist/{chunk-H5LHTC5X.js → chunk-NYD7W7AT.js} +1 -1
  68. package/dist/{chunk-PNNBMH4E.js → chunk-OP7HFIWE.js} +28 -12
  69. package/dist/{chunk-SOCEY746.js → chunk-OR3A3RLH.js} +1 -1
  70. package/dist/{chunk-XWEONSLV.js → chunk-PCVVCS4A.js} +1 -1
  71. package/dist/{chunk-KJRALILH.js → chunk-PRZXYILJ.js} +2 -2
  72. package/dist/{chunk-OSSDK5RS.js → chunk-RBPJO4KG.js} +6 -2
  73. package/dist/{chunk-TIWURSLS.js → chunk-SFNRAEEW.js} +1 -1
  74. package/dist/{chunk-USQDVBEV.js → chunk-TDKE3V6W.js} +1 -1
  75. package/dist/{chunk-HU5LSYL2.js → chunk-VMNI33F5.js} +1 -1
  76. package/dist/{chunk-UYDTFCHW.js → chunk-VZANUMIF.js} +1 -1
  77. package/dist/{chunk-3ZSGKLSO.js → chunk-XGL5JC6U.js} +2 -2
  78. package/dist/chunk-XQOT4CCK.js +305 -0
  79. package/dist/{chunk-T4QY64OR.js → chunk-YFD7CRIZ.js} +376 -10
  80. package/dist/{reapply-D2TFN6XK.js → reapply-RRDVJATI.js} +12 -8
  81. package/dist/src/index.d.ts +1 -0
  82. package/dist/src/index.js +12 -12
  83. package/package.json +1 -1
@@ -1,27 +1,34 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ describeCodexTrustConfirmation
4
+ } from "../chunk-BY2CRWBO.js";
5
+ import {
6
+ ensureCodexTrustAfterReapply,
3
7
  reapplyAllAgents
4
- } from "../chunk-PNNBMH4E.js";
5
- import "../chunk-3NBODGQS.js";
8
+ } from "../chunk-OP7HFIWE.js";
9
+ import "../chunk-NDS27FXU.js";
10
+ import "../chunk-XQOT4CCK.js";
6
11
  import {
7
12
  waitForMachineReadiness
8
- } from "../chunk-F57RGL7K.js";
9
- import "../chunk-J4J45VPZ.js";
13
+ } from "../chunk-BW3Y2D24.js";
14
+ import "../chunk-HWG7X3VI.js";
10
15
  import {
11
16
  detectProviderLiveCapabilities,
12
17
  hasSpawnProvider,
13
18
  resolveControlPolicy
14
- } from "../chunk-KEOLNHR3.js";
19
+ } from "../chunk-5MH5P366.js";
15
20
  import {
16
21
  AUTO_UPDATE_DISABLE_ENV,
17
22
  describeAutoUpdateCheck,
18
23
  globalInstallPrefix,
24
+ hasPendingUpgradeFinish,
19
25
  isAutoUpdateDisabledByEnv,
20
26
  parseAutoUpdateFlag,
27
+ readAutoUpdateState,
21
28
  updateAutoUpdateState,
22
29
  upgradeEntryFor
23
- } from "../chunk-OSSDK5RS.js";
24
- import "../chunk-NTQSICPJ.js";
30
+ } from "../chunk-RBPJO4KG.js";
31
+ import "../chunk-MOQOJOMD.js";
25
32
  import {
26
33
  daemonHasRemoteProof,
27
34
  daemonServiceManagerAvailable,
@@ -32,13 +39,13 @@ import {
32
39
  replaceDaemonService,
33
40
  stopDaemonService,
34
41
  waitForDaemonRemoteProof
35
- } from "../chunk-7XT76LWT.js";
36
- import "../chunk-EADZPVYW.js";
42
+ } from "../chunk-DZ75BJ7V.js";
43
+ import "../chunk-BK5F3FGE.js";
37
44
  import {
38
45
  needsShell
39
46
  } from "../chunk-XHKBHWLX.js";
40
- import "../chunk-UYDTFCHW.js";
41
- import "../chunk-UQHUUZ5H.js";
47
+ import "../chunk-VZANUMIF.js";
48
+ import "../chunk-7JSE6JTZ.js";
42
49
  import {
43
50
  LATEST_TAG,
44
51
  autoUpdateLock,
@@ -54,22 +61,22 @@ import {
54
61
  npmErrorMessage,
55
62
  resolveGlobalBinary,
56
63
  vscodePluginDir
57
- } from "../chunk-DYHXOXUF.js";
64
+ } from "../chunk-F2OPOBRO.js";
58
65
  import {
59
66
  exitOnHelpFlag
60
67
  } from "../chunk-P4BNYJ5Q.js";
61
68
  import {
62
69
  readControlMode
63
- } from "../chunk-USQDVBEV.js";
70
+ } from "../chunk-TDKE3V6W.js";
64
71
  import {
65
72
  EXIT
66
73
  } from "../chunk-KZERVKTD.js";
67
- import "../chunk-HU5LSYL2.js";
74
+ import "../chunk-VMNI33F5.js";
68
75
  import "../chunk-T7E75EKA.js";
69
76
  import {
70
77
  getApiKey
71
78
  } from "../chunk-OSJEMXSR.js";
72
- import "../chunk-T4QY64OR.js";
79
+ import "../chunk-YFD7CRIZ.js";
73
80
  import {
74
81
  NPX_LATEST_COMMAND
75
82
  } from "../chunk-EA3IELHP.js";
@@ -172,12 +179,26 @@ var finishInNewInstall = (request) => {
172
179
  };
173
180
  var incompleteFinishDetail = (logPath) => `installed, but refreshing the agent configs did not finish cleanly; see ${logPath}`;
174
181
  var newMajorDetail = (latest) => `${latest} is a new major version; run ${MANUAL_UPGRADE_COMMAND}`;
182
+ var finishInstalledUpgrade = (context, from, to) => {
183
+ const pending = { result: "finish_pending", from, to, detail: incompleteFinishDetail(context.logPath) };
184
+ recordAutoUpdateCheck(context.statePath, pending, new Date(context.now()).toISOString());
185
+ try {
186
+ context.finish({ entry: upgradeEntryFor(context.prefix), prefix: context.prefix, logPath: context.logPath });
187
+ return { result: "updated", from, to };
188
+ } catch {
189
+ return pending;
190
+ }
191
+ };
192
+ var isInstallableRelease = (latest, installed) => latest !== void 0 && isNewerVersion(latest, installed) && isSameMajorVersion(latest, installed);
175
193
  var checkAndInstall = async (context) => {
176
194
  const installed = packageVersionAt(context.packageRoot);
177
195
  if (installed === void 0 || !isReleaseVersion(installed)) {
178
196
  return { result: "failed", from: installed, detail: UNREADABLE_INSTALLED_VERSION };
179
197
  }
198
+ const previous = readAutoUpdateState(context.statePath);
199
+ const pendingFinish = hasPendingUpgradeFinish(previous, installed);
180
200
  const latest = await fetchLatestPublishedVersion({ fetchImpl: context.fetchImpl });
201
+ if (pendingFinish && !isInstallableRelease(latest, installed)) return finishInstalledUpgrade(context, previous.from, installed);
181
202
  if (latest === void 0) return { result: "failed", from: installed, detail: UNREACHABLE_REGISTRY };
182
203
  if (!isNewerVersion(latest, installed)) return { result: "current", from: installed };
183
204
  if (!isSameMajorVersion(latest, installed)) {
@@ -187,14 +208,10 @@ var checkAndInstall = async (context) => {
187
208
  try {
188
209
  installAgentHooksGlobally({ version: latest, prefix: context.prefix, timeoutMs: INSTALL_TIMEOUT_MS }, context.runNpm);
189
210
  } catch (error) {
211
+ if (pendingFinish) return finishInstalledUpgrade(context, previous.from, installed);
190
212
  return { result: "failed", from: installed, to: latest, detail: npmErrorMessage(error) };
191
213
  }
192
- try {
193
- context.finish({ entry: upgradeEntryFor(context.prefix), prefix: context.prefix, logPath: context.logPath });
194
- } catch {
195
- return { result: "updated", from: installed, to: latest, detail: incompleteFinishDetail(context.logPath) };
196
- }
197
- return { result: "updated", from: installed, to: latest };
214
+ return finishInstalledUpgrade(context, installed, latest);
198
215
  };
199
216
  var recordAutoUpdateCheck = (statePath, check, at) => updateAutoUpdateState(statePath, {
200
217
  lastCheckAt: at,
@@ -206,6 +223,7 @@ var recordAutoUpdateCheck = (statePath, check, at) => updateAutoUpdateState(stat
206
223
  announced: check.result === "updated" ? false : void 0
207
224
  });
208
225
  var runAutoUpdate = async (run = {}) => {
226
+ if ((run.platform ?? process.platform) === "linux") return { kind: "linux" };
209
227
  const packageRoot = run.packageRoot ?? ownPackageRoot();
210
228
  const prefix = packageRoot === void 0 ? null : globalInstallPrefix(packageRoot);
211
229
  if (packageRoot === void 0 || prefix === null) return { kind: "not_global_install" };
@@ -216,6 +234,7 @@ var runAutoUpdate = async (run = {}) => {
216
234
  try {
217
235
  const check = await checkAndInstall({
218
236
  packageRoot,
237
+ statePath: run.statePath ?? autoUpdateState(),
219
238
  prefix,
220
239
  logPath,
221
240
  now,
@@ -284,7 +303,9 @@ var finishUpgrade = async () => {
284
303
  apiKey = void 0;
285
304
  }
286
305
  const inspectedAgents = reapplyAllAgents(apiKey);
306
+ const codexTrust = await ensureCodexTrustAfterReapply(inspectedAgents);
287
307
  const refreshed = inspectedAgents.filter((agent) => agent.result.reapplied);
308
+ const failedRefreshes = inspectedAgents.filter((agent) => agent.result.failed);
288
309
  const configuredControlProviders = inspectedAgents.filter((agent) => agent.result.configured && (agent.id === "claude" || agent.id === "codex" || agent.id === "gemini")).map((agent) => agent.id);
289
310
  const controlMode = readControlMode();
290
311
  const daemonStatus = readDaemonStatus();
@@ -329,21 +350,31 @@ var finishUpgrade = async () => {
329
350
  console.log();
330
351
  console.log("No key was readable here, so MCP entries kept the key they already had.");
331
352
  }
332
- } else {
353
+ } else if (failedRefreshes.length === 0) {
333
354
  console.log("No agent config on this machine needed refreshing.");
334
355
  }
356
+ if (codexTrust) {
357
+ console.log();
358
+ console.log(describeCodexTrustConfirmation(codexTrust));
359
+ }
335
360
  console.log();
336
361
  if (!daemonReady) {
337
362
  console.error(controlPolicy === "disabled" ? "Upgrade installed, but the disabled background service could not be fully removed. Re-run setup with --control off." : controlPolicy === "legacy" ? legacyStopFailure ? `Upgrade installed, but the legacy background service could not be stopped: ${legacyStopFailure}. Run setup with --control off.` : "Upgrade installed and the legacy background service was stopped, but it cannot be safely adopted. Run setup with --control off, or restore its provider and native service manager." : controlPolicy === "enabled" && !apiKey ? "Upgrade installed, but phone-start could not be reconciled because no API key was readable. Re-run setup." : "Upgrade installed, but the background service did not start. Run: pushary daemon install");
338
363
  process.exitCode = 1;
339
364
  return;
340
365
  }
366
+ if (failedRefreshes.length > 0) {
367
+ console.error(`Upgrade installed, but refreshing agent configuration failed for: ${failedRefreshes.map((agent) => agent.label).join(", ")}. Check the config files and run pushary upgrade again.`);
368
+ process.exitCode = 1;
369
+ return;
370
+ }
341
371
  console.log(controlPolicy === "disabled" ? "Done. Your hooks use the new global install; phone-start remains disabled." : controlPolicy === "unsupported" || controlPolicy === "preserve-absent" ? "Done. Your hooks use the new global install; no background service was added." : "Done. Your hooks and background service use the new global install.");
342
372
  console.log("Verify with: pushary doctor");
343
373
  };
344
374
  var AUTO_UPDATE_ON_MESSAGE = "Automatic updates are on. Pushary checks for a new version once a day, when an agent session starts.";
345
375
  var AUTO_UPDATE_OFF_MESSAGE = "Automatic updates are off. Turn them back on with: pushary upgrade --auto=on";
346
376
  var AUTO_UPDATE_RUN_MESSAGES = {
377
+ linux: `Automatic updates are paused on Linux to protect running sessions. When your sessions have finished, run: ${NPX_LATEST_COMMAND} upgrade`,
347
378
  not_global_install: `This copy of Pushary is not a global npm install, so it does not update itself. Run: ${NPX_LATEST_COMMAND} upgrade`,
348
379
  locked: "Another automatic update is already running."
349
380
  };
@@ -361,7 +392,26 @@ var runAutomaticUpdate = async () => {
361
392
  return;
362
393
  }
363
394
  console.log(`Automatic update: ${describeAutoUpdateCheck(outcome.state)}`);
364
- if (outcome.state.lastResult === "failed") process.exitCode = 1;
395
+ if (outcome.state.lastResult === "failed" || outcome.state.lastResult === "finish_pending") process.exitCode = 1;
396
+ };
397
+ var FINISH_FAILED_MESSAGE = "Upgrade installed, but refreshing the agent configs did not finish. Fix the problem printed above, then run pushary upgrade again.";
398
+ var finishGlobalUpgrade = () => {
399
+ const upgradedBinary = resolveGlobalBinary("pushary-upgrade");
400
+ if (!upgradedBinary) {
401
+ console.error("Upgrade installed, but the new pushary-upgrade binary could not be found on PATH.");
402
+ process.exit(1);
403
+ }
404
+ try {
405
+ execFileSync2(upgradedBinary, [FINISH_UPGRADE_FLAG], {
406
+ stdio: "inherit",
407
+ shell: needsShell(upgradedBinary)
408
+ });
409
+ return true;
410
+ } catch {
411
+ console.error(FINISH_FAILED_MESSAGE);
412
+ process.exitCode = 1;
413
+ return false;
414
+ }
365
415
  };
366
416
  var main = async () => {
367
417
  if (process.argv.includes(FINISH_UPGRADE_FLAG)) {
@@ -400,7 +450,13 @@ var main = async () => {
400
450
  console.log("Check the result with: pushary doctor");
401
451
  return;
402
452
  }
453
+ const pendingFinish = hasPendingUpgradeFinish(readAutoUpdateState(autoUpdateState()), installed);
403
454
  const latest = await fetchLatestPublishedVersion();
455
+ const newerPublished = latest !== void 0 && isNewerVersion(latest, installed);
456
+ if (pendingFinish && !newerPublished) {
457
+ if (!finishGlobalUpgrade()) return;
458
+ updateAutoUpdateState(autoUpdateState(), { lastResult: "updated", detail: void 0, announced: false });
459
+ }
404
460
  if (latest && !isNewerVersion(latest, installed)) {
405
461
  console.log(`Already on the latest version (${installed}).`);
406
462
  return;
@@ -412,14 +468,6 @@ var main = async () => {
412
468
  console.error(`Upgrade failed: ${npmErrorMessage(err)}`);
413
469
  process.exit(1);
414
470
  }
415
- const upgradedBinary = resolveGlobalBinary("pushary-upgrade");
416
- if (!upgradedBinary) {
417
- console.error("Upgrade installed, but the new pushary-upgrade binary could not be found on PATH.");
418
- process.exit(1);
419
- }
420
- execFileSync2(upgradedBinary, [FINISH_UPGRADE_FLAG], {
421
- stdio: "inherit",
422
- shell: needsShell(upgradedBinary)
423
- });
471
+ finishGlobalUpgrade();
424
472
  };
425
473
  main();
@@ -4,8 +4,8 @@ import {
4
4
  } from "../chunk-CVWG2N3Y.js";
5
5
  import {
6
6
  exitOnFailedResponse
7
- } from "../chunk-XWEONSLV.js";
8
- import "../chunk-43LJSM4F.js";
7
+ } from "../chunk-PCVVCS4A.js";
8
+ import "../chunk-CSW6A2EW.js";
9
9
  import {
10
10
  createIo
11
11
  } from "../chunk-5RUIFDTP.js";
@@ -26,7 +26,7 @@ import {
26
26
  getApiKey,
27
27
  getBaseUrl
28
28
  } from "../chunk-OSJEMXSR.js";
29
- import "../chunk-T4QY64OR.js";
29
+ import "../chunk-YFD7CRIZ.js";
30
30
  import "../chunk-EA3IELHP.js";
31
31
  import "../chunk-HWJW3CPO.js";
32
32
 
@@ -2,10 +2,10 @@ import {
2
2
  resolveBinary,
3
3
  resolveGlobalPackageVersion,
4
4
  resolvePackageVersionFromBinary
5
- } from "./chunk-DYHXOXUF.js";
5
+ } from "./chunk-F2OPOBRO.js";
6
6
  import {
7
7
  MANAGED_PROVIDERS
8
- } from "./chunk-T4QY64OR.js";
8
+ } from "./chunk-YFD7CRIZ.js";
9
9
 
10
10
  // src/live-capabilities.ts
11
11
  var CLAUDE_BRIDGE_CAPABILITY = "claude-bridge";
@@ -3,7 +3,7 @@ import {
3
3
  decodePublicKey,
4
4
  generateSessionKey,
5
5
  wrapSessionKey
6
- } from "./chunk-TIWURSLS.js";
6
+ } from "./chunk-SFNRAEEW.js";
7
7
  import {
8
8
  fetchTranscriptRecipients,
9
9
  uploadTranscriptRecords
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  activeHookSource,
3
3
  activeIdentity
4
- } from "./chunk-JF736N4C.js";
4
+ } from "./chunk-FI3LQCUH.js";
5
5
  import {
6
6
  blockedActionFingerprint,
7
7
  defersToNativeMode,
@@ -9,11 +9,11 @@ import {
9
9
  hasBlockedActionHint,
10
10
  recordBlockedActionHint,
11
11
  reportMachineDenial
12
- } from "./chunk-CQYHOHOK.js";
12
+ } from "./chunk-BE4P7ERZ.js";
13
13
  import {
14
14
  isGatingMoment,
15
15
  recordKeylessMoment
16
- } from "./chunk-43ZDACBO.js";
16
+ } from "./chunk-F4KRNFDE.js";
17
17
  import {
18
18
  denyReasonFrom,
19
19
  isDeferAnswer
@@ -36,7 +36,7 @@ import {
36
36
  reportEvent,
37
37
  scopePathFor,
38
38
  settleQuestionsForToolUse
39
- } from "./chunk-FDHMNT24.js";
39
+ } from "./chunk-66BIMA62.js";
40
40
  import {
41
41
  DECISION_STOP_REASON,
42
42
  askUser,
@@ -51,7 +51,7 @@ import {
51
51
  } from "./chunk-PYCQXCI5.js";
52
52
  import {
53
53
  getMachineId
54
- } from "./chunk-UQHUUZ5H.js";
54
+ } from "./chunk-7JSE6JTZ.js";
55
55
  import {
56
56
  getApiKey,
57
57
  getBaseUrl
@@ -61,9 +61,13 @@ import {
61
61
  GATE_BLOCK_REASON_MAX_LENGTH,
62
62
  GATE_WIRE,
63
63
  agentQuestionStrategy,
64
+ agentRulesAllowEveryInput,
64
65
  buildDecisionEpisodeFeatures,
66
+ claudeAllowlistOwnsCall,
67
+ claudeConsultsItsAllowlist,
65
68
  claudePermissionDeniedOutput,
66
69
  claudePermissionRequestOutput,
70
+ claudePermissionRulesFromSettings,
67
71
  claudePreToolUseOutput,
68
72
  claudePromptsBeforeAnEdit,
69
73
  editAsksAtTheAgentsPrompt,
@@ -79,7 +83,51 @@ import {
79
83
  parseAgentQuestions,
80
84
  resolveGate,
81
85
  stoppedOutput
82
- } from "./chunk-T4QY64OR.js";
86
+ } from "./chunk-YFD7CRIZ.js";
87
+
88
+ // src/claude-permission-rules.ts
89
+ import { readFileSync, statSync } from "fs";
90
+ import { homedir } from "os";
91
+ import { join } from "path";
92
+ var MANAGED_CLAUDE_SETTINGS_BY_PLATFORM = {
93
+ darwin: "/Library/Application Support/ClaudeCode/managed-settings.json",
94
+ linux: "/etc/claude-code/managed-settings.json",
95
+ win32: "C:\\ProgramData\\ClaudeCode\\managed-settings.json"
96
+ };
97
+ var MAX_CLAUDE_SETTINGS_BYTES = 1048576;
98
+ var claudeSettingsLocationFor = (cwd, environment = process.env, home = homedir(), platform = process.platform) => ({
99
+ configDir: environment.CLAUDE_CONFIG_DIR || join(home, ".claude"),
100
+ projectDir: environment.CLAUDE_PROJECT_DIR || cwd || void 0,
101
+ managedSettingsPath: MANAGED_CLAUDE_SETTINGS_BY_PLATFORM[platform]
102
+ });
103
+ var claudeSettingsSources = (location) => [
104
+ ...location.managedSettingsPath ? [{ path: location.managedSettingsPath, trust: "grants" }] : [],
105
+ { path: join(location.configDir, "settings.json"), trust: "grants" },
106
+ ...location.projectDir ? [
107
+ { path: join(location.projectDir, ".claude", "settings.json"), trust: "restricts_only" },
108
+ { path: join(location.projectDir, ".claude", "settings.local.json"), trust: "grants" }
109
+ ] : []
110
+ ];
111
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
112
+ var restrictionsOnly = (document) => {
113
+ if (!isRecord(document) || !isRecord(document.permissions)) return null;
114
+ const { ask: ask2, deny: deny2 } = document.permissions;
115
+ return { permissions: { ask: ask2, deny: deny2 } };
116
+ };
117
+ var readSettingsDocument = (path) => {
118
+ try {
119
+ const stats = statSync(path);
120
+ if (!stats.isFile() || stats.size > MAX_CLAUDE_SETTINGS_BYTES) return null;
121
+ return JSON.parse(readFileSync(path, "utf8"));
122
+ } catch {
123
+ return null;
124
+ }
125
+ };
126
+ var trustedDocument = ({ path, trust }) => {
127
+ const document = readSettingsDocument(path);
128
+ return trust === "grants" ? document : restrictionsOnly(document);
129
+ };
130
+ var readClaudePermissionRules = (location) => claudePermissionRulesFromSettings(claudeSettingsSources(location).map(trustedDocument));
83
131
 
84
132
  // src/decision-episode.ts
85
133
  var EPISODE_PATH = "/api/agent/decision-episode";
@@ -104,7 +152,7 @@ var reportDecisionEpisode = async (apiKey, input) => {
104
152
  };
105
153
 
106
154
  // src/hook.ts
107
- import { basename, join } from "path";
155
+ import { basename, join as join2 } from "path";
108
156
  import { tmpdir } from "os";
109
157
  import { existsSync, writeFileSync } from "fs";
110
158
  var START_MS = Date.now();
@@ -259,7 +307,8 @@ var dispatchModeHandler = async (apiKey, input, toolPolicy, machineId, trainingC
259
307
  // The gate asks at most one question per tool call, so the runtime's id needs
260
308
  // no suffix here. Absent on runtimes that do not send one, and the server then
261
309
  // creates a fresh decision exactly as before.
262
- toolUseId: input.tool_use_id
310
+ toolUseId: input.tool_use_id,
311
+ sessionToolAware: true
263
312
  };
264
313
  const signals = {};
265
314
  const runHandler = () => {
@@ -298,7 +347,7 @@ var KEYLESS_NOTICE = "[pushary] Not connected (no API key), so your agent runs u
298
347
  var oncePerSession = (kind, sessionId) => {
299
348
  try {
300
349
  const key = (sessionId || DEFAULT_SESSION).replace(/[^a-zA-Z0-9_-]/g, "");
301
- const marker = join(tmpdir(), `pushary-${kind}-${key}`);
350
+ const marker = join2(tmpdir(), `pushary-${kind}-${key}`);
302
351
  if (existsSync(marker)) return false;
303
352
  writeFileSync(marker, "1", "utf-8");
304
353
  return true;
@@ -457,6 +506,8 @@ var handleKeyless = (input) => {
457
506
  }
458
507
  return void 0;
459
508
  };
509
+ var claudePermissionRulesFor = (input) => ACTIVE_SOURCE === "claude" ? readClaudePermissionRules(claudeSettingsLocationFor(input.cwd)) : null;
510
+ var claudeRulesMayCover = (input, rules) => rules !== null && claudeConsultsItsAllowlist(input.permission_mode) && agentRulesAllowEveryInput(rules, input.tool_name, [input.tool_input ?? {}], input.cwd);
460
511
  var claudeGateInput = (modeState, config, input, canonical) => {
461
512
  const toolName = canonical?.toolName ?? input.tool_name;
462
513
  const toolInputs = canonical?.toolInputs ?? [input.tool_input ?? {}];
@@ -549,6 +600,7 @@ var handlePreToolUse = async (input, canonical) => {
549
600
  if (!(verdict.kind === "gate" && verdict.scopeReason) && shouldDeferToNativeMode(input.permission_mode, input.tool_name)) {
550
601
  return void 0;
551
602
  }
603
+ if (claudeAllowlistOwnsCall(gateInput, verdict, input.permission_mode, claudePermissionRulesFor(input))) return void 0;
552
604
  if (claudePromptsBeforeAnEdit(input.permission_mode) && editAsksAtTheAgentsPrompt(gateInput, verdict)) return handleTerminalOnly();
553
605
  switch (verdict.kind) {
554
606
  case "allow":
@@ -578,7 +630,8 @@ var toPermissionRequestOutput = (hookOutput) => {
578
630
  return void 0;
579
631
  };
580
632
  var handlePermissionRequest = async (input, canonical) => {
581
- if (canonical === void 0 && isPermissionRequestOwnedByPreToolUse(input.tool_name, input.permission_mode, shouldDeferToNativeMode)) return void 0;
633
+ const claudeRules = claudePermissionRulesFor(input);
634
+ if (canonical === void 0 && !claudeRulesMayCover(input, claudeRules) && isPermissionRequestOwnedByPreToolUse(input.tool_name, input.permission_mode, shouldDeferToNativeMode)) return void 0;
582
635
  if (isPusharyOwnTool(input.tool_name)) return void 0;
583
636
  let apiKey;
584
637
  try {
@@ -589,7 +642,8 @@ var handlePermissionRequest = async (input, canonical) => {
589
642
  try {
590
643
  const modeState = await fetchModeState(apiKey, input.session_id);
591
644
  const policy = await getPolicy(apiKey, modeState.policyVersion, ACTIVE_AGENT.type, true, input.session_id);
592
- const verdict = resolveGate(claudeGateInput(modeState, policy, input, canonical));
645
+ const gateInput = claudeGateInput(modeState, policy, input, canonical);
646
+ const verdict = resolveGate(gateInput);
593
647
  if (verdict.kind === "kill") {
594
648
  await reportMachineDenial(input, verdict, ACTIVE_AGENT);
595
649
  return permReqHalted(verdict.reason);
@@ -601,7 +655,7 @@ var handlePermissionRequest = async (input, canonical) => {
601
655
  if (canonical === null) return permReqDeny(unreadableReason);
602
656
  if (agentQuestionStrategy(ACTIVE_SOURCE, "PermissionRequest", input.tool_name) === AGENT_QUESTION_STRATEGY.native) return void 0;
603
657
  if (verdict.kind === "gate" && verdict.scopeReason && (canonical?.toolInputs.length ?? 0) > 1) return permReqDeny(batchScopeReason);
604
- if (!(verdict.kind === "gate" && verdict.scopeReason) && isPermissionRequestOwnedByPreToolUse(input.tool_name, input.permission_mode, shouldDeferToNativeMode)) return void 0;
658
+ if (!(verdict.kind === "gate" && verdict.scopeReason) && !claudeAllowlistOwnsCall(gateInput, verdict, input.permission_mode, claudeRules) && isPermissionRequestOwnedByPreToolUse(input.tool_name, input.permission_mode, shouldDeferToNativeMode)) return void 0;
605
659
  switch (verdict.kind) {
606
660
  case "allow":
607
661
  return permReqAllow();
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  NOTIFICATION_PUSH_TYPES,
3
3
  POSTTOOLUSE_MIRROR_ONLY_TOOLS
4
- } from "./chunk-UYDTFCHW.js";
4
+ } from "./chunk-VZANUMIF.js";
5
5
  import {
6
6
  cancelQuestion,
7
7
  isPolicyConfig,
@@ -10,13 +10,13 @@ import {
10
10
  } from "./chunk-PYCQXCI5.js";
11
11
  import {
12
12
  getMachineId
13
- } from "./chunk-UQHUUZ5H.js";
13
+ } from "./chunk-7JSE6JTZ.js";
14
14
  import {
15
15
  withRetry
16
16
  } from "./chunk-HETOKNIL.js";
17
17
  import {
18
18
  reportedInstallSource
19
- } from "./chunk-HU5LSYL2.js";
19
+ } from "./chunk-VMNI33F5.js";
20
20
  import {
21
21
  getApiKey,
22
22
  getBaseUrl
@@ -44,7 +44,7 @@ import {
44
44
  resolveAutoResolveOrigin,
45
45
  resolvePolicy,
46
46
  toToolLookup
47
- } from "./chunk-T4QY64OR.js";
47
+ } from "./chunk-YFD7CRIZ.js";
48
48
 
49
49
  // src/policy.ts
50
50
  import { createHash } from "crypto";
@@ -58,7 +58,7 @@ var policyRequestFor = (agentType) => ({
58
58
  repoAware: REPO_AWARE_AGENTS.includes(agentType)
59
59
  });
60
60
  var policyCacheFile = (apiKey, agent, repoAware = false) => {
61
- const parts = [apiKey, agent, repoAware ? "repoAware" : void 0].filter(Boolean);
61
+ const parts = [apiKey, agent, repoAware ? "repoAware" : void 0, "sessionToolAware"].filter(Boolean);
62
62
  const hash = createHash("sha256").update(parts.join(":")).digest("hex").slice(0, 12);
63
63
  return join(tmpdir(), `pushary-policy-${hash}.json`);
64
64
  };
@@ -69,6 +69,7 @@ var fetchPolicy = async (apiKey, agent, repoAware = false, sessionId) => {
69
69
  if (agent) params.set("agent", agent);
70
70
  if (repoAware) params.set("repoAware", "1");
71
71
  params.set("scopeAware", "1");
72
+ params.set("sessionToolAware", "1");
72
73
  if (sessionId) params.set("sessionId", sessionId);
73
74
  const query = params.toString();
74
75
  const url = query ? `${baseUrl}/api/mcp/policy?${query}` : `${baseUrl}/api/mcp/policy`;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pusharyDir
3
- } from "./chunk-DYHXOXUF.js";
3
+ } from "./chunk-F2OPOBRO.js";
4
4
  import {
5
5
  writeFileAtomic
6
6
  } from "./chunk-T7E75EKA.js";
@@ -6,16 +6,16 @@ import {
6
6
  } from "./chunk-SGZJ5LYH.js";
7
7
  import {
8
8
  hookOwnerOf
9
- } from "./chunk-PCGZXWGQ.js";
9
+ } from "./chunk-KZBGITM4.js";
10
10
  import {
11
11
  ensureDaemonRunning
12
- } from "./chunk-7XT76LWT.js";
12
+ } from "./chunk-DZ75BJ7V.js";
13
13
  import {
14
14
  buildTranscriptRecords,
15
15
  decodePublicKey,
16
16
  generateSessionKey,
17
17
  wrapSessionKey
18
- } from "./chunk-TIWURSLS.js";
18
+ } from "./chunk-SFNRAEEW.js";
19
19
  import {
20
20
  fetchTranscriptRecipients,
21
21
  uploadTranscriptRecords
@@ -23,14 +23,14 @@ import {
23
23
  import {
24
24
  transcriptEnvironmentPreference,
25
25
  transcriptsEnabled
26
- } from "./chunk-2QT3GCU4.js";
26
+ } from "./chunk-GP6SFVEN.js";
27
27
  import {
28
28
  codexHome,
29
29
  pusharyDir
30
- } from "./chunk-DYHXOXUF.js";
30
+ } from "./chunk-F2OPOBRO.js";
31
31
  import {
32
32
  readTranscriptPreference
33
- } from "./chunk-USQDVBEV.js";
33
+ } from "./chunk-TDKE3V6W.js";
34
34
  import {
35
35
  writeJsonAtomic
36
36
  } from "./chunk-T7E75EKA.js";
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  COMPATIBLE_AGENT_TYPES,
9
9
  isValidApiKey
10
- } from "./chunk-T4QY64OR.js";
10
+ } from "./chunk-YFD7CRIZ.js";
11
11
 
12
12
  // src/setup/options.ts
13
13
  var AGENT_CHOICES = ["claude_code", "codex", "gemini_cli", "hermes", "cursor", "vscode", "opencode", ...COMPATIBLE_AGENT_TYPES, "custom"];
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pusharyDir
3
- } from "./chunk-DYHXOXUF.js";
3
+ } from "./chunk-F2OPOBRO.js";
4
4
  import {
5
5
  readJsonSafe
6
6
  } from "./chunk-T7E75EKA.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  HOOK_BUDGETS,
3
3
  OPENCODE_APPROVAL_EVENT
4
- } from "./chunk-T4QY64OR.js";
4
+ } from "./chunk-YFD7CRIZ.js";
5
5
 
6
6
  // src/opencode-plugin.ts
7
7
  var OPENCODE_PLUGIN_MARKER = "pushary-opencode-plugin w1";
@@ -7,10 +7,10 @@ import {
7
7
  permissionDeniedAction,
8
8
  releaseThrottle,
9
9
  reportEvent
10
- } from "./chunk-FDHMNT24.js";
10
+ } from "./chunk-66BIMA62.js";
11
11
  import {
12
12
  canonicalJson
13
- } from "./chunk-DYHXOXUF.js";
13
+ } from "./chunk-F2OPOBRO.js";
14
14
  import {
15
15
  writeFileAtomic
16
16
  } from "./chunk-T7E75EKA.js";
@@ -20,7 +20,7 @@ import {
20
20
  machineDecisionFor,
21
21
  shouldDeferToNativeMode,
22
22
  wireVerdictFor
23
- } from "./chunk-T4QY64OR.js";
23
+ } from "./chunk-YFD7CRIZ.js";
24
24
 
25
25
  // src/machine-decision-audit.ts
26
26
  import { basename } from "path";
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  NOTIFICATION_MATCHED_TYPES,
3
3
  POSTTOOLUSE_MIRRORED_TOOLS
4
- } from "./chunk-UYDTFCHW.js";
4
+ } from "./chunk-VZANUMIF.js";
5
5
  import {
6
6
  isProtectedByScope,
7
7
  registerHookEntry
8
- } from "./chunk-DYHXOXUF.js";
8
+ } from "./chunk-F2OPOBRO.js";
9
9
  import {
10
10
  CLAUDE_PRETOOLUSE_MATCHER,
11
11
  HOOK_BUDGETS,
12
12
  HOOK_LOCATOR_BINARY
13
- } from "./chunk-T4QY64OR.js";
13
+ } from "./chunk-YFD7CRIZ.js";
14
14
 
15
15
  // src/gemini-config.ts
16
16
  var GEMINI_HOOK_BINARY = "pushary-gemini-hook";
@@ -2,21 +2,21 @@ import {
2
2
  detectProviderLiveCapabilities,
3
3
  hasSpawnProvider,
4
4
  resolveControlPolicy
5
- } from "./chunk-KEOLNHR3.js";
5
+ } from "./chunk-5MH5P366.js";
6
6
  import {
7
7
  daemonHasRemoteProof,
8
8
  daemonServiceManagerAvailable,
9
9
  hasDaemonServiceDefinition,
10
10
  readDaemonNeedsLogin,
11
11
  readDaemonStatus
12
- } from "./chunk-7XT76LWT.js";
12
+ } from "./chunk-DZ75BJ7V.js";
13
13
  import {
14
14
  getMachineId
15
- } from "./chunk-UQHUUZ5H.js";
15
+ } from "./chunk-7JSE6JTZ.js";
16
16
  import {
17
17
  readControlMode,
18
18
  readKeySource
19
- } from "./chunk-USQDVBEV.js";
19
+ } from "./chunk-TDKE3V6W.js";
20
20
  import {
21
21
  getBaseUrl
22
22
  } from "./chunk-OSJEMXSR.js";