@pushary/agent-hooks 1.4.1 → 1.5.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 (92) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +27 -0
  3. package/data/vscode-plugin/README.md +1 -1
  4. package/data/vscode-plugin/scripts/pushary-gate.mjs +2 -2
  5. package/dist/bin/pushary-bell-hook.js +22 -21
  6. package/dist/bin/pushary-bell.js +10 -10
  7. package/dist/bin/pushary-claude.js +28 -24
  8. package/dist/bin/pushary-clean.js +30 -26
  9. package/dist/bin/pushary-codex-bridge.js +16 -14
  10. package/dist/bin/pushary-codex-hook.js +41 -31
  11. package/dist/bin/pushary-codex.js +15 -10
  12. package/dist/bin/pushary-connect.js +11 -11
  13. package/dist/bin/pushary-cowork.js +6 -6
  14. package/dist/bin/pushary-daemon.js +31 -28
  15. package/dist/bin/pushary-disconnect.js +16 -16
  16. package/dist/bin/pushary-doctor.js +81 -38
  17. package/dist/bin/pushary-elicitation-hook.js +23 -22
  18. package/dist/bin/pushary-gemini-bridge.js +13 -11
  19. package/dist/bin/pushary-gemini-hook.js +29 -24
  20. package/dist/bin/pushary-hook.js +30 -30
  21. package/dist/bin/pushary-login.js +14 -14
  22. package/dist/bin/pushary-logout.js +8 -8
  23. package/dist/bin/pushary-mode.js +7 -7
  24. package/dist/bin/pushary-notification-hook.js +26 -25
  25. package/dist/bin/pushary-opencode-hook.js +25 -24
  26. package/dist/bin/pushary-permission-denied-hook.js +30 -29
  27. package/dist/bin/pushary-permission-hook.js +29 -28
  28. package/dist/bin/pushary-post-hook.js +26 -25
  29. package/dist/bin/pushary-prompt-hook.js +26 -25
  30. package/dist/bin/pushary-session-end-hook.js +26 -25
  31. package/dist/bin/pushary-session-start-hook.js +32 -27
  32. package/dist/bin/pushary-setup.js +85 -59
  33. package/dist/bin/pushary-stats.js +6 -6
  34. package/dist/bin/pushary-status.js +15 -15
  35. package/dist/bin/pushary-stop-hook.js +26 -25
  36. package/dist/bin/pushary-stopfailure-hook.js +26 -25
  37. package/dist/bin/pushary-suggestions.js +4 -4
  38. package/dist/bin/pushary-transcript-register.js +20 -19
  39. package/dist/bin/pushary-transcripts.js +8 -8
  40. package/dist/bin/pushary-upgrade.js +231 -37
  41. package/dist/bin/pushary-wait.js +7 -7
  42. package/dist/bin/pushary.js +8 -8
  43. package/dist/{chunk-MN3XOVRK.js → chunk-2QT3GCU4.js} +1 -1
  44. package/dist/{chunk-LUT2EZLG.js → chunk-3NBODGQS.js} +1 -1
  45. package/dist/{chunk-43JKGLZZ.js → chunk-3ZSGKLSO.js} +2 -2
  46. package/dist/{chunk-QBS6LGEK.js → chunk-43LJSM4F.js} +2 -2
  47. package/dist/{chunk-SWFF5U2N.js → chunk-43ZDACBO.js} +1 -1
  48. package/dist/{chunk-HK3IXIQJ.js → chunk-5HYNICS7.js} +1 -1
  49. package/dist/{chunk-EQRS3SGM.js → chunk-66H2QQAK.js} +1 -1
  50. package/dist/{chunk-3BPB2HYZ.js → chunk-7XT76LWT.js} +7 -7
  51. package/dist/{chunk-ALFT7H5B.js → chunk-CQYHOHOK.js} +56 -5
  52. package/dist/{chunk-3UA6FPRC.js → chunk-DLJN5XEU.js} +3 -3
  53. package/dist/{chunk-BZBUPZC6.js → chunk-DTQNDR7C.js} +1 -1
  54. package/dist/{chunk-SAF6NNXY.js → chunk-DYHXOXUF.js} +43 -6
  55. package/dist/{chunk-FAH3D74E.js → chunk-EA3IELHP.js} +6 -0
  56. package/dist/{chunk-ED5TA2FJ.js → chunk-EADZPVYW.js} +3 -3
  57. package/dist/{chunk-I6HRQOMT.js → chunk-F57RGL7K.js} +8 -8
  58. package/dist/{chunk-LNGYW6G4.js → chunk-FDHMNT24.js} +20 -16
  59. package/dist/{chunk-37VLIYLI.js → chunk-H5LHTC5X.js} +1 -1
  60. package/dist/{chunk-EYRGBYZG.js → chunk-HETOKNIL.js} +1 -1
  61. package/dist/{chunk-K6I5M2ME.js → chunk-HU5LSYL2.js} +2 -2
  62. package/dist/{chunk-SKXLIVFM.js → chunk-HVBF35GT.js} +2 -2
  63. package/dist/{chunk-DINDL2CF.js → chunk-HWJW3CPO.js} +25 -5
  64. package/dist/{chunk-GOFDGTEI.js → chunk-IYTQ4B5I.js} +18 -45
  65. package/dist/{chunk-WIOXWUUH.js → chunk-J4J45VPZ.js} +3 -3
  66. package/dist/{chunk-HQLAZWJJ.js → chunk-JF736N4C.js} +5 -5
  67. package/dist/{chunk-LYXX5NSB.js → chunk-K3QVDAZW.js} +1 -1
  68. package/dist/{chunk-KI36MAT6.js → chunk-KEOLNHR3.js} +2 -2
  69. package/dist/{chunk-S3EP4B35.js → chunk-KJRALILH.js} +28 -11
  70. package/dist/{chunk-PHHGHHOW.js → chunk-MYP4UUFH.js} +1 -1
  71. package/dist/{chunk-TNS3YLFE.js → chunk-NFKVRMTM.js} +8 -8
  72. package/dist/{chunk-TF4IOINR.js → chunk-NTQSICPJ.js} +3 -3
  73. package/dist/{chunk-4FN6VV56.js → chunk-ORLJNJEO.js} +2 -2
  74. package/dist/{chunk-2UMNXADU.js → chunk-OSJEMXSR.js} +5 -1
  75. package/dist/chunk-OSSDK5RS.js +162 -0
  76. package/dist/{chunk-TWWLVOPB.js → chunk-P4BNYJ5Q.js} +5 -5
  77. package/dist/{chunk-KEMEBTCJ.js → chunk-PCGZXWGQ.js} +4 -4
  78. package/dist/{chunk-2GMI6JH6.js → chunk-PNNBMH4E.js} +5 -5
  79. package/dist/{chunk-LGXUGYUH.js → chunk-PYCQXCI5.js} +2 -2
  80. package/dist/{chunk-JOVWYVSR.js → chunk-SOCEY746.js} +1 -1
  81. package/dist/{chunk-FVKFDTN6.js → chunk-T4QY64OR.js} +19 -14
  82. package/dist/{chunk-R3AMKNIW.js → chunk-TFKBFQCE.js} +1 -1
  83. package/dist/{chunk-CRNAXFQ6.js → chunk-TIWURSLS.js} +1 -1
  84. package/dist/{chunk-VYUDGQM7.js → chunk-TUXFIVOH.js} +1 -1
  85. package/dist/{chunk-3T52B2OF.js → chunk-UQHUUZ5H.js} +1 -1
  86. package/dist/{chunk-TI3ZWXZG.js → chunk-USQDVBEV.js} +2 -2
  87. package/dist/{chunk-WEO5JCB4.js → chunk-UYDTFCHW.js} +1 -1
  88. package/dist/{chunk-D7ERHWYB.js → chunk-XWEONSLV.js} +1 -1
  89. package/dist/{chunk-GKIUEIDX.js → chunk-YQMFGWBD.js} +1 -1
  90. package/dist/{reapply-BAWDJTG7.js → reapply-D2TFN6XK.js} +9 -8
  91. package/dist/src/index.js +18 -16
  92. package/package.json +1 -1
