@pushary/agent-hooks 0.85.0 → 0.85.2

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 (64) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/data/cursor-plugin/CHANGELOG.md +21 -0
  3. package/data/cursor-plugin/scripts/pushary-gate.mjs +54 -222
  4. package/data/cursor-plugin/scripts/pushary-gate.test.mjs +11 -106
  5. package/data/vscode-plugin/CHANGELOG.md +26 -0
  6. package/data/vscode-plugin/scripts/pushary-gate.mjs +66 -74
  7. package/dist/bin/pushary-bell-hook.js +4 -4
  8. package/dist/bin/pushary-bell.js +6 -6
  9. package/dist/bin/pushary-claude.js +12 -11
  10. package/dist/bin/pushary-clean.js +6 -6
  11. package/dist/bin/pushary-codex-bridge.js +5 -5
  12. package/dist/bin/pushary-codex-hook.js +9 -9
  13. package/dist/bin/pushary-codex.js +3 -3
  14. package/dist/bin/pushary-connect.js +6 -6
  15. package/dist/bin/pushary-daemon.js +4 -4
  16. package/dist/bin/pushary-disconnect.js +5 -5
  17. package/dist/bin/pushary-doctor.js +11 -11
  18. package/dist/bin/pushary-gemini-bridge.js +5 -5
  19. package/dist/bin/pushary-gemini-hook.js +17 -12
  20. package/dist/bin/pushary-hook.js +8 -8
  21. package/dist/bin/pushary-login.js +4 -4
  22. package/dist/bin/pushary-logout.js +4 -4
  23. package/dist/bin/pushary-mode.js +3 -3
  24. package/dist/bin/pushary-notification-hook.js +3 -3
  25. package/dist/bin/pushary-permission-denied-hook.js +8 -8
  26. package/dist/bin/pushary-permission-hook.js +8 -8
  27. package/dist/bin/pushary-post-hook.js +3 -3
  28. package/dist/bin/pushary-prompt-hook.js +3 -3
  29. package/dist/bin/pushary-session-end-hook.js +3 -3
  30. package/dist/bin/pushary-session-start-hook.js +3 -3
  31. package/dist/bin/pushary-setup.js +14 -14
  32. package/dist/bin/pushary-stats.js +2 -2
  33. package/dist/bin/pushary-status.js +5 -5
  34. package/dist/bin/pushary-stop-hook.js +3 -3
  35. package/dist/bin/pushary-stopfailure-hook.js +3 -3
  36. package/dist/bin/pushary-upgrade.js +6 -6
  37. package/dist/bin/pushary-wait.js +3 -3
  38. package/dist/{chunk-ADISVXZL.js → chunk-4U2YRHNF.js} +1 -1
  39. package/dist/{chunk-WEAQQSHQ.js → chunk-4YMWLMAP.js} +1 -1
  40. package/dist/{chunk-437T77TY.js → chunk-CWV4CMB6.js} +1 -1
  41. package/dist/{chunk-EXMUM226.js → chunk-DPDUB4XF.js} +62 -156
  42. package/dist/{chunk-7PZPJSWI.js → chunk-GM74DUMS.js} +1 -1
  43. package/dist/{chunk-DOXSWT4Q.js → chunk-GY3I353G.js} +6 -6
  44. package/dist/chunk-HSGEEBBL.js +37 -0
  45. package/dist/{chunk-ERYKGH4J.js → chunk-JBLRZGTT.js} +1 -1
  46. package/dist/{chunk-4QPOMJUB.js → chunk-JT5NQQCE.js} +2 -2
  47. package/dist/{chunk-MQMPG5X4.js → chunk-K337LIBD.js} +260 -10
  48. package/dist/{chunk-HVZIHTOO.js → chunk-KJW6NKF7.js} +7 -7
  49. package/dist/{chunk-K7CSRGKZ.js → chunk-KZIGJLOX.js} +1 -1
  50. package/dist/{chunk-6LC4WSCL.js → chunk-LCA2EQTK.js} +1 -1
  51. package/dist/{chunk-F52SIIDG.js → chunk-LSB6PFLN.js} +1 -1
  52. package/dist/{chunk-YKW6JCWI.js → chunk-LXWISFF3.js} +1 -1
  53. package/dist/{chunk-FBGBJXVC.js → chunk-NTIUQB3E.js} +1 -1
  54. package/dist/{chunk-NJ7JT26G.js → chunk-PKUNB3SN.js} +1 -1
  55. package/dist/{chunk-AXRATIS6.js → chunk-Q4URN3E7.js} +1 -1
  56. package/dist/{chunk-GCKAWHFP.js → chunk-T54OT7IY.js} +1 -1
  57. package/dist/{chunk-64PXDATC.js → chunk-XJDL3MUE.js} +17 -17
  58. package/dist/{chunk-GFM3STWO.js → chunk-Y7E2MC3G.js} +20 -49
  59. package/dist/chunk-YHG74UFF.js +12 -0
  60. package/dist/src/index.d.ts +7 -29
  61. package/dist/src/index.js +10 -9
  62. package/package.json +4 -2
  63. package/dist/chunk-GXIFADGD.js +0 -66
  64. package/dist/chunk-PWTKKQQI.js +0 -27
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-VT4IVERX.js";
8
8
  import {
9
9
  pusharyDir
10
- } from "./chunk-HVZIHTOO.js";
10
+ } from "./chunk-KJW6NKF7.js";
11
11
  import {
12
12
  getMachineId
13
13
  } from "./chunk-RN3NOEJF.js";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-2UMNXADU.js";
