@pushary/agent-hooks 0.87.4 → 0.88.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 (62) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/data/cursor-plugin/scripts/pushary-gate.mjs +63 -7
  3. package/data/vscode-plugin/scripts/pushary-gate.mjs +56 -18
  4. package/dist/bin/pushary-bell-hook.js +4 -4
  5. package/dist/bin/pushary-bell.js +7 -7
  6. package/dist/bin/pushary-claude.js +9 -9
  7. package/dist/bin/pushary-clean.js +13 -14
  8. package/dist/bin/pushary-codex-bridge.js +6 -6
  9. package/dist/bin/pushary-codex-hook.js +15 -9
  10. package/dist/bin/pushary-codex.js +4 -4
  11. package/dist/bin/pushary-connect.js +6 -6
  12. package/dist/bin/pushary-daemon.js +5 -5
  13. package/dist/bin/pushary-disconnect.js +9 -11
  14. package/dist/bin/pushary-doctor.js +17 -16
  15. package/dist/bin/pushary-elicitation-hook.js +7 -120
  16. package/dist/bin/pushary-gemini-bridge.js +6 -6
  17. package/dist/bin/pushary-gemini-hook.js +15 -9
  18. package/dist/bin/pushary-hook.js +6 -6
  19. package/dist/bin/pushary-login.js +4 -4
  20. package/dist/bin/pushary-logout.js +4 -4
  21. package/dist/bin/pushary-mode.js +3 -3
  22. package/dist/bin/pushary-notification-hook.js +4 -4
  23. package/dist/bin/pushary-opencode-hook.js +5 -5
  24. package/dist/bin/pushary-permission-denied-hook.js +6 -6
  25. package/dist/bin/pushary-permission-hook.js +6 -6
  26. package/dist/bin/pushary-post-hook.js +4 -4
  27. package/dist/bin/pushary-prompt-hook.js +4 -4
  28. package/dist/bin/pushary-session-end-hook.js +4 -4
  29. package/dist/bin/pushary-session-start-hook.js +4 -4
  30. package/dist/bin/pushary-setup.js +26 -25
  31. package/dist/bin/pushary-stats.js +2 -2
  32. package/dist/bin/pushary-status.js +5 -5
  33. package/dist/bin/pushary-stop-hook.js +4 -4
  34. package/dist/bin/pushary-stopfailure-hook.js +4 -4
  35. package/dist/bin/pushary-upgrade.js +9 -11
  36. package/dist/bin/pushary-wait.js +3 -3
  37. package/dist/{chunk-H5PIPIKQ.js → chunk-4FANZF2L.js} +2 -2
  38. package/dist/{chunk-ZGC3W23N.js → chunk-4KMWTOBK.js} +4 -1
  39. package/dist/{chunk-QLMX5LLV.js → chunk-6GBQDZ7K.js} +1 -1
  40. package/dist/{chunk-B7ZBHWOW.js → chunk-AIGDBRIJ.js} +1 -1
  41. package/dist/{chunk-KBS53WOE.js → chunk-AJ4EMW5D.js} +1 -1
  42. package/dist/{chunk-ICERLAE2.js → chunk-DLI5IXSD.js} +1 -1
  43. package/dist/{chunk-YX6ZKCC5.js → chunk-EKNFTIKO.js} +1 -1
  44. package/dist/{chunk-K42RXJPG.js → chunk-F3ZDPL6O.js} +187 -60
  45. package/dist/{chunk-NAPRGHZ3.js → chunk-FRH2QIMY.js} +1 -1
  46. package/dist/{chunk-TV3UFGT7.js → chunk-LNAQWWBP.js} +1 -1
  47. package/dist/{chunk-7J67NYK4.js → chunk-LXTX5CT7.js} +2 -1
  48. package/dist/{chunk-KULUNLRO.js → chunk-O7P7O4VY.js} +3 -7
  49. package/dist/{chunk-VOE4SYPR.js → chunk-OSE7X44J.js} +23 -7
  50. package/dist/{chunk-VIHRP25S.js → chunk-PXEFENML.js} +1 -1
  51. package/dist/{chunk-DMW54VWK.js → chunk-Q6MK2YKV.js} +213 -4
  52. package/dist/{chunk-EJL3PJU7.js → chunk-SHVW5KFR.js} +1 -1
  53. package/dist/{chunk-QXZ2CKRK.js → chunk-SUZF64M4.js} +2 -2
  54. package/dist/{chunk-BFBAHOGR.js → chunk-U44C3ULB.js} +1 -1
  55. package/dist/{chunk-OMA2OZRE.js → chunk-U65EIMUJ.js} +27 -62
  56. package/dist/{chunk-KFAH6KRE.js → chunk-WFFPWJN6.js} +1 -1
  57. package/dist/{chunk-YYTLTEGU.js → chunk-WPDMGNQR.js} +1 -1
  58. package/dist/{chunk-TD3M232T.js → chunk-ZPRF4YLA.js} +1 -1
  59. package/dist/src/index.js +6 -6
  60. package/package.json +1 -1
  61. package/dist/chunk-2JYQAW4B.js +0 -137
  62. /package/dist/{chunk-VT4IVERX.js → chunk-PZA7G4CN.js} +0 -0
