@pushary/agent-hooks 1.3.1 → 1.4.1

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 (84) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +1 -1
  3. package/dist/bin/pushary-bell-hook.js +18 -18
  4. package/dist/bin/pushary-bell.js +8 -8
  5. package/dist/bin/pushary-claude.js +18 -18
  6. package/dist/bin/pushary-clean.js +490 -95
  7. package/dist/bin/pushary-codex-bridge.js +10 -10
  8. package/dist/bin/pushary-codex-hook.js +28 -26
  9. package/dist/bin/pushary-codex.js +6 -6
  10. package/dist/bin/pushary-connect.js +8 -8
  11. package/dist/bin/pushary-cowork.js +5 -5
  12. package/dist/bin/pushary-daemon.js +24 -24
  13. package/dist/bin/pushary-disconnect.js +12 -12
  14. package/dist/bin/pushary-doctor.js +75 -26
  15. package/dist/bin/pushary-elicitation-hook.js +17 -17
  16. package/dist/bin/pushary-gemini-bridge.js +9 -9
  17. package/dist/bin/pushary-gemini-hook.js +19 -19
  18. package/dist/bin/pushary-hook.js +27 -27
  19. package/dist/bin/pushary-login.js +9 -9
  20. package/dist/bin/pushary-logout.js +6 -6
  21. package/dist/bin/pushary-mode.js +5 -5
  22. package/dist/bin/pushary-notification-hook.js +20 -20
  23. package/dist/bin/pushary-opencode-hook.js +19 -19
  24. package/dist/bin/pushary-permission-denied-hook.js +24 -24
  25. package/dist/bin/pushary-permission-hook.js +25 -25
  26. package/dist/bin/pushary-post-hook.js +20 -20
  27. package/dist/bin/pushary-prompt-hook.js +20 -20
  28. package/dist/bin/pushary-session-end-hook.js +20 -20
  29. package/dist/bin/pushary-session-start-hook.js +22 -22
  30. package/dist/bin/pushary-setup.js +38 -59
  31. package/dist/bin/pushary-stats.js +4 -4
  32. package/dist/bin/pushary-status.js +12 -12
  33. package/dist/bin/pushary-stop-hook.js +20 -20
  34. package/dist/bin/pushary-stopfailure-hook.js +20 -20
  35. package/dist/bin/pushary-suggestions.js +2 -2
  36. package/dist/bin/pushary-transcript-register.js +16 -16
  37. package/dist/bin/pushary-transcripts.js +6 -6
  38. package/dist/bin/pushary-upgrade.js +16 -16
  39. package/dist/bin/pushary-wait.js +5 -5
  40. package/dist/bin/pushary.js +1 -1
  41. package/dist/{chunk-RERJ2ZDV.js → chunk-2GMI6JH6.js} +5 -5
  42. package/dist/{chunk-AFOTOA24.js → chunk-37VLIYLI.js} +35 -4
  43. package/dist/{chunk-6HH4IH4K.js → chunk-3BPB2HYZ.js} +3 -3
  44. package/dist/{chunk-465UENKO.js → chunk-3T52B2OF.js} +1 -1
  45. package/dist/{chunk-PEV6ULSM.js → chunk-3UA6FPRC.js} +3 -3
  46. package/dist/{chunk-QDYJQLXT.js → chunk-43JKGLZZ.js} +2 -2
  47. package/dist/{chunk-CKLWJ6EL.js → chunk-4FN6VV56.js} +33 -7
  48. package/dist/{chunk-HCTSTMDD.js → chunk-ALFT7H5B.js} +3 -3
  49. package/dist/{chunk-35RPUNYU.js → chunk-BZBUPZC6.js} +1 -1
  50. package/dist/{chunk-CDSL3LLO.js → chunk-CRNAXFQ6.js} +1 -1
  51. package/dist/{chunk-NDSOOJDX.js → chunk-D7ERHWYB.js} +1 -1
  52. package/dist/{chunk-KHGIM2BN.js → chunk-ED5TA2FJ.js} +3 -3
  53. package/dist/{chunk-LZQVAEWP.js → chunk-FAH3D74E.js} +2 -1
  54. package/dist/{chunk-5UWDYOZX.js → chunk-FVKFDTN6.js} +81 -8
  55. package/dist/{chunk-I2OLM3DM.js → chunk-GOFDGTEI.js} +62 -12
  56. package/dist/{chunk-JZA2JOGO.js → chunk-HK3IXIQJ.js} +1 -1
  57. package/dist/{chunk-LWT34GSY.js → chunk-HQLAZWJJ.js} +7 -7
  58. package/dist/{chunk-5XKMOZO6.js → chunk-I6HRQOMT.js} +4 -4
  59. package/dist/{chunk-EAGMQMRM.js → chunk-JOVWYVSR.js} +1 -1
  60. package/dist/{chunk-5WLH2ENB.js → chunk-K6I5M2ME.js} +1 -1
  61. package/dist/{chunk-REIZ5GXG.js → chunk-KEMEBTCJ.js} +4 -4
  62. package/dist/{chunk-PHXU4NOP.js → chunk-KI36MAT6.js} +2 -2
  63. package/dist/{chunk-WOBHHXW5.js → chunk-LNGYW6G4.js} +5 -4
  64. package/dist/{chunk-AFKOWCMQ.js → chunk-LUT2EZLG.js} +1 -1
  65. package/dist/{chunk-KLZJEMSE.js → chunk-LYXX5NSB.js} +1 -1
  66. package/dist/{chunk-YXWM4TNX.js → chunk-MN3XOVRK.js} +1 -1
  67. package/dist/{chunk-XOUQUZ43.js → chunk-PHHGHHOW.js} +1 -1
  68. package/dist/{chunk-TW7KA27C.js → chunk-QBS6LGEK.js} +1 -1
  69. package/dist/{chunk-FGNABUPN.js → chunk-R3AMKNIW.js} +1 -1
  70. package/dist/{chunk-TGG4FWWB.js → chunk-S3EP4B35.js} +2 -2
  71. package/dist/{chunk-34NNTYK6.js → chunk-SAF6NNXY.js} +1 -1
  72. package/dist/{chunk-R5CU7ED6.js → chunk-SKXLIVFM.js} +1 -1
  73. package/dist/{chunk-OMP3KDDU.js → chunk-SWFF5U2N.js} +1 -1
  74. package/dist/{chunk-QOCWB4Q6.js → chunk-TF4IOINR.js} +3 -3
  75. package/dist/{chunk-5SALHATY.js → chunk-TI3ZWXZG.js} +11 -2
  76. package/dist/{chunk-P232YODQ.js → chunk-TNS3YLFE.js} +6 -6
  77. package/dist/{chunk-GOQHN2UH.js → chunk-TWWLVOPB.js} +1 -1
  78. package/dist/{chunk-XVE52YFZ.js → chunk-VYUDGQM7.js} +1 -1
  79. package/dist/{chunk-XP2KRTZD.js → chunk-WEO5JCB4.js} +1 -1
  80. package/dist/{chunk-SGZE2JBF.js → chunk-WIOXWUUH.js} +3 -3
  81. package/dist/{reapply-ADFRVH5N.js → reapply-BAWDJTG7.js} +8 -8
  82. package/dist/src/index.d.ts +19 -16
  83. package/dist/src/index.js +12 -12
  84. package/package.json +1 -1
