@pushary/agent-hooks 0.54.1 → 0.55.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.
@@ -16,14 +16,14 @@ import {
16
16
  reportEvent,
17
17
  resolvePolicy,
18
18
  waitForAnswer
19
- } from "../chunk-SWNBIHDX.js";
19
+ } from "../chunk-H6RGO7DN.js";
20
20
  import {
21
21
  getMachineId
22
22
  } from "../chunk-RN3NOEJF.js";
23
23
  import "../chunk-DWED7BS3.js";
24
24
  import {
25
25
  redactSecrets
26
- } from "../chunk-SY3NBF67.js";
26
+ } from "../chunk-P5VOLS3Q.js";
27
27
  import {
28
28
  getApiKey,
29
29
  getBaseUrl
@@ -529,7 +529,7 @@ var createRemoteApprover = (deps) => {
529
529
  const modeState = await fetchModeState2(deps.apiKey, sessionId);
530
530
  if (modeState.kill) return deny("Stopped by user \u2014 this agent was halted from Pushary");
531
531
  const policyConfig = await getPolicy2(deps.apiKey, modeState.policyVersion, "claude_code");
532
- const policy = resolvePolicy2(policyConfig, toolName, modeState.mode, input);
532
+ const policy = resolvePolicy2(policyConfig, toolName, modeState.mode, input, deps.cwd);
533
533
  if (policy.timeoutSeconds === 0 && policy.timeoutAction === "approve") return allow(input);
534
534
  if (policy.timeoutSeconds === 0 && policy.timeoutAction === "deny") {
535
535
  return deny(`Denied by policy for ${policy.tool}`);
@@ -1341,6 +1341,7 @@ var runDualMode = async (binary, args2, startingMode) => {
1341
1341
  apiKey,
1342
1342
  machineId,
1343
1343
  projectName,
1344
+ cwd: process.cwd(),
1344
1345
  getSessionId: () => sessionId
1345
1346
  });
1346
1347
  const initialModeState = await fetchModeState(apiKey).catch(() => null);
@@ -6,15 +6,15 @@ import {
6
6
  removeCodexHooks,
7
7
  removeGeminiSettings,
8
8
  removeInstructionBlock
9
- } from "../chunk-PZWZ77QH.js";
9
+ } from "../chunk-2VW2FEYC.js";
10
10
  import {
11
11
  execNpm
12
12
  } from "../chunk-J7JWI3KU.js";
13
13
  import {
14
14
  removeClaudeMcpServers,
15
15
  removePusharySettings
16
- } from "../chunk-T2EEBR2D.js";
17
- import "../chunk-SY3NBF67.js";
16
+ } from "../chunk-PSZAXNUB.js";
17
+ import "../chunk-P5VOLS3Q.js";
18
18
 
19
19
  // bin/pushary-clean.ts
20
20
  import { existsSync, readFileSync, writeFileSync, rmSync, readdirSync } from "fs";
@@ -31,21 +31,21 @@ import {
31
31
  toCodexWire,
32
32
  toPolicyLookup,
33
33
  waitForAnswer
34
- } from "../chunk-SWNBIHDX.js";
34
+ } from "../chunk-H6RGO7DN.js";
35
35
  import {
36
36
  getMachineId
37
37
  } from "../chunk-RN3NOEJF.js";
38
38
  import {
39
39
  isGatingMoment,
40
40
  recordKeylessMoment
41
- } from "../chunk-WYQSLB7K.js";
41
+ } from "../chunk-UXIAIMSS.js";
42
42
  import "../chunk-DWED7BS3.js";
43
43
  import {
44
44
  DECISION_LINE_MAX,
45
45
  effectiveWaitSeconds,
46
46
  hookWaitClamped,
47
47
  hookWaitDeadline
48
- } from "../chunk-SY3NBF67.js";
48
+ } from "../chunk-P5VOLS3Q.js";
49
49
  import {
50
50
  getApiKey
51
51
  } from "../chunk-NKXSILEW.js";
@@ -3,12 +3,12 @@ import {
3
3
  askUser,
4
4
  reportEvent,
5
5
  waitForAnswer
6
- } from "../chunk-SWNBIHDX.js";
6
+ } from "../chunk-H6RGO7DN.js";
7
7
  import {
8
8
  getMachineId
9
9
  } from "../chunk-RN3NOEJF.js";
10
10
  import "../chunk-DWED7BS3.js";
