@pushary/agent-hooks 0.57.0 → 0.59.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.
@@ -17,14 +17,14 @@ import {
17
17
  reportEvent,
18
18
  resolvePolicy,
19
19
  waitForAnswer
20
- } from "../chunk-LEWSYLHL.js";
20
+ } from "../chunk-WNRYRN2R.js";
21
21
  import {
22
22
  getMachineId
23
23
  } from "../chunk-RN3NOEJF.js";
24
24
  import "../chunk-DWED7BS3.js";
25
25
  import {
26
26
  redactSecrets
27
- } from "../chunk-SYAAGYLZ.js";
27
+ } from "../chunk-DQAN3JQP.js";
28
28
  import {
29
29
  getApiKey,
30
30
  getBaseUrl
@@ -6,15 +6,15 @@ import {
6
6
  removeCodexHooks,
7
7
  removeGeminiSettings,
8
8
  removeInstructionBlock
9
- } from "../chunk-GSERIC6Q.js";
9
+ } from "../chunk-BVAWO6RE.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-QYQO6RHJ.js";
17
- import "../chunk-SYAAGYLZ.js";
16
+ } from "../chunk-CAJZAFVS.js";
17
+ import "../chunk-DQAN3JQP.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-LEWSYLHL.js";
34
+ } from "../chunk-WNRYRN2R.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-5TECIV6T.js";
41
+ } from "../chunk-WLGEY4UX.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-SYAAGYLZ.js";
48
+ } from "../chunk-DQAN3JQP.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-LEWSYLHL.js";
6
+ } from "../chunk-WNRYRN2R.js";
7
7
  import {
8
8
  getMachineId
9
9
  } from "../chunk-RN3NOEJF.js";
10
10
  import "../chunk-DWED7BS3.js";
11
- import "../chunk-SYAAGYLZ.js";
11
+ import "../chunk-DQAN3JQP.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-GSERIC6Q.js";
14
+ } from "../chunk-BVAWO6RE.js";
15
15
  import {
16
16
  execNpm
17
17
  } from "../chunk-J7JWI3KU.js";
18
18
  import {
19
19
  readLedgerSummary
20
- } from "../chunk-5TECIV6T.js";
20
+ } from "../chunk-WLGEY4UX.js";
21
21
  import {
22
22
  callMcpTool,
23
23
  sendMcpRequest
24
24
  } from "../chunk-DWED7BS3.js";
25
- import "../chunk-SYAAGYLZ.js";
25
+ import "../chunk-DQAN3JQP.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-LEWSYLHL.js";
26
+ } from "../chunk-WNRYRN2R.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-5TECIV6T.js";
33
+ } from "../chunk-WLGEY4UX.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-SYAAGYLZ.js";
40
+ } from "../chunk-DQAN3JQP.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-NPYANTRC.js";
5
- import "../chunk-QYQO6RHJ.js";
4
+ } from "../chunk-BE5X3WXL.js";
5
+ import "../chunk-CAJZAFVS.js";
6
6
  import "../chunk-YHG74UFF.js";
7
- import "../chunk-LEWSYLHL.js";
7
+ import "../chunk-WNRYRN2R.js";
8
8
  import "../chunk-RN3NOEJF.js";
9
- import "../chunk-5TECIV6T.js";
9
+ import "../chunk-WLGEY4UX.js";
10
10
  import "../chunk-DWED7BS3.js";
11
- import "../chunk-SYAAGYLZ.js";
11
+ import "../chunk-DQAN3JQP.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-LEWSYLHL.js";
4
+ } from "../chunk-WNRYRN2R.js";
5
5
  import "../chunk-RN3NOEJF.js";
6
6
  import "../chunk-DWED7BS3.js";
7
- import "../chunk-SYAAGYLZ.js";
7
+ import "../chunk-DQAN3JQP.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-NPYANTRC.js";
5
- import "../chunk-QYQO6RHJ.js";
4
+ } from "../chunk-BE5X3WXL.js";
5
+ import "../chunk-CAJZAFVS.js";
6
6
  import "../chunk-YHG74UFF.js";