@@ -4,15 +4,15 @@ import {
4
4
  } from "../chunk-CVWG2N3Y.js";
5
5
  import {
6
6
  exitOnFailedResponse
7
- } from "../chunk-NDSOOJDX.js";
8
- import "../chunk-TW7KA27C.js";
7
+ } from "../chunk-D7ERHWYB.js";
8
+ import "../chunk-QBS6LGEK.js";
9
9
  import {
10
10
  createIo
11
11
  } from "../chunk-5RUIFDTP.js";
12
12
  import {
13
13
  exitOnHelpFlag
14
- } from "../chunk-GOQHN2UH.js";
15
- import "../chunk-LZQVAEWP.js";
14
+ } from "../chunk-TWWLVOPB.js";
15
+ import "../chunk-FAH3D74E.js";
16
16
  import {
17
17
  rejectUnknownFlags
18
18
  } from "../chunk-GMXKITVA.js";
@@ -28,7 +28,7 @@ import {
28
28
  getApiKey,
29
29
  getBaseUrl
30
30
  } from "../chunk-2UMNXADU.js";
31
- import "../chunk-5UWDYOZX.js";
31
+ import "../chunk-FVKFDTN6.js";
32
32
 
33
33
  // bin/pushary-wait.ts
34
34
  exitOnHelpFlag("wait");