11
- import "../chunk-SY3NBF67.js";
11
+ import "../chunk-P5VOLS3Q.js";
12
12
  import {
13
13
  getApiKey
14
14
  } from "../chunk-NKXSILEW.js";
@@ -11,18 +11,18 @@ import {
11
11
  missingGeminiHookEvents,
12
12
  readCodexMcpAuth,
13
13
  untrustedCodexHookEvents
14
- } from "../chunk-PZWZ77QH.js";
14
+ } from "../chunk-2VW2FEYC.js";
15
15
  import {
16
16
  execNpm
17
17
  } from "../chunk-J7JWI3KU.js";
18
18
  import {
19
19
  readLedgerSummary
20
- } from "../chunk-WYQSLB7K.js";
20
+ } from "../chunk-UXIAIMSS.js";
21
21
  import {
22
22
  callMcpTool,
23
23
  sendMcpRequest
24
24
  } from "../chunk-DWED7BS3.js";
25
- import "../chunk-SY3NBF67.js";
25
+ import "../chunk-P5VOLS3Q.js";
26
26
  import {
27
27
  getBaseUrl
28
28
  } from "../chunk-NKXSILEW.js";
@@ -23,21 +23,21 @@ import {
23
23
  savePendingQuestion,
24
24
  sendNotification,
25
25
  waitForAnswer
26
- } from "../chunk-SWNBIHDX.js";
26
+ } from "../chunk-H6RGO7DN.js";
27
27
  import {
28
28
  getMachineId
29
29
  } from "../chunk-RN3NOEJF.js";
30
30
  import {
31
31
  isGatingMoment,
32
32
  recordKeylessMoment
33
- } from "../chunk-WYQSLB7K.js";
33
+ } from "../chunk-UXIAIMSS.js";
34
34
  import "../chunk-DWED7BS3.js";
35
35
  import {
36
36
  DECISION_LINE_MAX,
37
37
  effectiveWaitSeconds,
38
38
  hookWaitClamped,
39
39
  hookWaitDeadline
40
- } from "../chunk-SY3NBF67.js";
40
+ } from "../chunk-P5VOLS3Q.js";
41
41
  import {
42
42
  getApiKey
43
43
  } from "../chunk-NKXSILEW.js";
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePreToolUse
4
- } from "../chunk-SVRDT5PP.js";
5
- import "../chunk-T2EEBR2D.js";
4
+ } from "../chunk-XKXF2G7T.js";
5
+ import "../chunk-PSZAXNUB.js";
6
6
  import "../chunk-YHG74UFF.js";
7
- import "../chunk-SWNBIHDX.js";
7
+ import "../chunk-H6RGO7DN.js";
8
8
  import "../chunk-RN3NOEJF.js";
9
- import "../chunk-WYQSLB7K.js";
9
+ import "../chunk-UXIAIMSS.js";
10
10
  import "../chunk-DWED7BS3.js";
11
- import "../chunk-SY3NBF67.js";
11
+ import "../chunk-P5VOLS3Q.js";
12
12
  import "../chunk-NKXSILEW.js";
13
13
 
14
14
  // bin/pushary-hook.ts
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleNotification
4
- } from "../chunk-SWNBIHDX.js";
4
+ } from "../chunk-H6RGO7DN.js";
5
5
  import "../chunk-RN3NOEJF.js";
6
6
  import "../chunk-DWED7BS3.js";
7
- import "../chunk-SY3NBF67.js";
7
+ import "../chunk-P5VOLS3Q.js";
8
8
  import "../chunk-NKXSILEW.js";
9
9
 
10
10
  // bin/pushary-notification-hook.ts
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePermissionDenied
4
- } from "../chunk-SVRDT5PP.js";
5
- import "../chunk-T2EEBR2D.js";
4
+ } from "../chunk-XKXF2G7T.js";
5
+ import "../chunk-PSZAXNUB.js";
6
6
  import "../chunk-YHG74UFF.js";
7
- import "../chunk-SWNBIHDX.js";
7
+ import "../chunk-H6RGO7DN.js";
8
8
  import "../chunk-RN3NOEJF.js";
9
- import "../chunk-WYQSLB7K.js";
9
+ import "../chunk-UXIAIMSS.js";
10
10
  import "../chunk-DWED7BS3.js";
