@pushary/agent-hooks 0.2.8 → 0.3.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.
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ askUser,
4
+ waitForAnswer
5
+ } from "../chunk-4TWRLEOX.js";
6
+ import {
7
+ reportEvent
8
+ } from "../chunk-EQE6Z4YQ.js";
9
+ import {
10
+ getApiKey
11
+ } from "../chunk-VUNL35KE.js";
12
+
13
+ // bin/pushary-codex.ts
14
+ import { hostname } from "os";
15
+ import { basename } from "path";
16
+ var main = async () => {
17
+ let rawInput = "";
18
+ for await (const chunk of process.stdin) {
19
+ rawInput += chunk;
20
+ }
21
+ if (!rawInput.trim()) {
22
+ process.exit(0);
23
+ }
24
+ let event;
25
+ try {
26
+ event = JSON.parse(rawInput);
27
+ } catch {
28
+ process.exit(0);
29
+ }
30
+ const projectName = basename(event.cwd ?? process.cwd());
31
+ const agentName = `Codex - ${projectName}`;
32
+ try {
33
+ if (event.type === "agent-turn-complete") {
34
+ await reportEvent({
35
+ event: "turn_complete",
36
+ agentType: "codex",
37
+ agentName,
38
+ action: event.message ?? "Turn complete",
39
+ machineId: hostname()
40
+ });
41
+ process.stdout.write(JSON.stringify({ acknowledged: true }));
42
+ }
43
+ if (event.type === "approval-requested") {
44
+ const apiKey = getApiKey();
45
+ const description = event.command ?? event.message ?? "Codex needs approval";
46
+ await reportEvent({
47
+ event: "approval_requested",
48
+ agentType: "codex",
49
+ agentName,
50
+ action: description,
51
+ machineId: hostname()
52
+ });
53
+ const result = await askUser(apiKey, {
54
+ question: `Allow: ${description}?`,
55
+ type: "confirm",
56
+ context: `Codex wants to run this in ${projectName}`,
57
+ agentName
58
+ });
59
+ const deadline = Date.now() + 12e4;
60
+ while (Date.now() < deadline) {
61
+ const remaining = Math.min(Math.max(deadline - Date.now(), 1e3), 3e4);
62
+ const answer = await waitForAnswer(apiKey, result.correlationId, remaining);
63
+ if (answer.answered) {
64
+ const approved = answer.value === "yes";
65
+ process.stdout.write(JSON.stringify({ approved }));
66
+ await reportEvent({
67
+ event: approved ? "approval_granted" : "approval_denied",
68
+ agentType: "codex",
69
+ agentName,
70
+ action: approved ? `Approved: ${description}` : `Denied: ${description}`,
71
+ machineId: hostname()
72
+ });
73
+ process.exit(0);
74
+ }
75
+ if (Date.now() + 2e3 >= deadline) break;
76
+ await new Promise((r) => setTimeout(r, 2e3));
77
+ }
78
+ process.stdout.write(JSON.stringify({ approved: false }));
79
+ process.exit(0);
80
+ }
81
+ } catch (err) {
82
+ process.stderr.write(
83
+ `[pushary-codex] Error: ${err instanceof Error ? err.message : String(err)}
84
+ `
85
+ );
86
+ if (event.type === "approval-requested") {
87
+ process.stdout.write(JSON.stringify({ approved: false }));
88
+ }
89
+ }
90
+ };
91
+ main();
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePreToolUse
4
- } from "../chunk-5ZMTG7GF.js";
4
+ } from "../chunk-KINE5LNQ.js";
5
+ import "../chunk-4TWRLEOX.js";
6
+ import "../chunk-VUNL35KE.js";
5
7
 
6
8
  // bin/pushary-hook.ts
7
9
  var main = async () => {
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ handlePostToolUse
4
+ } from "../chunk-EQE6Z4YQ.js";
5
+ import "../chunk-VUNL35KE.js";
6
+
7
+ // bin/pushary-post-hook.ts
8
+ var main = async () => {
9
+ let rawInput = "";
10
+ for await (const chunk of process.stdin) {
11
+ rawInput += chunk;
12
+ }
13
+ if (!rawInput.trim()) {
14
+ process.exit(0);
15
+ }
16
+ try {
17
+ const input = JSON.parse(rawInput);
18
+ await handlePostToolUse(input);
19
+ } catch {
20
+ }
21
+ };
22
+ main();
@@ -72,8 +72,31 @@ var addPermissionHooks = (settings) => {
72
72
  }]