@@ -3,7 +3,7 @@ import {
3
3
  COMMANDS,
4
4
  isCommandName,
5
5
  renderHelp
6
- } from "../chunk-LZQVAEWP.js";
6
+ } from "../chunk-FAH3D74E.js";
7
7
  import {
8
8
  getPackageVersion
9
9
  } from "../chunk-DINDL2CF.js";
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  detectClaudeVersion
3
- } from "./chunk-AFKOWCMQ.js";
3
+ } from "./chunk-LUT2EZLG.js";
4
4
  import {
5
5
  addClaudeMcpServer,
6
6
  addPusharyHooks,
7
7
  addPusharyToolPermissions
8
- } from "./chunk-SGZE2JBF.js";
8
+ } from "./chunk-WIOXWUUH.js";
9
9
  import {
10
10
  claudeUnprovenHolds,
11
11
  claudeWired,
12
12
  codexUnprovenHolds,
13
13
  codexWired,
14
14
  geminiWired
15
- } from "./chunk-QOCWB4Q6.js";
15
+ } from "./chunk-TF4IOINR.js";
16
16
  import {
17
17
  CLAUDE_HOOK_BINARY,
18
18
  CLAUDE_HOOK_EVENTS,
@@ -24,7 +24,7 @@ import {
24
24
  needsReregistration,
25
25
  registrationSignatures,
26
26
  supportedClaudeEvents
27
- } from "./chunk-KHGIM2BN.js";
27
+ } from "./chunk-ED5TA2FJ.js";
28
28
  import {
29
29
  CODEX_HOOK_BINARY,
30
30
  addCodexHookTrust,
@@ -44,7 +44,7 @@ import {
44
44
  registrationHolderOf,
45
45
  resolveGlobalBinary,
46
46
  vscodePluginMcp
47
- } from "./chunk-34NNTYK6.js";
47
+ } from "./chunk-SAF6NNXY.js";
48
48
  import {
49
49
  readJsonSafe,
50
50
  writeFileAtomic,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolvePathBinary
3
- } from "./chunk-34NNTYK6.js";
3
+ } from "./chunk-SAF6NNXY.js";
4
4
 
5
5
  // src/hermes-config.ts
6
6
  import { execFileSync } from "child_process";
@@ -233,8 +233,35 @@ var runHermesPythonScript = (python, script, ...args) => {
233
233
  }
234
234
  };
235
235
 
236
- // src/cli/dry-run.ts
236
+ // src/skills-cli.ts
237
237
  import { execSync } from "child_process";
238
+ var PUSHARY_SKILL_SOURCE = "Pushary/pushary-skill";
239
+ var PUSHARY_SKILL_NAME = "pushary";
240
+ var installSkillViaSkillsCli = (agent) => {
241
+ try {
242
+ execSync(`npx -y skills@latest add ${PUSHARY_SKILL_SOURCE}@${PUSHARY_SKILL_NAME} -y -g --agent ${agent}`, {
243
+ stdio: "pipe",
244
+ timeout: 9e4
245
+ });
246
+ return true;
247
+ } catch {
248
+ return false;
249
+ }
250
+ };
251
+ var installAgentSkill = async (request, effects) => {
252
+ if (request.skillsCliInUse) {
253
+ const startedAt = effects.now();
254
+ if (effects.runSkillsCli(request.agent)) {
255
+ const modifiedAt = effects.skillModifiedAt(request.agentSkillDir);
256
+ if (modifiedAt !== null && modifiedAt >= startedAt) return "skills-cli";
257
+ }
258
+ }
259
+ await effects.writePackagedSkill(request.agentSkillDir);
260
+ return "packaged-copy";
261
+ };
262
+
263
+ // src/cli/dry-run.ts
264
+ import { execFileSync as execFileSync2 } from "child_process";
238
265
  import { rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
239
266
  var createGuards = (isDryRun, note) => ({
240
267
  write: (path, contents) => {
@@ -245,9 +272,9 @@ var createGuards = (isDryRun, note) => ({
245
272
  if (isDryRun()) return note("remove ", path);
246
273
  rmSync2(path, { recursive: true, force: options.force ?? false });
247
274
  },
248
- exec: (command, options, describe) => {
275
+ execFile: (file, args, options, describe) => {
249
276
  if (isDryRun()) return note("run ", describe);
250
- execSync(command, options);
277
+ execFileSync2(file, args, options);
251
278
  }
252
279
  });
253
280
  var describeService = (effects) => {
@@ -271,6 +298,10 @@ export {
271
298
  HERMES_CONFIG_SCRIPT,
272
299
  resolveHermesPython,
273
300
  runHermesPythonScript,
301
+ PUSHARY_SKILL_SOURCE,
302
+ PUSHARY_SKILL_NAME,
303
+ installSkillViaSkillsCli,
304
+ installAgentSkill,
274
305
  createGuards,
275
306
  describeSetupSideEffects
276
307
  };
@@ -4,17 +4,17 @@ import {
4
4
  } from "./chunk-XHKBHWLX.js";
5
5
  import {
6
6
  getMachineId
7
- } from "./chunk-465UENKO.js";
7
+ } from "./chunk-3T52B2OF.js";
8
8
  import {
9
9
  pusharyDir,
10
10
  resolveGlobalBinary
11
- } from "./chunk-34NNTYK6.js";
11
+ } from "./chunk-SAF6NNXY.js";
12
12
  import {
13
13
  getPackageVersion
14
14
  } from "./chunk-DINDL2CF.js";
15
15
  import {
16
16
  readControlMode
17
- } from "./chunk-5SALHATY.js";
17
+ } from "./chunk-TI3ZWXZG.js";
18
18
  import {
19
19
  readJsonSafe,
20
20
  writeFileAtomic,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pusharyDir
3
- } from "./chunk-34NNTYK6.js";
3
+ } from "./chunk-SAF6NNXY.js";
4
4
  import {
5
5
  writeFileAtomic
6
6
  } from "./chunk-T7E75EKA.js";
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  openCodeConfigDirFrom
3
- } from "./chunk-XVE52YFZ.js";
3
+ } from "./chunk-VYUDGQM7.js";
4
4
  import {
5
5
  codexHomeFrom
6
- } from "./chunk-34NNTYK6.js";
6
+ } from "./chunk-SAF6NNXY.js";
7
7
  import {
8
8
  HOOK_COMPATIBLE_PROFILES
9
- } from "./chunk-5UWDYOZX.js";
9
+ } from "./chunk-FVKFDTN6.js";
10
10
 