11
- import "../chunk-SY3NBF67.js";
11
+ import "../chunk-P5VOLS3Q.js";
12
12
  import "../chunk-NKXSILEW.js";
13
13
 
14
14
  // bin/pushary-permission-denied-hook.ts
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePermissionRequest
4
- } from "../chunk-SVRDT5PP.js";
5
- import "../chunk-T2EEBR2D.js";
4
+ } from "../chunk-XKXF2G7T.js";
5
+ import "../chunk-PSZAXNUB.js";
6
6
  import "../chunk-YHG74UFF.js";
7
- import "../chunk-SWNBIHDX.js";
7
+ import "../chunk-H6RGO7DN.js";
8
8
  import "../chunk-RN3NOEJF.js";
9
- import "../chunk-WYQSLB7K.js";
9
+ import "../chunk-UXIAIMSS.js";
10
10
  import "../chunk-DWED7BS3.js";
11
- import "../chunk-SY3NBF67.js";
11
+ import "../chunk-P5VOLS3Q.js";
12
12
  import "../chunk-NKXSILEW.js";
13
13
 
14
14
  // bin/pushary-permission-hook.ts
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePostToolUse
4
- } from "../chunk-SWNBIHDX.js";
4
+ } from "../chunk-H6RGO7DN.js";
5
5
  import "../chunk-RN3NOEJF.js";
6
6
  import "../chunk-DWED7BS3.js";
7
- import "../chunk-SY3NBF67.js";
7
+ import "../chunk-P5VOLS3Q.js";
8
8
  import "../chunk-NKXSILEW.js";
9
9
 
10
10
  // bin/pushary-post-hook.ts
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleUserPrompt
4
- } from "../chunk-SWNBIHDX.js";
4
+ } from "../chunk-H6RGO7DN.js";
5
5
  import "../chunk-RN3NOEJF.js";
6
6
  import "../chunk-DWED7BS3.js";
7
- import "../chunk-SY3NBF67.js";
7
+ import "../chunk-P5VOLS3Q.js";
8
8
  import "../chunk-NKXSILEW.js";
9
9
 
10
10
  // bin/pushary-prompt-hook.ts
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleSessionEnd
4
- } from "../chunk-SWNBIHDX.js";
4
+ } from "../chunk-H6RGO7DN.js";
5
5
  import "../chunk-RN3NOEJF.js";
6
6
  import "../chunk-DWED7BS3.js";
7
- import "../chunk-SY3NBF67.js";
7
+ import "../chunk-P5VOLS3Q.js";
8
8
  import "../chunk-NKXSILEW.js";
9
9
 
10
10
  // bin/pushary-session-end-hook.ts
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleSessionStart
4
- } from "../chunk-SWNBIHDX.js";
4
+ } from "../chunk-H6RGO7DN.js";
5
5
  import "../chunk-RN3NOEJF.js";
6
6
  import "../chunk-DWED7BS3.js";
7
- import "../chunk-SY3NBF67.js";
7
+ import "../chunk-P5VOLS3Q.js";
8
8
  import "../chunk-NKXSILEW.js";
9
9
 
10
10
  // bin/pushary-session-start-hook.ts
@@ -13,7 +13,7 @@ import {
13
13
  renderAgentInstructions,
14
14
  renderProjectAgentInstructions,
15
15
  writeInstructionBlock
16
- } from "../chunk-PZWZ77QH.js";
16
+ } from "../chunk-2VW2FEYC.js";
17
17
  import {
18
18
  execNpm,
19
19
  npmErrorMessage,
@@ -25,15 +25,15 @@ import {
25
25
  addClaudeMcpServer,
26
26
  addPusharyHooks,
27
27
  addPusharyToolPermissions
28
- } from "../chunk-T2EEBR2D.js";
28
+ } from "../chunk-PSZAXNUB.js";
29
29
  import {
30
30
  reportEvent
31
- } from "../chunk-SWNBIHDX.js";
31
+ } from "../chunk-H6RGO7DN.js";
32
32
  import "../chunk-RN3NOEJF.js";
33
33
  import "../chunk-DWED7BS3.js";
34
34
  import {
35
35
  isValidApiKey
36
- } from "../chunk-SY3NBF67.js";
36
+ } from "../chunk-P5VOLS3Q.js";
37
37
  import "../chunk-NKXSILEW.js";
38
38
 