7
- import "../chunk-LEWSYLHL.js";
7
+ import "../chunk-WNRYRN2R.js";
8
8
  import "../chunk-RN3NOEJF.js";
9
- import "../chunk-5TECIV6T.js";
9
+ import "../chunk-WLGEY4UX.js";
10
10
  import "../chunk-DWED7BS3.js";
11
- import "../chunk-SYAAGYLZ.js";
11
+ import "../chunk-DQAN3JQP.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-NPYANTRC.js";
5
- import "../chunk-QYQO6RHJ.js";
4
+ } from "../chunk-BE5X3WXL.js";
5
+ import "../chunk-CAJZAFVS.js";
6
6
  import "../chunk-YHG74UFF.js";
7
- import "../chunk-LEWSYLHL.js";
7
+ import "../chunk-WNRYRN2R.js";
8
8
  import "../chunk-RN3NOEJF.js";
9
- import "../chunk-5TECIV6T.js";
9
+ import "../chunk-WLGEY4UX.js";
10
10
  import "../chunk-DWED7BS3.js";
11
- import "../chunk-SYAAGYLZ.js";
11
+ import "../chunk-DQAN3JQP.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-LEWSYLHL.js";
4
+ } from "../chunk-WNRYRN2R.js";
5
5
  import "../chunk-RN3NOEJF.js";
6
6
  import "../chunk-DWED7BS3.js";
7
- import "../chunk-SYAAGYLZ.js";
7
+ import "../chunk-DQAN3JQP.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-LEWSYLHL.js";
4
+ } from "../chunk-WNRYRN2R.js";
5
5
  import "../chunk-RN3NOEJF.js";
6
6
  import "../chunk-DWED7BS3.js";
7
- import "../chunk-SYAAGYLZ.js";
7
+ import "../chunk-DQAN3JQP.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-LEWSYLHL.js";
4
+ } from "../chunk-WNRYRN2R.js";
5
5
  import "../chunk-RN3NOEJF.js";
6
6
  import "../chunk-DWED7BS3.js";
7
- import "../chunk-SYAAGYLZ.js";
7
+ import "../chunk-DQAN3JQP.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-LEWSYLHL.js";
4
+ } from "../chunk-WNRYRN2R.js";
5
5
  import "../chunk-RN3NOEJF.js";
6
6
  import "../chunk-DWED7BS3.js";
7
- import "../chunk-SYAAGYLZ.js";
7
+ import "../chunk-DQAN3JQP.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-GSERIC6Q.js";
16
+ } from "../chunk-BVAWO6RE.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-QYQO6RHJ.js";
28
+ } from "../chunk-CAJZAFVS.js";
29
29
  import {
30
30
  reportEvent
31
- } from "../chunk-LEWSYLHL.js";
31
+ } from "../chunk-WNRYRN2R.js";
32
32
  import "../chunk-RN3NOEJF.js";
33
33
  import "../chunk-DWED7BS3.js";
34
34
  import {
35
35
  isValidApiKey
36
- } from "../chunk-SYAAGYLZ.js";
36
+ } from "../chunk-DQAN3JQP.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-5TECIV6T.js";
5
- import "../chunk-SYAAGYLZ.js";
4
+ } from "../chunk-WLGEY4UX.js";
5
+ import "../chunk-DQAN3JQP.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-LEWSYLHL.js";
4
+ } from "../chunk-WNRYRN2R.js";
5
5
  import "../chunk-RN3NOEJF.js";
6
6
  import "../chunk-DWED7BS3.js";
7
- import "../chunk-SYAAGYLZ.js";
7
+ import "../chunk-DQAN3JQP.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-LEWSYLHL.js";
4
+ } from "../chunk-WNRYRN2R.js";
5
5
  import "../chunk-RN3NOEJF.js";
6
6
  import "../chunk-DWED7BS3.js";
