@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.
- package/CHANGELOG.md +20 -0
- package/data/cursor-plugin/scripts/pushary-gate.mjs +63 -7
- package/data/vscode-plugin/scripts/pushary-gate.mjs +56 -18
- package/dist/bin/pushary-bell-hook.js +4 -4
- package/dist/bin/pushary-bell.js +7 -7
- package/dist/bin/pushary-claude.js +9 -9
- package/dist/bin/pushary-clean.js +13 -14
- package/dist/bin/pushary-codex-bridge.js +6 -6
- package/dist/bin/pushary-codex-hook.js +15 -9
- package/dist/bin/pushary-codex.js +4 -4
- package/dist/bin/pushary-connect.js +6 -6
- package/dist/bin/pushary-daemon.js +5 -5
- package/dist/bin/pushary-disconnect.js +9 -11
- package/dist/bin/pushary-doctor.js +17 -16
- package/dist/bin/pushary-elicitation-hook.js +7 -120
- package/dist/bin/pushary-gemini-bridge.js +6 -6
- package/dist/bin/pushary-gemini-hook.js +15 -9
- package/dist/bin/pushary-hook.js +6 -6
- package/dist/bin/pushary-login.js +4 -4
- package/dist/bin/pushary-logout.js +4 -4
- package/dist/bin/pushary-mode.js +3 -3
- package/dist/bin/pushary-notification-hook.js +4 -4
- package/dist/bin/pushary-opencode-hook.js +5 -5
- package/dist/bin/pushary-permission-denied-hook.js +6 -6
- package/dist/bin/pushary-permission-hook.js +6 -6
- package/dist/bin/pushary-post-hook.js +4 -4
- package/dist/bin/pushary-prompt-hook.js +4 -4
- package/dist/bin/pushary-session-end-hook.js +4 -4
- package/dist/bin/pushary-session-start-hook.js +4 -4
- package/dist/bin/pushary-setup.js +26 -25
- package/dist/bin/pushary-stats.js +2 -2
- package/dist/bin/pushary-status.js +5 -5
- package/dist/bin/pushary-stop-hook.js +4 -4
- package/dist/bin/pushary-stopfailure-hook.js +4 -4
- package/dist/bin/pushary-upgrade.js +9 -11
- package/dist/bin/pushary-wait.js +3 -3
- package/dist/{chunk-H5PIPIKQ.js → chunk-4FANZF2L.js} +2 -2
- package/dist/{chunk-ZGC3W23N.js → chunk-4KMWTOBK.js} +4 -1
- package/dist/{chunk-QLMX5LLV.js → chunk-6GBQDZ7K.js} +1 -1
- package/dist/{chunk-B7ZBHWOW.js → chunk-AIGDBRIJ.js} +1 -1
- package/dist/{chunk-KBS53WOE.js → chunk-AJ4EMW5D.js} +1 -1
- package/dist/{chunk-ICERLAE2.js → chunk-DLI5IXSD.js} +1 -1
- package/dist/{chunk-YX6ZKCC5.js → chunk-EKNFTIKO.js} +1 -1
- package/dist/{chunk-K42RXJPG.js → chunk-F3ZDPL6O.js} +187 -60
- package/dist/{chunk-NAPRGHZ3.js → chunk-FRH2QIMY.js} +1 -1
- package/dist/{chunk-TV3UFGT7.js → chunk-LNAQWWBP.js} +1 -1
- package/dist/{chunk-7J67NYK4.js → chunk-LXTX5CT7.js} +2 -1
- package/dist/{chunk-KULUNLRO.js → chunk-O7P7O4VY.js} +3 -7
- package/dist/{chunk-VOE4SYPR.js → chunk-OSE7X44J.js} +23 -7
- package/dist/{chunk-VIHRP25S.js → chunk-PXEFENML.js} +1 -1
- package/dist/{chunk-DMW54VWK.js → chunk-Q6MK2YKV.js} +213 -4
- package/dist/{chunk-EJL3PJU7.js → chunk-SHVW5KFR.js} +1 -1
- package/dist/{chunk-QXZ2CKRK.js → chunk-SUZF64M4.js} +2 -2
- package/dist/{chunk-BFBAHOGR.js → chunk-U44C3ULB.js} +1 -1
- package/dist/{chunk-OMA2OZRE.js → chunk-U65EIMUJ.js} +27 -62
- package/dist/{chunk-KFAH6KRE.js → chunk-WFFPWJN6.js} +1 -1
- package/dist/{chunk-YYTLTEGU.js → chunk-WPDMGNQR.js} +1 -1
- package/dist/{chunk-TD3M232T.js → chunk-ZPRF4YLA.js} +1 -1
- package/dist/src/index.js +6 -6
- package/package.json +1 -1
- package/dist/chunk-2JYQAW4B.js +0 -137
- /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-
|
|
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
|
|
21
|
-
var
|
|
22
|
-
const existing =
|
|
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 = (
|
|
29
|
-
const 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(
|
|
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 =
|
|
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 =
|
|
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((
|
|
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 =
|
|
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((
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
156
|
-
|
|
279
|
+
addClaudeMcpServer,
|
|
280
|
+
removeClaudeMcpServers,
|
|
281
|
+
addPusharyToolPermissions,
|
|
282
|
+
addPusharyHooks,
|
|
283
|
+
removePusharySettings,
|
|
157
284
|
GEMINI_HOOK_BINARY,
|
|
158
285
|
addGeminiMcpServer,
|
|
159
286
|
addGeminiHooks,
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
FILE_TARGET_TOOLS,
|
|
6
6
|
redactSecrets,
|
|
7
7
|
redactSecretsDeep
|
|
8
|
-
} from "./chunk-
|
|
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-
|
|
3
|
+
} from "./chunk-4KMWTOBK.js";
|
|
4
4
|
import {
|
|
5
5
|
codexHomeFrom
|
|
6
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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
|
|
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
|
|
799
|
+
if (consumesActivityContext(agent.type)) {
|
|
784
800
|
additionalContext = mergeAdditionalContext(additionalContext, reported);
|
|
785
801
|
}
|
|
786
802
|
return additionalContext;
|