11
11
  // src/vscode-config.ts
12
12
  import { homedir } from "os";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  SETUP_FLAGS
3
- } from "./chunk-FGNABUPN.js";
3
+ } from "./chunk-R3AMKNIW.js";
4
4
  import {
5
5
  parseFlags
6
6
  } from "./chunk-GMXKITVA.js";
@@ -14,7 +14,7 @@ import {
14
14
  CLAUDE_CONNECTOR_URL,
15
15
  COWORK_CONNECTOR_LIMIT,
16
16
  COWORK_STANDING_INSTRUCTIONS
17
- } from "./chunk-5UWDYOZX.js";
17
+ } from "./chunk-FVKFDTN6.js";
18
18
 
19
19
  // src/cli/cowork.ts
20
20
  import { readFileSync } from "fs";
@@ -1,9 +1,29 @@
1
1
  import {
2
2
  registerTranscript
3
- } from "./chunk-P232YODQ.js";
3
+ } from "./chunk-TNS3YLFE.js";
4
4
  import {
5
5
  degradedLine
6
- } from "./chunk-5UWDYOZX.js";
6
+ } from "./chunk-FVKFDTN6.js";
7
+
8
+ // src/tool-hook-input.ts
9
+ var OPTIONAL_TEXT_FIELDS = ["hook_event_name", "session_id", "cwd", "transcript_path", "tool_use_id", "permission_mode"];
10
+ function isInputRecord(value) {
11
+ return value !== null && typeof value === "object" && !Array.isArray(value);
12
+ }
13
+ function isToolHookInput(value) {
14
+ if (!isInputRecord(value)) return false;
15
+ if (typeof value.tool_name !== "string" || value.tool_name.length === 0) return false;
16
+ if (!isInputRecord(value.tool_input)) return false;
17
+ for (const field of OPTIONAL_TEXT_FIELDS) {
18
+ if (value[field] !== void 0 && typeof value[field] !== "string") return false;
19
+ }
20
+ return true;
21
+ }
22
+ function parseToolHookInput(value) {
23
+ if (!isInputRecord(value)) return null;
24
+ const input = { ...value, tool_input: value.tool_input === void 0 ? {} : value.tool_input };
25
+ return isToolHookInput(input) ? input : null;
26
+ }
7
27
 
8
28
  // src/admission.ts
9
29
  import { readFileSync } from "fs";
@@ -41,7 +61,7 @@ var matches = (rule, source, event) => {
41
61
  return (ruleSource === "*" || ruleSource === source) && (ruleEvent === "*" || ruleEvent === event);
42
62
  };
43
63
  var isAdmitted = (rules, source, event) => !rules.disabled.some((rule) => matches(rule, source, event));