7
- import "../chunk-SYAAGYLZ.js";
7
+ import "../chunk-DQAN3JQP.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-QYQO6RHJ.js";
12
- import "../chunk-SYAAGYLZ.js";
11
+ } from "../chunk-CAJZAFVS.js";
12
+ import "../chunk-DQAN3JQP.js";
13
13
  import {
14
14
  getApiKey
15
15
  } from "../chunk-NKXSILEW.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  PRETOOLUSE_HANDLED_TOOLS
3
- } from "./chunk-QYQO6RHJ.js";
3
+ } from "./chunk-CAJZAFVS.js";
4
4
  import {
5
5
  denyReasonFrom,
6
6
  isDeferAnswer
@@ -21,23 +21,27 @@ import {
21
21
  repoKeyFor,
22
22
  resolvePolicy,
23
23
  savePendingQuestion,
24
+ scopePathFor,
24
25
  sendNotification,
25
26
  throttlePass,
26
27
  waitForAnswer
27
- } from "./chunk-LEWSYLHL.js";
28
+ } from "./chunk-WNRYRN2R.js";
28
29
  import {
29
30
  getMachineId
30
31
  } from "./chunk-RN3NOEJF.js";
31
32
  import {
32
33
  isGatingMoment,
33
34
  recordKeylessMoment
34
- } from "./chunk-5TECIV6T.js";
35
+ } from "./chunk-WLGEY4UX.js";
35
36
  import {
36
37
  buildDecisionEpisodeFeatures,
37
38
  effectiveWaitSeconds,
39
+ evaluateScope,
38
40
  hookWaitClamped,
39
- hookWaitDeadline
40
- } from "./chunk-SYAAGYLZ.js";
41
+ hookWaitDeadline,
42
+ scopeChangeReason,
43
+ scopeRequiresHuman
44
+ } from "./chunk-DQAN3JQP.js";
41
45
  import {
42
46
  getApiKey,
43
47
  getBaseUrl
@@ -257,7 +261,7 @@ var emitDecisionEpisode = (apiKey, input, toolPolicy, machineId, toolTarget, dec
257
261
  machineId
258
262
  });
259
263
  };
260
- var dispatchModeHandler = async (apiKey, input, toolPolicy, machineId, trainingConsent = false) => {
264
+ var dispatchModeHandler = async (apiKey, input, toolPolicy, machineId, trainingConsent = false, scopeReason, scopePath) => {
261
265
  const description = describeToolCall(input.tool_name, input.tool_input, "hook");
262
266
  const projectName = basename(input.cwd ?? process.cwd());
263
267
  const sessionId = input.session_id;
@@ -266,8 +270,11 @@ var dispatchModeHandler = async (apiKey, input, toolPolicy, machineId, trainingC
266
270
  const decision = {
267
271
  intent,
268
272
  action: deriveAction(input.tool_name, input.tool_input),
269
- blocker: deriveBlocker(toolPolicy.mode),
270
- actionBody: deriveActionBody(input.tool_name, input.tool_input)
273
+ blocker: scopeReason ?? deriveBlocker(toolPolicy.mode),
274
+ actionBody: deriveActionBody(input.tool_name, input.tool_input),
275
+ // Only when the breach is what caused the question, so an ordinary approval
276
+ // can never silently widen a scope.
277
+ scopePath: scopeReason ? scopePath : void 0
271
278
  };
272
279
  const signals = {};
273
280
  const runHandler = () => {
@@ -397,13 +404,16 @@ var handlePreToolUse = async (input) => {
397
404
  return void 0;
398
405
  }
399
406
  const toolPolicy = resolvePolicy(policy, input.tool_name, modeState.mode, input.tool_input, input.cwd, repoKeyFor(input.cwd));
407
+ const scopePath = modeState.scope ? scopePathFor(input.tool_name, input.tool_input, input.cwd) : void 0;
408
+ const scopeVerdict = evaluateScope(modeState.scope, scopePath);
409
+ const scopeReason = scopeChangeReason(scopeVerdict);
400
410
  if (toolPolicy.timeoutSeconds === 0 && toolPolicy.timeoutAction === "approve") {
401
- return allow();
411
+ if (!scopeRequiresHuman(scopeVerdict)) return allow();
402
412
  }
403
413
  if (toolPolicy.timeoutSeconds === 0 && toolPolicy.timeoutAction === "deny") {
404
414
  return deny(`Denied by policy for ${toolPolicy.tool}`);
405
415
  }
406
- return dispatchModeHandler(apiKey, input, toolPolicy, getMachineId(), modeState.trainingConsent);
416
+ return dispatchModeHandler(apiKey, input, toolPolicy, getMachineId(), modeState.trainingConsent, scopeReason, scopePath);
407
417
  } catch {
408
418
  return void 0;
409
419
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  HOOK_BUDGETS
3
- } from "./chunk-SYAAGYLZ.js";
3
+ } from "./chunk-DQAN3JQP.js";
4
4
 
5
5
  // src/codex-config.ts
6
6
  import { createHash } from "crypto";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  HOOK_BUDGETS
3
- } from "./chunk-SYAAGYLZ.js";
3
+ } from "./chunk-DQAN3JQP.js";
4
4
 
