@pushary/agent-hooks 0.34.0 → 0.35.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.
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  removeClaudeMcpServers,
4
4
  removePusharySettings
5
- } from "../chunk-RQSJVS3L.js";
5
+ } from "../chunk-ZJICOAAN.js";
6
6
  import {
7
7
  removeCodexHooks,
8
8
  removeGeminiSettings,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePreToolUse
4
- } from "../chunk-M3YN5ZNW.js";
4
+ } from "../chunk-JE3WQW63.js";
5
5
  import "../chunk-KQYIHZ5E.js";
6
6
  import "../chunk-FIBI2QZC.js";
7
7
  import "../chunk-R5AJNXZS.js";
@@ -3,7 +3,7 @@ import {
3
3
  addClaudeMcpServer,
4
4
  addPusharyHooks,
5
5
  addPusharyToolPermissions
6
- } from "../chunk-RQSJVS3L.js";
6
+ } from "../chunk-ZJICOAAN.js";
7
7
  import {
8
8
  GEMINI_HOOK_BINARY,
9
9
  addCodexHookTrust,
@@ -53,6 +53,13 @@ var deny = (reason) => ({
53
53
  permissionDecisionReason: reason
54
54
  }
55
55
  });
56
+ var allowWithInput = (updatedInput) => ({
57
+ hookSpecificOutput: {
58
+ hookEventName: "PreToolUse",
59
+ permissionDecision: "allow",
60
+ updatedInput
61
+ }
62
+ });
56
63
  var ask = (reason) => ({
57
64
  hookSpecificOutput: {
58
65
  hookEventName: "PreToolUse",
@@ -217,6 +224,48 @@ var shouldDeferToNativeMode = (permissionMode, toolName) => {
217
224
  }
218
225
  return false;
219
226
  };
227
+ var parseSingleQuestion = (toolInput) => {
228
+ const questions = toolInput.questions;
229
+ if (!Array.isArray(questions) || questions.length !== 1) return void 0;
230
+ const q = questions[0];
231
+ if (!q || typeof q.question !== "string" || q.multiSelect === true) return void 0;
232
+ const labels = Array.isArray(q.options) ? q.options.map((o) => o && typeof o === "object" ? o.label : void 0).filter((l) => typeof l === "string" && l.length > 0) : [];
233
+ if (labels.length < 2) return void 0;
234
+ return { question: q.question, header: typeof q.header === "string" ? q.header : void 0, labels };
235
+ };
236
+ var handleAskUserQuestion = async (apiKey, input) => {
237
+ const parsed = parseSingleQuestion(input.tool_input ?? {});
238
+ if (!parsed) return void 0;
239
+ const projectName = basename(input.cwd ?? process.cwd());
240
+ let result;
241
+ try {
242
+ result = await askUser(apiKey, {
243
+ question: parsed.question,
244
+ type: "select",
245
+ options: [...parsed.labels],
246
+ context: parsed.header ? `${parsed.header}: your agent is asking in ${projectName}` : `Your agent is asking in ${projectName}`,
247
+ agentName: `Claude Code - ${projectName}`,
248
+ sessionId: input.session_id,
249
+ machineId: getMachineId(),
250
+ toolName: "AskUserQuestion"
251
+ });
252
+ } catch {
253
+ return void 0;
254
+ }
255
+ if (result.suppressed || result.noDevices) {
256
+ await cancelQuestion(apiKey, result.correlationId).catch(() => {
257
+ });
258
+ return void 0;
259
+ }
260
+ const deadline = hookWaitDeadline(START_MS, effectiveWaitSeconds("wait", 0, "claude"), "claude", Date.now());
261
+ const answer = await pollForAnswer(apiKey, result.correlationId, deadline);
262
+ const value = answer.answered ? (answer.value ?? "").trim() : "";
263
+ if (!value || isDeferAnswer(answer.value)) {
264
+ savePendingQuestion(input.session_id || DEFAULT_SESSION, result.correlationId);
265
+ return void 0;
266
+ }
267
+ return allowWithInput({ ...input.tool_input ?? {}, answers: { [parsed.question]: value } });
268
+ };
220
269
  var handleKeyless = (input) => {
221
270
  try {
222
271
  if (isGatingMoment(input.tool_name, input.tool_input ?? {})) {
@@ -246,6 +295,9 @@ var handlePreToolUse = async (input) => {
246
295
  if (modeState.kill) {
247
296
  return deny("Stopped by user \u2014 this agent was halted from Pushary");
248
297
  }
298
+ if (input.tool_name === "AskUserQuestion") {
299
+ return handleAskUserQuestion(apiKey, input);
300
+ }
249
301
  if (shouldDeferToNativeMode(input.permission_mode, input.tool_name)) {
250
302
  return void 0;
251
303
  }
@@ -68,7 +68,7 @@ var addPusharyHooks = (settings, binDir) => {
68
68
  const SHELL_AND_FILE_TOOLS = "Bash|Write|Edit|MultiEdit|NotebookEdit|PowerShell|Monitor";
69
69
  const preToolUse = (Array.isArray(hooks.PreToolUse) ? hooks.PreToolUse : []).filter((entry) => !isPusharyHook(entry));
70
70
  preToolUse.push({
71
- matcher: SHELL_AND_FILE_TOOLS,
71
+ matcher: `${SHELL_AND_FILE_TOOLS}|AskUserQuestion`,
72
72
  hooks: [{
73
73
  type: "command",
74
74
  command: resolve("pushary-hook"),
@@ -14,6 +14,7 @@ interface HookOutput {
14
14
  hookEventName: 'PreToolUse';
15
15
  permissionDecision: 'allow' | 'deny' | 'ask';
16
16
  permissionDecisionReason?: string;
17
+ updatedInput?: Record<string, unknown>;
17
18
  };
18
19
  }
19
20
  declare const handlePreToolUse: (input: ToolInput) => Promise<HookOutput | undefined>;
package/dist/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  handlePreToolUse
3
- } from "../chunk-M3YN5ZNW.js";
3
+ } from "../chunk-JE3WQW63.js";
4
4
  import "../chunk-KQYIHZ5E.js";
5
5
  import {
6
6
  askUser,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushary/agent-hooks",
3
- "version": "0.34.0",
3
+ "version": "0.35.0",
4
4
  "description": "Permission hooks for AI coding agents: route tool approvals through Pushary push notifications",
5
5
  "keywords": [
6
6
  "pushary",