73
73
  });
74
74
  hooks.PreToolUse = preToolUse;
75
- settings.hooks = hooks;
76
75
  }
76
+ const postToolUse = hooks.PostToolUse ?? [];
77
+ if (!JSON.stringify(postToolUse).includes("pushary-post-hook")) {
78
+ postToolUse.push({
79
+ matcher: "Bash|Write|Edit",
80
+ hooks: [{
81
+ type: "command",
82
+ command: "pushary-post-hook",
83
+ timeout: 10
84
+ }]
85
+ });
86
+ hooks.PostToolUse = postToolUse;
87
+ }
88
+ const stop = hooks.Stop ?? [];
89
+ if (!JSON.stringify(stop).includes("pushary-stop-hook")) {
90
+ stop.push({
91
+ hooks: [{
92
+ type: "command",
93
+ command: "pushary-stop-hook",
94
+ timeout: 10
95
+ }]
96
+ });
97
+ hooks.Stop = stop;
98
+ }
99
+ settings.hooks = hooks;
77
100
  };
78
101
  var addToolPermissions = (settings) => {
79
102
  const permissions = settings.permissions ?? {};
@@ -95,7 +118,7 @@ var setupClaudeCode = async (apiKey) => {
95
118
  addToolPermissions(settings);
96
119
  });
97
120
  await installGlobally();