39
39
  // bin/pushary-setup.ts
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  readLedgerSummary
4
- } from "../chunk-WYQSLB7K.js";
5
- import "../chunk-SY3NBF67.js";
4
+ } from "../chunk-UXIAIMSS.js";
5
+ import "../chunk-P5VOLS3Q.js";
6
6
  import {
7
7
  getApiKey
8
8
  } from "../chunk-NKXSILEW.js";
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleStop
4
- } from "../chunk-SWNBIHDX.js";
4
+ } from "../chunk-H6RGO7DN.js";
5
5
  import "../chunk-RN3NOEJF.js";
6
6
  import "../chunk-DWED7BS3.js";
7
- import "../chunk-SY3NBF67.js";
7
+ import "../chunk-P5VOLS3Q.js";
8
8
  import "../chunk-NKXSILEW.js";
9
9
 
10
10
  // bin/pushary-stop-hook.ts
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleStopFailure
4
- } from "../chunk-SWNBIHDX.js";
4
+ } from "../chunk-H6RGO7DN.js";
5
5
  import "../chunk-RN3NOEJF.js";
6
6
  import "../chunk-DWED7BS3.js";
7
- import "../chunk-SY3NBF67.js";
7
+ import "../chunk-P5VOLS3Q.js";
8
8
  import "../chunk-NKXSILEW.js";
9
9
 
10
10
  // bin/pushary-stopfailure-hook.ts
@@ -8,8 +8,8 @@ import {
8
8
  addClaudeMcpServer,
9
9
  addPusharyHooks,
10
10
  addPusharyToolPermissions
11
- } from "../chunk-T2EEBR2D.js";
12
- import "../chunk-SY3NBF67.js";
11
+ } from "../chunk-PSZAXNUB.js";
12
+ import "../chunk-P5VOLS3Q.js";
13
13
  import {
14
14
  getApiKey
15
15
  } from "../chunk-NKXSILEW.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  HOOK_BUDGETS
3
- } from "./chunk-SY3NBF67.js";
3
+ } from "./chunk-P5VOLS3Q.js";
4
4
 
5
5
  // src/codex-config.ts
6
6
  import { createHash } from "crypto";
@@ -9,14 +9,14 @@ import {
9
9
  ACTION_BODY_MAX,
10
10
  DECISION_LINE_MAX,
11
11
  classifyDecisionRisk,
12
- extractPolicyArg,
13
12
  isApprovalMode,
14
13
  isSafeReadOnlyCommand,
15
14
  matchRankWeight,
16
- matchToolPattern,
15
+ matchToolPatternAny,
16
+ policyArgForms,
17
17
  redactSecrets,
18
18
  redactSecretsDeep
19
- } from "./chunk-SY3NBF67.js";
19
+ } from "./chunk-P5VOLS3Q.js";
20
20
  import {
21
21
  getApiKey,
22
22
  getBaseUrl
@@ -96,12 +96,12 @@ var getPolicy = async (apiKey, expectedVersion, agent) => {
96
96
  throw new Error("Failed to fetch policy and no cached policy available");
97
97
  }
98
98
  };
