@pushary/agent-hooks 0.21.1 → 0.22.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.
@@ -231,6 +231,25 @@ const fetchModeState = async (apiKey, sessionId) => {
231
231
  }
232
232
  }
233
233
 
234
+ // ── action body capture + redaction (inlined mirror of describe.ts, since this
235
+ // dependency-free hook cannot import the workspace) ──────────────────────────────
236
+ const ACTION_BODY_MAX = 4000
237
+ const ACTION_BODY_TRUNCATION_MARKER = '\n… [truncated]'
238
+ const REDACTION_RULES = [
239
+ [/\bsk-[A-Za-z0-9]{20,}\b/g, '[redacted]'],
240
+ [/\bpk_(?:live|test)_[A-Za-z0-9]+\b/g, '[redacted]'],
241
+ [/\brk_[A-Za-z0-9]+\b/g, '[redacted]'],
242
+ [/\bAKIA[0-9A-Z]{16}\b/g, '[redacted]'],
243
+ [/\bbearer\s+[A-Za-z0-9._-]+/gi, 'bearer [redacted]'],
244
+ [/\bauthorization:\s*\S+/gi, 'authorization: [redacted]'],
245
+ [/((?:secret|token|password|passwd|api[_-]?key|private[_-]?key)\s*[=:]\s*)(\S+)/gi, '$1[redacted]'],
246
+ [/[A-Za-z0-9+/]{40,}={0,2}/g, '[redacted]'],
247
+ ]
248
+ const redactSecrets = (text) => REDACTION_RULES.reduce((acc, [pattern, replacement]) => acc.replace(pattern, replacement), text)
249
+ const capActionBody = (text) =>
250
+ text.length <= ACTION_BODY_MAX ? text : `${text.slice(0, ACTION_BODY_MAX - ACTION_BODY_TRUNCATION_MARKER.length)}${ACTION_BODY_TRUNCATION_MARKER}`
251
+ const deriveActionBody = (command) => capActionBody(redactSecrets(command))
252
+
234
253
  // ── ask / wait ───────────────────────────────────────────────────────────────
235
254
  const askArgs = (command, project, ident) => ({
236
255
  question: `Allow this command?\n\n${command}`,
@@ -240,6 +259,7 @@ const askArgs = (command, project, ident) => ({
240
259
  sessionId: ident.sessionId,
241
260
  machineId: ident.machineId,
242
261
  toolName: 'Bash',
262
+ actionBody: deriveActionBody(command),
243
263
  wait: false,
244
264
  })
245
265
 
@@ -278,7 +298,10 @@ const handlePushOnly = async (apiKey, command, project, ident, timeoutSeconds, t
278
298
  const realMs = Math.max(timeoutSeconds, 1) * 1000
279
299
  const cap = Math.min(realMs, MAX_BLOCK_MS)
280
300
  const answer = await pollForAnswer(apiKey, asked.correlationId, Date.now() + cap)
281
- if (answer.answered) return answer.value === 'yes' ? ALLOW : deny(DENIED)
301
+ if (answer.answered) {
302
+ if (answer.value === 'defer') return ask()
303
+ return answer.value === 'yes' ? ALLOW : deny(DENIED)
304
+ }
282
305
 
283
306
  // If Cursor's hook limit cut us off before the configured timeout, hand off to
284
307
  // Cursor's own prompt rather than misapplying the policy's timeout action.
@@ -298,7 +321,10 @@ const handlePushFirst = async (apiKey, command, project, ident, pushFirstSeconds
298
321
 
299
322
  const cap = Math.min(Math.max(pushFirstSeconds, 1) * 1000, MAX_BLOCK_MS)
300
323
  const answer = await pollForAnswer(apiKey, asked.correlationId, Date.now() + cap)
301
- if (answer.answered) return answer.value === 'yes' ? ALLOW : deny(DENIED)
324
+ if (answer.answered) {
325
+ if (answer.value === 'defer') return ask()
326
+ return answer.value === 'yes' ? ALLOW : deny(DENIED)
327
+ }
302
328
  return ask('Sent to your phone via Pushary — you can also approve here.')
303
329
  }
304
330
 
@@ -1,36 +1,40 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- denyReasonFrom
4
- } from "../chunk-N7VXDBQU.js";
3
+ denyReasonFrom,
4
+ isDeferAnswer
5
+ } from "../chunk-KQYIHZ5E.js";
5
6
  import {
6
7
  CODEX_AGENT,
8
+ DEFAULT_SESSION,
9
+ askUser,
7
10
  codexAllow,
8
11
  codexDeny,
9
12
  codexPass,
13
+ deriveActionBody,
14
+ deriveBlocker,
15
+ deriveToolTarget,
10
16
  describeApplyPatch,
17
+ describeToolCall,
18
+ fetchModeState,
19
+ getMachineId,
20
+ getPolicy,
11
21
  handlePostToolUse,
12
22
  handleStop,
13
23
  handleUserPrompt,
14
24
  permissionTimeoutDecision,
15
25
  preToolUseTimeoutDecision,
26
+ readLastPrompt,
16
27
  reportEvent,
17
- toCodexWire,
18
- toPolicyLookup
19
- } from "../chunk-BYNYYZWW.js";
20
- import {
21
- DEFAULT_SESSION,
22
- askUser,
23
- deriveToolTarget,
24
- describeToolCall,
25
- fetchModeState,
26
- getMachineId,
27
- getPolicy,
28
28
  resolvePolicy,
29
29
  savePendingQuestion,
30
30
  sendNotification,
31
+ toCodexWire,
32
+ toPolicyLookup,
31
33
  waitForAnswer
32
- } from "../chunk-6QWFMVCD.js";
33
- import "../chunk-USUCPCUC.js";
34
+ } from "../chunk-M4GDBGXF.js";
35
+ import {
36
+ DECISION_LINE_MAX
37
+ } from "../chunk-WPVL6VIT.js";
34
38
  import "../chunk-DWED7BS3.js";