4
4
  import {
5
5
  normalizeInstallSource
6
- } from "./chunk-MQMPG5X4.js";
6
+ } from "./chunk-K337LIBD.js";
7
7
 
8
8
  // src/install-source.ts
9
9
  import { readFileSync } from "fs";
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-SAF6HGAA.js";
11
11
  import {
12
12
  reportedInstallSource
13
- } from "./chunk-437T77TY.js";
13
+ } from "./chunk-CWV4CMB6.js";
14
14
  import {
15
15
  getApiKey,
16
16
  getBaseUrl
@@ -18,19 +18,16 @@ import {
18
18
  import {
19
19
  ACTION_BODY_MAX,
20
20
  DECISION_LINE_MAX,
21
- classifyDecisionRisk,
22
- isApprovalMode,
21
+ gateOutputFor,
23
22
  isAutoApprove,
24
- isAutoDeny,
25
- isSafeReadOnlyCommand,
26
- isScopeContract,
27
23
  localRepoKey,
24
+ modeStateFromResponse,
28
25
  normalizeRepoRemote,
29
- policyArgForms,
30
26
  redactSecrets,
31
27
  redactSecretsDeep,
32
- selectGoverningRule
33
- } from "./chunk-MQMPG5X4.js";
28
+ resolveAutoResolveOrigin,
29
+ resolvePolicy
30
+ } from "./chunk-K337LIBD.js";
34
31
 
35
32
  // src/policy.ts
36
33
  import { createHash } from "crypto";
@@ -120,66 +117,6 @@ var getPolicy = async (apiKey, expectedVersion, agent, repoAware = false, sessio
120
117
  throw new Error("Failed to fetch policy and no cached policy available");
121
118
  }
122
119
  };
