@pushary/agent-hooks 0.85.2 → 0.87.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.
Files changed (60) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/bin/pushary-bell-hook.js +4 -4
  3. package/dist/bin/pushary-bell.js +6 -6
  4. package/dist/bin/pushary-claude.js +12 -10
  5. package/dist/bin/pushary-clean.js +10 -9
  6. package/dist/bin/pushary-codex-bridge.js +5 -5
  7. package/dist/bin/pushary-codex-hook.js +13 -29
  8. package/dist/bin/pushary-codex.js +6 -4
  9. package/dist/bin/pushary-connect.js +6 -6
  10. package/dist/bin/pushary-daemon.js +4 -4
  11. package/dist/bin/pushary-disconnect.js +25 -10
  12. package/dist/bin/pushary-doctor.js +21 -15
  13. package/dist/bin/pushary-elicitation-hook.d.ts +1 -0
  14. package/dist/bin/pushary-elicitation-hook.js +210 -0
  15. package/dist/bin/pushary-gemini-bridge.js +5 -5
  16. package/dist/bin/pushary-gemini-hook.js +10 -8
  17. package/dist/bin/pushary-hook.js +7 -8
  18. package/dist/bin/pushary-login.js +4 -4
  19. package/dist/bin/pushary-logout.js +4 -4
  20. package/dist/bin/pushary-mode.js +3 -3
  21. package/dist/bin/pushary-notification-hook.js +4 -3
  22. package/dist/bin/pushary-permission-denied-hook.js +7 -8
  23. package/dist/bin/pushary-permission-hook.js +7 -8
  24. package/dist/bin/pushary-post-hook.js +4 -3
  25. package/dist/bin/pushary-prompt-hook.js +4 -3
  26. package/dist/bin/pushary-session-end-hook.js +4 -3
  27. package/dist/bin/pushary-session-start-hook.js +4 -3
  28. package/dist/bin/pushary-setup.js +26 -21
  29. package/dist/bin/pushary-stats.js +2 -2
  30. package/dist/bin/pushary-status.js +5 -5
  31. package/dist/bin/pushary-stop-hook.js +4 -3
  32. package/dist/bin/pushary-stopfailure-hook.js +4 -3
  33. package/dist/bin/pushary-upgrade.js +13 -11
  34. package/dist/bin/pushary-wait.js +3 -3
  35. package/dist/{chunk-GM74DUMS.js → chunk-2T3GX7WG.js} +1 -1
  36. package/dist/{chunk-XJDL3MUE.js → chunk-5646VKR4.js} +18 -20
  37. package/dist/{chunk-PKUNB3SN.js → chunk-7MBDFNUC.js} +1 -1
  38. package/dist/{chunk-K337LIBD.js → chunk-7YJS2VTG.js} +36 -4
  39. package/dist/{chunk-LCA2EQTK.js → chunk-A3PFIWWN.js} +1 -1
  40. package/dist/{chunk-LSB6PFLN.js → chunk-A4I5JGCW.js} +1 -1
  41. package/dist/chunk-ATBKJNWS.js +19 -0
  42. package/dist/{chunk-KJW6NKF7.js → chunk-B3V2H6SA.js} +39 -15
  43. package/dist/{chunk-T54OT7IY.js → chunk-ECEUMWBH.js} +1 -1
  44. package/dist/{chunk-Q4URN3E7.js → chunk-HAUTLCMA.js} +1 -1
  45. package/dist/{chunk-Y7E2MC3G.js → chunk-HJ44HIUW.js} +60 -31
  46. package/dist/{chunk-4U2YRHNF.js → chunk-IWL5LWIE.js} +2 -2
  47. package/dist/chunk-J3YDT4HM.js +128 -0
  48. package/dist/{chunk-NTIUQB3E.js → chunk-JAICP7BA.js} +1 -1
  49. package/dist/{chunk-HSGEEBBL.js → chunk-M7RYIZX6.js} +3 -3
  50. package/dist/{chunk-KZIGJLOX.js → chunk-OT4YD54Q.js} +1 -1
  51. package/dist/{chunk-LXWISFF3.js → chunk-QBWYNVKY.js} +1 -1
  52. package/dist/{chunk-4YMWLMAP.js → chunk-SJVLFIYP.js} +1 -1
  53. package/dist/{chunk-DPDUB4XF.js → chunk-V2XPF77V.js} +104 -163
  54. package/dist/{chunk-JBLRZGTT.js → chunk-WLLBFDVY.js} +1 -1
  55. package/dist/{chunk-JT5NQQCE.js → chunk-XW5CHAQX.js} +2 -2
  56. package/dist/{chunk-CWV4CMB6.js → chunk-Y3UTTFTZ.js} +1 -1
  57. package/dist/{chunk-GY3I353G.js → chunk-ZZE6FN7T.js} +7 -3
  58. package/dist/src/index.d.ts +2 -2
  59. package/dist/src/index.js +11 -11
  60. package/package.json +3 -1