5
5
  // src/claude-config.ts
6
6
  import { join } from "path";
@@ -724,6 +724,39 @@ var buildDecisionEpisodeFeatures = (input) => {
724
724
  agentType: input.agentType
725
725
  };
726
726
  };
727
+ var matchesGlobPath = (glob, path) => {
728
+ if (glob === path) return true;
729
+ const compiled = compiledGlob(glob);
730
+ return compiled ? matchGlobTokens(compiled, path) : false;
731
+ };
732
+ var evaluateScope = (contract, path) => {
733
+ if (!contract) return { outcome: "no_contract" };
734
+ if (typeof path !== "string" || path.length === 0) return { outcome: "in_scope" };
735
+ for (const rule of contract.offLimitsPaths) {
736
+ if (matchesGlobPath(rule, path)) return { outcome: "off_limits", path, rule };
737
+ }
738
+ if (contract.allowedPaths.length === 0) return { outcome: "in_scope" };
739
+ for (const rule of contract.allowedPaths) {
740
+ if (matchesGlobPath(rule, path)) return { outcome: "in_scope" };
741
+ }
742
+ return { outcome: "out_of_scope", path };
743
+ };
744
+ var scopeRequiresHuman = (verdict) => verdict.outcome === "out_of_scope" || verdict.outcome === "off_limits";
745
+ var scopeChangeReason = (verdict) => {
746
+ if (verdict.outcome === "out_of_scope") {
747
+ return `Outside the scope you approved: ${verdict.path}`;
748
+ }
749
+ if (verdict.outcome === "off_limits") {
750
+ return `You marked this off limits: ${verdict.path} (${verdict.rule})`;
751
+ }
752
+ return void 0;
753
+ };
754
+ var isScopeContract = (value) => {
755
+ if (!value || typeof value !== "object") return false;
756
+ const c = value;
757
+ const strings = (v) => Array.isArray(v) && v.every((x) => typeof x === "string");
758
+ return strings(c.allowedPaths) && strings(c.offLimitsPaths) && typeof c.doneWhen === "string";
759
+ };
727
760
 
728
761
  export {
729
762
  isApprovalMode,
@@ -744,5 +777,9 @@ export {
744
777
  redactSecrets,
745
778
  redactSecretsDeep,
746
779
  classifyDecisionRisk,
747
- buildDecisionEpisodeFeatures
780
+ buildDecisionEpisodeFeatures,
781
+ evaluateScope,
782
+ scopeRequiresHuman,
783
+ scopeChangeReason,
784
+ isScopeContract
748
785
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isSafeReadOnlyCommand
3
- } from "./chunk-SYAAGYLZ.js";
3
+ } from "./chunk-DQAN3JQP.js";
4
4
 
5
5
  // src/ledger.ts
6
6
  import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync } from "fs";