35
39
  import {
36
40
  getApiKey
@@ -107,7 +111,7 @@ var pollForAnswer = async (apiKey, correlationId, deadlineMs, pollInterval = 2e3
107
111
  };
108
112
  var agentNameFor = (input) => `Codex - ${basename(input.cwd ?? process.cwd())}`;
109
113
  var describeFor = (input, lookup) => input.tool_name === "apply_patch" ? describeApplyPatch(input.tool_input?.command) ?? describeToolCall(lookup.tool, lookup.input, "hook") : describeToolCall(lookup.tool, lookup.input, "hook");
110
- var pushQuestion = async (apiKey, input, lookup, waitSeconds) => {
114
+ var pushQuestion = async (apiKey, input, lookup, waitSeconds, mode) => {
111
115
  const projectName = basename(input.cwd ?? process.cwd());
112
116
  const description = describeFor(input, lookup);
113
117
  const result = await askUser(apiKey, {
@@ -118,7 +122,11 @@ var pushQuestion = async (apiKey, input, lookup, waitSeconds) => {
118
122
  sessionId: input.session_id,
119
123
  machineId: getMachineId(),
120
124
  toolName: lookup.tool,
121
- toolTarget: deriveToolTarget(lookup.tool, lookup.input)
125
+ toolTarget: deriveToolTarget(lookup.tool, lookup.input),
126
+ intent: readLastPrompt(input.session_id || DEFAULT_SESSION),
127
+ action: description.slice(0, DECISION_LINE_MAX),
128
+ blocker: deriveBlocker(mode),
129
+ actionBody: deriveActionBody(input.tool_name ?? "", input.tool_input ?? {})
122
130
  });
123
131
  const deadline = Math.min(
124
132
  Date.now() + Math.min(waitSeconds, MAX_WAIT_SECONDS) * 1e3,
@@ -157,8 +165,9 @@ var decidePermissionRequest = async (input) => {
157
165
  return codexPass();
158
166
  }
159
167
  const waitSeconds = toolPolicy.mode === "push_first" ? toolPolicy.pushFirstSeconds : toolPolicy.timeoutSeconds;
160
- const { answer, correlationId } = await pushQuestion(apiKey, input, lookup, waitSeconds);
168
+ const { answer, correlationId } = await pushQuestion(apiKey, input, lookup, waitSeconds, toolPolicy.mode);
161
169
  if (answer.answered) {
170
+ if (isDeferAnswer(answer.value)) return codexPass();
162
171
  if (answer.value === "yes") {
163
172
  if (toolPolicy.mode === "push_only") markApproved(input.tool_use_id);
164
173
  return codexAllow();
@@ -190,12 +199,13 @@ var decidePreToolUse = async (input) => {
190
199
  if (consumeApproval(input.tool_use_id)) return codexPass();
191
200
  let pushed;
192
201
  try {
193
- pushed = await pushQuestion(apiKey, input, lookup, toolPolicy.timeoutSeconds);
202
+ pushed = await pushQuestion(apiKey, input, lookup, toolPolicy.timeoutSeconds, "push_only");
194
203
  } catch {
195
204
  return preToolUseTimeoutDecision(toolPolicy.timeoutAction, "Push notification failed, denying per policy");
196
205
  }
197
206
  const { answer, correlationId } = pushed;
198
207
  if (answer.answered) {
208
+ if (isDeferAnswer(answer.value)) return codexPass();
199
209
  return answer.value === "yes" ? codexPass() : codexDeny(denyReasonFrom(answer.value));
200
210
  }
201
211
  savePendingQuestion(input.session_id || DEFAULT_SESSION, correlationId);
@@ -1,13 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- reportEvent
4
- } from "../chunk-BYNYYZWW.js";
5
2
  import {
6
3
  askUser,
7
4
  getMachineId,
5
+ reportEvent,
8
6
  waitForAnswer
9
- } from "../chunk-6QWFMVCD.js";
10
- import "../chunk-USUCPCUC.js";
7
+ } from "../chunk-M4GDBGXF.js";
8
+ import "../chunk-WPVL6VIT.js";
11
9
  import "../chunk-DWED7BS3.js";
12
10
  import {
13
11
  getApiKey
@@ -1,27 +1,32 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- denyReasonFrom
4
- } from "../chunk-N7VXDBQU.js";
5
- import {
6
- handlePostToolUse,
7
- handleStop,
8
- handleUserPrompt,
9
- reportEvent
10
- } from "../chunk-BYNYYZWW.js";
3
+ denyReasonFrom,
4
+ isDeferAnswer
5
+ } from "../chunk-KQYIHZ5E.js";
11
6
  import {
12
7
  DEFAULT_SESSION,
13
8
  askUser,
9
+ deriveActionBody,
10
+ deriveBlocker,
14
11
  deriveToolTarget,
15
12
  describeToolCall,
16
13
  fetchModeState,
17
14
  getMachineId,
18
15
  getPolicy,
16
+ handlePostToolUse,
17
+ handleStop,
18
+ handleUserPrompt,
19
+ readLastPrompt,
20
+ readLastUserPrompt,
21
+ reportEvent,
19
22
  resolvePolicy,
20
23
  savePendingQuestion,
21
24
  sendNotification,
22
25
  waitForAnswer
23
- } from "../chunk-6QWFMVCD.js";
24
- import "../chunk-USUCPCUC.js";
26
+ } from "../chunk-M4GDBGXF.js";
27
+ import {
28
+ DECISION_LINE_MAX
29
+ } from "../chunk-WPVL6VIT.js";
25
30
  import "../chunk-DWED7BS3.js";
26
31
  import {
27
32
  getApiKey
@@ -86,7 +91,7 @@ var pollForAnswer = async (apiKey, correlationId, deadlineMs, pollInterval = 2e3
86
91
  return { answered: false };
87
92
  };
88
93
  var agentNameFor = (input) => `${GEMINI_AGENT.label} - ${basename(input.cwd ?? process.cwd())}`;
89
- var pushQuestion = async (apiKey, input, lookup, waitSeconds, pollInterval = 2e3) => {
94
+ var pushQuestion = async (apiKey, input, lookup, waitSeconds, mode, pollInterval = 2e3) => {
90
95
  const projectName = basename(input.cwd ?? process.cwd());
91
96
  const description = describeToolCall(lookup.tool, lookup.input, "hook");
92
97
  const result = await askUser(apiKey, {
@@ -97,7 +102,11 @@ var pushQuestion = async (apiKey, input, lookup, waitSeconds, pollInterval = 2e3
97
102
  sessionId: input.session_id,
98
103
  machineId: getMachineId(),
99
104
  toolName: lookup.tool,
100
- toolTarget: deriveToolTarget(lookup.tool, lookup.input)
105
+ toolTarget: deriveToolTarget(lookup.tool, lookup.input),
106
+ intent: readLastPrompt(input.session_id || DEFAULT_SESSION) ?? (input.transcript_path ? readLastUserPrompt(input.transcript_path) : void 0),
107
+ action: description.slice(0, DECISION_LINE_MAX),
108
+ blocker: deriveBlocker(mode),
109
+ actionBody: deriveActionBody(input.tool_name ?? "", input.tool_input ?? {})
101
110
  });
102
111
  const deadline = Math.min(
103
112
  Date.now() + Math.min(waitSeconds, MAX_WAIT_SECONDS) * 1e3,
@@ -121,12 +130,13 @@ var notifyApprovalNeeded = async (apiKey, input, lookup) => {
121
130
  var handlePushOnly = async (apiKey, input, lookup, timeoutSeconds, timeoutAction) => {
122
131
  let pushed;
123
132
  try {
124
- pushed = await pushQuestion(apiKey, input, lookup, timeoutSeconds);
133
+ pushed = await pushQuestion(apiKey, input, lookup, timeoutSeconds, "push_only");
125
134
  } catch {
126
135
  return geminiTimeoutDecision(timeoutAction, "Push notification failed, denying per policy");
127
136
  }
128
137
  const { answer, correlationId } = pushed;
129
138
  if (answer.answered) {
139
+ if (isDeferAnswer(answer.value)) return geminiPass();
130
140
  return answer.value === "yes" ? geminiAllow() : geminiDeny(denyReasonFrom(answer.value));
131
141
  }
132
142
  savePendingQuestion(input.session_id || DEFAULT_SESSION, correlationId);
@@ -135,12 +145,13 @@ var handlePushOnly = async (apiKey, input, lookup, timeoutSeconds, timeoutAction
135
145
  var handlePushFirst = async (apiKey, input, lookup, pushFirstSeconds) => {
136
146
  let pushed;
137
147
  try {
138
- pushed = await pushQuestion(apiKey, input, lookup, pushFirstSeconds, 1500);
148
+ pushed = await pushQuestion(apiKey, input, lookup, pushFirstSeconds, "push_first", 1500);
139
149
  } catch {
140
150
  return geminiPass();
141
151
  }
142
152
  const { answer, correlationId } = pushed;
143
153
  if (answer.answered) {
154
+ if (isDeferAnswer(answer.value)) return geminiPass();
144
155
  return answer.value === "yes" ? geminiAllow() : geminiDeny(denyReasonFrom(answer.value));
145
156
  }
146
157
  savePendingQuestion(input.session_id || DEFAULT_SESSION, correlationId);
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePreToolUse
4
- } from "../chunk-M5F2L4KF.js";
5
- import "../chunk-N7VXDBQU.js";
6
- import "../chunk-6QWFMVCD.js";
7
- import "../chunk-USUCPCUC.js";
4
+ } from "../chunk-FGZZRCOG.js";
5
+ import "../chunk-KQYIHZ5E.js";
6
+ import "../chunk-M4GDBGXF.js";
7
+ import "../chunk-WPVL6VIT.js";
8
8
  import "../chunk-DWED7BS3.js";
9
9
  import "../chunk-NKXSILEW.js";
10
10
 
@@ -1,9 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePostToolUse
4
- } from "../chunk-BYNYYZWW.js";
5
- import "../chunk-6QWFMVCD.js";
6
- import "../chunk-USUCPCUC.js";
4
+ } from "../chunk-M4GDBGXF.js";
5
+ import "../chunk-WPVL6VIT.js";
7
6
  import "../chunk-DWED7BS3.js";
8
7
  import "../chunk-NKXSILEW.js";
9
8
 
@@ -1,9 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleUserPrompt
4
- } from "../chunk-BYNYYZWW.js";
5
- import "../chunk-6QWFMVCD.js";
6
- import "../chunk-USUCPCUC.js";
4
+ } from "../chunk-M4GDBGXF.js";
5
+ import "../chunk-WPVL6VIT.js";
7
6
  import "../chunk-DWED7BS3.js";
8
7
  import "../chunk-NKXSILEW.js";
9
8
 
@@ -17,7 +17,7 @@ import {
17
17
  } from "../chunk-BHAMEPOP.js";
18
18
  import {
19
19
  isValidApiKey
20
- } from "../chunk-USUCPCUC.js";
20
+ } from "../chunk-WPVL6VIT.js";
21
21
 
22
22
  // bin/pushary-setup.ts
23
23
  import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync, cpSync, rmSync, chmodSync } from "fs";
@@ -1,9 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleStop
4
- } from "../chunk-BYNYYZWW.js";
5
- import "../chunk-6QWFMVCD.js";
6
- import "../chunk-USUCPCUC.js";
4
+ } from "../chunk-M4GDBGXF.js";
5
+ import "../chunk-WPVL6VIT.js";
7
6
  import "../chunk-DWED7BS3.js";
8
7
  import "../chunk-NKXSILEW.js";
9
8
 
@@ -0,0 +1,194 @@
1
+ import {
2
+ denyReasonFrom,
3
+ isDeferAnswer
4
+ } from "./chunk-KQYIHZ5E.js";
5
+ import {
6
+ DEFAULT_SESSION,
7
+ askUser,
8
+ deriveAction,
9
+ deriveActionBody,
10
+ deriveBlocker,
11
+ deriveToolTarget,
12
+ describeToolCall,
13
+ fetchModeState,
14
+ getMachineId,
15
+ getPolicy,
16
+ readLastPrompt,
17
+ readLastUserPrompt,
18
+ resolvePolicy,
19
+ savePendingQuestion,
20
+ sendNotification,
21
+ waitForAnswer
22
+ } from "./chunk-5LTQNC7R.js";
23
+ import {
24
+ getApiKey
25
+ } from "./chunk-NKXSILEW.js";
26
+
27
+ // src/hook.ts
28
+ import { basename } from "path";
29
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
30
+ var allow = () => ({
31
+ hookSpecificOutput: {
32
+ hookEventName: "PreToolUse",
33
+ permissionDecision: "allow"
34
+ }
35
+ });
36
+ var deny = (reason) => ({
37
+ hookSpecificOutput: {
38
+ hookEventName: "PreToolUse",
39
+ permissionDecision: "deny",
40
+ permissionDecisionReason: reason
41
+ }
42
+ });
43
+ var ask = (reason) => ({
44
+ hookSpecificOutput: {
45
+ hookEventName: "PreToolUse",
46
+ permissionDecision: "ask",
47
+ ...reason ? { permissionDecisionReason: reason } : {}
48
+ }
49
+ });
50
+ var pollForAnswer = async (apiKey, correlationId, deadlineMs, pollInterval = 2e3) => {
51
+ while (Date.now() < deadlineMs) {
52
+ const remaining = Math.min(Math.max(deadlineMs - Date.now(), 1e3), 3e4);
53
+ let answer;
54
+ try {
55
+ answer = await waitForAnswer(apiKey, correlationId, remaining);
56
+ } catch {
57
+ if (Date.now() + pollInterval >= deadlineMs) break;
58
+ await sleep(pollInterval);
59
+ continue;
60
+ }
61
+ if (answer.answered) return answer;
62
+ if (Date.now() + pollInterval >= deadlineMs) break;
63
+ await sleep(pollInterval);
64
+ }
65
+ return { answered: false };
66
+ };
67
+ var handlePushOnly = async (apiKey, description, projectName, timeoutSeconds, timeoutAction, sessionId, machineId, toolName, toolTarget, decision) => {
68
+ let result;
69
+ try {
70
+ result = await askUser(apiKey, {
71
+ question: `Allow ${description}?`,
72
+ type: "confirm",
73
+ context: `Agent wants to run this in ${projectName}`,
74
+ agentName: `Claude Code - ${projectName}`,
75
+ sessionId,
76
+ machineId,
77
+ toolName,
78
+ toolTarget,
79
+ ...decision
80
+ });
81
+ } catch {
82
+ switch (timeoutAction) {
83
+ case "approve":
84
+ return allow();
85
+ case "deny":
86
+ return deny("Push notification failed, denying per policy");
87
+ default:
88
+ return ask("Push notification failed, asking in terminal");
89
+ }
90
+ }
91
+ const deadline = Date.now() + timeoutSeconds * 1e3;
92
+ const answer = await pollForAnswer(apiKey, result.correlationId, deadline);
93
+ if (answer.answered) {
94
+ if (isDeferAnswer(answer.value)) return ask("Handling on your machine");
95
+ return answer.value === "yes" ? allow() : deny(denyReasonFrom(answer.value));
96
+ }
97
+ switch (timeoutAction) {
98
+ case "approve":
99
+ return allow();
100
+ case "deny":
101
+ return deny("No response within timeout");
102
+ default:
103
+ return ask("No push response, asking in terminal");
104
+ }
105
+ };
106
+ var handleTerminalOnly = () => {
107
+ return ask();
108
+ };
109
+ var handlePushFirst = async (apiKey, description, projectName, pushFirstSeconds, sessionId, machineId, toolName, toolTarget, decision) => {
110
+ let result;
111
+ try {
112
+ result = await askUser(apiKey, {
113
+ question: `Allow ${description}?`,
114
+ type: "confirm",
115
+ context: `Agent wants to run this in ${projectName}`,
116
+ agentName: `Claude Code - ${projectName}`,
117
+ sessionId,
118
+ machineId,
119
+ toolName,
120
+ toolTarget,
121
+ ...decision
122
+ });
123
+ } catch {
124
+ return ask("Push notification failed, asking in terminal");
125
+ }
126
+ const deadline = Date.now() + pushFirstSeconds * 1e3;
127
+ const answer = await pollForAnswer(apiKey, result.correlationId, deadline, 1500);
128
+ if (answer.answered) {
129
+ if (isDeferAnswer(answer.value)) return ask("Handling on your machine");
130
+ return answer.value === "yes" ? allow() : deny(denyReasonFrom(answer.value));
131
+ }
132
+ savePendingQuestion(sessionId || DEFAULT_SESSION, result.correlationId);
133
+ return ask("Sent as push notification. You can also approve here.");
134
+ };
135
+ var handleNotifyOnly = async (apiKey, description, projectName, sessionId, machineId) => {
136
+ try {
137
+ await sendNotification(apiKey, {
138
+ title: "Agent needs approval",
139
+ body: description,
140
+ agentName: `Claude Code - ${projectName}`,
141
+ sessionId,
142
+ machineId
143
+ });
144
+ } catch {
145
+ }
146
+ return ask();
147
+ };
148
+ var handlePreToolUse = async (input) => {
149
+ try {
150
+ const apiKey = getApiKey();
151
+ const modeState = await fetchModeState(apiKey, input.session_id);
152
+ const policy = await getPolicy(apiKey, modeState.policyVersion);
153
+ if (modeState.kill) {
154
+ return deny("Stopped by user \u2014 this agent was halted from Pushary");
155
+ }
156
+ const toolPolicy = resolvePolicy(policy, input.tool_name, modeState.mode, input.tool_input);
157
+ if (toolPolicy.timeoutSeconds === 0 && toolPolicy.timeoutAction === "approve") {
158
+ return allow();
159
+ }
160
+ if (toolPolicy.timeoutSeconds === 0 && toolPolicy.timeoutAction === "deny") {
161
+ return deny(`Denied by policy for ${toolPolicy.tool}`);
162
+ }
163
+ const description = describeToolCall(input.tool_name, input.tool_input, "hook");
164
+ const projectName = basename(input.cwd ?? process.cwd());
165
+ const sessionId = input.session_id;
166
+ const machineId = getMachineId();
167
+ const toolTarget = deriveToolTarget(input.tool_name, input.tool_input);
168
+ const intent = readLastPrompt(sessionId ?? DEFAULT_SESSION) ?? (input.transcript_path ? readLastUserPrompt(input.transcript_path) : void 0);
169
+ const decision = {
170
+ intent,
171
+ action: deriveAction(input.tool_name, input.tool_input),
172
+ blocker: deriveBlocker(toolPolicy.mode),
173
+ actionBody: deriveActionBody(input.tool_name, input.tool_input)
174
+ };
175
+ switch (toolPolicy.mode) {
176
+ case "push_only":
177
+ return handlePushOnly(apiKey, description, projectName, toolPolicy.timeoutSeconds, toolPolicy.timeoutAction, sessionId, machineId, input.tool_name, toolTarget, decision);
178
+ case "terminal_only":
179
+ return handleTerminalOnly();
180
+ case "push_first":
181
+ return handlePushFirst(apiKey, description, projectName, toolPolicy.pushFirstSeconds, sessionId, machineId, input.tool_name, toolTarget, decision);
182
+ case "notify_only":
183
+ return handleNotifyOnly(apiKey, description, projectName, sessionId, machineId);
184
+ default:
185
+ return handlePushFirst(apiKey, description, projectName, toolPolicy.pushFirstSeconds, sessionId, machineId, input.tool_name, toolTarget, decision);
186
+ }
187
+ } catch {
188
+ return ask("Pushary unavailable, falling back to terminal approval");
189
+ }
190
+ };
191
+
192
+ export {
193
+ handlePreToolUse
194
+ };