@@ -1,18 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  detectClaudeVersion
4
- } from "../chunk-Q4URN3E7.js";
4
+ } from "../chunk-HAUTLCMA.js";
5
5
  import {
6
6
  claudeWired,
7
7
  codexWired,
8
8
  geminiWired
9
- } from "../chunk-JT5NQQCE.js";
9
+ } from "../chunk-XW5CHAQX.js";
10
10
  import {
11
11
  runBrowserLogin
12
12
  } from "../chunk-Z3Z4VK5F.js";
13
13
  import {
14
14
  ensureDaemonRunning
15
- } from "../chunk-4YMWLMAP.js";
15
+ } from "../chunk-SJVLFIYP.js";
16
+ import {
17
+ addClaudeMcpServer,
18
+ addPusharyHooks,
19
+ addPusharyToolPermissions,
20
+ compareVersion,
21
+ parseVersion
22
+ } from "../chunk-5646VKR4.js";
16
23
  import {
17
24
  describeDetection,
18
25
  detectAllAgents,
@@ -24,23 +31,17 @@ import {
24
31
  shortenHome,
25
32
  vscodeSettingsTargets,
26
33
  writeInstructionBlock
27
- } from "../chunk-4U2YRHNF.js";
34
+ } from "../chunk-IWL5LWIE.js";
28
35
  import {
29
36
  GEMINI_HOOK_BINARY,
30
37
  addGeminiHooks,
31
38
  addGeminiMcpServer
32
- } from "../chunk-GY3I353G.js";
33
- import {
34
- addClaudeMcpServer,
35
- addPusharyHooks,
36
- addPusharyToolPermissions,
37
- compareVersion,
38
- parseVersion
39
- } from "../chunk-XJDL3MUE.js";
39
+ } from "../chunk-ZZE6FN7T.js";
40
+ import "../chunk-ATBKJNWS.js";
40
41
  import {
41
42
  guardBinary,
42
43
  guardNodeScript
43
- } from "../chunk-HSGEEBBL.js";
44
+ } from "../chunk-M7RYIZX6.js";
44
45
  import "../chunk-XHKBHWLX.js";
45
46
  import {
46
47
  installGlobally,
@@ -58,6 +59,7 @@ import {
58
59
  codexAgentsMd2 as codexAgentsMd,
59
60
  codexConfigToml,
60
61
  codexHome,
62
+ codexHookPositions,
61
63
  codexSkillDir2 as codexSkillDir,
62
64
  cursorPluginDir,
63
65
  cursorUserHooks,
@@ -65,10 +67,11 @@ import {
65
67
  geminiSettings,
66
68
  pusharyConfigFile,
67
69
  vscodePluginDir
68
- } from "../chunk-KJW6NKF7.js";
70
+ } from "../chunk-B3V2H6SA.js";
69
71
  import {
70
72
  reportEvent
71
- } from "../chunk-DPDUB4XF.js";
73
+ } from "../chunk-V2XPF77V.js";
74
+ import "../chunk-J3YDT4HM.js";
72
75
  import "../chunk-RN3NOEJF.js";
73
76
  import {
74
77
  confirmAppConnection,
@@ -78,12 +81,12 @@ import {
78
81
  printConnectInstructions,
79
82
  setHumanStream,
80
83
  verifyRoundTrip
81
- } from "../chunk-LCA2EQTK.js";
84
+ } from "../chunk-A3PFIWWN.js";
82
85
  import "../chunk-3EGEA4KH.js";
83
86
  import {
84
87
  checkApiKey,
85
88
  describeKeyCheck
86
- } from "../chunk-LSB6PFLN.js";
89
+ } from "../chunk-A4I5JGCW.js";
87
90
  import {
88
91
  useColor
89
92
  } from "../chunk-5RUIFDTP.js";
@@ -94,7 +97,7 @@ import {
94
97
  readConfigFileKey,
95
98
  readKeySource,
96
99
  writeKey
97
- } from "../chunk-KZIGJLOX.js";
100
+ } from "../chunk-OT4YD54Q.js";
98
101
  import {
99
102
  parseFlags
100
103
  } from "../chunk-GMXKITVA.js";
@@ -117,7 +120,7 @@ import {
117
120
  } from "../chunk-6MTNS63X.js";
118
121
  import "../chunk-BSZYIAZL.js";
119
122
  import "../chunk-SAF6HGAA.js";
120
- import "../chunk-CWV4CMB6.js";
123
+ import "../chunk-Y3UTTFTZ.js";
121
124
  import {
122
125
  UsageError
123
126
  } from "../chunk-7QLSKOSU.js";
@@ -127,7 +130,7 @@ import {
127
130
  import "../chunk-2UMNXADU.js";
128
131
  import {
129
132
  isValidApiKey
130
- } from "../chunk-K337LIBD.js";
133
+ } from "../chunk-7YJS2VTG.js";
131
134
 
132
135
  // bin/pushary-setup.ts
133
136
  import { existsSync, readFileSync, writeFileSync, mkdirSync, cpSync, rmSync, renameSync, realpathSync, readdirSync, statSync } from "fs";