98
- await spinner("Adding permission hooks (Bash, Write, Edit)", async () => {
121
+ await spinner("Adding hooks (PreToolUse, PostToolUse, Stop)", async () => {
99
122
  addPermissionHooks(settings);
100
123
  });
101
124
  await spinner(`Writing ${CLAUDE_SETTINGS}`, async () => {
@@ -104,7 +127,9 @@ var setupClaudeCode = async (apiKey) => {
104
127
  console.log();
105
128
  console.log(` ${dim("What this configured:")}`);
106
129
  console.log(` ${dim("\u2022")} MCP server: your agent can send notifications and ask questions`);
107
- console.log(` ${dim("\u2022")} Permission hooks: approve Bash/Write/Edit from your phone`);
130
+ console.log(` ${dim("\u2022")} PreToolUse: approve Bash/Write/Edit from your phone`);
131
+ console.log(` ${dim("\u2022")} PostToolUse: track when tools finish`);
132
+ console.log(` ${dim("\u2022")} Stop: detect when the agent session ends`);
108
133
  console.log(` ${dim("\u2022")} Auto-allowed tools: no permission prompts for Pushary`);
109
134
  };
110
135
  var setupHermes = async (apiKey) => {
@@ -134,6 +159,55 @@ var setupHermes = async (apiKey) => {
134
159
  console.log(` ${dim("\u2022")} Auto-notifications: push alert when tools return errors`);
135
160
  console.log(` ${dim("\u2022")} Session alerts: opt-in with PUSHARY_AUTO_NOTIFY_SESSION_END=1`);
136
161
  };
162
+ var setupCodex = async (_apiKey) => {
163
+ console.log(`
164
+ ${bold("Setting up Codex")}
165
+ `);
166
+ const hasCodex = (() => {
167
+ try {
168
+ execSync("which codex", { stdio: "ignore" });
169
+ return true;
170
+ } catch {
171
+ return false;
172
+ }
173
+ })();
174
+ if (!hasCodex) {
175
+ console.log(` ${yellow("!")} Codex CLI not found. Skipping.`);
176
+ console.log(` ${dim("Install Codex and re-run setup to configure.")}`);
177
+ return;
178
+ }
179
+ await installGlobally();
180
+ await spinner("Adding Pushary MCP server to Codex", async () => {
181
+ try {
182
+ execSync(
183
+ "codex mcp add pushary --url https://pushary.com/api/mcp/mcp --bearer-token-env-var PUSHARY_API_KEY",
184
+ { stdio: "ignore" }
185
+ );
186
+ } catch {
187
+ }
188
+ });
189
+ const codexConfig = join(homedir(), ".codex", "config.toml");
190
+ await spinner("Adding notify handler for Codex events", async () => {
191
+ const pusharyCodexPath = execSync("which pushary-codex", { encoding: "utf-8" }).trim();
192
+ if (!pusharyCodexPath) throw new Error("pushary-codex not found");
193
+ let config = "";
194
+ try {
195
+ config = readFileSync(codexConfig, "utf-8");
196
+ } catch {
197
+ }
198
+ if (!config.includes("pushary-codex")) {
199
+ const notifyLine = `
200
+ notify = ["${pusharyCodexPath}"]
201
+ `;
202
+ appendFileSync(codexConfig, notifyLine, "utf-8");
203
+ }
204
+ });
205
+ console.log();
206
+ console.log(` ${dim("What this configured:")}`);
207
+ console.log(` ${dim("\u2022")} MCP server: Codex can send notifications and ask questions`);
208
+ console.log(` ${dim("\u2022")} Notify handler: captures turn completions and approval requests`);
209
+ console.log(` ${dim("\u2022")} Uses PUSHARY_API_KEY env var for auth`);
210
+ };
137
211
  var setupCursor = async (apiKey) => {
138
212
  console.log(`
139
213
  ${bold("Setting up Cursor")}
@@ -213,29 +287,34 @@ var main = async () => {
213
287
  console.log(` ${bold("Which agent do you use?")}`);
214
288
  console.log();
215
289
  console.log(` ${cyan("1.")} Claude Code ${dim("MCP + permission hooks + auto-allowed tools")}`);
216
- console.log(` ${cyan("2.")} Hermes ${dim("native plugin + auto-error notifications")}`);
217
- console.log(` ${cyan("3.")} Cursor ${dim("MCP server")}`);
218
- console.log(` ${cyan("4.")} All ${dim("configure everything")}`);
219
- console.log(` ${cyan("5.")} Other ${dim("just save the API key")}`);
290
+ console.log(` ${cyan("2.")} Codex ${dim("MCP server via codex mcp add")}`);
291
+ console.log(` ${cyan("3.")} Hermes ${dim("native plugin + auto-error notifications")}`);
292
+ console.log(` ${cyan("4.")} Cursor ${dim("MCP server")}`);
293
+ console.log(` ${cyan("5.")} All ${dim("configure everything")}`);
294
+ console.log(` ${cyan("6.")} Other ${dim("just save the API key")}`);
220
295
  console.log();
221
- const choice = await ask(` Choice ${dim("[1-5]")}: `);
296
+ const choice = await ask(` Choice ${dim("[1-6]")}: `);
222
297
  await saveApiKey(trimmedKey);
223
298
  switch (choice.trim()) {
224
299
  case "1":
225
300
  await setupClaudeCode(trimmedKey);
226
301
  break;
227
302
  case "2":
228
- await setupHermes(trimmedKey);
303
+ await setupCodex(trimmedKey);
229
304
  break;
230
305
  case "3":
231
- await setupCursor(trimmedKey);
306
+ await setupHermes(trimmedKey);
232
307
  break;
233
308
  case "4":
309
+ await setupCursor(trimmedKey);
310
+ break;
311
+ case "5":
234
312
  await setupClaudeCode(trimmedKey);
313
+ await setupCodex(trimmedKey);
235
314
  await setupHermes(trimmedKey);
236
315
  await setupCursor(trimmedKey);
237
316
  break;
238
- case "5":
317
+ case "6":
239
318
  default:
240
319
  break;
241
320
  }
@@ -250,7 +329,7 @@ var main = async () => {
250
329
  console.log(` ${dim("Next:")}`);
251
330
  console.log(` ${dim("1.")} Enable notifications on your phone at ${cyan("pushary.com")}`);
252
331
  console.log(` ${dim("2.")} Restart your agent to load the new config`);
253
- console.log(` ${dim("3.")} Start coding \u2014 your agent will notify you automatically`);
332
+ console.log(` ${dim("3.")} Start coding. Your agent will notify you automatically`);
254
333
  console.log();
255
334
  rl.close();
256
335
  };
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ handleStop
4
+ } from "../chunk-EQE6Z4YQ.js";
5
+ import "../chunk-VUNL35KE.js";
6
+
7
+ // bin/pushary-stop-hook.ts
8
+ var main = async () => {
9
+ let rawInput = "";
10
+ for await (const chunk of process.stdin) {
11
+ rawInput += chunk;
12
+ }
13
+ try {
14
+ const input = rawInput.trim() ? JSON.parse(rawInput) : {};
15
+ await handleStop(input);
16
+ } catch {
17
+ }
18
+ };
19
+ main();
@@ -0,0 +1,49 @@
1
+ import {
2
+ getBaseUrl
3
+ } from "./chunk-VUNL35KE.js";
4
+
5
+ // src/api.ts
6
+ var mcpToolCall = async (apiKey, toolName, params) => {
7
+ const baseUrl = getBaseUrl();
8
+ const response = await fetch(`${baseUrl}/api/mcp/mcp`, {
9
+ method: "POST",
10
+ headers: {
11
+ "Content-Type": "application/json",
12
+ "Authorization": `Bearer ${apiKey}`
13
+ },
14
+ body: JSON.stringify({
15
+ jsonrpc: "2.0",
16
+ id: Date.now(),
17
+ method: "tools/call",
18
+ params: { name: toolName, arguments: params }
19
+ })
20
+ });
21
+ if (!response.ok) {
22
+ throw new Error(`Pushary API error: ${response.status} ${response.statusText}`);
23
+ }
24
+ const json = await response.json();
25
+ if (json.error) throw new Error(json.error.message);
26
+ const text = json.result?.content?.[0]?.text;
27
+ if (!text) throw new Error("Empty response from Pushary");
28
+ return JSON.parse(text);
29
+ };
30
+ var askUser = async (apiKey, params) => {
31
+ const result = await mcpToolCall(apiKey, "ask_user", { ...params });
32
+ return result;
33
+ };
34
+ var waitForAnswer = async (apiKey, correlationId, timeoutMs = 3e4) => {
35
+ const result = await mcpToolCall(apiKey, "wait_for_answer", {
36
+ correlationId,
37
+ timeoutMs
38
+ });
39
+ return result;
40
+ };
41
+ var cancelQuestion = async (apiKey, correlationId) => {
42
+ await mcpToolCall(apiKey, "cancel_question", { correlationId });
43
+ };
44
+
45
+ export {
46
+ askUser,
47
+ waitForAnswer,
48
+ cancelQuestion
49
+ };
@@ -0,0 +1,77 @@
1
+ import {
2
+ getApiKey,
3
+ getBaseUrl
4
+ } from "./chunk-VUNL35KE.js";
5
+
6
+ // src/events.ts
7
+ import { hostname } from "os";
8
+ import { basename } from "path";
9
+ var reportEvent = async (event) => {
10
+ const apiKey = getApiKey();
11
+ const baseUrl = getBaseUrl();
12
+ await fetch(`${baseUrl}/api/agent/event`, {
13
+ method: "POST",
14
+ headers: {
15
+ "Content-Type": "application/json",
16
+ "Authorization": `Bearer ${apiKey}`
17
+ },
18
+ body: JSON.stringify({
19
+ ...event,
20
+ machineId: event.machineId ?? hostname()
21
+ })
22
+ });
23
+ };
24
+ var handlePostToolUse = async (input) => {
25
+ const projectName = basename(input.cwd ?? process.cwd());
26
+ let action;
27
+ switch (input.tool_name) {
28
+ case "Bash":
29
+ action = `ran: ${String(input.tool_input.command ?? "").slice(0, 120)}`;
30
+ break;
31
+ case "Write":
32
+ action = `wrote: ${input.tool_input.file_path ?? "unknown"}`;
33
+ break;
34
+ case "Edit":
35
+ action = `edited: ${input.tool_input.file_path ?? "unknown"}`;
36
+ break;
37
+ case "Read":
38
+ action = `read: ${input.tool_input.file_path ?? "unknown"}`;
39
+ break;
40
+ default:
41
+ action = `${input.tool_name}: done`;
42
+ }
43
+ const isError = input.tool_result && ("error" in input.tool_result || "is_error" in input.tool_result);
44
+ await reportEvent({
45
+ event: isError ? "tool_error" : "tool_complete",
46
+ agentType: "claude_code",
47
+ agentName: `Claude Code - ${projectName}`,
48
+ action,
49
+ error: isError ? String(input.tool_result?.error ?? input.tool_result?.stderr ?? "").slice(0, 500) : void 0
50
+ });
51
+ };
52
+ var handleStop = async (input) => {
53
+ const projectName = basename(input.cwd ?? process.cwd());
54
+ await reportEvent({
55
+ event: "session_end",
56
+ agentType: "claude_code",
57
+ agentName: `Claude Code - ${projectName}`,
58
+ action: "Session ended"
59
+ });
60
+ };
61
+ var handleNotification = async (input) => {
62
+ const projectName = basename(input.cwd ?? process.cwd());
63
+ await reportEvent({
64
+ event: input.type === "error" ? "error" : "notification",
65
+ agentType: "claude_code",
66
+ agentName: `Claude Code - ${projectName}`,
67
+ action: input.title ?? input.message ?? "Notification",
68
+ error: input.type === "error" ? input.message : void 0
69
+ });
70
+ };
71
+
72
+ export {
73
+ reportEvent,
74
+ handlePostToolUse,
75
+ handleStop,
76
+ handleNotification
77
+ };
@@ -0,0 +1,136 @@
1
+ import {
2
+ askUser,
3
+ waitForAnswer
4
+ } from "./chunk-4TWRLEOX.js";
5
+ import {
6
+ getApiKey,
7
+ getBaseUrl
8
+ } from "./chunk-VUNL35KE.js";
9
+
10
+ // src/policy.ts
11
+ import { createHash } from "crypto";
12
+ import { existsSync, readFileSync, writeFileSync } from "fs";
13
+ import { join } from "path";
14
+ import { tmpdir } from "os";
15
+ var cacheFile = (apiKey) => {
16
+ const hash = createHash("sha256").update(apiKey).digest("hex").slice(0, 12);
17
+ return join(tmpdir(), `pushary-policy-${hash}.json`);
18
+ };
19
+ var fetchPolicy = async (apiKey) => {
20
+ const baseUrl = getBaseUrl();
21
+ const response = await fetch(`${baseUrl}/api/mcp/policy`, {
22
+ headers: { "Authorization": `Bearer ${apiKey}` },
23
+ signal: AbortSignal.timeout(1e4)
24
+ });
25
+ if (!response.ok) {
26
+ throw new Error(`Failed to fetch policy: ${response.status}`);
27
+ }
28
+ return response.json();
29
+ };
30
+ var getPolicy = async (apiKey) => {
31
+ const path = cacheFile(apiKey);
32
+ if (existsSync(path)) {
33
+ try {
34
+ return JSON.parse(readFileSync(path, "utf-8"));
35
+ } catch {
36
+ }
37
+ }
38
+ const policy = await fetchPolicy(apiKey);
39
+ writeFileSync(path, JSON.stringify(policy), "utf-8");
40
+ return policy;
41
+ };
42
+ var resolvePolicy = (config, toolName) => {
43
+ const exact = config.policies.find((p) => p.tool === toolName);
44
+ if (exact) return exact;
45
+ const wildcard = config.policies.find((p) => p.tool === "*");
46
+ if (wildcard) return wildcard;
47
+ return {
48
+ tool: toolName,
49
+ timeoutSeconds: config.defaultTimeoutSeconds,
50
+ timeoutAction: config.defaultTimeoutAction
51
+ };
52
+ };
53
+
54
+ // src/hook.ts
55
+ import { basename } from "path";
56
+ var describeToolCall = (input) => {
57
+ const { tool_name, tool_input } = input;
58
+ switch (tool_name) {
59
+ case "Bash":
60
+ return `bash: ${tool_input.command ?? "(no command)"}`;
61
+ case "Write":
62
+ return `write file: ${tool_input.file_path ?? "(unknown path)"}`;
63
+ case "Edit":
64
+ return `edit file: ${tool_input.file_path ?? "(unknown path)"}`;
65
+ case "Read":
66
+ return `read file: ${tool_input.file_path ?? "(unknown path)"}`;
67
+ default:
68
+ return `${tool_name}: ${JSON.stringify(tool_input).slice(0, 200)}`;
69
+ }
70
+ };
71
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
72
+ var allow = () => ({
73
+ hookSpecificOutput: {
74
+ hookEventName: "PreToolUse",
75
+ permissionDecision: "allow"
76
+ }
77
+ });
78
+ var deny = (reason) => ({
79
+ hookSpecificOutput: {
80
+ hookEventName: "PreToolUse",
81
+ permissionDecision: "deny",
82
+ permissionDecisionReason: reason
83
+ }
84
+ });
85
+ var ask = (reason) => ({
86
+ hookSpecificOutput: {
87
+ hookEventName: "PreToolUse",
88
+ permissionDecision: "ask",
89
+ permissionDecisionReason: reason
90
+ }
91
+ });
92
+ var handlePreToolUse = async (input) => {
93
+ const apiKey = getApiKey();
94
+ const policy = await getPolicy(apiKey);
95
+ const toolPolicy = resolvePolicy(policy, input.tool_name);
96
+ if (toolPolicy.timeoutSeconds === 0 && toolPolicy.timeoutAction === "approve") {
97
+ return allow();
98
+ }
99
+ const description = describeToolCall(input);
100
+ const projectName = basename(input.cwd ?? process.cwd());
101
+ const result = await askUser(apiKey, {
102
+ question: `Allow ${description}?`,
103
+ type: "confirm",
104
+ context: `Agent wants to run this in ${projectName}`,
105
+ agentName: `Claude Code - ${projectName}`
106
+ });
107
+ const deadline = Date.now() + toolPolicy.timeoutSeconds * 1e3;
108
+ const pollInterval = 2e3;
109
+ while (Date.now() < deadline) {
110
+ const remaining = Math.min(
111
+ Math.max(deadline - Date.now(), 1e3),
112
+ 3e4
113
+ );
114
+ const answer = await waitForAnswer(apiKey, result.correlationId, remaining);
115
+ if (answer.answered) {
116
+ return answer.value === "yes" ? allow() : deny("Denied via Pushary push notification");
117
+ }
118
+ if (Date.now() + pollInterval >= deadline) break;
119
+ await sleep(pollInterval);
120
+ }
121
+ switch (toolPolicy.timeoutAction) {
122
+ case "approve":
123
+ return allow();
124
+ case "deny":
125
+ return deny("No response within timeout");
126
+ case "escalate":
127
+ default:
128
+ return ask("Pushary: no response, asking in terminal");
129
+ }
130
+ };
131
+
132
+ export {
133
+ getPolicy,
134
+ resolvePolicy,
135
+ handlePreToolUse
136
+ };
@@ -0,0 +1,16 @@
1
+ // src/config.ts
2
+ var getApiKey = () => {
3
+ const key = process.env.PUSHARY_API_KEY;
4
+ if (!key) {
5
+ throw new Error(
6
+ "PUSHARY_API_KEY environment variable is not set. Get your API key at https://pushary.com/sign-up?from=ai-coding"
7
+ );
8
+ }
9
+ return key;
10
+ };
11
+ var getBaseUrl = () => process.env.PUSHARY_BASE_URL ?? "https://pushary.com";
12
+
13
+ export {
14
+ getApiKey,
15
+ getBaseUrl
16
+ };
@@ -13,6 +13,35 @@ interface HookOutput {
13
13
  }
14
14
  declare const handlePreToolUse: (input: ToolInput) => Promise<HookOutput | null>;
15
15
 
16
+ interface AgentEvent {
17
+ event: string;
18
+ agentType: string;
19
+ agentName?: string;
20
+ action?: string;
21
+ machineId?: string;
22
+ error?: string;
23
+ }
24
+ declare const reportEvent: (event: AgentEvent) => Promise<void>;
25
+ declare const handlePostToolUse: (input: {
26
+ tool_name: string;
27
+ tool_input: Record<string, unknown>;
28
+ tool_result?: Record<string, unknown>;
29
+ cwd?: string;
30
+ session_id?: string;
31
+ }) => Promise<void>;
32
+ declare const handleStop: (input: {
33
+ cwd?: string;
34
+ session_id?: string;
35
+ stop_hook_active?: boolean;
36
+ }) => Promise<void>;
37
+ declare const handleNotification: (input: {
38
+ message?: string;
39
+ title?: string;
40
+ type?: string;
41
+ cwd?: string;
42
+ session_id?: string;
43
+ }) => Promise<void>;
44
+
16
45
  interface AskUserParams {
17
46
  question: string;
18
47
  type?: 'confirm' | 'select' | 'input';
@@ -48,4 +77,4 @@ declare const resolvePolicy: (config: PolicyConfig, toolName: string) => ToolPol
48
77
  declare const getApiKey: () => string;
49
78
  declare const getBaseUrl: () => string;
50
79
 
51
- export { type PolicyConfig, type ToolPolicy, askUser, cancelQuestion, getApiKey, getBaseUrl, getPolicy, handlePreToolUse, resolvePolicy, waitForAnswer };
80
+ export { type PolicyConfig, type ToolPolicy, askUser, cancelQuestion, getApiKey, getBaseUrl, getPolicy, handleNotification, handlePostToolUse, handlePreToolUse, handleStop, reportEvent, resolvePolicy, waitForAnswer };
package/dist/src/index.js CHANGED
@@ -1,20 +1,34 @@
1
1
  import {
2
- askUser,
3
- cancelQuestion,
4
- getApiKey,
5
- getBaseUrl,
6
2
  getPolicy,
7
3
  handlePreToolUse,
8
- resolvePolicy,
4
+ resolvePolicy
5
+ } from "../chunk-KINE5LNQ.js";
6
+ import {
7
+ askUser,
8
+ cancelQuestion,
9
9
  waitForAnswer
10
- } from "../chunk-5ZMTG7GF.js";
10
+ } from "../chunk-4TWRLEOX.js";
11
+ import {
12
+ handleNotification,
13
+ handlePostToolUse,
14
+ handleStop,
15
+ reportEvent
16
+ } from "../chunk-EQE6Z4YQ.js";
17
+ import {
18
+ getApiKey,
19
+ getBaseUrl
20
+ } from "../chunk-VUNL35KE.js";
11
21
  export {
12
22
  askUser,
13
23
  cancelQuestion,
14
24
  getApiKey,
15
25
  getBaseUrl,
16
26
  getPolicy,
27
+ handleNotification,
28
+ handlePostToolUse,
17
29
  handlePreToolUse,
30
+ handleStop,
31
+ reportEvent,
18
32
  resolvePolicy,
19
33
  waitForAnswer
20
34
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pushary/agent-hooks",
3
- "version": "0.2.8",
4
- "description": "Permission hooks for AI coding agents route tool approvals through Pushary push notifications",
3
+ "version": "0.3.0",
4
+ "description": "Permission hooks for AI coding agents: route tool approvals through Pushary push notifications",
5
5
  "author": "Pushary <business@pushary.com>",
6
6
  "homepage": "https://pushary.com",
7
7
  "repository": {
@@ -17,14 +17,17 @@
17
17
  "agent-hooks": "./dist/bin/pushary.js",
18
18
  "pushary": "./dist/bin/pushary.js",
19
19
  "pushary-hook": "./dist/bin/pushary-hook.js",
20
+ "pushary-post-hook": "./dist/bin/pushary-post-hook.js",
21
+ "pushary-stop-hook": "./dist/bin/pushary-stop-hook.js",
22
+ "pushary-codex": "./dist/bin/pushary-codex.js",
20
23
  "pushary-setup": "./dist/bin/pushary-setup.js"
21
24
  },
22
25
  "files": [
23
26
  "dist"
24
27
  ],
25
28
  "scripts": {
26
- "build": "tsup src/index.ts bin/pushary.ts bin/pushary-hook.ts bin/pushary-setup.ts --format esm --dts --outDir dist",
27
- "dev": "tsup src/index.ts bin/pushary.ts bin/pushary-hook.ts bin/pushary-setup.ts --format esm --watch"
29
+ "build": "tsup src/index.ts bin/pushary.ts bin/pushary-hook.ts bin/pushary-post-hook.ts bin/pushary-stop-hook.ts bin/pushary-codex.ts bin/pushary-setup.ts --format esm --dts --outDir dist",
30
+ "dev": "tsup src/index.ts bin/pushary.ts bin/pushary-hook.ts bin/pushary-post-hook.ts bin/pushary-stop-hook.ts bin/pushary-codex.ts bin/pushary-setup.ts --format esm --watch"
28
31
  },
29
32
  "devDependencies": {
30
33
  "tsup": "^8.0.0",