@@ -2,10 +2,177 @@ import {
2
2
  PRETOOLUSE_GATED_TOOLS,
3
3
  PRETOOLUSE_PHONE_ANSWERED_TOOLS
4
4
  } from "./chunk-ATBKJNWS.js";
5
+ import {
6
+ guardBinary
7
+ } from "./chunk-AIGDBRIJ.js";
5
8
  import {
6
9
  HOOK_BUDGETS,
7
10
  HOOK_LOCATOR_BINARY
8
- } from "./chunk-DMW54VWK.js";
11
+ } from "./chunk-Q6MK2YKV.js";
12
+
13
+ // src/claude-config.ts
14
+ import { join } from "path";
15
+
16
+ // src/agent-version.ts
17
+ var parseVersion = (raw) => {
18
+ const match = raw.match(/(\d+)\.(\d+)\.(\d+)/);
19
+ return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
20
+ };
21
+ var compareVersion = (a, b) => {
22
+ for (let index = 0; index < 3; index++) {
23
+ if (a[index] !== b[index]) return a[index] < b[index] ? -1 : 1;
24
+ }
25
+ return 0;
26
+ };
27
+ var atLeast = (version, floor) => compareVersion(version, floor) >= 0;
28
+
29
+ // src/claude-events.ts
30
+ var GATED_TOOLS = [...PRETOOLUSE_GATED_TOOLS, ...PRETOOLUSE_PHONE_ANSWERED_TOOLS].join("|");
31
+ var MIRRORED_TOOLS = [...PRETOOLUSE_GATED_TOOLS, "TodoWrite"].join("|");
32
+ var ESTABLISHED = [1, 0, 0];
33
+ var OBSERVED = [2, 0, 0];
34
+ var CLAUDE_HOOK_EVENTS = [
35
+ { event: "PreToolUse", binary: "pushary-hook", matcher: GATED_TOOLS, timeout: HOOK_BUDGETS.claude.budgetSeconds, delivery: "approval", since: ESTABLISHED },
36
+ { event: "PostToolUse", binary: "pushary-post-hook", matcher: MIRRORED_TOOLS, timeout: 10, delivery: "telemetry", since: ESTABLISHED },
37
+ { event: "Stop", binary: "pushary-stop-hook", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
38
+ { event: "UserPromptSubmit", binary: "pushary-prompt-hook", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
39
+ { event: "Notification", binary: "pushary-notification-hook", matcher: "permission_prompt|idle_prompt|agent_needs_input|agent_completed", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
40
+ { event: "SessionStart", binary: "pushary-session-start-hook", matcher: "startup|resume|clear", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
41
+ { event: "SessionEnd", binary: "pushary-session-end-hook", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
42
+ { event: "StopFailure", binary: "pushary-stopfailure-hook", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
43
+ { event: "PermissionRequest", binary: "pushary-permission-hook", timeout: HOOK_BUDGETS.claude.budgetSeconds, delivery: "approval", since: ESTABLISHED },
44
+ { event: "PermissionDenied", binary: "pushary-permission-denied-hook", timeout: 60, delivery: "telemetry", since: ESTABLISHED },
45
+ // Observability only. Each carries session shape the island cannot get any other
46
+ // way, and none of them decides anything.
47
+ { event: "SubagentStart", binary: "pushary-session-start-hook", timeout: 10, delivery: "telemetry", since: OBSERVED },
48
+ { event: "SubagentStop", binary: "pushary-stop-hook", timeout: 10, delivery: "telemetry", since: OBSERVED },
49
+ { event: "PreCompact", binary: "pushary-post-hook", matcher: "manual|auto", timeout: 10, delivery: "telemetry", since: OBSERVED },
50
+ { event: "PostCompact", binary: "pushary-post-hook", matcher: "manual|auto", 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 }
56
+ ];
57
+ var supportedClaudeEvents = (version) => CLAUDE_HOOK_EVENTS.filter((hook) => version ? atLeast(version, hook.since) : hook.since === ESTABLISHED);
58
+
59
+ // src/claude-config.ts
60
+ var PUSHARY_MCP_URL = "https://pushary.com/api/mcp/mcp";
61
+ var PUSHARY_PERMISSION_RULE = "mcp__pushary__*";
62
+ var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
63
+ var ensureRecord = (target, key) => {
64
+ const existing = asRecord(target[key]);
65
+ if (existing) return existing;
66
+ const created = {};
67
+ target[key] = created;
68
+ return created;
69
+ };
70
+ var isPusharyPermission = (rule) => typeof rule === "string" && (rule.includes("pushary") || rule.includes("MCP(pushary"));
71
+ var HOOK_BINARIES = /* @__PURE__ */ new Set([
72
+ ...CLAUDE_HOOK_EVENTS.map((hook) => hook.binary),
73
+ HOOK_LOCATOR_BINARY
74
+ ]);
75
+ var namesPusharyBinary = (command) => command.split(/[\s/\\"']+/).some((segment) => HOOK_BINARIES.has(segment.replace(/\.(cmd|exe)$/i, "")));
76
+ var isPusharyHook = (entry2) => {
77
+ const hooks = asRecord(entry2)?.hooks;
78
+ if (!Array.isArray(hooks)) return false;
79
+ return hooks.some((hook) => namesPusharyBinary(String(asRecord(hook)?.command ?? "")));
80
+ };
81
+ var addClaudeMcpServer = (config, apiKey) => {
82
+ const mcpServers = ensureRecord(config, "mcpServers");
83
+ mcpServers.pushary = {
84
+ type: "http",
85
+ url: PUSHARY_MCP_URL,
86
+ headers: { Authorization: `Bearer ${apiKey}` }
87
+ };
88
+ };
89
+ var removeClaudeMcpServers = (config) => {
90
+ let changed = false;
91
+ const removeFrom = (target) => {
92
+ const mcpServers = asRecord(target.mcpServers);
93
+ if (!mcpServers?.pushary) return;
94
+ delete mcpServers.pushary;
95
+ if (Object.keys(mcpServers).length === 0) delete target.mcpServers;
96
+ changed = true;
97
+ };
98
+ removeFrom(config);
99
+ const projects = asRecord(config.projects);
100
+ if (projects) {
101
+ for (const project of Object.values(projects)) {
102
+ const projectConfig = asRecord(project);
103
+ if (projectConfig) removeFrom(projectConfig);
104
+ }
105
+ }
106
+ return changed;
107
+ };
108
+ var addPusharyToolPermissions = (settings) => {
109
+ const permissions = ensureRecord(settings, "permissions");
110
+ const allow = Array.isArray(permissions.allow) ? permissions.allow : [];
111
+ const filtered = allow.filter((rule) => !isPusharyPermission(rule));
112
+ if (!filtered.includes(PUSHARY_PERMISSION_RULE)) {
113
+ filtered.push(PUSHARY_PERMISSION_RULE);
114
+ }
115
+ permissions.allow = filtered;
116
+ };
117
+ var addPusharyHooks = (settings, binDir, version = null) => {
118
+ const resolve = (name) => guardBinary(binDir ? join(binDir, name) : name);
119
+ const hooks = ensureRecord(settings, "hooks");
120
+ const supported = new Map(supportedClaudeEvents(version).map((hook) => [hook.event, hook]));
121
+ for (const known of CLAUDE_HOOK_EVENTS) {
122
+ const current = hooks[known.event];
123
+ const others = (Array.isArray(current) ? current : []).filter((item) => !isPusharyHook(item));
124
+ const definition = supported.get(known.event);
125
+ if (definition) {
126
+ hooks[known.event] = [...others, entry(definition, resolve)];
127
+ } else if (others.length > 0) {
128
+ hooks[known.event] = others;
129
+ } else {
130
+ delete hooks[known.event];
131
+ }
132
+ }
133
+ };
134
+ var entry = (definition, resolve) => ({
135
+ ...definition.matcher ? { matcher: definition.matcher } : {},
136
+ hooks: [{
137
+ type: "command",
138
+ command: resolve(definition.binary),
139
+ timeout: definition.timeout
140
+ }]
141
+ });
142
+ var removePusharySettings = (settings) => {
143
+ let changed = removeClaudeMcpServers(settings);
144
+ const permissions = asRecord(settings.permissions);
145
+ if (permissions && Array.isArray(permissions.allow)) {
146
+ const filtered = permissions.allow.filter((rule) => !isPusharyPermission(rule));
147
+ if (filtered.length !== permissions.allow.length) {
148
+ if (filtered.length === 0) {
149
+ delete permissions.allow;
150
+ } else {
151
+ permissions.allow = filtered;
152
+ }
153
+ if (Object.keys(permissions).length === 0) delete settings.permissions;
154
+ changed = true;
155
+ }
156
+ }
157
+ const hooks = asRecord(settings.hooks);
158
+ if (hooks) {
159
+ for (const { event: key } of CLAUDE_HOOK_EVENTS) {
160
+ const entries = hooks[key];
161
+ if (!Array.isArray(entries)) continue;
162
+ const filtered = entries.filter((entry2) => !isPusharyHook(entry2));
163
+ if (filtered.length !== entries.length) {
164
+ if (filtered.length === 0) {
165
+ delete hooks[key];
166
+ } else {
167
+ hooks[key] = filtered;
168
+ }
169
+ changed = true;
170
+ }
171
+ }
172
+ if (Object.keys(hooks).length === 0) delete settings.hooks;
173
+ }
174
+ return changed;
175
+ };
9
176
 
10
177
  // src/gemini-config.ts
11
178
  var GEMINI_HOOK_BINARY = "pushary-gemini-hook";
@@ -17,24 +184,24 @@ var GEMINI_HOOK_EVENTS = [
17
184
  { event: "SessionStart", delivery: "telemetry", timeoutMs: 1e4 },
18
185
  { event: "SessionEnd", delivery: "telemetry", timeoutMs: 1e4 }
19
186
  ];
20
- var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
21
- var ensureRecord = (target, key) => {
22
- const existing = asRecord(target[key]);
187
+ var asRecord2 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
188
+ var ensureRecord2 = (target, key) => {
189
+ const existing = asRecord2(target[key]);
23
190
  if (existing) return existing;
24
191
  const created = {};
25
192
  target[key] = created;
26
193
  return created;
27
194
  };
28
- var isPusharyGeminiHook = (entry) => {
29
- const hooks = asRecord(entry)?.hooks;
195
+ var isPusharyGeminiHook = (entry2) => {
196
+ const hooks = asRecord2(entry2)?.hooks;
30
197
  if (!Array.isArray(hooks)) return false;
31
198
  return hooks.some((hook) => {
32
- const command = String(asRecord(hook)?.command ?? "");
199
+ const command = String(asRecord2(hook)?.command ?? "");
33
200
  return command.includes(GEMINI_HOOK_BINARY) || command.includes(HOOK_LOCATOR_BINARY);
34
201
  });
35
202
  };
36
203
  var addGeminiMcpServer = (settings, apiKey) => {
37
- const mcpServers = ensureRecord(settings, "mcpServers");
204
+ const mcpServers = ensureRecord2(settings, "mcpServers");
38
205
  mcpServers.pushary = {
39
206
  httpUrl: GEMINI_MCP_URL,
40
207
  headers: { Authorization: `Bearer ${apiKey}` },
@@ -42,10 +209,10 @@ var addGeminiMcpServer = (settings, apiKey) => {
42
209
  };
43
210
  };
44
211
  var addGeminiHooks = (settings, command) => {
45
- const hooks = ensureRecord(settings, "hooks");
212
+ const hooks = ensureRecord2(settings, "hooks");
46
213
  for (const definition of GEMINI_HOOK_EVENTS) {
47
214
  const existing = Array.isArray(hooks[definition.event]) ? hooks[definition.event] : [];
48
- const entries = existing.filter((entry) => !isPusharyGeminiHook(entry));
215
+ const entries = existing.filter((entry2) => !isPusharyGeminiHook(entry2));
49
216
  entries.push({
50
217
  ...definition.matcher ? { matcher: definition.matcher } : {},
51
218
  hooks: [{
@@ -59,13 +226,13 @@ var addGeminiHooks = (settings, command) => {
59
226
  }
60
227
  };
61
228
  var removeGeminiHooks = (settings) => {
62
- const hooks = asRecord(settings.hooks);
229
+ const hooks = asRecord2(settings.hooks);
63
230
  if (!hooks) return false;
64
231
  let changed = false;
65
232
  for (const definition of GEMINI_HOOK_EVENTS) {
66
233
  const entries = hooks[definition.event];
67
234
  if (!Array.isArray(entries)) continue;
68
- const filtered = entries.filter((entry) => !isPusharyGeminiHook(entry));
235
+ const filtered = entries.filter((entry2) => !isPusharyGeminiHook(entry2));
69
236
  if (filtered.length !== entries.length) {
70
237
  if (filtered.length === 0) {
71
238
  delete hooks[definition.event];
@@ -79,7 +246,7 @@ var removeGeminiHooks = (settings) => {
79
246
  return changed;
80
247
  };
81
248
  var removeGeminiMcpServer = (settings) => {
82
- const mcpServers = asRecord(settings.mcpServers);
249
+ const mcpServers = asRecord2(settings.mcpServers);
83
250
  if (!mcpServers?.pushary) return false;
84
251
  delete mcpServers.pushary;
85
252
  if (Object.keys(mcpServers).length === 0) delete settings.mcpServers;
@@ -91,7 +258,7 @@ var removeGeminiSettings = (settings) => {
91
258
  return mcpRemoved || hooksRemoved;
92
259
  };
93
260
  var hasGeminiHooks = (settings) => {
94
- const hooks = asRecord(settings.hooks);
261
+ const hooks = asRecord2(settings.hooks);
95
262
  if (!hooks) return false;
96
263
  return GEMINI_HOOK_EVENTS.some((definition) => {
97
264
  const entries = hooks[definition.event];
@@ -99,61 +266,21 @@ var hasGeminiHooks = (settings) => {
99
266
  });
100
267
  };
101
268
  var missingGeminiHookEvents = (settings) => {
102
- const hooks = asRecord(settings.hooks);
269
+ const hooks = asRecord2(settings.hooks);
103
270
  return GEMINI_HOOK_EVENTS.filter((definition) => {
104
271
  const entries = hooks?.[definition.event];
105
272
  return !Array.isArray(entries) || !entries.some(isPusharyGeminiHook);
106
273
  }).map((definition) => definition.event);
107
274
  };
108
275
 
109
- // src/agent-version.ts
110
- var parseVersion = (raw) => {
111
- const match = raw.match(/(\d+)\.(\d+)\.(\d+)/);
112
- return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
113
- };
114
- var compareVersion = (a, b) => {
115
- for (let index = 0; index < 3; index++) {
116
- if (a[index] !== b[index]) return a[index] < b[index] ? -1 : 1;
117
- }
118
- return 0;
119
- };
120
- var atLeast = (version, floor) => compareVersion(version, floor) >= 0;
121
-
122
- // src/claude-events.ts
123
- var GATED_TOOLS = [...PRETOOLUSE_GATED_TOOLS, ...PRETOOLUSE_PHONE_ANSWERED_TOOLS].join("|");
124
- var MIRRORED_TOOLS = [...PRETOOLUSE_GATED_TOOLS, "TodoWrite"].join("|");
125
- var ESTABLISHED = [1, 0, 0];
126
- var OBSERVED = [2, 0, 0];
127
- var CLAUDE_HOOK_EVENTS = [
128
- { event: "PreToolUse", binary: "pushary-hook", matcher: GATED_TOOLS, timeout: HOOK_BUDGETS.claude.budgetSeconds, delivery: "approval", since: ESTABLISHED },
129
- { event: "PostToolUse", binary: "pushary-post-hook", matcher: MIRRORED_TOOLS, timeout: 10, delivery: "telemetry", since: ESTABLISHED },
130
- { event: "Stop", binary: "pushary-stop-hook", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
131
- { event: "UserPromptSubmit", binary: "pushary-prompt-hook", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
132
- { event: "Notification", binary: "pushary-notification-hook", matcher: "permission_prompt|idle_prompt|agent_needs_input|agent_completed", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
133
- { event: "SessionStart", binary: "pushary-session-start-hook", matcher: "startup|resume|clear", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
134
- { event: "SessionEnd", binary: "pushary-session-end-hook", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
135
- { event: "StopFailure", binary: "pushary-stopfailure-hook", timeout: 10, delivery: "telemetry", since: ESTABLISHED },
136
- { event: "PermissionRequest", binary: "pushary-permission-hook", timeout: HOOK_BUDGETS.claude.budgetSeconds, delivery: "approval", since: ESTABLISHED },
137
- { event: "PermissionDenied", binary: "pushary-permission-denied-hook", timeout: 60, delivery: "telemetry", since: ESTABLISHED },
138
- // Observability only. Each carries session shape the island cannot get any other
139
- // way, and none of them decides anything.
140
- { event: "SubagentStart", binary: "pushary-session-start-hook", timeout: 10, delivery: "telemetry", since: OBSERVED },
141
- { event: "SubagentStop", binary: "pushary-stop-hook", timeout: 10, delivery: "telemetry", since: OBSERVED },
142
- { event: "PreCompact", binary: "pushary-post-hook", matcher: "manual|auto", timeout: 10, delivery: "telemetry", since: OBSERVED },
143
- { event: "PostCompact", binary: "pushary-post-hook", matcher: "manual|auto", timeout: 10, delivery: "telemetry", since: OBSERVED },
144
- { event: "TeammateIdle", binary: "pushary-notification-hook", timeout: 10, delivery: "telemetry", since: OBSERVED },
145
- // An MCP server asking the person for a value, answered from the phone rather
146
- // than the terminal. No matcher: Claude Code matches this event on the MCP
147
- // server's name, and we have no business preferring one server over another.
148
- { event: "Elicitation", binary: "pushary-elicitation-hook", timeout: HOOK_BUDGETS.claude.budgetSeconds, delivery: "approval", since: OBSERVED, cliOnly: true }
149
- ];
150
- var supportedClaudeEvents = (version) => CLAUDE_HOOK_EVENTS.filter((hook) => version ? atLeast(version, hook.since) : hook.since === ESTABLISHED);
151
-
152
276
  export {
153
277
  parseVersion,
154
278
  compareVersion,
155
- CLAUDE_HOOK_EVENTS,
156
- supportedClaudeEvents,
279
+ addClaudeMcpServer,
280
+ removeClaudeMcpServers,
281
+ addPusharyToolPermissions,
282
+ addPusharyHooks,
283
+ removePusharySettings,
157
284
  GEMINI_HOOK_BINARY,
158
285
  addGeminiMcpServer,
159
286
  addGeminiHooks,
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  HOOK_BUDGETS,
6
6
  HOOK_LOCATOR_BINARY
7
- } from "./chunk-DMW54VWK.js";
7
+ } from "./chunk-Q6MK2YKV.js";
8
8
 
9
9
  // src/codex-config.ts
10
10
  import { createHash } from "crypto";
@@ -5,7 +5,7 @@ import {
5
5
  generateSessionKey,
6
6
  uploadTranscriptRecords,
7
7
  wrapSessionKey
8
- } from "./chunk-QLMX5LLV.js";
8
+ } from "./chunk-6GBQDZ7K.js";
9
9
 
10
10
  // src/live-session.ts
11
11
  var MAX_TRANSCRIPT_QUEUE = 100;
@@ -5,7 +5,7 @@ import {
5
5
  FILE_TARGET_TOOLS,
6
6
  redactSecrets,
7
7
  redactSecretsDeep
8
- } from "./chunk-DMW54VWK.js";
8
+ } from "./chunk-Q6MK2YKV.js";
9
9
 
10
10
  // ../hook-mapping/src/describe.ts
11
11
  import { isAbsolute, relative, resolve } from "path";
@@ -280,6 +280,7 @@ export {
280
280
  deriveActionBody,
281
281
  deriveAction,
282
282
  deriveBlocker,
283
+ AGENT_IDENTITIES,
283
284
  summarizeStop,
284
285
  sessionStartAction,
285
286
  sessionEndAction,
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  openCodeConfigDirFrom
3
- } from "./chunk-ZGC3W23N.js";
3
+ } from "./chunk-4KMWTOBK.js";
4
4
  import {
5
5
  codexHomeFrom
6
- } from "./chunk-NAPRGHZ3.js";
6
+ } from "./chunk-FRH2QIMY.js";
7
7
 
8
8
  // src/vscode-config.ts
9
9
  import { homedir } from "os";
@@ -326,9 +326,6 @@ var hasInstructionBlock = (filePath) => {
326
326
  }
327
327
  };
328
328
 
329
- // src/hooks-spec.ts
330
- var CURSOR_GATE_EVENTS = ["beforeShellExecution", "beforeMCPExecution"];
331
-
332
329
  export {
333
330
  registerPluginLocation,
334
331
  unregisterPluginLocation,
@@ -345,6 +342,5 @@ export {
345
342
  renderProjectAgentInstructions,
346
343
  writeInstructionBlock,
347
344
  removeInstructionBlock,
348
- hasInstructionBlock,
349
- CURSOR_GATE_EVENTS
345
+ hasInstructionBlock
350
346
  };
@@ -10,6 +10,7 @@ import {
10
10
  waitForAnswer
11
11
  } from "./chunk-J3YDT4HM.js";
12
12
  import {
13
+ AGENT_IDENTITIES,
13
14
  deriveReceiptMeta,
14
15
  deriveToolTarget,
15
16
  describeToolCall,
@@ -21,7 +22,7 @@ import {
21
22
  summarizeStop,
22
23
  taskTitleFrom,
23
24
  toolResultErrorText
24
- } from "./chunk-7J67NYK4.js";
25
+ } from "./chunk-LXTX5CT7.js";
25
26
  import {
26
27
  getMachineId
27
28
  } from "./chunk-RN3NOEJF.js";
@@ -30,20 +31,23 @@ import {
30
31
  } from "./chunk-BSZYIAZL.js";
31
32
  import {
32
33
  reportedInstallSource
33
- } from "./chunk-KBS53WOE.js";
34
+ } from "./chunk-AJ4EMW5D.js";
34
35
  import {
35
36
  getApiKey,
36
37
  getBaseUrl
37
38
  } from "./chunk-2UMNXADU.js";
38
39
  import {
40
+ HOOK_SOURCES,
41
+ PENDING_COMMAND_PREFIX,
39
42
  gateOutputFor,
40
43
  isAutoApprove,
41
44
  localRepoKey,
42
45
  modeStateFromResponse,
43
46
  normalizeRepoRemote,
47
+ pendingCommandEvents,
44
48
  resolveAutoResolveOrigin,
45
49
  resolvePolicy
46
- } from "./chunk-DMW54VWK.js";
50
+ } from "./chunk-Q6MK2YKV.js";
47
51
 
48
52
  // src/policy.ts
49
53
  import { createHash } from "crypto";
@@ -648,7 +652,6 @@ var deriveUsage = (transcriptPath, sessionId) => {
648
652
  return void 0;
649
653
  }
650
654
  };
651
- var PENDING_COMMAND_PREFIX = "The user sent a new instruction from their phone via Pushary:";
652
655
  var mergeAdditionalContext = (existing, reported) => {
653
656
  const pendingCommand = reported.status === "fulfilled" ? reported.value?.pendingCommand : void 0;
654
657
  if (typeof pendingCommand !== "string" || pendingCommand.trim().length === 0) return existing;
@@ -657,6 +660,11 @@ var mergeAdditionalContext = (existing, reported) => {
657
660
 
658
661
  ${injected}` : injected;
659
662
  };
663
+ var consumesActivityContext = (agentType) => {
664
+ const source = HOOK_SOURCES.find((candidate) => AGENT_IDENTITIES[candidate].type === agentType);
665
+ if (!source) return false;
666
+ return pendingCommandEvents(source).some((event) => event !== "Stop");
667
+ };
660
668
  var detectInstallMode = () => (process.argv[1] ?? "").includes("_npx") ? "npx" : "cli";
661
669
  var reportEvent = async (event, options = {}) => {
662
670
  const apiKey = options.apiKey ?? getApiKey();
@@ -691,7 +699,15 @@ var reportEvent = async (event, options = {}) => {
691
699
  // Only Claude Code consumes additionalContext from these hooks; Codex and
692
700
  // Gemini keep their existing session_end-only drain, so they must NOT
693
701
  // advertise it or the server would pop-and-drop their queued command.
694
- canDrainCommand: event.agentType === CLAUDE_CODE_AGENT.type
702
+ //
703
+ // And only when this caller kept the full budget. The pop is a destructive
704
+ // LPOP that happens before the response is written, so a caller that
705
+ // abandons the request destroys the message: `user_prompt` runs on a human
706
+ // keystroke and gave it 800ms, which a cold function misses routinely.
707
+ // Asking the server to consume something we may not wait to receive is the
708
+ // one shape that loses it outright, and the instruction reaches the agent
709
+ // on its next tool call instead.
710
+ canDrainCommand: consumesActivityContext(event.agentType) && options.timeoutMs === void 0
695
711
  }),
696
712
  signal: AbortSignal.timeout(options.timeoutMs ?? 1e4)
697
713
  });
@@ -750,7 +766,7 @@ var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
750
766
  );
751
767
  }
752
768
  const [reported] = await Promise.allSettled([toolReport, ...extraReports]);
753
- if (agent.type === CLAUDE_CODE_AGENT.type) {
769
+ if (consumesActivityContext(agent.type)) {
754
770
  additionalContext = mergeAdditionalContext(additionalContext, reported);
755
771
  }
756
772
  return additionalContext;
@@ -780,7 +796,7 @@ var handleUserPrompt = async (input, agent = CLAUDE_CODE_AGENT) => {
780
796
  taskTitle
781
797
  }, { maxAttempts: 1, timeoutMs: 800 })
782
798
  ]);
783
- if (agent.type === CLAUDE_CODE_AGENT.type) {
799
+ if (consumesActivityContext(agent.type)) {
784
800
  additionalContext = mergeAdditionalContext(additionalContext, reported);
785
801
  }
786
802
  return additionalContext;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isSafeReadOnlyCommand
3
- } from "./chunk-DMW54VWK.js";
3
+ } from "./chunk-Q6MK2YKV.js";
4
4
 
5
5
  // src/ledger.ts
6
6
  import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync } from "fs";