@@ -940,10 +943,12 @@ var setupCodex = async (apiKey) => {
940
943
  let trusted = false;
941
944
  if (hooksSupported) {
942
945
  const hookCommand = guardBinary(resolveGlobalBinary("pushary-codex-hook") ?? "pushary-codex-hook");
946
+ let hookPositions = {};
943
947
  await spinner("Adding native hooks (~/.codex/hooks.json)", async () => {
944
948
  const hooksConfig = readAgentJson(CODEX_HOOKS_JSON);
945
949
  addCodexHooks(hooksConfig, hookCommand);
946
950
  writeJson(CODEX_HOOKS_JSON, hooksConfig);
951
+ hookPositions = codexHookPositions(hooksConfig);
947
952
  });
948
953
  if (trustAuto) {
949
954
  await spinner("Trusting the Pushary hook (skips the /hooks step)", async () => {
@@ -953,7 +958,7 @@ var setupCodex = async (apiKey) => {
953
958
  } catch {
954
959
  }
955
960
  const config = raw ? parseTOML(raw) : {};
956
- addCodexHookTrust(config, CODEX_HOOKS_JSON, hookCommand);
961
+ addCodexHookTrust(config, CODEX_HOOKS_JSON, hookCommand, hookPositions);
957
962
  writeFileSync(codexConfig, stringifyTOML(config), "utf-8");
958
963
  trusted = true;
959
964
  }, { optional: true });
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  readLedgerSummary
4
- } from "../chunk-PKUNB3SN.js";
4
+ } from "../chunk-7MBDFNUC.js";
5
5
  import {
6
6
  exitOnHelpFlag
7
7
  } from "../chunk-SQOFGPNX.js";
@@ -11,7 +11,7 @@ import "../chunk-KZERVKTD.js";
11
11
  import {
12
12
  getApiKey
13
13
  } from "../chunk-2UMNXADU.js";
14
- import "../chunk-K337LIBD.js";
14
+ import "../chunk-7YJS2VTG.js";
15
15
 
16
16
  // bin/pushary-stats.ts
17
17
  exitOnHelpFlag("stats");
@@ -8,18 +8,18 @@ import {
8
8
  describeReach,
9
9
  fetchChannels,
10
10
  reachVerdict
11
- } from "../chunk-LCA2EQTK.js";
11
+ } from "../chunk-A3PFIWWN.js";
12
12
  import "../chunk-3EGEA4KH.js";
13
13
  import {
14
14
  checkApiKey,
15
15
  describeKeyCheck
16
- } from "../chunk-LSB6PFLN.js";
16
+ } from "../chunk-A4I5JGCW.js";
17
17
  import {
18
18
  createIo
19
19
  } from "../chunk-5RUIFDTP.js";
20
20
  import {
21
21
  readKeySource
22
- } from "../chunk-KZIGJLOX.js";
22
+ } from "../chunk-OT4YD54Q.js";
23
23
  import {
24
24
  rejectUnknownFlags
25
25
  } from "../chunk-GMXKITVA.js";
@@ -32,7 +32,7 @@ import "../chunk-DINDL2CF.js";
32
32
  import "../chunk-6MTNS63X.js";
33
33
  import "../chunk-BSZYIAZL.js";
34
34
  import "../chunk-SAF6HGAA.js";
35
- import "../chunk-CWV4CMB6.js";
35
+ import "../chunk-Y3UTTFTZ.js";
36
36
  import {
37
37
  UsageError
38
38
  } from "../chunk-7QLSKOSU.js";
@@ -40,7 +40,7 @@ import {
40
40
  EXIT
41
41
  } from "../chunk-KZERVKTD.js";
42
42
  import "../chunk-2UMNXADU.js";
43
- import "../chunk-K337LIBD.js";
43
+ import "../chunk-7YJS2VTG.js";
44
44
 
45
45
  // src/status.ts
46
46
  var keySourceLine = (source) => {
@@ -4,15 +4,16 @@ import {
4
4
  } from "../chunk-6CUUA7HO.js";
5
5
  import {
6
6
  handleStop
7
- } from "../chunk-DPDUB4XF.js";
7
+ } from "../chunk-V2XPF77V.js";
8
+ import "../chunk-J3YDT4HM.js";
8
9
  import "../chunk-RN3NOEJF.js";
9
10
  import "../chunk-BSZYIAZL.js";
10
11
  import "../chunk-SAF6HGAA.js";
11
- import "../chunk-CWV4CMB6.js";
12
+ import "../chunk-Y3UTTFTZ.js";
12
13
  import "../chunk-7QLSKOSU.js";
13
14
  import "../chunk-KZERVKTD.js";
14
15
  import "../chunk-2UMNXADU.js";
15
- import "../chunk-K337LIBD.js";
16
+ import "../chunk-7YJS2VTG.js";
16
17
 
17
18
  // bin/pushary-stop-hook.ts