@@ -12,6 +12,7 @@ import {
12
12
  isApprovalMode,
13
13
  isRepoKeyMatch,
14
14
  isSafeReadOnlyCommand,
15
+ isScopeContract,
15
16
  localRepoKey,
16
17
  matchRankWeight,
17
18
  matchToolPatternAny,
@@ -19,7 +20,7 @@ import {
19
20
  policyArgForms,
20
21
  redactSecrets,
21
22
  redactSecretsDeep
22
- } from "./chunk-SYAAGYLZ.js";
23
+ } from "./chunk-DQAN3JQP.js";
23
24
  import {
24
25
  getApiKey,
25
26
  getBaseUrl
@@ -183,7 +184,7 @@ var fetchModeState = async (apiKey, sessionId) => {
183
184
  headers: { "Authorization": `Bearer ${apiKey}` },
184
185
  signal: AbortSignal.timeout(3e3)
185
186
  });
186
- if (!response.ok) return { mode: null, kill: false, policyVersion: null, relayUrl: null, trainingConsent: false };
187
+ if (!response.ok) return { mode: null, kill: false, policyVersion: null, relayUrl: null, trainingConsent: false, scope: null };
187
188
  const data = await response.json();
188
189
  const mode = data.override?.mode;
189
190
  return {
@@ -191,10 +192,13 @@ var fetchModeState = async (apiKey, sessionId) => {
191
192
  kill: data.kill === true,
192
193
  policyVersion: toPolicyVersion(data.policyVersion),
193
194
  relayUrl: typeof data.relayUrl === "string" && data.relayUrl.length > 0 ? data.relayUrl : null,
194
- trainingConsent: data.trainingConsent === true
195
+ trainingConsent: data.trainingConsent === true,
196
+ // Validated rather than cast: a malformed contract must read as no contract,
197
+ // never as one that silently matches nothing.
198
+ scope: isScopeContract(data.scope) ? data.scope : null
195
199
  };
196
200
  } catch {
197
- return { mode: null, kill: false, policyVersion: null, relayUrl: null, trainingConsent: false };
201
+ return { mode: null, kill: false, policyVersion: null, relayUrl: null, trainingConsent: false, scope: null };
198
202
  }
199
203
  };
200
204
  var fetchModeOverride = async (apiKey) => (await fetchModeState(apiKey)).mode;
@@ -295,13 +299,26 @@ var deriveReceiptCommandHead = (command) => {
295
299
  return head ? head.slice(0, TOOL_TARGET_MAX_LENGTH) : void 0;
296
300
  };
297
301
  var RECEIPT_TARGET_MAX_LENGTH = 256;
302
+ var EXIT_CODE_FAILURE = /^Error: Exit code \d+/;
298
303
  var isToolResultError = (toolResult) => {
299
304
  try {
300
- return Boolean(toolResult && ("error" in toolResult || "is_error" in toolResult));
305
+ if (typeof toolResult === "string") return EXIT_CODE_FAILURE.test(toolResult);
306
+ if (!toolResult || typeof toolResult !== "object") return false;
307
+ return "error" in toolResult || "is_error" in toolResult;
301
308
  } catch {
302
309
  return false;
303
310
  }
304
311
  };
312
+ var toolResultErrorText = (toolResult) => {
313
+ try {
314
+ const raw = typeof toolResult === "string" ? toolResult : toolResult && typeof toolResult === "object" ? String(
315
+ toolResult.error ?? toolResult.stderr ?? ""
316
+ ) : "";
317
+ return redactSecrets(raw);
318
+ } catch {
319
+ return "";
320
+ }
321
+ };
305
322
  var relativizeReceiptPath = (filePath, cwd) => {
306
323
  if (!cwd || !isAbsolute(filePath)) return filePath;
307
324
  return relative(cwd, filePath);
@@ -332,6 +349,11 @@ var deriveReceiptMeta = (toolName, toolInput, toolResult, cwd) => {
332
349
  return void 0;
333
350
  }
334
351
  };
352
+ var scopePathFor = (toolName, toolInput, cwd) => {
353
+ const meta = deriveReceiptMeta(toolName, toolInput, void 0, cwd);
354
+ if (!meta) return void 0;
355
+ return meta.kind === "edit" || meta.kind === "write" ? meta.target : void 0;
356
+ };
335
357
  var firstString = (...values) => values.find((v) => typeof v === "string" && v.length > 0);