@@ -1,17 +1,67 @@
1
1
  import {
2
- canonicalGateInputs
3
- } from "./chunk-LNGYW6G4.js";
2
+ AUTO_DECISION_WINDOW_MS,
3
+ DEFAULT_SESSION,
4
+ canonicalGateInputs,
5
+ claimThrottle,
6
+ deriveToolTarget,
7
+ permissionDeniedAction,
8
+ releaseThrottle,
9
+ reportEvent
10
+ } from "./chunk-FDHMNT24.js";
4
11
  import {
5
12
  canonicalJson
6
- } from "./chunk-SAF6NNXY.js";
13
+ } from "./chunk-DYHXOXUF.js";
7
14
  import {
8
15
  writeFileAtomic
9
16
  } from "./chunk-T7E75EKA.js";
10
17
  import {
11
18
  BLOCKED_ACTION_GRANT_TTL_SECONDS,
12
19
  blockedActionIdentity,
13
- shouldDeferToNativeMode
14
- } from "./chunk-FVKFDTN6.js";
20
+ machineDecisionFor,
21
+ shouldDeferToNativeMode,
22
+ wireVerdictFor
23
+ } from "./chunk-T4QY64OR.js";
24
+
25
+ // src/machine-decision-audit.ts
26
+ import { basename } from "path";
27
+ var reportMachineDenial = async (input, verdict, agent) => {
28
+ const decision = machineDecisionFor(wireVerdictFor(verdict, 0));
29
+ if (!decision) return;
30
+ const sessionKey = input.session_id || DEFAULT_SESSION;
31
+ const toolTarget = deriveToolTarget(input.tool_name, input.tool_input);
32
+ const throttleKey = `machinedecision:${agent.type}:${sessionKey}:${input.tool_name}:${decision.origin}:${toolTarget ?? ""}`;
33
+ const throttle = claimThrottle(throttleKey, AUTO_DECISION_WINDOW_MS);
34
+ if (throttle === "throttled") return;
35
+ if (throttle === "unavailable") {
36
+ console.error("[Pushary] Could not access the audit throttle; reporting this denial without deduplication.");
37
+ }
38
+ try {
39
+ const response = await reportEvent({
40
+ event: "permission_denied",
41
+ occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
42
+ toolUseId: input.tool_use_id,
43
+ agentType: agent.type,
44
+ agentName: `${agent.label} - ${basename(input.cwd ?? process.cwd())}`,
45
+ action: permissionDeniedAction(input.tool_name),
46
+ sessionId: input.session_id,
47
+ decisionSource: "policy_auto",
48
+ decisionOrigin: decision.origin,
49
+ decisionOutcome: decision.outcome,
50
+ toolName: input.tool_name,
51
+ toolTarget
52
+ }, { maxAttempts: 1, timeoutMs: 800, requireOk: true, skipDrain: true });
53
+ if (response?.ok !== true) throw new Error("Audit delivery was not acknowledged");
54
+ } catch {
55
+ console.error("[Pushary] Could not record the machine denial. The action remains blocked; its audit delivery will be retried on the next matching denial.");
56
+ if (throttle === "passed") {
57
+ try {
58
+ releaseThrottle(throttleKey);
59
+ } catch {
60
+ console.error("[Pushary] Could not reset the failed audit throttle.");
61
+ }
62
+ }
63
+ }
64
+ };
15
65
 