123
- var autoApprove = (tool) => ({
124
- tool,
125
- timeoutSeconds: 0,
126
- timeoutAction: "approve",
127
- mode: "terminal_only",
128
- pushFirstSeconds: 0
129
- });
130
- var resolveAutoResolveOrigin = (config, toolName, toolInput, cwd, repoKey, sessionId) => {
131
- const args = toolInput ? policyArgForms(toolName, toolInput, cwd) : [];
132
- const arg = args[0];
133
- const match = selectGoverningRule(config.policies, toolName, args, repoKey, sessionId);
134
- const governedBySpecificRule = match?.rank === "exact" || match?.rank === "prefix";
135
- if (!governedBySpecificRule && toolName === "Bash" && typeof arg === "string" && isSafeReadOnlyCommand(arg)) {
136
- return "safe_readonly";
137
- }
138
- return "policy_timeout";
139
- };
140
- var resolvePolicy = (config, toolName, modeOverride, toolInput, cwd, repoKey, sessionId) => {
141
- const args = toolInput ? policyArgForms(toolName, toolInput, cwd) : [];
142
- const arg = args[0];
143
- const match = selectGoverningRule(config.policies, toolName, args, repoKey, sessionId);
144
- let base = match?.policy ?? config.policies.find((p) => p.tool === "*") ?? {
145
- tool: toolName,
146
- timeoutSeconds: config.defaultTimeoutSeconds,
147
- timeoutAction: config.defaultTimeoutAction,
148
- mode: config.defaultMode ?? "push_first",
149
- pushFirstSeconds: config.defaultPushFirstSeconds ?? 20
150
- };
151
- const governedBySpecificRule = match?.rank === "exact" || match?.rank === "prefix";
152
- if (!governedBySpecificRule && toolName === "Bash" && typeof arg === "string" && isSafeReadOnlyCommand(arg)) {
153
- base = autoApprove(base.tool);
154
- }
155
- const wouldAutoApprove = isAutoApprove(base);
156
- if (!governedBySpecificRule && wouldAutoApprove && toolName === "Bash" && typeof arg === "string" && classifyDecisionRisk(toolName, arg) === "destructive") {
157
- base = {
158
- tool: base.tool,
159
- timeoutSeconds: config.defaultTimeoutSeconds,
160
- timeoutAction: "wait",
161
- mode: "push_first",
162
- pushFirstSeconds: config.defaultPushFirstSeconds ?? 20
163
- };
164
- }
165
- const effectiveOverride = modeOverride ?? config.modeOverride;
166
- if (effectiveOverride) {
167
- return { ...base, mode: effectiveOverride };
168
- }
169
- return base;
170
- };
171
- var restraintRank = (policy) => {
172
- if (isAutoDeny(policy)) return 4;
173
- if (isAutoApprove(policy)) return 0;
174
- if (policy.mode === "push_only") return 3;
175
- return policy.mode === "terminal_only" || policy.mode === "notify_only" ? 1 : 2;
176
- };
177
- var strictestPolicy = (a, b) => restraintRank(b) > restraintRank(a) ? b : a;
178
- var resolvePolicyAcross = (config, toolName, modeOverride, toolInputs, cwd, repoKey, sessionId) => {
179
- if (toolInputs.length === 0) return resolvePolicy(config, toolName, modeOverride, void 0, cwd, repoKey, sessionId);
180
- return toolInputs.map((input) => resolvePolicy(config, toolName, modeOverride, input, cwd, repoKey, sessionId)).reduce(strictestPolicy);
181
- };
182
- var isModeStateDegraded = (state) => state?.degraded === true;
183
120
  var MODE_GRACE_MS = 60 * 1e3;
184
121
  var modeStateCacheFile = (apiKey) => {
185
122
  const hash = createHash("sha256").update(`mode:${apiKey}`).digest("hex").slice(0, 12);
@@ -220,7 +157,6 @@ var degradedFallback = (apiKey, authoritative = false) => {
220
157
  }
221
158
  return unknownMode();
222
159
  };
223
- var toPolicyVersion = (value) => typeof value === "string" || typeof value === "number" ? String(value) : null;
224
160
  var MODE_REUSE_MS = CACHE_TTL_MS;