44
- var readHookInput = async (source, fallbackEvent = "", stdin = process.stdin) => {
64
+ var readHookInput = async (source, fallbackEvent = "", stdin = process.stdin, parseInput) => {
45
65
  if (source === null) {
46
66
  process.stderr.write(`${degradedLine("hook", {
47
67
  reason: "unknown_agent",
@@ -61,17 +81,23 @@ var readHookInput = async (source, fallbackEvent = "", stdin = process.stdin) =>
61
81
  return null;
62
82
  }
63
83
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
64
- const event = eventNameOf(parsed) ?? fallbackEvent;
84
+ const input = parseInput ? parseInput(parsed) : parsed;
85
+ if (input === null) return null;
86
+ const event = eventNameOf(input) ?? fallbackEvent;
65
87
  if (!isAdmitted(readAdmissionRules(), source, event)) return null;
66
- if (stdin === process.stdin) registerTranscript(source, parsed);
67
- return parsed;
88
+ if (stdin === process.stdin) registerTranscript(source, input);
89
+ return input;
68
90
  };
69
91
  var eventNameOf = (input) => {
70
92
  if (!("hook_event_name" in input)) return void 0;
71
93
  const name = input.hook_event_name;
72
94
  return typeof name === "string" && name.length > 0 ? name : void 0;
73
95
  };
96
+ function readToolHookInput(source, event, stdin = process.stdin) {
97
+ return readHookInput(source, event, stdin, parseToolHookInput);
98
+ }
74
99
 
75
100
  export {
76
- readHookInput
101
+ readHookInput,
102
+ readToolHookInput
77
103
  };
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  canonicalGateInputs
3
- } from "./chunk-WOBHHXW5.js";
3
+ } from "./chunk-LNGYW6G4.js";
4
4
  import {
5
5
  canonicalJson
6
- } from "./chunk-34NNTYK6.js";
6
+ } from "./chunk-SAF6NNXY.js";
7
7
  import {
8
8
  writeFileAtomic
9
9
  } from "./chunk-T7E75EKA.js";
@@ -11,7 +11,7 @@ import {
11
11
  BLOCKED_ACTION_GRANT_TTL_SECONDS,
12
12
  blockedActionIdentity,
13
13
  shouldDeferToNativeMode
14
- } from "./chunk-5UWDYOZX.js";
14
+ } from "./chunk-FVKFDTN6.js";
15
15
 
16
16
  // src/native-defer.ts
17
17
  var nativeDeferOptions = () => {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  readConfigFileKey
3
- } from "./chunk-5SALHATY.js";
3
+ } from "./chunk-TI3ZWXZG.js";
4
4
 
5
5
  // src/bell/fleet.ts
6
6
  import { closeSync, constants, futimesSync, lstatSync, mkdirSync, openSync, readdirSync, unlinkSync } from "fs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  redactSecrets
3
- } from "./chunk-5UWDYOZX.js";
3
+ } from "./chunk-FVKFDTN6.js";
4
4
 
5
5
  // src/crypto.ts
6
6
  import nacl from "tweetnacl";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  describeKeyCheck,
3
3
  keyCheckFromResponse
4
- } from "./chunk-TW7KA27C.js";
4
+ } from "./chunk-QBS6LGEK.js";
5
5
  import {
6
6
  createIo
7
7
  } from "./chunk-5RUIFDTP.js";
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  NOTIFICATION_MATCHED_TYPES,
3
3
  POSTTOOLUSE_MIRRORED_TOOLS
4
- } from "./chunk-XP2KRTZD.js";
4
+ } from "./chunk-WEO5JCB4.js";
5
5
  import {
6
6
  isProtectedByScope,
7
7
  registerHookEntry
8
- } from "./chunk-34NNTYK6.js";
8
+ } from "./chunk-SAF6NNXY.js";
9
9
  import {
10
10
  CLAUDE_PRETOOLUSE_MATCHER,
11
11
  HOOK_BUDGETS,
12
12
  HOOK_LOCATOR_BINARY
13
- } from "./chunk-5UWDYOZX.js";
13
+ } from "./chunk-FVKFDTN6.js";
14
14
 
15
15
  // src/gemini-config.ts
16
16
  var GEMINI_HOOK_BINARY = "pushary-gemini-hook";
@@ -59,7 +59,7 @@ var COMMAND_LIST = [
59
59
  },
60
60
  { name: "doctor", module: "pushary-doctor", summary: "Verify your Pushary installation is working" },
61
61
  { name: "disconnect", module: "pushary-disconnect", summary: "Turn off one agent (claude|codex|gemini|cursor)" },
62
- { name: "clean", module: "pushary-clean", summary: "Remove all Pushary configuration (--yes for non-interactive)" },
62
+ { name: "clean", module: "pushary-clean", summary: "Remove Pushary from this machine (--everything: the Mac app's setup too, --dry-run: preview)" },
63
63
  { name: "mode", module: "pushary-mode", summary: "Choose where approval requests appear" },
64
64
  { name: "wait", module: "pushary-wait", summary: 'Show or set the "wait for your phone" ladder (pushary wait 45)' },
65
65
  { name: "stats", module: "pushary-stats", summary: "Show the approval moments your agents hit while not connected" },
@@ -98,6 +98,7 @@ var COMMAND_OPTIONS = {
98
98
  ],
99
99
  clean: [
100
100
  ["--dry-run", "List everything it would remove and change nothing"],
101
+ ["--everything", "Also remove what the Mac app set up: quits it, then its keychain items, local state and editor extension"],
101
102
  ["--yes", "Remove everything without asking"]
102
103
  ],
103
104
  transcripts: [
@@ -216,7 +216,7 @@ var AGENTS = {
216
216
  connectVia: "Native hooks",
217
217
  setupCommand: "npx @pushary/agent-hooks setup",
218
218
  enforcementDetail: "exec, write and edit through native PreToolUse hooks, answered in Devin's own approve/block schema.",
219
- capabilityNote: "Devin CLI answers PreToolUse with `{decision}` rather than a permission decision. That schema has no third value, so where another agent would be asked, Pushary stays silent and Devin's own prompt decides; and it cannot carry an updated tool input, so Devin's own question and plan dialogs are left alone rather than answered from the phone without the answer reaching it. It also fires no Notification event."
219
+ capabilityNote: "Devin CLI answers PreToolUse with `{decision}` rather than a permission decision. Pushary blocks an unanswered approval because this adapter cannot request a native prompt reliably. Question and plan dialogs remain with Devin; this adapter does not render their answers. It also fires no Notification event."
220
220
  },
221
221
  windsurf: {
222
222
  ...defaults,
@@ -292,7 +292,8 @@ var toToolLookup = (profile, toolName, toolInput, resolvePath = (path) => path)
292
292
  var renderPreToolUseVerdict = (profile, verdict) => {
293
293
  if (profile.wire === "permission_decision") return verdict;
294
294
  const { permissionDecision, permissionDecisionReason, updatedInput } = verdict.hookSpecificOutput;
295
- if (permissionDecision === "ask" || updatedInput) return void 0;
295
+ if (permissionDecision === "ask") return { decision: "block", reason: permissionDecisionReason ?? "Pushary requires an explicit approval before this tool can run." };
296
+ if (updatedInput) return void 0;
296
297
  const stop = verdict.continue === false ? { continue: false, ...verdict.stopReason ? { stopReason: verdict.stopReason } : {} } : {};
297
298
  return {
298
299
  decision: permissionDecision === "allow" ? "approve" : "block",
@@ -333,7 +334,9 @@ var QWEN_CODE = {
333
334
  replace: "Edit",
334
335
  read_file: "Read",
335
336
  WriteFile: "Write",
336
- ReadFile: "Read"
337
+ ReadFile: "Read",
338
+ ask_user_question: "AskUserQuestion",
339
+ exit_plan_mode: "ExitPlanMode"
337
340
  },
338
341
  extraMatchers: ["mcp__.*"],
339
342
  pathInputKeys: ["absolute_path"],
@@ -415,12 +418,14 @@ var DEVIN = {
415
418
  exec: "Bash",
416
419
  write: "Write",
417
420
  edit: "Edit",
421
+ apply_patch: "Edit",
422
+ notebook_edit: "NotebookEdit",
418
423
  read: "Read",
419
424
  webfetch: "WebFetch",
420
425
  web_search: "WebSearch",
421
426
  run_subagent: "Task"
422
427
  },
423
- extraMatchers: ["mcp__.*"],
428
+ extraMatchers: ["mcp__.*", "mcp_call_tool", "write_to_process"],
424
429
  pathInputKeys: [],
425
430
  shellCommandKeys: [],
426
431
  shellContextKeys: [],
@@ -602,6 +607,8 @@ var hookWaitClamped = (startMs, policyWaitSeconds, agent, nowMs) => startMs + ho
602
607
  var effectiveWaitSeconds = (timeoutAction, policySeconds, agent) => timeoutAction === "wait" ? hookMaxWaitSeconds(agent) : policySeconds;
603
608
  var OPENCODE_APPROVAL_EVENT = "permission.ask";
604
609
  var CURSOR_GATE_EVENTS = ["beforeShellExecution", "beforeMCPExecution", "preToolUse"];
610
+ var SUPPORT_EMAIL = "business@pushary.com";
611
+ var SUPPORT_DISCORD = "https://discord.gg/9v3VvUByrr";
605
612
  var HOOK_LOCATOR_BINARY = "pushary-bridge";
606
613
  var HOOK_BATCH_MAX_BYTES = 4 * 1024 * 1024;
607
614
  var REPO_KEY_MAX_LENGTH = 200;
@@ -1221,6 +1228,7 @@ var computeDeltaSignal = (input) => {
1221
1228
  return { deltaSignal: "match", deltaScore: 0, remoteApprove: !destructive };
1222
1229
  };
1223
1230
  var SECRET_REDACTION_RULES = [
1231
+ { pattern: /\bpk_[A-Za-z0-9_]+\.[A-Za-z0-9_]+/g, replacement: "[redacted]" },
1224
1232
  { pattern: /-----BEGIN[A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END[A-Z0-9 ]*PRIVATE KEY-----/g, replacement: "[redacted key]" },
1225
1233
  { pattern: /\bsk-[A-Za-z0-9_-]{16,}\b/g, replacement: "[redacted]" },
1226
1234
  { pattern: /\b[spr]k_(?:live|test)_[A-Za-z0-9]{8,}\b/g, replacement: "[redacted]" },
@@ -1344,6 +1352,10 @@ var ANSWER_SOURCES = [
1344
1352
  ];
1345
1353
  var isAnswerSource = (value) => typeof value === "string" && ANSWER_SOURCES.includes(value);
1346
1354
  var SETTLED_OUTCOMES = ["approve", "deny"];
1355
+ var SETTLED_OUTCOME = {
1356
+ approve: "approve",
1357
+ deny: "deny"
1358
+ };
1347
1359
  var isSettledOutcome = (value) => typeof value === "string" && SETTLED_OUTCOMES.includes(value);
1348
1360
  var classifyDecisionRisk = (toolName, toolTarget) => {
1349
1361
  const parts = [toolName, toolTarget ?? ""];
@@ -1621,6 +1633,10 @@ var resolvePolicyAcross = (config, toolName, modeOverride, toolInputs, cwd, repo
1621
1633
  };
1622
1634
  var isModeStateDegraded = (state) => state?.degraded === true;
1623
1635
  var KILL_REASON = "Stopped by user, this agent was halted from Pushary";
1636
+ var GATE_ALLOW_SOURCE = {
1637
+ allowlist: "allowlist",
1638
+ policy: "policy"
1639
+ };
1624
1640
  var PUSHARY_TOOL_PREFIX = "mcp__pushary__";
1625
1641
  var isPusharyOwnTool = (toolName) => toolName.startsWith(PUSHARY_TOOL_PREFIX);
1626
1642
  var strictestScopeVerdict = (scope, paths) => {
@@ -1649,7 +1665,15 @@ var shouldDeferToNativeMode = (permissionMode, toolName, options = {}) => {
1649
1665
  if (permissionMode === "bypassPermissions") return options.deferBypass === true;
1650
1666
  return false;
1651
1667
  };
1652
- var ASKED_IN_EVERY_MODE_TOOLS = ["AskUserQuestion", "ExitPlanMode"];
1668
+ var AGENT_QUESTION_TOOL = "AskUserQuestion";
1669
+ var AGENT_QUESTION_STRATEGY = { native: "native_dialog", updatedInput: "updated_input", none: "not_a_question" };
1670
+ var UPDATED_INPUT_QUESTION_SOURCES = /* @__PURE__ */ new Set(["claude", "qoder", "codebuddy", "droid"]);
1671
+ function agentQuestionStrategy(source, event, toolName) {
1672
+ if (toolName !== AGENT_QUESTION_TOOL) return AGENT_QUESTION_STRATEGY.none;
1673
+ if (source !== null && event === "PreToolUse" && UPDATED_INPUT_QUESTION_SOURCES.has(source)) return AGENT_QUESTION_STRATEGY.updatedInput;
1674
+ return AGENT_QUESTION_STRATEGY.native;
1675
+ }
1676
+ var ASKED_IN_EVERY_MODE_TOOLS = [AGENT_QUESTION_TOOL, "ExitPlanMode"];
1653
1677
  var ASKED_IN_EVERY_MODE = new Set(ASKED_IN_EVERY_MODE_TOOLS);
1654
1678
  var isAskedInEveryMode = (toolName) => ASKED_IN_EVERY_MODE.has(toolName);
1655
1679
  var NATIVE_BLOCK_EVENTS = /* @__PURE__ */ new Set(["PermissionDenied"]);
@@ -1728,6 +1752,8 @@ var resolveGate = (input) => {
1728
1752
  scopePath: scopeReason && "path" in scopeVerdict ? widenablePath(scopeVerdict.path) : void 0
1729
1753
  };
1730
1754
  };
1755
+ var editAsksAtTheAgentsPrompt = (input, verdict) => verdict.kind === "gate" && !verdict.scopeReason && (input.modeState.mode ?? input.config.modeOverride ?? null) === null && verdict.policy.origin === "builtin" && verdict.policy.mode === "push_first" && ACCEPT_EDITS_DEFER_TOOLS.has(input.toolName);
1756
+ var claudePromptsBeforeAnEdit = (permissionMode) => permissionMode === "default";
1731
1757
  var toPolicyVersion = (value) => typeof value === "string" || typeof value === "number" ? String(value) : null;
1732
1758
  var modeStateFromResponse = (data) => {
1733
1759
  const mode = data.override?.mode;
@@ -1747,6 +1773,42 @@ var modeStateFromResponse = (data) => {
1747
1773
  var GATE_WIRE = 1;
1748
1774
  var GATE_MAX_TOOL_INPUTS = 32;
1749
1775
  var GATE_BLOCK_REASON_MAX_LENGTH = 200;
1776
+ var wireVerdictFor = (verdict, deadlineSeconds) => {
1777
+ switch (verdict.kind) {
1778
+ case "kill":
1779
+ return { kind: "kill", reason: verdict.reason };
1780
+ case "allow":
1781
+ return { kind: "allow", source: verdict.source, policy: verdict.policy };
1782
+ case "deny":
1783
+ return { kind: "deny", reason: verdict.reason, policy: verdict.policy };
1784
+ case "defer":
1785
+ return { kind: "no_opinion", reason: verdict.reason === "own_tool" ? "not_gated" : "degraded" };
1786
+ case "gate":
1787
+ return {
1788
+ kind: "ask",
1789
+ policy: verdict.policy,
1790
+ deadlineSeconds,
1791
+ ...verdict.scopeReason ? { scopeReason: verdict.scopeReason } : {},
1792
+ ...verdict.scopePath ? { scopePath: verdict.scopePath } : {}
1793
+ };
1794
+ }
1795
+ };
1796
+ var machineDecisionFor = (verdict) => {
1797
+ switch (verdict.kind) {
1798
+ case "kill":
1799
+ return { origin: DECISION_ORIGIN.killSwitch, outcome: SETTLED_OUTCOME.deny };
1800
+ case "allow":
1801
+ return {
1802
+ origin: verdict.source === GATE_ALLOW_SOURCE.allowlist ? DECISION_ORIGIN.safeReadonly : DECISION_ORIGIN.autopilot,
1803
+ outcome: SETTLED_OUTCOME.approve
1804
+ };
1805
+ case "deny":
1806
+ return { origin: DECISION_ORIGIN.autopilot, outcome: SETTLED_OUTCOME.deny };
1807
+ case "ask":
1808
+ case "no_opinion":
1809
+ return null;
1810
+ }
1811
+ };
1750
1812
  var claudePermissionDeniedOutput = (decision) => ({
1751
1813
  hookSpecificOutput: {
1752
1814
  hookEventName: "PermissionDenied",
@@ -1807,7 +1869,6 @@ var claudePermissionRequestOutput = (decision, reason, updatedInput) => ({
1807
1869
  decision: decision === "allow" ? { behavior: "allow", ...updatedInput ? { updatedInput } : {} } : { behavior: "deny", ...reason ? { message: reason } : {} }
1808
1870
  }
1809
1871
  });
1810
- var COMPATIBLE_GATE_EVENT = "PreToolUse";
1811
1872
  var gateOutputFor = (source, event, decision, reason) => {
1812
1873
  let output;
1813
1874
  if (source === "claude" || source === "vscode") {
@@ -1847,8 +1908,12 @@ var gateOutputFor = (source, event, decision, reason) => {
1847
1908
  };
1848
1909
  } else {
1849
1910
  const profile = hookCompatibleProfileBySource(source);
1850
- if (profile && event === COMPATIBLE_GATE_EVENT) {
1851
- output = renderPreToolUseVerdict(profile, claudePreToolUseOutput(decision, reason));
1911
+ if (profile?.events.includes(event)) {
1912
+ if (event === "PreToolUse") {
1913
+ output = renderPreToolUseVerdict(profile, claudePreToolUseOutput(decision, reason));
1914
+ } else if (event === "PermissionRequest" && decision !== "ask") {
1915
+ output = claudePermissionRequestOutput(decision, reason);
1916
+ }
1852
1917
  }
1853
1918
  }
1854
1919
  return output;
@@ -2037,6 +2102,8 @@ export {
2037
2102
  effectiveWaitSeconds,
2038
2103
  OPENCODE_APPROVAL_EVENT,
2039
2104
  CURSOR_GATE_EVENTS,
2105
+ SUPPORT_EMAIL,
2106
+ SUPPORT_DISCORD,
2040
2107
  HOOK_LOCATOR_BINARY,
2041
2108
  normalizeRepoRemote,
2042
2109
  localRepoKey,
@@ -2055,6 +2122,8 @@ export {
2055
2122
  KILL_REASON,
2056
2123
  isPusharyOwnTool,
2057
2124
  shouldDeferToNativeMode,
2125
+ AGENT_QUESTION_STRATEGY,
2126
+ agentQuestionStrategy,
2058
2127
  CODEX_RESCUE_TOOL_NAME,
2059
2128
  isBlockedActionRequest,
2060
2129
  BLOCKED_ACTION_GRANT_TTL_SECONDS,
@@ -2063,10 +2132,14 @@ export {
2063
2132
  isPermissionRequestOwnedByPreToolUse,
2064
2133
  CLAUDE_PRETOOLUSE_MATCHER,
2065
2134
  resolveGate,
2135
+ editAsksAtTheAgentsPrompt,
2136
+ claudePromptsBeforeAnEdit,
2066
2137
  modeStateFromResponse,
2067
2138
  GATE_WIRE,
2068
2139
  GATE_MAX_TOOL_INPUTS,
2069
2140
  GATE_BLOCK_REASON_MAX_LENGTH,
2141
+ wireVerdictFor,
2142
+ machineDecisionFor,
2070
2143
  claudePermissionDeniedOutput,
2071
2144
  codexStopRescueOutput,
2072
2145
  stoppedOutput,