16
66
  // src/native-defer.ts
17
67
  var nativeDeferOptions = () => {
@@ -190,6 +240,7 @@ var forgetBlockedActionHint = (fingerprint) => {
190
240
  };
191
241
 
192
242
  export {
243
+ reportMachineDenial,
193
244
  defersToNativeMode,
194
245
  userScope,
195
246
  codexCallKey,
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  openCodeConfigDirFrom
3
- } from "./chunk-VYUDGQM7.js";
3
+ } from "./chunk-TUXFIVOH.js";
4
4
  import {
5
5
  codexHomeFrom
6
- } from "./chunk-SAF6NNXY.js";
6
+ } from "./chunk-DYHXOXUF.js";
7
7
  import {
8
8
  HOOK_COMPATIBLE_PROFILES
9
- } from "./chunk-FVKFDTN6.js";
9
+ } from "./chunk-T4QY64OR.js";
10
10
 
11
11
  // src/vscode-config.ts
12
12
  import { homedir } from "os";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  readConfigFileKey
3
- } from "./chunk-TI3ZWXZG.js";
3
+ } from "./chunk-USQDVBEV.js";
4
4
 
5
5
  // src/bell/fleet.ts
6
6
  import { closeSync, constants, futimesSync, lstatSync, mkdirSync, openSync, readdirSync, unlinkSync } from "fs";
@@ -2,12 +2,19 @@ import {
2
2
  HOOK_BUDGETS,
3
3
  HOOK_LOCATOR_BINARY,
4
4
  withHookHoldBudget
5
- } from "./chunk-FVKFDTN6.js";
5
+ } from "./chunk-T4QY64OR.js";
6
+ import {
7
+ isReleaseVersion
8
+ } from "./chunk-HWJW3CPO.js";
6
9
 
7
10
  // src/npm.ts
8
11
  import { execFileSync, execSync } from "child_process";
9
12
  import { existsSync, readFileSync, realpathSync } from "fs";
10
13
  import { dirname, isAbsolute, join, relative, resolve } from "path";