225
161
  var readReusableMode = (apiKey, sessionId, maxAgeMs) => {
226
162
  const last = readLastGoodMode(apiKey);
@@ -243,19 +179,7 @@ var fetchModeState = async (apiKey, sessionId, reuseWithinMs = 0) => {
243
179
  if (!response.ok) {
244
180
  return degradedFallback(apiKey, response.status === 401 || response.status === 403);
245
181
  }
246
- const data = await response.json();
247
- const mode = data.override?.mode;
248
- const state = {
249
- mode: isApprovalMode(mode) ? mode : null,
250
- kill: data.kill === true,
251
- policyVersion: toPolicyVersion(data.policyVersion),
252
- relayUrl: typeof data.relayUrl === "string" && data.relayUrl.length > 0 ? data.relayUrl : null,
253
- trainingConsent: data.trainingConsent === true,
254
- // Validated rather than cast: a malformed contract must read as no contract,
255
- // never as one that silently matches nothing.
256
- scope: isScopeContract(data.scope) ? data.scope : null,
257
- degraded: false
258
- };
182
+ const state = modeStateFromResponse(await response.json());
259
183
  writeLastGoodMode(apiKey, state, sessionId);
260
184
  return state;
261
185
  } catch {
@@ -265,9 +189,11 @@ var fetchModeState = async (apiKey, sessionId, reuseWithinMs = 0) => {
265
189
  var fetchModeOverride = async (apiKey) => (await fetchModeState(apiKey)).mode;
266
190
 
267
191
  // src/api.ts
192
+ import { randomUUID } from "crypto";
268
193
  installProxyDispatcher();
269
194
  var askUser = async (apiKey, params, timeoutMs = 15e3) => {
270
- const result = await callMcpTool(apiKey, "ask_user", { ...params, wait: false }, { maxRetries: 3, timeoutMs });
195
+ const identified = params.toolUseId || params.requestId ? params : { ...params, requestId: randomUUID() };
196
+ const result = await callMcpTool(apiKey, "ask_user", { ...identified, wait: false }, { maxRetries: 3, timeoutMs });
271
197
  if (!isAskUserResponse(result)) throw new Error("Invalid ask_user response");
272
198
  return result;
273
199
  };
@@ -286,7 +212,7 @@ var sendNotification = async (apiKey, params, timeoutMs = 15e3) => {
286
212
  await callMcpTool(apiKey, "send_notification", { ...params }, { maxRetries: 3, timeoutMs });
287
213
  };
288
214
 
289
- // src/describe.ts
215
+ // ../hook-mapping/src/describe.ts
290
216
  import { isAbsolute, relative } from "path";
291
217
  var hookPrefixes = {
292
218
  Bash: (input) => `bash: ${input.command ?? "(no command)"}`,
@@ -455,6 +381,36 @@ var deriveBlocker = (mode, reason) => {
455
381
  return text.slice(0, DECISION_LINE_MAX);
456
382
  };
457
383
 
384
+ // ../hook-mapping/src/map.ts
385
+ import { basename } from "path";
386
+ var TASK_TITLE_MAX_LENGTH = 120;
387
+ var STOP_SUMMARY_MAX_LENGTH = 200;
388
+ var SESSION_END_ACTIONS = {
389
+ clear: "Session cleared",
390
+ logout: "Logged out",
391
+ resume: "Session suspended",
392
+ prompt_input_exit: "Session ended",
393
+ bypass_permissions_disabled: "Session ended",
394
+ other: "Session ended"
395
+ };
396
+ var countArray = (value) => Array.isArray(value) ? value.length : 0;
397
+ var summarizeFinalMessage = (message) => {
398
+ if (typeof message !== "string") return "Session ended";
399
+ const collapsed = message.replace(/\s+/g, " ").trim();
400
+ if (!collapsed) return "Session ended";
401
+ return collapsed.slice(0, STOP_SUMMARY_MAX_LENGTH);
402
+ };
403
+ var summarizeStop = (input) => {
404
+ const running = countArray(input.background_tasks);
405
+ if (running > 0) return `Paused with ${running} background task${running === 1 ? "" : "s"} still running`;
406
+ const crons = countArray(input.session_crons);
407
+ if (crons > 0) return `Idle until a scheduled task wakes it (${crons} pending)`;
408
+ return summarizeFinalMessage(input.last_assistant_message);
409
+ };
410
+ var sessionStartAction = (source) => source === "resume" ? "Session resumed" : "Session started";
411
+ var sessionEndAction = (reason) => typeof reason === "string" && SESSION_END_ACTIONS[reason] || "Session ended";
412
+ var taskTitleFrom = (prompt) => typeof prompt === "string" ? prompt.replace(/\s+/g, " ").trim().slice(0, TASK_TITLE_MAX_LENGTH) || void 0 : void 0;
413
+
458
414
  // src/pending.ts
459
415
  import { join as join2 } from "path";
460
416
  import { tmpdir as tmpdir2 } from "os";
@@ -503,7 +459,7 @@ var removePendingSession = (sessionId) => {
503
459
 
504
460
  // src/repo.ts
505
461
  import { existsSync as existsSync3, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
506
- import { basename, dirname, isAbsolute as isAbsolute2, join as join3, resolve } from "path";
462
+ import { basename as basename2, dirname, isAbsolute as isAbsolute2, join as join3, resolve } from "path";
507
463
  var MAX_PARENT_WALK = 64;
508
464
  var GIT_FILE_PREFIX = "gitdir:";
509
465
  var findGitDir = (startDir) => {
@@ -562,9 +518,9 @@ var deriveRepoKey = (cwd) => {
562
518
  const normalized = remote ? normalizeRepoRemote(remote) : void 0;
563
519
  if (normalized) return normalized;
564
520
  const root = gitDir.endsWith(".git") ? dirname(gitDir) : dir;
565
- return localRepoKey(basename(root));
521
+ return localRepoKey(basename2(root));
566
522
  }
567
- return localRepoKey(basename(resolve(dir)));
523
+ return localRepoKey(basename2(resolve(dir)));
568
524
  } catch {
569
525
  return void 0;
570
526
  }
@@ -763,35 +719,13 @@ var codexAllow = () => ({ kind: "allow" });
763
719
  var codexDeny = (reason) => ({ kind: "deny", reason });
764
720
  var codexPass = () => ({ kind: "pass" });
765
721
  var toCodexWire = (event, decision) => {
766
- if (event === "PermissionRequest") {
767
- if (decision.kind === "allow") {
768
- return {
769
- hookSpecificOutput: {
770
- hookEventName: "PermissionRequest",
771
- decision: { behavior: "allow" }
772
- }
773
- };
774
- }
775
- if (decision.kind === "deny") {
776
- return {
777
- hookSpecificOutput: {
778
- hookEventName: "PermissionRequest",
779
- decision: { behavior: "deny", message: decision.reason }
780
- }
781
- };
782
- }
783
- return null;
784
- }
785
- if (event === "PreToolUse" && decision.kind === "deny") {
786
- return {
787
- hookSpecificOutput: {
788
- hookEventName: "PreToolUse",
789
- permissionDecision: "deny",
790
- permissionDecisionReason: decision.reason
791
- }
792
- };
793
- }
794
- return null;
722
+ if (decision.kind === "pass") return null;
723
+ return gateOutputFor(
724
+ "codex",
725
+ event,
726
+ decision.kind,
727
+ decision.kind === "deny" ? decision.reason : void 0
728
+ ) ?? null;
795
729
  };
796
730
  var parseApplyPatchOps = (command) => {
797
731
  if (typeof command !== "string") return [];
@@ -869,7 +803,7 @@ var throttlePass = (key, windowMs) => {
869
803
  };
870
804
 
871
805
  // src/events.ts
872
- import { basename as basename2, join as join6 } from "path";
806
+ import { basename as basename3, join as join6 } from "path";
873
807
  import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync4, statSync as statSync5, writeFileSync as writeFileSync5 } from "fs";
874
808
  import { tmpdir as tmpdir5 } from "os";
875
809
  var INTENT_DIR = join6(tmpdir5(), "pushary-intent");
@@ -1058,7 +992,7 @@ var reportEvent = async (event, options = {}) => {
1058
992
  var NON_GATED_MIRROR_TOOLS = /* @__PURE__ */ new Set(["TodoWrite"]);
1059
993
  var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
1060
994
  try {
1061
- const projectName = basename2(input.cwd ?? process.cwd());
995
+ const projectName = basename3(input.cwd ?? process.cwd());
1062
996
  const action = describeToolCall(input.tool_name, input.tool_input, "event");
1063
997
  const lookup = toPolicyLookup(input.tool_name, input.tool_input);
1064
998
  const toolResult = input.tool_response ?? input.tool_result;
@@ -1110,13 +1044,12 @@ var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
1110
1044
  return void 0;
1111
1045
  }
1112
1046
  };
1113
- var TASK_TITLE_MAX_LENGTH = 120;
1114
1047
  var handleUserPrompt = async (input, agent = CLAUDE_CODE_AGENT) => {
1115
1048
  try {
1116
- const projectName = basename2(input.cwd ?? process.cwd());
1049
+ const projectName = basename3(input.cwd ?? process.cwd());
1117
1050
  const sessionKey = input.session_id || DEFAULT_SESSION;
1118
1051
  const titlesEnabled = process.env.PUSHARY_TASK_TITLES !== "off";
1119
- const taskTitle = titlesEnabled ? input.prompt?.replace(/\s+/g, " ").trim().slice(0, TASK_TITLE_MAX_LENGTH) || void 0 : void 0;
1052
+ const taskTitle = titlesEnabled ? taskTitleFrom(input.prompt) : void 0;
1120
1053
  if (input.prompt) saveLastPrompt(sessionKey, input.prompt);
1121
1054
  const late = await reconcilePendingQuestions(sessionKey);
1122
1055
  let additionalContext;
@@ -1141,24 +1074,9 @@ var handleUserPrompt = async (input, agent = CLAUDE_CODE_AGENT) => {
1141
1074
  return void 0;
1142
1075
  }
1143
1076
  };
1144
- var STOP_SUMMARY_MAX_LENGTH = 200;
1145
- var summarizeFinalMessage = (message) => {
1146
- if (typeof message !== "string") return "Session ended";
1147
- const collapsed = message.replace(/\s+/g, " ").trim();
1148
- if (!collapsed) return "Session ended";
1149
- return collapsed.slice(0, STOP_SUMMARY_MAX_LENGTH);
1150
- };
1151
- var countArray = (value) => Array.isArray(value) ? value.length : 0;
1152
- var summarizeStop = (input) => {
1153
- const running = countArray(input.background_tasks);
1154
- if (running > 0) return `Paused with ${running} background task${running === 1 ? "" : "s"} still running`;
1155
- const crons = countArray(input.session_crons);
1156
- if (crons > 0) return `Idle until a scheduled task wakes it (${crons} pending)`;
1157
- return summarizeFinalMessage(input.last_assistant_message);
1158
- };
1159
1077
  var handleStop = async (input, agent = CLAUDE_CODE_AGENT) => {
1160
1078
  try {
1161
- const projectName = basename2(input.cwd ?? process.cwd());
1079
+ const projectName = basename3(input.cwd ?? process.cwd());
1162
1080
  const sessionKey = input.session_id || DEFAULT_SESSION;
1163
1081
  const late = await reconcilePendingQuestions(sessionKey);
1164
1082
  const tasks = [
@@ -1194,8 +1112,8 @@ var handleStop = async (input, agent = CLAUDE_CODE_AGENT) => {
1194
1112
  };
1195
1113
  var handleSessionStart = async (input, agent = CLAUDE_CODE_AGENT) => {
1196
1114
  try {
1197
- const projectName = basename2(input.cwd ?? process.cwd());
1198
- const action = input.source === "resume" ? "Session resumed" : "Session started";
1115
+ const projectName = basename3(input.cwd ?? process.cwd());
1116
+ const action = sessionStartAction(input.source);
1199
1117
  await reportEvent({
1200
1118
  event: "session_start",
1201
1119
  agentType: agent.type,
@@ -1206,18 +1124,10 @@ var handleSessionStart = async (input, agent = CLAUDE_CODE_AGENT) => {
1206
1124
  } catch {
1207
1125
  }
1208
1126
  };
1209
- var SESSION_END_ACTIONS = {
1210
- clear: "Session cleared",
1211
- logout: "Logged out",
1212
- resume: "Session suspended",
1213
- prompt_input_exit: "Session ended",
1214
- bypass_permissions_disabled: "Session ended",
1215
- other: "Session ended"
1216
- };
1217
1127
  var handleSessionEnd = async (input, agent = CLAUDE_CODE_AGENT) => {
1218
1128
  try {
1219
- const projectName = basename2(input.cwd ?? process.cwd());
1220
- const action = typeof input.reason === "string" && SESSION_END_ACTIONS[input.reason] || "Session ended";
1129
+ const projectName = basename3(input.cwd ?? process.cwd());
1130
+ const action = sessionEndAction(input.reason);
1221
1131
  const sessionKey = input.session_id || DEFAULT_SESSION;
1222
1132
  const late = await reconcilePendingQuestions(sessionKey);
1223
1133
  if (late.length > 0) {
@@ -1240,7 +1150,7 @@ var NOTIFICATION_PUSH_TYPES = /* @__PURE__ */ new Set(["idle_prompt", "agent_nee
1240
1150
  var NOTIFICATION_THROTTLE_MS = 60 * 1e3;
1241
1151
  var handleNotification = async (input, agent = CLAUDE_CODE_AGENT) => {
1242
1152
  try {
1243
- const projectName = basename2(input.cwd ?? process.cwd());
1153
+ const projectName = basename3(input.cwd ?? process.cwd());
1244
1154
  const notifType = input.notification_type ?? input.type ?? "";
1245
1155
  const sessionKey = input.session_id || DEFAULT_SESSION;
1246
1156
  if (NOTIFICATION_PUSH_TYPES.has(notifType)) {
@@ -1313,7 +1223,7 @@ var handleStopFailure = async (input, agent = CLAUDE_CODE_AGENT) => {
1313
1223
  } catch {
1314
1224
  return;
1315
1225
  }
1316
- const projectName = basename2(input.cwd ?? process.cwd());
1226
+ const projectName = basename3(input.cwd ?? process.cwd());
1317
1227
  const mode = await fetchModeState(apiKey, input.session_id, MODE_REUSE_MS).catch(() => null);
1318
1228
  if (mode?.kill || mode?.mode === "terminal_only") return;
1319
1229
  const reason = describeStopFailure(input.error);
@@ -1332,10 +1242,6 @@ var handleStopFailure = async (input, agent = CLAUDE_CODE_AGENT) => {
1332
1242
  export {
1333
1243
  policyRequestFor,
1334
1244
  getPolicy,
1335
- resolveAutoResolveOrigin,
1336
- resolvePolicy,
1337
- resolvePolicyAcross,
1338
- isModeStateDegraded,
1339
1245
  fetchModeState,
1340
1246
  fetchModeOverride,
1341
1247
  askUser,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  readConfigFileKey
3
- } from "./chunk-K7CSRGKZ.js";
3
+ } from "./chunk-KZIGJLOX.js";
4
4
 
5
5
  // src/bell/fleet.ts
6
6
  import { closeSync, constants, futimesSync, lstatSync, mkdirSync, openSync, readdirSync, unlinkSync } from "fs";
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  HOOK_BUDGETS
3
- } from "./chunk-MQMPG5X4.js";
3
+ } from "./chunk-K337LIBD.js";
4
4
 
5
5
  // src/gemini-config.ts
6
6
  var GEMINI_HOOK_BINARY = "pushary-gemini-hook";
7
7
  var GEMINI_MCP_URL = "https://pushary.com/api/mcp/mcp";
8
8
  var GEMINI_HOOK_EVENTS = [
9
- { event: "BeforeTool", matcher: "run_shell_command|write_file|replace", timeoutMs: HOOK_BUDGETS.gemini.budgetSeconds * 1e3 },
10
- { event: "AfterTool", matcher: "run_shell_command|write_file|replace", timeoutMs: 1e4 },
11
- { event: "BeforeAgent", timeoutMs: 1e4 },
12
- { event: "SessionStart", timeoutMs: 1e4 },
13
- { event: "SessionEnd", timeoutMs: 1e4 }
9
+ { event: "BeforeTool", matcher: "run_shell_command|write_file|replace", delivery: "approval", timeoutMs: HOOK_BUDGETS.gemini.budgetSeconds * 1e3 },
10
+ { event: "AfterTool", matcher: "run_shell_command|write_file|replace", delivery: "telemetry", timeoutMs: 1e4 },
11
+ { event: "BeforeAgent", delivery: "telemetry", timeoutMs: 1e4 },
12
+ { event: "SessionStart", delivery: "telemetry", timeoutMs: 1e4 },
13
+ { event: "SessionEnd", delivery: "telemetry", timeoutMs: 1e4 }
14
14
  ];
15
15
  var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
16
16
  var ensureRecord = (target, key) => {
@@ -0,0 +1,37 @@
1
+ import {
2
+ quoteIfNeeded
3
+ } from "./chunk-VT4IVERX.js";
4
+
5
+ // src/hook-command.ts
6
+ var HOOK_SHELL = "/bin/sh -c";
7
+ var LOCATE = 'B=$(command -v "$0") || exit 0; [ -f "$B" ] || exit 0; [ -x "$B" ] || exit 0';
8
+ var NODE_PRESENT = "command -v node >/dev/null 2>&1 || exit 0";
9
+ var HOOK_GUARD_SCRIPTS = {
10
+ native_binary: `${LOCATE}; exec "$B"`,
11
+ node_binary: `${LOCATE}; ${NODE_PRESENT}; exec "$B"`,
12
+ node_script: `[ -f "$0" ] || exit 0; ${NODE_PRESENT}; exec node "$0"`
13
+ };
14
+ var BINARY_GUARDS = {
15
+ native: "native_binary",
16
+ node: "node_binary"
17
+ };
18
+ var guardKindOf = (target) => {
19
+ switch (target.kind) {
20
+ case "node":
21
+ return "node_script";
22
+ case "binary":
23
+ return BINARY_GUARDS[target.runtime];
24
+ }
25
+ };
26
+ var guardHookCommand = (target, platform = process.platform) => {
27
+ const path = quoteIfNeeded(target.kind === "node" ? target.script : target.path);
28
+ if (platform === "win32") return target.kind === "node" ? `node ${path}` : path;
29
+ return `${HOOK_SHELL} '${HOOK_GUARD_SCRIPTS[guardKindOf(target)]}' ${path}`;
30
+ };
31
+ var guardBinary = (path, platform) => guardHookCommand({ kind: "binary", path, runtime: "node" }, platform);
32
+ var guardNodeScript = (script, platform) => guardHookCommand({ kind: "node", script }, platform);
33
+
34
+ export {
35
+ guardBinary,
36
+ guardNodeScript
37
+ };
@@ -5,7 +5,7 @@ import {
5
5
  generateSessionKey,
6
6
  uploadTranscriptRecords,
7
7
  wrapSessionKey
8
- } from "./chunk-GCKAWHFP.js";
8
+ } from "./chunk-T54OT7IY.js";
9
9
 
10
10
  // src/live-session.ts
11
11
  var MAX_TRANSCRIPT_QUEUE = 100;
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  hasGeminiHooks
3
- } from "./chunk-DOXSWT4Q.js";
3
+ } from "./chunk-GY3I353G.js";
4
4
  import {
5
5
  hasCodexHooks
6
- } from "./chunk-HVZIHTOO.js";
6
+ } from "./chunk-KJW6NKF7.js";
7
7
 
8
8
  // src/diagnostics/wiring.ts
9
9
  var record = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;