18
19
  var main = async () => {
@@ -4,15 +4,16 @@ import {
4
4
  } from "../chunk-6CUUA7HO.js";
5
5
  import {
6
6
  handleStopFailure
7
- } from "../chunk-DPDUB4XF.js";
7
+ } from "../chunk-V2XPF77V.js";
8
+ import "../chunk-J3YDT4HM.js";
8
9
  import "../chunk-RN3NOEJF.js";
9
10
  import "../chunk-BSZYIAZL.js";
10
11
  import "../chunk-SAF6HGAA.js";
11
- import "../chunk-CWV4CMB6.js";
12
+ import "../chunk-Y3UTTFTZ.js";
12
13
  import "../chunk-7QLSKOSU.js";
13
14
  import "../chunk-KZERVKTD.js";
14
15
  import "../chunk-2UMNXADU.js";
15
- import "../chunk-K337LIBD.js";
16
+ import "../chunk-7YJS2VTG.js";
16
17
 
17
18
  // bin/pushary-stopfailure-hook.ts
18
19
  var main = async () => {
@@ -1,21 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  detectClaudeVersion
4
- } from "../chunk-Q4URN3E7.js";
4
+ } from "../chunk-HAUTLCMA.js";
5
+ import {
6
+ addClaudeMcpServer,
7
+ addPusharyHooks,
8
+ addPusharyToolPermissions
9
+ } from "../chunk-5646VKR4.js";
5
10
  import {
6
11
  GEMINI_HOOK_BINARY,
7
12
  addGeminiHooks,
8
13
  addGeminiMcpServer,
9
14
  hasGeminiHooks
10
- } from "../chunk-GY3I353G.js";
11
- import {
12
- addClaudeMcpServer,
13
- addPusharyHooks,
14
- addPusharyToolPermissions
15
- } from "../chunk-XJDL3MUE.js";
15
+ } from "../chunk-ZZE6FN7T.js";
16
+ import "../chunk-ATBKJNWS.js";
16
17
  import {
17
18
  guardBinary
18
- } from "../chunk-HSGEEBBL.js";
19
+ } from "../chunk-M7RYIZX6.js";
19
20
  import {
20
21
  execNpm,
21
22
  npmErrorMessage,
@@ -29,13 +30,14 @@ import {
29
30
  addCodexMcpServer,
30
31
  claudeJson,
31
32
  codexConfigToml,
33
+ codexHookPositions,
32
34
  codexHooksJson,
33
35
  cursorPluginDir,
34
36
  geminiSettings,
35
37
  hasCodexHooks,
36
38
  vscodePluginDir,
37
39
  vscodePluginMcp
38
- } from "../chunk-KJW6NKF7.js";
40
+ } from "../chunk-B3V2H6SA.js";
39
41
  import {
40
42
  exitOnHelpFlag
41
43
  } from "../chunk-SQOFGPNX.js";
@@ -50,7 +52,7 @@ import "../chunk-KZERVKTD.js";
50
52
  import {
51
53
  getApiKey
52
54
  } from "../chunk-2UMNXADU.js";
53
- import "../chunk-K337LIBD.js";
55
+ import "../chunk-7YJS2VTG.js";
54
56
 
55
57
  // bin/pushary-upgrade.ts
56
58
  import { existsSync as existsSync2 } from "fs";
@@ -137,7 +139,7 @@ var reapplyCodexSettings = (apiKey, paths = {}) => {
137
139
  }
138
140
  if (config != null) {
139
141
  try {
140
- if (hooks) addCodexHookTrust(config, hooksPath, command);
142
+ if (hooks) addCodexHookTrust(config, hooksPath, command, codexHookPositions(hooksConfig ?? void 0));
141
143
  if (apiKey) {
142
144
  addCodexMcpServer(config, apiKey);
143
145
  mcp = true;
@@ -4,8 +4,8 @@ import {
4
4
  } from "../chunk-IIENZE2J.js";
5
5
  import {
6
6
  exitOnFailedResponse
7
- } from "../chunk-NTIUQB3E.js";
8
- import "../chunk-LSB6PFLN.js";
7
+ } from "../chunk-JAICP7BA.js";
8
+ import "../chunk-A4I5JGCW.js";
9
9
  import {
10
10
  createIo
11
11
  } from "../chunk-5RUIFDTP.js";
@@ -28,7 +28,7 @@ import {
28
28
  getApiKey,
29
29
  getBaseUrl
30
30
  } from "../chunk-2UMNXADU.js";
31
- import "../chunk-K337LIBD.js";
31
+ import "../chunk-7YJS2VTG.js";
32
32
 
33
33
  // bin/pushary-wait.ts
34
34
  exitOnHelpFlag("wait");
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  readConfigFileKey
3
- } from "./chunk-KZIGJLOX.js";
3
+ } from "./chunk-OT4YD54Q.js";
4
4
 
5
5
  // src/bell/fleet.ts
6
6
  import { closeSync, constants, futimesSync, lstatSync, mkdirSync, openSync, readdirSync, unlinkSync } from "fs";