14
+ var AGENT_HOOKS_PACKAGE = "@pushary/agent-hooks";
15
+ var LATEST_RELEASE_URL = `https://registry.npmjs.org/${AGENT_HOOKS_PACKAGE}/latest`;
16
+ var REGISTRY_TIMEOUT_MS = 5e3;
17
+ var LATEST_TAG = "latest";
11
18
  var cleanNpmEnv = () => {
12
19
  const env = {};
13
20
  for (const [key, value] of Object.entries(process.env)) {
@@ -16,10 +23,11 @@ var cleanNpmEnv = () => {
16
23
  }
17
24
  return env;
18
25
  };
26
+ var NPM_ERROR_METADATA = /^(code|syscall|path|dest|errno)\s/i;
19
27
  var npmErrorMessage = (err) => {
20
28
  const e = err;
21
29
  const text = [e?.stderr, e?.stdout].map((part) => part ? part.toString() : "").join("\n");
22
- const line = text.split("\n").map((l) => l.replace(/^npm error\s*/i, "").trim()).find((l) => l && !l.startsWith("A complete log") && !/^code\s/i.test(l));
30
+ const line = text.split("\n").map((l) => l.replace(/^npm error\s*/i, "").trim()).find((l) => l && !l.startsWith("A complete log") && !NPM_ERROR_METADATA.test(l));
23
31
  return line || e?.message || String(err);
24
32
  };
25
33
  var execNpm = (args, options = {}) => {
@@ -143,6 +151,26 @@ var resolveGlobalBinDir = (probe) => {
143
151
  return resolved ? resolved.slice(0, resolved.length - probe.length - 1) : void 0;
144
152
  };
145
153
  var quoteIfNeeded = (path) => /\s/.test(path) ? `"${path}"` : path;
154
+ var fetchLatestPublishedVersion = async (request = {}) => {
155
+ try {
156
+ const response = await (request.fetchImpl ?? fetch)(LATEST_RELEASE_URL, {
157
+ signal: AbortSignal.timeout(request.timeoutMs ?? REGISTRY_TIMEOUT_MS)
158
+ });
159
+ if (!response.ok) return void 0;
160
+ const body = await response.json();
161
+ const version = body && typeof body === "object" && "version" in body ? body.version : void 0;
162
+ return typeof version === "string" && isReleaseVersion(version) ? version : void 0;
163
+ } catch {
164
+ return void 0;
165
+ }
166
+ };
167
+ var POSIX_SHELL_WORD = /^[\w@%+=:,./-]+$/;
168
+ var quoteForPosixShell = (value) => POSIX_SHELL_WORD.test(value) ? value : `'${value.replaceAll("'", `'\\''`)}'`;
169
+ var installAgentHooksGlobally = (request, runNpm = execNpm) => {
170
+ const prefixFlag = request.prefix === void 0 ? "" : ` --prefix ${quoteForPosixShell(request.prefix)}`;
171
+ const spec = quoteForPosixShell(`${AGENT_HOOKS_PACKAGE}@${request.version}`);
172
+ runNpm(`install -g --no-workspaces${prefixFlag} ${spec}`, { timeout: request.timeoutMs });
173
+ };
146
174
  var needsGlobalInstall = (requested, installed, binaryPresent) => requested !== installed || !binaryPresent;
147
175
  var installState;
148
176
  var installGlobally = (options) => {
@@ -153,13 +181,13 @@ var installGlobally = (options) => {
153
181
  const pinned = process.env.PUSHARY_PIN_GLOBAL_VERSION !== "0";
154
182
  if (pinned && !needsGlobalInstall(
155
183
  options.version,
156
- resolveGlobalPackageVersion("@pushary/agent-hooks"),
157
- globalPackageBinsPresent("@pushary/agent-hooks")
184
+ resolveGlobalPackageVersion(AGENT_HOOKS_PACKAGE),
185
+ globalPackageBinsPresent(AGENT_HOOKS_PACKAGE)
158
186
  )) {
159
187
  return "skipped";
160
188
  }
161
- const spec = pinned && options.version && options.version !== "0.0.0" ? `@pushary/agent-hooks@${options.version}` : "@pushary/agent-hooks@latest";
162
- execNpm(`install -g --no-workspaces ${spec}`, { timeout: options.timeoutMs ?? 12e4 });
189
+ const version = pinned && options.version && options.version !== "0.0.0" ? options.version : LATEST_TAG;
190
+ installAgentHooksGlobally({ version, timeoutMs: options.timeoutMs ?? 12e4 });
163
191
  return "installed";
164
192
  })();
165
193
  installState = started;
@@ -609,6 +637,9 @@ var claudeSettingsLocal = () => join3(homedir2(), ".claude", "settings.local.jso
609
637
  var pusharyDir = () => join3(homedir2(), ".pushary");
610
638
  var claudeMcpReceipt = () => join3(pusharyDir(), "setup", "claude-mcp.json");
611
639
  var bridgeAgentKey = () => join3(pusharyDir(), "bridge-auth", "agent-key.json");
640
+ var autoUpdateState = () => join3(pusharyDir(), "auto-update.json");
641
+ var autoUpdateLock = () => join3(pusharyDir(), "auto-update.lock");
642
+ var autoUpdateLog = () => join3(pusharyDir(), "logs", "auto-update.log");
612
643
  var claudeRegistrationReceipt = () => join3(pusharyDir(), "setup", "claude-registration.json");
613
644
  var hermesConfigReceipt = () => join3(pusharyDir(), "setup", "hermes-config.json");
614
645
  var hookTakeoverReceipt = (agent) => join3(pusharyDir(), "setup", `hook-takeover-${agent}.json`);
@@ -622,6 +653,7 @@ export {
622
653
  registeredCommands,
623
654
  namesOurBinary,
624
655
  registrationHolderOf,
656
+ LATEST_TAG,
625
657
  npmErrorMessage,
626
658
  execNpm,
627
659
  resolveGlobalBinary,
@@ -630,6 +662,8 @@ export {
630
662
  resolvePackageVersionFromBinary,
631
663
  resolveGlobalPackageVersion,
632
664
  resolveGlobalBinDir,
665
+ fetchLatestPublishedVersion,
666
+ installAgentHooksGlobally,
633
667
  installGlobally,
634
668
  holdBudgetOf,
635
669
  guardBinary,
@@ -675,6 +709,9 @@ export {
675
709
  pusharyDir,
676
710
  claudeMcpReceipt,
677
711
  bridgeAgentKey,
712
+ autoUpdateState,
713
+ autoUpdateLock,
714
+ autoUpdateLog,
678
715
  claudeRegistrationReceipt,
679
716
  hermesConfigReceipt,
680
717
  hookTakeoverReceipt,
@@ -1,4 +1,5 @@
1
1
  // src/cli/commands.ts
2
+ var NPX_LATEST_COMMAND = "npx @pushary/agent-hooks@latest";
2
3
  var COMMAND_LIST = [
3
4
  {
4
5
  name: "cowork",
@@ -132,6 +133,10 @@ var COMMAND_OPTIONS = {
132
133
  ["--bundle", "Write a redacted diagnostics file you can attach to a support thread"]
133
134
  ],
134
135
  suggestions: [["accept <id>", "Turn a mined suggestion into an always-allow rule"]],
136
+ upgrade: [
137
+ ["--auto=off", "Stop Pushary updating itself in the background"],
138
+ ["--auto=on", "Update in the background again: once a day at session start, within the same major version"]
139
+ ],
135
140
  bell: [
136
141
  ["(no flags)", "Turn the bell on for Claude Code"],
137
142
  ["--test", "Ring once, now, so you can hear what it does"],
@@ -232,6 +237,7 @@ var renderCommandHelp = (name, version) => {
232
237
  };
233
238
 
234
239
  export {
240
+ NPX_LATEST_COMMAND,
235
241
  COMMANDS,
236
242
  isCommandName,
237
243
  renderHelp,
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  NOTIFICATION_MATCHED_TYPES,
3
3
  POSTTOOLUSE_MIRRORED_TOOLS
4
- } from "./chunk-WEO5JCB4.js";
4
+ } from "./chunk-UYDTFCHW.js";
5
5
  import {
6
6
  isProtectedByScope,
7
7
  registerHookEntry
8
- } from "./chunk-SAF6NNXY.js";
8
+ } from "./chunk-DYHXOXUF.js";
9
9
  import {
10
10
  CLAUDE_PRETOOLUSE_MATCHER,
11
11
  HOOK_BUDGETS,
12
12
  HOOK_LOCATOR_BINARY
13
- } from "./chunk-FVKFDTN6.js";
13
+ } from "./chunk-T4QY64OR.js";
14
14
 
15
15
  // src/gemini-config.ts
16
16
  var GEMINI_HOOK_BINARY = "pushary-gemini-hook";
@@ -2,27 +2,27 @@ import {
2
2
  detectProviderLiveCapabilities,
3
3
  hasSpawnProvider,
4
4
  resolveControlPolicy
5
- } from "./chunk-KI36MAT6.js";
5
+ } from "./chunk-KEOLNHR3.js";
6
6
  import {
7
7
  daemonHasRemoteProof,
8
8
  daemonServiceManagerAvailable,
9
9
  hasDaemonServiceDefinition,
10
10
  readDaemonNeedsLogin,
11
11
  readDaemonStatus
12
- } from "./chunk-3BPB2HYZ.js";
12
+ } from "./chunk-7XT76LWT.js";
13
13
  import {
14
14
  getMachineId
15
- } from "./chunk-3T52B2OF.js";
16
- import {
17
- getPackageVersion
18
- } from "./chunk-DINDL2CF.js";
15
+ } from "./chunk-UQHUUZ5H.js";
19
16
  import {
20
17
  readControlMode,
21
18
  readKeySource
22
- } from "./chunk-TI3ZWXZG.js";
19
+ } from "./chunk-USQDVBEV.js";
23
20
  import {
24
21
  getBaseUrl
25
- } from "./chunk-2UMNXADU.js";
22
+ } from "./chunk-OSJEMXSR.js";
23
+ import {
24
+ getPackageVersion
25
+ } from "./chunk-HWJW3CPO.js";
26
26
 
27
27
  // src/machines.ts
28
28
  import { hostname } from "os";
@@ -1,26 +1,26 @@
1
1
  import {
2
2
  NOTIFICATION_PUSH_TYPES,
3
3
  POSTTOOLUSE_MIRROR_ONLY_TOOLS
4
- } from "./chunk-WEO5JCB4.js";
4
+ } from "./chunk-UYDTFCHW.js";
5
5
  import {
6
6
  cancelQuestion,
7
7
  isPolicyConfig,
8
8
  sendNotification,
9
9
  waitForAnswer
10
- } from "./chunk-LGXUGYUH.js";
10
+ } from "./chunk-PYCQXCI5.js";
11
11
  import {
12
12
  getMachineId
13
- } from "./chunk-3T52B2OF.js";
13
+ } from "./chunk-UQHUUZ5H.js";
14
14
  import {
15
15
  withRetry
16
- } from "./chunk-EYRGBYZG.js";
16
+ } from "./chunk-HETOKNIL.js";
17
17
  import {
18
18
  reportedInstallSource
19
- } from "./chunk-K6I5M2ME.js";
19
+ } from "./chunk-HU5LSYL2.js";
20
20
  import {
21
21
  getApiKey,
22
22
  getBaseUrl
23
- } from "./chunk-2UMNXADU.js";
23
+ } from "./chunk-OSJEMXSR.js";
24
24
  import {
25
25
  ACTION_BODY_MAX,
26
26
  AGENT_LABELS_BY_TYPE,
@@ -44,7 +44,7 @@ import {
44
44
  resolveAutoResolveOrigin,
45
45
  resolvePolicy,
46
46
  toToolLookup
47
- } from "./chunk-FVKFDTN6.js";
47
+ } from "./chunk-T4QY64OR.js";
48
48
 
49
49
  // src/policy.ts
50
50
  import { createHash } from "crypto";
@@ -1368,20 +1368,23 @@ var phoneDrivenEnv = (base) => ({
1368
1368
  import { join as join5 } from "path";
1369
1369
  import { tmpdir as tmpdir4 } from "os";
1370
1370
  import { createHash as createHash4 } from "crypto";
1371
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, statSync as statSync4, writeFileSync as writeFileSync4 } from "fs";
1371
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, statSync as statSync4, writeFileSync as writeFileSync4, rmSync as rmSync2 } from "fs";
1372
1372
  var THROTTLE_DIR = join5(tmpdir4(), "pushary-throttle");
1373
1373
  var markerPath = (key) => join5(THROTTLE_DIR, createHash4("sha256").update(key).digest("hex").slice(0, 16));
1374
- var throttlePass = (key, windowMs) => {
1374
+ var claimThrottle = (key, windowMs) => {
1375
1375
  try {
1376
1376
  const path = markerPath(key);
1377
- if (existsSync4(path) && Date.now() - statSync4(path).mtimeMs < windowMs) return false;
1377
+ if (existsSync4(path) && Date.now() - statSync4(path).mtimeMs < windowMs) return "throttled";
1378
1378
  mkdirSync3(THROTTLE_DIR, { recursive: true });
1379
1379
  writeFileSync4(path, "", "utf-8");
1380
- return true;
1380
+ return "passed";
1381
1381
  } catch {
1382
- return false;
1382
+ return "unavailable";
1383
1383
  }
1384
1384
  };
1385
+ var releaseThrottle = (key) => {
1386
+ rmSync2(markerPath(key), { force: true });
1387
+ };
1385
1388
 
1386
1389
  // src/events.ts
1387
1390
  import { basename as basename3, join as join6 } from "path";
@@ -1688,7 +1691,7 @@ var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
1688
1691
  }
1689
1692
  const isMirrorOnly = NON_GATED_MIRROR_TOOLS.has(input.tool_name);
1690
1693
  const decisionSource = isMirrorOnly ? void 0 : deriveDecisionSource(lookup.tool, lookup.input, liveMode, agent.type, input.cwd, input.session_id);
1691
- const beacon = !isMirrorOnly && decisionSource === "policy_auto" && throttlePass(`autodecision:${sessionKey}:${lookup.tool}`, AUTO_DECISION_WINDOW_MS) ? deriveAutoDecisionBeacon(lookup.tool, lookup.input, liveMode, agent.type, input.cwd, input.session_id) : void 0;
1694
+ const beacon = !isMirrorOnly && decisionSource === "policy_auto" && claimThrottle(`autodecision:${sessionKey}:${lookup.tool}`, AUTO_DECISION_WINDOW_MS) === "passed" ? deriveAutoDecisionBeacon(lookup.tool, lookup.input, liveMode, agent.type, input.cwd, input.session_id) : void 0;
1692
1695
  const toolReport = reportEvent({
1693
1696
  event: isError ? "tool_error" : "tool_complete",
1694
1697
  occurredAt,
@@ -1704,7 +1707,7 @@ var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
1704
1707
  usage: deriveUsage(input.transcript_path, input.session_id)
1705
1708
  }, { maxAttempts: 1, budgetMs: Math.min(DRAINING_REPORT_BUDGET_MS, Math.max(0, deadline - Date.now())), signal });
1706
1709
  const extraReports = [];
1707
- if (throttlePass(`hookactive:${sessionKey}`, HOOK_ACTIVE_WINDOW_MS)) {
1710
+ if (claimThrottle(`hookactive:${sessionKey}`, HOOK_ACTIVE_WINDOW_MS) === "passed") {
1708
1711
  extraReports.push(
1709
1712
  reportEvent(
1710
1713
  {
@@ -1898,7 +1901,7 @@ var handleNotification = async (input, agent = CLAUDE_CODE_AGENT) => {
1898
1901
  }, { maxAttempts: 1, timeoutMs: 2500, signal }).catch(() => {
1899
1902
  });
1900
1903
  if (!teammateIdle && NOTIFICATION_PUSH_TYPES.has(notifType)) {
1901
- if (!throttlePass(`notify:${sessionKey}:${notifType}`, NOTIFICATION_THROTTLE_MS)) return;
1904
+ if (claimThrottle(`notify:${sessionKey}:${notifType}`, NOTIFICATION_THROTTLE_MS) !== "passed") return;
1902
1905
  let apiKey;
1903
1906
  try {
1904
1907
  apiKey = getApiKey();
@@ -1990,7 +1993,8 @@ export {
1990
1993
  markPendingCommandFailed,
1991
1994
  removePendingCommand,
1992
1995
  repoKeyFor,
1993
- throttlePass,
1996
+ claimThrottle,
1997
+ releaseThrottle,
1994
1998
  readLastUserPrompt,
1995
1999
  CODEX_AGENT,
1996
2000
  codexAllow,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolvePathBinary
3
- } from "./chunk-SAF6NNXY.js";
3
+ } from "./chunk-DYHXOXUF.js";
4
4
 
5
5
  // src/hermes-config.ts
6
6
  import { execFileSync } from "child_process";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-SAF6HGAA.js";
4
4
  import {
5
5
  getBaseUrl
6
- } from "./chunk-2UMNXADU.js";
6
+ } from "./chunk-OSJEMXSR.js";
7
7
 
8
8
  // src/retry.ts
9
9
  var isRetryable = (err) => {
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  configFilePath
3
- } from "./chunk-2UMNXADU.js";
3
+ } from "./chunk-OSJEMXSR.js";
4
4
  import {
5
5
  normalizeInstallSource
6
- } from "./chunk-FVKFDTN6.js";
6
+ } from "./chunk-T4QY64OR.js";
7
7
 
8
8
  // src/install-source.ts
9
9
  import { readFileSync } from "fs";
@@ -3,11 +3,11 @@ import {
3
3
  decodePublicKey,
4
4
  generateSessionKey,
5
5
  wrapSessionKey
6
- } from "./chunk-CRNAXFQ6.js";
6
+ } from "./chunk-TIWURSLS.js";
7
7
  import {
8
8
  fetchTranscriptRecipients,
9
9
  uploadTranscriptRecords
10
- } from "./chunk-EQRS3SGM.js";
10
+ } from "./chunk-66H2QQAK.js";
11
11
 
12
12
  // src/live-session.ts
13
13
  var MAX_TRANSCRIPT_QUEUE = 100;
@@ -3,6 +3,7 @@ import { readFileSync } from "fs";
3
3
  import { dirname, join, parse } from "path";
4
4
  import { fileURLToPath } from "url";
5
5
  var PACKAGE_NAME = "@pushary/agent-hooks";
6
+ var UNKNOWN_VERSION = "0.0.0";
6
7
  var findOwnPackageJson = (start) => {
7
8
  const { root } = parse(start);
8
9
  let dir = start;
@@ -20,13 +21,24 @@ var findOwnPackageJson = (start) => {
20
21
  }
21
22
  };
22
23
  var getPackageVersion = () => {
24
+ const root = ownPackageRoot();
25
+ return (root === void 0 ? void 0 : packageVersionAt(root)) ?? UNKNOWN_VERSION;
26
+ };
27
+ var ownPackageRoot = () => {
23
28
  try {
24
29
  const found = findOwnPackageJson(dirname(fileURLToPath(import.meta.url)));
25
- if (!found) return "0.0.0";
26
- const pkg = JSON.parse(readFileSync(found, "utf-8"));
27
- return pkg.version ?? "0.0.0";
30
+ return found ? dirname(found) : void 0;
31
+ } catch {
32
+ return void 0;
33
+ }
34
+ };
35
+ var packageVersionAt = (packageRoot) => {
36
+ try {
37
+ const manifest = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf-8"));
38
+ const version = manifest && typeof manifest === "object" && "version" in manifest ? manifest.version : void 0;
39
+ return typeof version === "string" ? version : void 0;
28
40
  } catch {
29
- return "0.0.0";
41
+ return void 0;
30
42
  }
31
43
  };
32
44
  var isNewerVersion = (candidate, current) => {
@@ -38,8 +50,16 @@ var isNewerVersion = (candidate, current) => {
38
50
  }
39
51
  return false;
40
52
  };
53
+ var RELEASE_VERSION = /^\d+\.\d+\.\d+$/;
54
+ var isReleaseVersion = (value) => RELEASE_VERSION.test(value);
55
+ var majorOf = (version) => parseInt(version.split(".")[0] ?? "", 10) || 0;
56
+ var isSameMajorVersion = (candidate, current) => majorOf(candidate) === majorOf(current);
41
57
 
42
58
  export {
43
59
  getPackageVersion,
44
- isNewerVersion
60
+ ownPackageRoot,
61
+ packageVersionAt,
62
+ isNewerVersion,
63
+ isReleaseVersion,
64
+ isSameMajorVersion
45
65
  };
@@ -1,26 +1,27 @@
1
1
  import {
2
2
  activeHookSource,
3
3
  activeIdentity
4
- } from "./chunk-HQLAZWJJ.js";
4
+ } from "./chunk-JF736N4C.js";
5
5
  import {
6
6
  blockedActionFingerprint,
7
7
  defersToNativeMode,
8
8
  forgetBlockedActionHint,
9
9
  hasBlockedActionHint,
10
- recordBlockedActionHint
11
- } from "./chunk-ALFT7H5B.js";
10
+ recordBlockedActionHint,
11
+ reportMachineDenial
12
+ } from "./chunk-CQYHOHOK.js";
12
13
  import {
13
14
  isGatingMoment,
14
15
  recordKeylessMoment
15
- } from "./chunk-SWFF5U2N.js";
16
+ } from "./chunk-43ZDACBO.js";
16
17
  import {
17
18
  denyReasonFrom,
18
19
  isDeferAnswer
19
20
  } from "./chunk-YHG74UFF.js";
20
21
  import {
21
- AUTO_DECISION_WINDOW_MS,
22
22
  DEFAULT_SESSION,
23
23
  UNNAMED_ACTION,
24
+ claimThrottle,
24
25
  deriveAction,
25
26
  deriveActionBody,
26
27
  deriveBlocker,
@@ -34,9 +35,8 @@ import {
34
35
  repoKeyFor,
35
36
  reportEvent,
36
37
  scopePathFor,
37
- settleQuestionsForToolUse,
38
- throttlePass
39
- } from "./chunk-LNGYW6G4.js";
38
+ settleQuestionsForToolUse
39
+ } from "./chunk-FDHMNT24.js";
40
40
  import {
41
41
  DECISION_STOP_REASON,
42
42
  askUser,
@@ -48,14 +48,14 @@ import {
48
48
  requestGate,
49
49
  sendNotification,
50
50
  waitForQuestion
51
- } from "./chunk-LGXUGYUH.js";
51
+ } from "./chunk-PYCQXCI5.js";
52
52
  import {
53
53
  getMachineId
54
- } from "./chunk-3T52B2OF.js";
54
+ } from "./chunk-UQHUUZ5H.js";
55
55
  import {
56
56
  getApiKey,
57
57
  getBaseUrl
58
- } from "./chunk-2UMNXADU.js";
58
+ } from "./chunk-OSJEMXSR.js";
59
59
  import {
60
60
  AGENT_QUESTION_STRATEGY,
61
61
  GATE_BLOCK_REASON_MAX_LENGTH,
@@ -75,13 +75,11 @@ import {
75
75
  isBlockedActionRequest,
76
76
  isPermissionRequestOwnedByPreToolUse,
77
77
  isPusharyOwnTool,
78
- machineDecisionFor,
79
78
  parseAgentQuestionAnswers,
80
79
  parseAgentQuestions,
81
80
  resolveGate,
82
- stoppedOutput,
83
- wireVerdictFor
84
- } from "./chunk-FVKFDTN6.js";
81
+ stoppedOutput
82
+ } from "./chunk-T4QY64OR.js";
85
83
 
86
84
  // src/decision-episode.ts
87
85
  var EPISODE_PATH = "/api/agent/decision-episode";
@@ -118,31 +116,6 @@ var deny = (reason) => claudePreToolUseOutput("deny", reason);
118
116
  var allowWithInput = (updatedInput) => claudePreToolUseOutput("allow", void 0, updatedInput);
119
117
  var ask = (reason) => claudePreToolUseOutput("ask", reason);
120
118
  var halted = (reason) => stoppedOutput(deny(reason), reason);
121
- var reportMachineDecision = async (input, verdict) => {
122
- const decision = machineDecisionFor(wireVerdictFor(verdict, 0));
123
- if (!decision) return;
124
- const sessionKey = input.session_id || DEFAULT_SESSION;
125
- const toolTarget = deriveToolTarget(input.tool_name, input.tool_input);
126
- const throttleKey = `machinedecision:${sessionKey}:${input.tool_name}:${decision.origin}:${toolTarget ?? ""}`;
127
- if (!throttlePass(throttleKey, AUTO_DECISION_WINDOW_MS)) return;
128
- await reportEvent(
129
- {
130
- event: "permission_denied",
131
- occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
132
- toolUseId: input.tool_use_id,
133
- agentType: ACTIVE_AGENT.type,
134
- agentName: agentNameIn(basename(input.cwd ?? process.cwd())),
135
- action: permissionDeniedAction(input.tool_name),
136
- sessionId: input.session_id,
137
- decisionSource: "policy_auto",
138
- decisionOrigin: decision.origin,
139
- decisionOutcome: decision.outcome,
140
- toolName: input.tool_name,
141
- toolTarget
142
- },
143
- { maxAttempts: 1, timeoutMs: 800 }
144
- ).catch(() => void 0);
145
- };
146
119
  var storedWaitDeadline = (result, requestedDeadline) => {
147
120
  const stored = result.waitEndsAt ? Date.parse(result.waitEndsAt) : Number.NaN;
148
121
  return Number.isFinite(stored) ? Math.min(stored, requestedDeadline) : requestedDeadline;
@@ -556,11 +529,11 @@ var handlePreToolUse = async (input, canonical) => {
556
529
  const gateInput = claudeGateInput(modeState, policy, input, canonical);
557
530
  const verdict = resolveGate(gateInput);
558
531
  if (verdict.kind === "kill") {
559
- await reportMachineDecision(input, verdict);
532
+ await reportMachineDenial(input, verdict, ACTIVE_AGENT);
560
533
  return halted(verdict.reason);
561
534
  }
562
535
  if (verdict.kind === "deny") {
563
- await reportMachineDecision(input, verdict);
536
+ await reportMachineDenial(input, verdict, ACTIVE_AGENT);
564
537
  return deny(verdict.reason);
565
538
  }
566
539
  if (canonical === null) return deny(unreadableReason);
@@ -618,11 +591,11 @@ var handlePermissionRequest = async (input, canonical) => {
618
591
  const policy = await getPolicy(apiKey, modeState.policyVersion, ACTIVE_AGENT.type, true, input.session_id);
619
592
  const verdict = resolveGate(claudeGateInput(modeState, policy, input, canonical));
620
593
  if (verdict.kind === "kill") {
621
- await reportMachineDecision(input, verdict);
594
+ await reportMachineDenial(input, verdict, ACTIVE_AGENT);
622
595
  return permReqHalted(verdict.reason);
623
596
  }
624
597
  if (verdict.kind === "deny") {
625
- await reportMachineDecision(input, verdict);
598
+ await reportMachineDenial(input, verdict, ACTIVE_AGENT);
626
599
  return permReqDeny(verdict.reason);
627
600
  }
628
601
  if (canonical === null) return permReqDeny(unreadableReason);
@@ -662,7 +635,7 @@ var PERMISSION_DENIED_NOTICE_WINDOW_MS = 5 * 60 * 1e3;
662
635
  var blockedActionHoldEndsAt = (holdBudgetSeconds) => START_MS + hookHoldWindowMs("claude", holdBudgetSeconds);
663
636
  var notifyPermissionDenied = async (apiKey, input) => {
664
637
  const sessionKey = input.session_id || DEFAULT_SESSION;
665
- if (!throttlePass(`permdenied:${sessionKey}:${input.tool_name}`, PERMISSION_DENIED_NOTICE_WINDOW_MS)) return;
638
+ if (claimThrottle(`permdenied:${sessionKey}:${input.tool_name}`, PERMISSION_DENIED_NOTICE_WINDOW_MS) !== "passed") return;
666
639
  const mode = await fetchModeState(apiKey, input.session_id).catch(() => null);
667
640
  if (mode?.kill || mode?.mode === "terminal_only") return;
668
641
  const projectName = basename(input.cwd ?? process.cwd());