336
358
  var ACTION_BODY_TRUNCATION_MARKER = "\n\u2026 [truncated]";
337
359
  var capActionBody = (text) => text.length <= ACTION_BODY_MAX ? text : `${text.slice(0, ACTION_BODY_MAX - ACTION_BODY_TRUNCATION_MARKER.length)}${ACTION_BODY_TRUNCATION_MARKER}`;
@@ -962,7 +984,7 @@ var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
962
984
  agentName: `${agent.label} - ${projectName}`,
963
985
  action,
964
986
  sessionId: input.session_id,
965
- error: isError ? String(toolResult?.error ?? toolResult?.stderr ?? "").slice(0, 500) : void 0,
987
+ error: isError ? toolResultErrorText(toolResult).slice(0, 500) : void 0,
966
988
  decisionSource,
967
989
  ...beacon ? { decisionOrigin: beacon.decisionOrigin, toolName: beacon.toolName, toolTarget: beacon.toolTarget } : {},
968
990
  meta: receiptsEnabled ? deriveReceiptMeta(lookup.tool, lookup.input, toolResult, input.cwd ?? process.cwd()) : void 0,
@@ -1218,6 +1240,7 @@ export {
1218
1240
  sendNotification,
1219
1241
  describeToolCall,
1220
1242
  deriveToolTarget,
1243
+ scopePathFor,
1221
1244
  deriveActionBody,
1222
1245
  deriveAction,
1223
1246
  deriveBlocker,
@@ -1,4 +1,4 @@
1
- import { PolicyConfig, ApprovalMode, ToolPolicy } from '@pushary/contracts';
1
+ import { PolicyConfig, ApprovalMode, ToolPolicy, ScopeContract } from '@pushary/contracts';
2
2
  export { ApprovalMode, PolicyConfig, ToolPolicy } from '@pushary/contracts';
3
3
 
4
4
  interface ToolInput {
@@ -35,6 +35,7 @@ interface ModeState {
35
35
  readonly policyVersion: string | null;
36
36
  readonly relayUrl: string | null;
37
37
  readonly trainingConsent?: boolean;
38
+ readonly scope?: ScopeContract | null;
38
39
  }
39
40
  declare const fetchModeState: (apiKey: string, sessionId?: string) => Promise<ModeState>;
40
41
  declare const fetchModeOverride: (apiKey: string) => Promise<ApprovalMode | null>;
@@ -81,8 +82,8 @@ declare const reportEvent: (event: AgentEvent, options?: ReportEventOptions) =>
81
82
  declare const handlePostToolUse: (input: {
82
83
  tool_name: string;
83
84
  tool_input: Record<string, unknown>;
84
- tool_response?: Record<string, unknown>;
85
- tool_result?: Record<string, unknown>;
85
+ tool_response?: unknown;
86
+ tool_result?: unknown;
86
87
  cwd?: string;
87
88
  session_id?: string;
88
89
  transcript_path?: string;
@@ -123,6 +124,7 @@ interface AskUserParams {
123
124
  action?: string;
124
125
  blocker?: string;
125
126
  actionBody?: string;
127
+ scopePath?: string;
126
128
  }
127
129
  interface AskUserResponse {
128
130
  correlationId: string;
package/dist/src/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  handlePreToolUse
3
- } from "../chunk-NPYANTRC.js";
4
- import "../chunk-QYQO6RHJ.js";
3
+ } from "../chunk-BE5X3WXL.js";
4
+ import "../chunk-CAJZAFVS.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-LEWSYLHL.js";
18
+ } from "../chunk-WNRYRN2R.js";
19
19
  import "../chunk-RN3NOEJF.js";
20
- import "../chunk-5TECIV6T.js";
20
+ import "../chunk-WLGEY4UX.js";
21
21
  import "../chunk-DWED7BS3.js";
22
- import "../chunk-SYAAGYLZ.js";
22
+ import "../chunk-DQAN3JQP.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.57.0",
3
+ "version": "0.59.0",
4
4
  "description": "Permission hooks for AI coding agents: route tool approvals through Pushary push notifications",
5
5
  "keywords": [
6
6
  "pushary",