@@ -1,9 +1,14 @@
1
+ import {
2
+ PRETOOLUSE_GATED_TOOLS,
3
+ PRETOOLUSE_PHONE_ANSWERED_TOOLS
4
+ } from "./chunk-ATBKJNWS.js";
1
5
  import {
2
6
  guardBinary
3
- } from "./chunk-HSGEEBBL.js";
7
+ } from "./chunk-M7RYIZX6.js";
4
8
  import {
5
- HOOK_BUDGETS
6
- } from "./chunk-K337LIBD.js";
9
+ HOOK_BUDGETS,
10
+ HOOK_LOCATOR_BINARY
11
+ } from "./chunk-7YJS2VTG.js";
7
12
 
8
13
  // src/claude-config.ts
9
14
  import { join } from "path";
@@ -21,21 +26,8 @@ var compareVersion = (a, b) => {
21
26
  };
22
27
  var atLeast = (version, floor) => compareVersion(version, floor) >= 0;
23
28
 
24
- // src/claude-tools.ts
25
- var PRETOOLUSE_GATED_TOOLS = [
26
- "Bash",
27
- "Write",
28
- "Edit",
29
- "MultiEdit",
30
- "NotebookEdit",
31
- "PowerShell",
32
- "Monitor"
33
- ];
34
- var POSTTOOLUSE_MIRRORED_TOOLS = [...PRETOOLUSE_GATED_TOOLS, "TodoWrite"];
35
- var PRETOOLUSE_HANDLED_TOOLS = /* @__PURE__ */ new Set([...PRETOOLUSE_GATED_TOOLS, "AskUserQuestion"]);
36
-
37
29
  // src/claude-events.ts
38
- var GATED_TOOLS = [...PRETOOLUSE_GATED_TOOLS, "AskUserQuestion"].join("|");
30
+ var GATED_TOOLS = [...PRETOOLUSE_GATED_TOOLS, ...PRETOOLUSE_PHONE_ANSWERED_TOOLS].join("|");
39
31
  var MIRRORED_TOOLS = [...PRETOOLUSE_GATED_TOOLS, "TodoWrite"].join("|");
40
32
  var ESTABLISHED = [1, 0, 0];
41
33
  var OBSERVED = [2, 0, 0];
@@ -56,7 +48,11 @@ var CLAUDE_HOOK_EVENTS = [
56
48
  { event: "SubagentStop", binary: "pushary-stop-hook", timeout: 10, delivery: "telemetry", since: OBSERVED },
57
49
  { event: "PreCompact", binary: "pushary-post-hook", matcher: "manual|auto", timeout: 10, delivery: "telemetry", since: OBSERVED },
58
50
  { event: "PostCompact", binary: "pushary-post-hook", matcher: "manual|auto", timeout: 10, delivery: "telemetry", since: OBSERVED },
59
- { event: "TeammateIdle", binary: "pushary-notification-hook", timeout: 10, delivery: "telemetry", since: OBSERVED }
51
+ { event: "TeammateIdle", binary: "pushary-notification-hook", timeout: 10, delivery: "telemetry", since: OBSERVED },
52
+ // An MCP server asking the person for a value, answered from the phone rather
53
+ // than the terminal. No matcher: Claude Code matches this event on the MCP
54
+ // server's name, and we have no business preferring one server over another.
55
+ { event: "Elicitation", binary: "pushary-elicitation-hook", timeout: HOOK_BUDGETS.claude.budgetSeconds, delivery: "approval", since: OBSERVED, cliOnly: true }
60
56
  ];
61
57
  var supportedClaudeEvents = (version) => CLAUDE_HOOK_EVENTS.filter((hook) => version ? atLeast(version, hook.since) : hook.since === ESTABLISHED);
62
58
 
@@ -72,7 +68,10 @@ var ensureRecord = (target, key) => {
72
68
  return created;
73
69
  };
74
70
  var isPusharyPermission = (rule) => typeof rule === "string" && (rule.includes("pushary") || rule.includes("MCP(pushary"));