99
- var findBestMatch = (policies, toolName, arg) => {
99
+ var findBestMatch = (policies, toolName, args) => {
100
100
  let best;
101
101
  let bestWeight = 0;
102
102
  let bestLength = -1;
103
103
  for (const candidate of policies) {
104
- const rank = matchToolPattern(candidate.tool, toolName, arg);
104
+ const rank = matchToolPatternAny(candidate.tool, toolName, args);
105
105
  if (rank === "none") continue;
106
106
  const weight = matchRankWeight(rank);
107
107
  const length = rank === "prefix" ? candidate.tool.length : -1;
@@ -120,18 +120,20 @@ var autoApprove = (tool) => ({
120
120
  mode: "terminal_only",
121
121
  pushFirstSeconds: 0
122
122
  });
123
- var resolveAutoResolveOrigin = (config, toolName, toolInput) => {
124
- const arg = toolInput ? extractPolicyArg(toolName, toolInput) : void 0;
125
- const match = findBestMatch(config.policies, toolName, arg);
123
+ var resolveAutoResolveOrigin = (config, toolName, toolInput, cwd) => {
124
+ const args = toolInput ? policyArgForms(toolName, toolInput, cwd) : [];
125
+ const arg = args[0];
126
+ const match = findBestMatch(config.policies, toolName, args);
126
127
  const governedBySpecificRule = match?.rank === "exact" || match?.rank === "prefix";
127
128
  if (!governedBySpecificRule && toolName === "Bash" && typeof arg === "string" && isSafeReadOnlyCommand(arg)) {
128
129
  return "safe_readonly";
129
130
  }
130
131
  return "policy_timeout";
131
132
  };
132
- var resolvePolicy = (config, toolName, modeOverride, toolInput) => {
133
- const arg = toolInput ? extractPolicyArg(toolName, toolInput) : void 0;
134
- const match = findBestMatch(config.policies, toolName, arg);
133
+ var resolvePolicy = (config, toolName, modeOverride, toolInput, cwd) => {
134
+ const args = toolInput ? policyArgForms(toolName, toolInput, cwd) : [];
135
+ const arg = args[0];
136
+ const match = findBestMatch(config.policies, toolName, args);
135
137
  let base = match?.policy ?? config.policies.find((p) => p.tool === "*") ?? {
136
138
  tool: toolName,
137
139
  timeoutSeconds: config.defaultTimeoutSeconds,
@@ -745,12 +747,12 @@ var readFreshCachedPolicy = (apiKey) => {
745
747
  if (!cached._cachedAt || Date.now() - cached._cachedAt >= POLICY_CACHE_TTL_MS) return null;
746
748
  return cached;
747
749
  };
748
- var deriveDecisionSource = (toolName, toolInput, liveMode) => {
750
+ var deriveDecisionSource = (toolName, toolInput, liveMode, cwd) => {
749
751
  try {
750
752
  if (liveMode.kill) return "terminal";
751
753
  const policy = readFreshCachedPolicy(getApiKey());
752
754
  if (!policy) return void 0;
753
- const resolved = resolvePolicy(policy, toolName, liveMode.mode, toolInput);
755
+ const resolved = resolvePolicy(policy, toolName, liveMode.mode, toolInput, cwd);
754
756
  if (resolved.timeoutSeconds === 0 && resolved.timeoutAction === "approve") return "policy_auto";
755
757
  if (resolved.mode === "push_only" || resolved.mode === "push_first") return "human";
756
758
  return "terminal";
@@ -758,15 +760,15 @@ var deriveDecisionSource = (toolName, toolInput, liveMode) => {
758
760
  return void 0;
759
761
  }
760
762
  };
761
- var deriveAutoDecisionBeacon = (toolName, toolInput, liveMode) => {
763
+ var deriveAutoDecisionBeacon = (toolName, toolInput, liveMode, cwd) => {
762
764
  try {
763
765
  if (liveMode.kill) return void 0;
764
766
  const policy = readFreshCachedPolicy(getApiKey());
765
767
  if (!policy) return void 0;
766
- const resolved = resolvePolicy(policy, toolName, liveMode.mode, toolInput);
768
+ const resolved = resolvePolicy(policy, toolName, liveMode.mode, toolInput, cwd);
767
769
  if (resolved.timeoutSeconds !== 0 || resolved.timeoutAction !== "approve") return void 0;
768
770
  return {
769
- decisionOrigin: resolveAutoResolveOrigin(policy, toolName, toolInput),
771
+ decisionOrigin: resolveAutoResolveOrigin(policy, toolName, toolInput, cwd),
770
772
  toolName,
771
773
  toolTarget: deriveToolTarget(toolName, toolInput)
772
774
  };
@@ -846,8 +848,8 @@ var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
846
848
  for (const l of late) removePendingQuestion(sessionKey, l.correlationId);
847
849
  }
848
850
  const isMirrorOnly = NON_GATED_MIRROR_TOOLS.has(input.tool_name);
849
- const decisionSource = isMirrorOnly ? void 0 : deriveDecisionSource(lookup.tool, lookup.input, liveMode);
850
- const beacon = !isMirrorOnly && decisionSource === "policy_auto" && throttlePass(`autodecision:${sessionKey}:${lookup.tool}`, AUTO_DECISION_WINDOW_MS) ? deriveAutoDecisionBeacon(lookup.tool, lookup.input, liveMode) : void 0;
851
+ const decisionSource = isMirrorOnly ? void 0 : deriveDecisionSource(lookup.tool, lookup.input, liveMode, input.cwd);
852
+ const beacon = !isMirrorOnly && decisionSource === "policy_auto" && throttlePass(`autodecision:${sessionKey}:${lookup.tool}`, AUTO_DECISION_WINDOW_MS) ? deriveAutoDecisionBeacon(lookup.tool, lookup.input, liveMode, input.cwd) : void 0;
851
853
  const toolReport = reportEvent({
852
854
  event: isError ? "tool_error" : "tool_complete",
853
855
  agentType: agent.type,
@@ -21,6 +21,71 @@ var hookWaitClamped = (startMs, policyWaitSeconds, agent, nowMs) => startMs + ho
21
21
  var effectiveWaitSeconds = (timeoutAction, policySeconds, agent) => timeoutAction === "wait" ? hookMaxWaitSeconds(agent) : policySeconds;
22
22
  var MATCH_RANKS = ["none", "tool", "prefix", "exact"];
23
23
  var matchRankWeight = (rank) => MATCH_RANKS.indexOf(rank);
24
+ var GLOB_MAX_WILDCARDS = 8;
25
+ var GLOB_MAX_ARG_LENGTH = 4096;
26
+ var GLOB_CACHE_MAX = 256;
27
+ var tokenizeGlob = (glob) => {
28
+ let stars = 0;
29
+ for (const char of glob) if (char === "*") stars += 1;
30
+ if (stars > GLOB_MAX_WILDCARDS) return void 0;
31
+ const tokens = [];
32
+ let literal = "";
33
+ const flush = () => {
34
+ if (literal.length > 0) {
35
+ tokens.push({ kind: "literal", value: literal });
36
+ literal = "";
37
+ }
38
+ };
39
+ for (let i = 0; i < glob.length; i += 1) {
40
+ if (glob[i] !== "*") {
41
+ literal += glob[i];
42
+ continue;
43
+ }
44
+ flush();
45
+ if (glob[i + 1] === "*") {
46
+ tokens.push({ kind: "globstar" });
47
+ i += 1;
48
+ continue;
49
+ }
50
+ tokens.push({ kind: "star" });
51
+ }
52
+ flush();
53
+ return tokens;
54
+ };
55
+ var SLASH = "/".charCodeAt(0);
56
+ var matchGlobTokens = (tokens, text) => {
57
+ const n = text.length;
58
+ let reachable = new Uint8Array(n + 1);
59
+ reachable[0] = 1;
60
+ for (const token of tokens) {
61
+ const next = new Uint8Array(n + 1);
62
+ if (token.kind === "literal") {
63
+ const { value } = token;
64
+ for (let p = 0; p <= n - value.length; p += 1) {
65
+ if (reachable[p] && text.startsWith(value, p)) next[p + value.length] = 1;
66
+ }
67
+ } else {
68
+ const spansSeparators = token.kind === "globstar";
69
+ let open = 0;
70
+ for (let p = 0; p <= n; p += 1) {
71
+ if (!spansSeparators && p > 0 && text.charCodeAt(p - 1) === SLASH) open = 0;
72
+ if (reachable[p]) open = 1;
73
+ if (open) next[p] = 1;
74
+ }
75
+ }
76
+ reachable = next;
77
+ }
78
+ return reachable[n] === 1;
79
+ };
80
+ var globCache = /* @__PURE__ */ new Map();
81
+ var compiledGlob = (glob) => {
82
+ const cached = globCache.get(glob);
83
+ if (cached !== void 0 || globCache.has(glob)) return cached;
84
+ const compiled = tokenizeGlob(glob);
85
+ if (globCache.size >= GLOB_CACHE_MAX) globCache.clear();
86
+ globCache.set(glob, compiled);
87
+ return compiled;
88
+ };
24
89
  var matchToolPattern = (pattern, toolName, arg) => {
25
90
  const open = pattern.indexOf("(");
26
91
  if (open === -1 || !pattern.endsWith(")")) {
@@ -31,19 +96,65 @@ var matchToolPattern = (pattern, toolName, arg) => {
31
96
  if (inner.endsWith(":*")) {
32
97
  return arg.startsWith(inner.slice(0, -2)) ? "prefix" : "none";
33
98
  }
99
+ if (inner.includes("*")) {
100
+ if (arg.length > GLOB_MAX_ARG_LENGTH) return "none";
101
+ const compiled = compiledGlob(inner);
102
+ return compiled && matchGlobTokens(compiled, arg) ? "prefix" : "none";
103
+ }
34
104
  return arg === inner ? "exact" : "none";
35
105
  };
36
- var POLICY_ARG_KEYS = {
37
- Bash: "command",
106
+ var POLICY_PATH_KEYS = {
107
+ Read: "file_path",
38
108
  Edit: "file_path",
39
- Write: "file_path"
109
+ Write: "file_path",
110
+ MultiEdit: "file_path",
111
+ NotebookEdit: "notebook_path",
112
+ LS: "path"
113
+ };
114
+ var POLICY_COMMAND_KEYS = {
115
+ Bash: "command",
116
+ PowerShell: "command",
117
+ Monitor: "command"
40
118
  };
119
+ var POLICY_ARG_KEYS = { ...POLICY_COMMAND_KEYS, ...POLICY_PATH_KEYS };
41
120
  var extractPolicyArg = (toolName, toolInput) => {
42
121
  const key = POLICY_ARG_KEYS[toolName];
43
122
  if (!key) return void 0;
44
123
  const value = toolInput[key];
45
124
  return typeof value === "string" ? value : void 0;
46
125
  };
126
+ var normalizeSeparators = (value) => value.replace(/\\/g, "/");
127
+ var isAbsolutePath = (value) => value.startsWith("/") || /^[A-Za-z]:\//.test(value);
128
+ var relativeToCwd = (path, cwd) => {
129
+ const base = normalizeSeparators(cwd).replace(/\/+$/, "");
130
+ if (!base) return void 0;
131
+ const prefix = `${base}/`;
132
+ if (!path.startsWith(prefix)) return void 0;
133
+ const rest = path.slice(prefix.length);
134
+ return rest.length > 0 ? rest : void 0;
135
+ };
136
+ var policyArgForms = (toolName, toolInput, cwd) => {
137
+ const raw = extractPolicyArg(toolName, toolInput);
138
+ if (raw === void 0) return [];
139
+ if (!(toolName in POLICY_PATH_KEYS)) return [raw];
140
+ const forms = [raw];
141
+ const normalized = normalizeSeparators(raw);
142
+ if (normalized !== raw) forms.push(normalized);
143
+ if (cwd && isAbsolutePath(normalized)) {
144
+ const relative = relativeToCwd(normalized, cwd);
145
+ if (relative !== void 0) forms.push(relative);
146
+ }
147
+ return forms;
148
+ };
149
+ var matchToolPatternAny = (pattern, toolName, args) => {
150
+ if (args.length === 0) return matchToolPattern(pattern, toolName);
151
+ let best = "none";
152
+ for (const arg of args) {
153
+ const rank = matchToolPattern(pattern, toolName, arg);
154
+ if (matchRankWeight(rank) > matchRankWeight(best)) best = rank;
155
+ }
156
+ return best;
157
+ };
47
158
  var SAFE_SHELL_COMMANDS = /* @__PURE__ */ new Set([
48
159
  "ls",
49
160
  "pwd",
@@ -582,8 +693,8 @@ export {
582
693
  hookWaitClamped,
583
694
  effectiveWaitSeconds,
584
695
  matchRankWeight,
585
- matchToolPattern,
586
- extractPolicyArg,
696
+ policyArgForms,
697
+ matchToolPatternAny,
587
698
  isSafeReadOnlyCommand,
588
699
  isValidApiKey,
589
700
  ACTION_BODY_MAX,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  HOOK_BUDGETS
3
- } from "./chunk-SY3NBF67.js";
3
+ } from "./chunk-P5VOLS3Q.js";
4
4
 
5
5
  // src/claude-config.ts
6
6
  import { join } from "path";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isSafeReadOnlyCommand
3
- } from "./chunk-SY3NBF67.js";
3
+ } from "./chunk-P5VOLS3Q.js";
4
4
 
5
5
  // src/ledger.ts
6
6
  import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync } from "fs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  PRETOOLUSE_HANDLED_TOOLS
3
- } from "./chunk-T2EEBR2D.js";
3
+ } from "./chunk-PSZAXNUB.js";
4
4
  import {
5
5
  denyReasonFrom,
6
6
  isDeferAnswer
@@ -23,20 +23,20 @@ import {
23
23
  sendNotification,
24
24
  throttlePass,
25
25
  waitForAnswer
26
- } from "./chunk-SWNBIHDX.js";
26
+ } from "./chunk-H6RGO7DN.js";
27
27
  import {
28
28
  getMachineId
29
29
  } from "./chunk-RN3NOEJF.js";
30
30
  import {
31
31
  isGatingMoment,
32
32
  recordKeylessMoment
33
- } from "./chunk-WYQSLB7K.js";
33
+ } from "./chunk-UXIAIMSS.js";
34
34
  import {
35
35
  buildDecisionEpisodeFeatures,
36
36
  effectiveWaitSeconds,
37
37
  hookWaitClamped,
38
38
  hookWaitDeadline
39
- } from "./chunk-SY3NBF67.js";
39
+ } from "./chunk-P5VOLS3Q.js";
40
40
  import {
41
41
  getApiKey,
42
42
  getBaseUrl
@@ -395,7 +395,7 @@ var handlePreToolUse = async (input) => {
395
395
  if (shouldDeferToNativeMode(input.permission_mode, input.tool_name)) {
396
396
  return void 0;
397
397
  }
398
- const toolPolicy = resolvePolicy(policy, input.tool_name, modeState.mode, input.tool_input);
398
+ const toolPolicy = resolvePolicy(policy, input.tool_name, modeState.mode, input.tool_input, input.cwd);
399
399
  if (toolPolicy.timeoutSeconds === 0 && toolPolicy.timeoutAction === "approve") {
400
400
  return allow();
401
401
  }
@@ -442,7 +442,7 @@ var handlePermissionRequest = async (input) => {
442
442
  const modeState = await fetchModeState(apiKey, input.session_id);
443
443
  const policy = await getPolicy(apiKey, modeState.policyVersion, "claude_code");
444
444
  if (modeState.kill) return permReqDeny("Stopped by user \u2014 this agent was halted from Pushary");
445
- const toolPolicy = resolvePolicy(policy, input.tool_name, modeState.mode, input.tool_input);
445
+ const toolPolicy = resolvePolicy(policy, input.tool_name, modeState.mode, input.tool_input, input.cwd);
446
446
  if (toolPolicy.timeoutSeconds === 0 && toolPolicy.timeoutAction === "approve") return permReqAllow();
447
447
  if (toolPolicy.timeoutSeconds === 0 && toolPolicy.timeoutAction === "deny") {
448
448
  return permReqDeny(`Denied by policy for ${toolPolicy.tool}`);
@@ -28,7 +28,7 @@ interface ReceiptMeta {
28
28
 
29
29
  declare const getPolicy: (apiKey: string, expectedVersion?: string | null, agent?: string) => Promise<PolicyConfig>;
30
30
  type AutoResolveOrigin = 'safe_readonly' | 'policy_timeout';
31
- declare const resolvePolicy: (config: PolicyConfig, toolName: string, modeOverride?: ApprovalMode | null, toolInput?: Record<string, unknown>) => ToolPolicy;
31
+ declare const resolvePolicy: (config: PolicyConfig, toolName: string, modeOverride?: ApprovalMode | null, toolInput?: Record<string, unknown>, cwd?: string) => ToolPolicy;
32
32
  interface ModeState {
33
33
  readonly mode: ApprovalMode | null;
34
34
  readonly kill: boolean;
package/dist/src/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  handlePreToolUse
3
- } from "../chunk-SVRDT5PP.js";
4
- import "../chunk-T2EEBR2D.js";
3
+ } from "../chunk-XKXF2G7T.js";
4
+ import "../chunk-PSZAXNUB.js";
5
5
  import "../chunk-YHG74UFF.js";
6
6
  import {
7
7
  askUser,
@@ -15,11 +15,11 @@ import {
15
15
  reportEvent,
16
16
  resolvePolicy,
17
17
  waitForAnswer
18
- } from "../chunk-SWNBIHDX.js";
18
+ } from "../chunk-H6RGO7DN.js";
19
19
  import "../chunk-RN3NOEJF.js";
20
- import "../chunk-WYQSLB7K.js";
20
+ import "../chunk-UXIAIMSS.js";
21
21
  import "../chunk-DWED7BS3.js";
22
- import "../chunk-SY3NBF67.js";
22
+ import "../chunk-P5VOLS3Q.js";
23
23
  import {
24
24
  getApiKey,
25
25
  getBaseUrl
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushary/agent-hooks",
3
- "version": "0.54.1",
3
+ "version": "0.55.0",
4
4
  "description": "Permission hooks for AI coding agents: route tool approvals through Pushary push notifications",
5
5
  "keywords": [
6
6
  "pushary",