75
- var HOOK_BINARIES = new Set(CLAUDE_HOOK_EVENTS.map((hook) => hook.binary));
71
+ var HOOK_BINARIES = /* @__PURE__ */ new Set([
72
+ ...CLAUDE_HOOK_EVENTS.map((hook) => hook.binary),
73
+ HOOK_LOCATOR_BINARY
74
+ ]);
76
75
  var namesPusharyBinary = (command) => command.split(/[\s/\\"']+/).some((segment) => HOOK_BINARIES.has(segment.replace(/\.(cmd|exe)$/i, "")));
77
76
  var isPusharyHook = (entry2) => {
78
77
  const hooks = asRecord(entry2)?.hooks;
@@ -178,7 +177,6 @@ var removePusharySettings = (settings) => {
178
177
  export {
179
178
  parseVersion,
180
179
  compareVersion,
181
- PRETOOLUSE_HANDLED_TOOLS,
182
180
  addClaudeMcpServer,
183
181
  removeClaudeMcpServers,
184
182
  addPusharyToolPermissions,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isSafeReadOnlyCommand
3
- } from "./chunk-K337LIBD.js";
3
+ } from "./chunk-7YJS2VTG.js";
4
4
 
5
5
  // src/ledger.ts
6
6
  import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync } from "fs";
@@ -53,7 +53,8 @@ var HOOK_BUDGETS = {
53
53
  gemini: { budgetSeconds: 180, guardSeconds: 10 },
54
54
  // The Cursor gate is a dependency-free .mjs that cannot import this module; it
55
55
  // mirrors these as MAX_BLOCK_MS (45s) inside its 60s failClosed budget.
56
- cursor: { budgetSeconds: 60, guardSeconds: 15 }
56
+ cursor: { budgetSeconds: 60, guardSeconds: 15 },
57
+ vscode: { budgetSeconds: 60, guardSeconds: 15 }
57
58
  };
58
59
  var hookMaxWaitSeconds = (agent) => Math.max(HOOK_BUDGETS[agent].budgetSeconds - HOOK_BUDGETS[agent].guardSeconds, 1);
59
60
  var hookWaitDeadline = (startMs, policyWaitSeconds, agent, nowMs) => {
@@ -65,6 +66,19 @@ var hookWaitDeadline = (startMs, policyWaitSeconds, agent, nowMs) => {
65
66
  };
66
67
  var hookWaitClamped = (startMs, policyWaitSeconds, agent, nowMs) => startMs + hookMaxWaitSeconds(agent) * 1e3 < nowMs + Math.max(policyWaitSeconds, 0) * 1e3;
67
68
  var effectiveWaitSeconds = (timeoutAction, policySeconds, agent) => timeoutAction === "wait" ? hookMaxWaitSeconds(agent) : policySeconds;
69
+ var AGENT_LABELS_BY_TYPE = {
70
+ claude_code: "Claude Code",
71
+ claude_cowork: "Claude Cowork",
72
+ codex: "Codex",
73
+ chatgpt: "ChatGPT",
74
+ gemini_cli: "Gemini CLI",
75
+ hermes: "Hermes",
76
+ cursor: "Cursor",
77
+ vscode: "VS Code",
78
+ windsurf: "Windsurf",
79
+ unknown: "Agent"
80
+ };
81
+ var HOOK_LOCATOR_BINARY = "pushary-bridge";
68
82
  var HOOK_BATCH_MAX_BYTES = 4 * 1024 * 1024;
69
83
  var REPO_KEY_MAX_LENGTH = 200;
70
84
  var isRepoKeyMatch = (ruleRepoKey, currentRepoKey) => {
@@ -502,6 +516,8 @@ var selectGoverningRule = (policies, toolName, args, repoKey, sessionId) => {
502
516
  }
503
517
  return best;
504
518
  };
519
+ var ARG_PREFIX_TARGET_TOOLS = Object.keys(POLICY_COMMAND_KEYS);
520
+ var FILE_TARGET_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit"]);
505
521
  var API_KEY_PATTERN = /^pk_[a-f0-9]+\.[a-f0-9]+$/;
506
522
  var isValidApiKey = (value) => API_KEY_PATTERN.test(value);
507
523
  var ACTION_BODY_MAX = 4e3;
@@ -945,6 +961,7 @@ var resolvePolicy = (config, toolName, modeOverride, toolInput, cwd, repoKey, se
945
961
  pushFirstSeconds: config.defaultPushFirstSeconds ?? 20
946
962
  };
947
963
  const governedBySpecificRule = match?.rank === "exact" || match?.rank === "prefix";
964
+ const governingMode = base.mode;
948
965
  if (!governedBySpecificRule && toolName === "Bash" && typeof arg === "string" && isSafeReadOnlyCommand(arg)) {
949
966
  base = autoApprove(base.tool);
950
967
  }
@@ -954,7 +971,7 @@ var resolvePolicy = (config, toolName, modeOverride, toolInput, cwd, repoKey, se
954
971
  tool: base.tool,
955
972
  timeoutSeconds: config.defaultTimeoutSeconds,
956
973
  timeoutAction: "wait",
957
- mode: "push_first",
974
+ mode: governingMode,
958
975
  pushFirstSeconds: config.defaultPushFirstSeconds ?? 20
959
976
  };
960
977
  }
@@ -1051,7 +1068,7 @@ var claudePermissionRequestOutput = (decision, reason, updatedInput) => ({
1051
1068
  });
1052
1069
  var gateOutputFor = (source, event, decision, reason) => {
1053
1070
  let output;
1054
- if (source === "claude") {
1071
+ if (source === "claude" || source === "vscode") {
1055
1072
  if (event === "PreToolUse") {
1056
1073
  output = claudePreToolUseOutput(decision, reason);
1057
1074
  } else if (event === "PermissionRequest" && decision !== "ask") {
@@ -1085,6 +1102,17 @@ var gateOutputFor = (source, event, decision, reason) => {
1085
1102
  }
1086
1103
  return output;
1087
1104
  };
1105
+ var ELICITATION_EVENTS = ["Elicitation", "ElicitationResult"];
1106
+ var claudeElicitationOutput = (event, action, content) => ({
1107
+ hookSpecificOutput: {
1108
+ hookEventName: event,
1109
+ action,
1110
+ // Only ever alongside an accept. A declined elicitation has nothing to carry,
1111
+ // and content beside a decline reads as an answer the person did not give.
1112
+ ...action === "accept" && content ? { content } : {}
1113
+ }
1114
+ });
1115
+ var renderElicitationOutput = (event, action, content) => ELICITATION_EVENTS.includes(event) ? JSON.stringify(claudeElicitationOutput(event, action, content)) : void 0;
1088
1116
 
1089
1117
  export {
1090
1118
  parseAgentQuestionAnswers,
@@ -1093,10 +1121,13 @@ export {
1093
1121
  hookWaitDeadline,
1094
1122
  hookWaitClamped,
1095
1123
  effectiveWaitSeconds,
1124
+ AGENT_LABELS_BY_TYPE,
1125
+ HOOK_LOCATOR_BINARY,
1096
1126
  normalizeRepoRemote,
1097
1127
  localRepoKey,
1098
1128
  isSafeReadOnlyCommand,
1099
1129
  isAutoApprove,
1130
+ FILE_TARGET_TOOLS,
1100
1131
  isValidApiKey,
1101
1132
  ACTION_BODY_MAX,
1102
1133
  DECISION_LINE_MAX,
@@ -1110,5 +1141,6 @@ export {
1110
1141
  modeStateFromResponse,
1111
1142
  claudePreToolUseOutput,
1112
1143
  claudePermissionRequestOutput,
1113
- gateOutputFor
1144
+ gateOutputFor,
1145
+ renderElicitationOutput
1114
1146
  };
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-BSZYIAZL.js";
12
12
  import {
13
13
  reportedInstallSource
14
- } from "./chunk-CWV4CMB6.js";
14
+ } from "./chunk-Y3UTTFTZ.js";
15
15
 
16
16
  // src/reach.ts
17
17
  var reachVerdict = (channels) => {
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-2UMNXADU.js";
13
13
  import {
14
14
  isValidApiKey
15
- } from "./chunk-K337LIBD.js";
15
+ } from "./chunk-7YJS2VTG.js";
16
16
 
17
17
  // src/session.ts
18
18
  var IDENTITY_PATH = "/api/v1/server/identity";
@@ -0,0 +1,19 @@
1
+ // src/claude-tools.ts
2
+ var PRETOOLUSE_GATED_TOOLS = [
3
+ "Bash",
4
+ "Write",
5
+ "Edit",
6
+ "MultiEdit",
7
+ "NotebookEdit",
8
+ "PowerShell",
9
+ "Monitor"
10
+ ];
11
+ var PRETOOLUSE_PHONE_ANSWERED_TOOLS = ["AskUserQuestion", "ExitPlanMode"];
12
+ var POSTTOOLUSE_MIRRORED_TOOLS = [...PRETOOLUSE_GATED_TOOLS, "TodoWrite"];
13
+ var PRETOOLUSE_HANDLED_TOOLS = /* @__PURE__ */ new Set([...PRETOOLUSE_GATED_TOOLS, ...PRETOOLUSE_PHONE_ANSWERED_TOOLS]);
14
+
15
+ export {
16
+ PRETOOLUSE_GATED_TOOLS,
17
+ PRETOOLUSE_PHONE_ANSWERED_TOOLS,
18
+ PRETOOLUSE_HANDLED_TOOLS
19
+ };
@@ -1,6 +1,7 @@
1
1
  import {
2
- HOOK_BUDGETS
3
- } from "./chunk-K337LIBD.js";
2
+ HOOK_BUDGETS,
3
+ HOOK_LOCATOR_BINARY
4
+ } from "./chunk-7YJS2VTG.js";
4
5
 
5
6
  // src/codex-config.ts
6
7
  import { createHash } from "crypto";
@@ -60,10 +61,13 @@ var readCodexMcpAuth = (config) => {
60
61
  if (typeof pushary.bearer_token === "string") return { method: "legacy-bearer" };
61
62
  return void 0;
62
63
  };
64
+ var isPusharyCommand = (hook) => {
65
+ const command = String(asRecord(hook)?.command ?? "");
66
+ return command.includes(CODEX_HOOK_BINARY) || command.includes(HOOK_LOCATOR_BINARY);
67
+ };
63
68
  var isPusharyCodexHook = (entry) => {
64
69
  const hooks = asRecord(entry)?.hooks;
65
- if (!Array.isArray(hooks)) return false;
66
- return hooks.some((hook) => String(asRecord(hook)?.command ?? "").includes(CODEX_HOOK_BINARY));
70
+ return Array.isArray(hooks) && hooks.some(isPusharyCommand);
67
71
  };
68
72
  var addCodexHooks = (config, command) => {
69
73
  const hooks = ensureRecord(config, "hooks");
@@ -130,13 +134,28 @@ var codexHookTrustHash = (definition, command) => {
130
134
  if (definition.matcher) identity.matcher = definition.matcher;
131
135
  return "sha256:" + createHash("sha256").update(canonicalJson(identity), "utf8").digest("hex");
132
136
  };
133
- var codexHookStateKey = (hooksJsonPath, event) => `${hooksJsonPath}:${CODEX_EVENT_KEY[event]}:0:0`;
134
- var untrustedCodexHookEvents = (config, hooksJsonPath, command) => {
137
+ var codexHookPositions = (hooksConfig) => {
138
+ const hooks = asRecord(hooksConfig?.hooks);
139
+ const positions = {};
140
+ for (const definition of CODEX_HOOK_EVENTS) {
141
+ const entries = hooks?.[definition.event];
142
+ if (!Array.isArray(entries)) continue;
143
+ const entryIndex = entries.findIndex(isPusharyCodexHook);
144
+ if (entryIndex < 0) continue;
145
+ const inner = asRecord(entries[entryIndex])?.hooks;
146
+ const hookIndex = Array.isArray(inner) ? inner.findIndex(isPusharyCommand) : -1;
147
+ positions[definition.event] = [entryIndex, Math.max(hookIndex, 0)];
148
+ }
149
+ return positions;
150
+ };
151
+ var codexHookStateKey = (hooksJsonPath, event, position) => `${hooksJsonPath}:${CODEX_EVENT_KEY[event]}:${position[0]}:${position[1]}`;
152
+ var untrustedCodexHookEvents = (config, hooksJsonPath, command, positions) => {
135
153
  const state = asRecord(asRecord(config.hooks)?.state);
136
154
  return CODEX_HOOK_EVENTS.filter((definition) => {
137
- const entry = asRecord(state?.[codexHookStateKey(hooksJsonPath, definition.event)]);
138
- const stored = entry?.trusted_hash;
139
- return stored !== codexHookTrustHash(definition, command);
155
+ const position = positions[definition.event];
156
+ if (!position) return false;
157
+ const entry = asRecord(state?.[codexHookStateKey(hooksJsonPath, definition.event, position)]);
158
+ return entry?.trusted_hash !== codexHookTrustHash(definition, command);
140
159
  }).map((definition) => definition.event);
141
160
  };
142
161
  var removeCodexMcpServer = (config) => {
@@ -146,12 +165,14 @@ var removeCodexMcpServer = (config) => {
146
165
  if (Object.keys(servers).length === 0) delete config.mcp_servers;
147
166
  return true;
148
167
  };
149
- var removeCodexHookTrust = (config, hooksJsonPath) => {
168
+ var removeCodexHookTrust = (config, hooksJsonPath, positions) => {
150
169
  const state = asRecord(asRecord(config.hooks)?.state);
151
170
  if (!state) return false;
152
171
  let changed = false;
153
172
  for (const definition of CODEX_HOOK_EVENTS) {
154
- const key = codexHookStateKey(hooksJsonPath, definition.event);
173
+ const position = positions[definition.event];
174
+ if (!position) continue;
175
+ const key = codexHookStateKey(hooksJsonPath, definition.event, position);
155
176
  if (key in state) {
156
177
  delete state[key];
157
178
  changed = true;
@@ -166,16 +187,18 @@ var removeCodexHookTrust = (config, hooksJsonPath) => {
166
187
  }
167
188
  return changed;
168
189
  };
169
- var removeCodexSettings = (config, hooksJsonPath) => {
190
+ var removeCodexSettings = (config, hooksJsonPath, positions) => {
170
191
  const mcp = removeCodexMcpServer(config);
171
- const trust = removeCodexHookTrust(config, hooksJsonPath);
192
+ const trust = removeCodexHookTrust(config, hooksJsonPath, positions);
172
193
  return mcp || trust;
173
194
  };
174
- var addCodexHookTrust = (config, hooksJsonPath, command) => {
195
+ var addCodexHookTrust = (config, hooksJsonPath, command, positions) => {
175
196
  const hooks = ensureRecord(config, "hooks");
176
197
  const state = ensureRecord(hooks, "state");
177
198
  for (const definition of CODEX_HOOK_EVENTS) {
178
- const key = codexHookStateKey(hooksJsonPath, definition.event);
199
+ const position = positions[definition.event];
200
+ if (!position) continue;
201
+ const key = codexHookStateKey(hooksJsonPath, definition.event, position);
179
202
  const existing = asRecord(state[key]) ?? {};
180
203
  state[key] = { ...existing, trusted_hash: codexHookTrustHash(definition, command) };
181
204
  }
@@ -214,6 +237,7 @@ export {
214
237
  removeCodexHooks,
215
238
  hasCodexHooks,
216
239
  missingCodexHookEvents,
240
+ codexHookPositions,
217
241
  untrustedCodexHookEvents,
218
242
  removeCodexSettings,
219
243
  addCodexHookTrust,
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-2UMNXADU.js";
4
4
  import {
5
5
  redactSecrets
6
- } from "./chunk-K337LIBD.js";
6
+ } from "./chunk-7YJS2VTG.js";
7
7
 
8
8
  // src/crypto.ts
9
9
  import nacl from "tweetnacl";