@pushary/agent-hooks 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,252 @@
1
+ #!/usr/bin/env node
2
+
3
+ // bin/pushary-doctor.ts
4
+ import { existsSync, readFileSync } from "fs";
5
+ import { join } from "path";
6
+ import { homedir } from "os";
7
+ import { confirm } from "@inquirer/prompts";
8
+ var dim = (s) => `\x1B[2m${s}\x1B[0m`;
9
+ var bold = (s) => `\x1B[1m${s}\x1B[0m`;
10
+ var green = (s) => `\x1B[32m${s}\x1B[0m`;
11
+ var red = (s) => `\x1B[31m${s}\x1B[0m`;
12
+ var yellow = (s) => `\x1B[33m${s}\x1B[0m`;
13
+ var cyan = (s) => `\x1B[36m${s}\x1B[0m`;
14
+ var pass = green("\u2713");
15
+ var fail = red("\u2717");
16
+ var warn = yellow("!");
17
+ var CLAUDE_SETTINGS = join(homedir(), ".claude", "settings.json");
18
+ var SKILL_PATH = join(homedir(), ".claude", "skills", "pushary", "SKILL.md");
19
+ var MCP_URL = "https://pushary.com/api/mcp/mcp";
20
+ var readJson = (path) => {
21
+ try {
22
+ return JSON.parse(readFileSync(path, "utf-8"));
23
+ } catch {
24
+ return null;
25
+ }
26
+ };
27
+ var results = [];
28
+ var check = (passed, label, detail) => {
29
+ results.push({ passed, label, detail });
30
+ const icon = passed ? pass : fail;
31
+ const suffix = detail ? ` ${dim(`(${detail})`)}` : "";
32
+ console.log(` ${icon} ${label}${suffix}`);
33
+ };
34
+ var main = async () => {
35
+ console.log();
36
+ console.log(` ${bold("Pushary Doctor")}`);
37
+ console.log();
38
+ console.log(` ${dim("Configuration")}`);
39
+ const apiKey = process.env.PUSHARY_API_KEY;
40
+ check(!!apiKey, "API key in environment", apiKey ? `pk_${apiKey.split(".")[0]?.slice(3, 7)}...` : "PUSHARY_API_KEY not set");
41
+ const settings = readJson(CLAUDE_SETTINGS);
42
+ if (settings) {
43
+ const mcpServers = settings.mcpServers;
44
+ const pusharyServer = mcpServers?.pushary;
45
+ check(!!pusharyServer, "Claude Code: MCP server configured");
46
+ if (pusharyServer) {
47
+ check(pusharyServer.type === "http", "Claude Code: MCP server type", pusharyServer.type ? String(pusharyServer.type) : 'missing \u2014 add type: "http"');
48
+ }
49
+ const hooks = settings.hooks;
50
+ const hasPreHook = JSON.stringify(hooks?.PreToolUse ?? []).includes("pushary-hook");
51
+ const hasPostHook = JSON.stringify(hooks?.PostToolUse ?? []).includes("pushary-post-hook");
52
+ const hasStopHook = JSON.stringify(hooks?.Stop ?? []).includes("pushary-stop-hook");
53
+ check(hasPreHook, "Claude Code: PreToolUse hook");
54
+ check(hasPostHook, "Claude Code: PostToolUse hook");
55
+ check(hasStopHook, "Claude Code: Stop hook");
56
+ const permissions = settings.permissions;
57
+ const hasWildcard = permissions?.allow?.some((r) => r === "MCP(pushary:*)") ?? false;
58
+ check(hasWildcard, "Claude Code: Pushary tools auto-allowed", hasWildcard ? "MCP(pushary:*)" : "missing");
59
+ const hasLegacyPerms = permissions?.allow?.some((r) => r.startsWith("mcp__pushary__")) ?? false;
60
+ if (hasLegacyPerms) {
61
+ console.log(` ${warn} Legacy individual permissions detected ${dim("(run pushary clean, then setup again)")}`);
62
+ }
63
+ } else {
64
+ check(false, "Claude Code: settings.json", "not found");
65
+ }
66
+ check(existsSync(SKILL_PATH), "Skill installed", existsSync(SKILL_PATH) ? SKILL_PATH : "not found");
67
+ let globalVersion = "";
68
+ try {
69
+ const { execSync } = await import("child_process");
70
+ globalVersion = execSync("npm list -g @pushary/agent-hooks --depth=0 2>/dev/null", { encoding: "utf-8" }).match(/@pushary\/agent-hooks@([\d.]+)/)?.[1] ?? "";
71
+ } catch {
72
+ }
73
+ check(!!globalVersion, "Global package installed", globalVersion || "not found");
74
+ console.log();
75
+ console.log(` ${dim("Connectivity")}`);
76
+ if (!apiKey) {
77
+ check(false, "MCP server reachable", "skipped \u2014 no API key");
78
+ check(false, "API key valid", "skipped");
79
+ check(false, "MCP handshake", "skipped");
80
+ } else {
81
+ let sessionId = "";
82
+ let toolCount = 0;
83
+ try {
84
+ const initRes = await fetch(MCP_URL, {
85
+ method: "POST",
86
+ headers: {
87
+ "Content-Type": "application/json",
88
+ "Accept": "application/json, text/event-stream",
89
+ "Authorization": `Bearer ${apiKey}`
90
+ },
91
+ body: JSON.stringify({
92
+ jsonrpc: "2.0",
93
+ id: 1,
94
+ method: "initialize",
95
+ params: {
96
+ protocolVersion: "2025-03-26",
97
+ capabilities: {},
98
+ clientInfo: { name: "pushary-doctor", version: "1.0" }
99
+ }
100
+ }),
101
+ signal: AbortSignal.timeout(1e4)
102
+ });
103
+ check(initRes.ok, "MCP server reachable", `${initRes.status} ${initRes.statusText}`);
104
+ sessionId = initRes.headers.get("mcp-session-id") ?? "";
105
+ check(!!sessionId, "Session ID returned", sessionId ? `${sessionId.slice(0, 8)}...` : "missing \u2014 update MCP SDK");
106
+ const initBody = await initRes.text();
107
+ const initMatch = initBody.match(/data: (.+)/);
108
+ if (initMatch) {
109
+ const initData = JSON.parse(initMatch[1]);
110
+ check(!!initData.result?.serverInfo, "API key valid", initData.result?.serverInfo?.name ?? "unknown server");
111
+ }
112
+ const toolsRes = await fetch(MCP_URL, {
113
+ method: "POST",
114
+ headers: {
115
+ "Content-Type": "application/json",
116
+ "Accept": "application/json, text/event-stream",
117
+ "Authorization": `Bearer ${apiKey}`,
118
+ ...sessionId ? { "Mcp-Session-Id": sessionId } : {}
119
+ },
120
+ body: JSON.stringify({
121
+ jsonrpc: "2.0",
122
+ id: 2,
123
+ method: "tools/list",
124
+ params: {}
125
+ }),
126
+ signal: AbortSignal.timeout(1e4)
127
+ });
128
+ const toolsBody = await toolsRes.text();
129
+ const toolsMatch = toolsBody.match(/data: (.+)/);
130
+ if (toolsMatch) {
131
+ const toolsData = JSON.parse(toolsMatch[1]);
132
+ toolCount = toolsData.result?.tools?.length ?? 0;
133
+ }
134
+ check(toolCount > 0, "MCP tools discovered", `${toolCount} tools`);
135
+ } catch (err) {
136
+ const msg = err instanceof Error ? err.message : "unknown error";
137
+ check(false, "MCP server reachable", msg);
138
+ }
139
+ console.log();
140
+ console.log(` ${dim("Notification Delivery")}`);
141
+ try {
142
+ const notifRes = await fetch("https://pushary.com/api/v1/server/send", {
143
+ method: "POST",
144
+ headers: {
145
+ "Content-Type": "application/json",
146
+ "Authorization": `Bearer ${apiKey}`
147
+ },
148
+ body: JSON.stringify({
149
+ title: "Pushary Doctor",
150
+ body: "If you see this, push notifications are working."
151
+ }),
152
+ signal: AbortSignal.timeout(1e4)
153
+ });
154
+ check(notifRes.ok, "Push notification sent", notifRes.ok ? "check your phone" : `${notifRes.status}`);
155
+ } catch (err) {
156
+ const msg = err instanceof Error ? err.message : "network error";
157
+ check(false, "Push notification sent", msg);
158
+ }
159
+ const testQuestion = await confirm({ message: "Test question roundtrip? (sends a push notification)", default: false });
160
+ if (testQuestion) {
161
+ console.log();
162
+ console.log(` ${dim("Question Roundtrip")}`);
163
+ try {
164
+ const mcpHeaders = {
165
+ "Content-Type": "application/json",
166
+ "Accept": "application/json, text/event-stream",
167
+ "Authorization": `Bearer ${apiKey}`,
168
+ ...sessionId ? { "Mcp-Session-Id": sessionId } : {}
169
+ };
170
+ const askRes = await fetch(MCP_URL, {
171
+ method: "POST",
172
+ headers: mcpHeaders,
173
+ body: JSON.stringify({
174
+ jsonrpc: "2.0",
175
+ id: 3,
176
+ method: "tools/call",
177
+ params: {
178
+ name: "ask_user",
179
+ arguments: {
180
+ question: "Pushary Doctor: tap Yes to verify the roundtrip works.",
181
+ type: "confirm",
182
+ agentName: "Pushary Doctor"
183
+ }
184
+ }
185
+ }),
186
+ signal: AbortSignal.timeout(15e3)
187
+ });
188
+ const askBody = await askRes.text();
189
+ const askMatch = askBody.match(/data: (.+)/);
190
+ let correlationId = "";
191
+ if (askMatch) {
192
+ const askData = JSON.parse(askMatch[1]);
193
+ const content = askData.result?.content?.[0]?.text;
194
+ if (content) {
195
+ const parsed = JSON.parse(content);
196
+ correlationId = parsed.correlationId;
197
+ }
198
+ }
199
+ if (correlationId) {
200
+ console.log(` ${dim("\u2192")} Question sent, waiting for your answer...`);
201
+ const start = Date.now();
202
+ const waitRes = await fetch(MCP_URL, {
203
+ method: "POST",
204
+ headers: mcpHeaders,
205
+ body: JSON.stringify({
206
+ jsonrpc: "2.0",
207
+ id: 4,
208
+ method: "tools/call",
209
+ params: {
210
+ name: "wait_for_answer",
211
+ arguments: { correlationId, timeoutMs: 55e3 }
212
+ }
213
+ }),
214
+ signal: AbortSignal.timeout(6e4)
215
+ });
216
+ const waitBody = await waitRes.text();
217
+ const waitMatch = waitBody.match(/data: (.+)/);
218
+ if (waitMatch) {
219
+ const waitData = JSON.parse(waitMatch[1]);
220
+ const content = waitData.result?.content?.[0]?.text;
221
+ if (content) {
222
+ const parsed = JSON.parse(content);
223
+ const elapsed = ((Date.now() - start) / 1e3).toFixed(1);
224
+ check(parsed.answered === true, "Answer received", `"${parsed.value}" (${elapsed}s roundtrip)`);
225
+ } else {
226
+ check(false, "Answer received", "no response within timeout");
227
+ }
228
+ }
229
+ } else {
230
+ check(false, "Question sent", "failed to get correlationId");
231
+ }
232
+ } catch (err) {
233
+ const msg = err instanceof Error ? err.message : "unknown error";
234
+ check(false, "Question roundtrip", msg);
235
+ }
236
+ }
237
+ }
238
+ console.log();
239
+ const failed = results.filter((r) => !r.passed);
240
+ if (failed.length === 0) {
241
+ console.log(` ${green(bold("All checks passed."))}`);
242
+ } else {
243
+ console.log(` ${red(bold(`${failed.length} check${failed.length === 1 ? "" : "s"} failed:`))}`);
244
+ for (const f of failed) {
245
+ console.log(` ${fail} ${f.label}${f.detail ? ` \u2014 ${f.detail}` : ""}`);
246
+ }
247
+ console.log();
248
+ console.log(` ${dim("Run")} ${cyan("npx @pushary/agent-hooks@latest clean")} ${dim("then")} ${cyan("setup")} ${dim("to fix.")}`);
249
+ }
250
+ console.log();
251
+ };
252
+ main();
@@ -0,0 +1,254 @@
1
+ #!/usr/bin/env node
2
+
3
+ // bin/pushary-doctor.ts
4
+ import { existsSync, readFileSync } from "fs";
5
+ import { join } from "path";
6
+ import { homedir } from "os";
7
+ import { confirm } from "@inquirer/prompts";
8
+ var dim = (s) => `\x1B[2m${s}\x1B[0m`;
9
+ var bold = (s) => `\x1B[1m${s}\x1B[0m`;
10
+ var green = (s) => `\x1B[32m${s}\x1B[0m`;
11
+ var red = (s) => `\x1B[31m${s}\x1B[0m`;
12
+ var yellow = (s) => `\x1B[33m${s}\x1B[0m`;
13
+ var cyan = (s) => `\x1B[36m${s}\x1B[0m`;
14
+ var pass = green("\u2713");
15
+ var fail = red("\u2717");
16
+ var warn = yellow("!");
17
+ var CLAUDE_SETTINGS = join(homedir(), ".claude", "settings.json");
18
+ var SKILL_PATH = join(homedir(), ".claude", "skills", "pushary", "SKILL.md");
19
+ var MCP_URL = "https://pushary.com/api/mcp/mcp";
20
+ var readJson = (path) => {
21
+ try {
22
+ return JSON.parse(readFileSync(path, "utf-8"));
23
+ } catch {
24
+ return null;
25
+ }
26
+ };
27
+ var results = [];
28
+ var check = (passed, label, detail) => {
29
+ results.push({ passed, label, detail });
30
+ const icon = passed ? pass : fail;
31
+ const suffix = detail ? ` ${dim(`(${detail})`)}` : "";
32
+ console.log(` ${icon} ${label}${suffix}`);
33
+ };
34
+ var main = async () => {
35
+ console.log();
36
+ console.log(` ${bold("Pushary Doctor")}`);
37
+ console.log();
38
+ console.log(` ${dim("Configuration")}`);
39
+ const apiKey = process.env.PUSHARY_API_KEY;
40
+ check(!!apiKey, "API key in environment", apiKey ? `pk_${apiKey.split(".")[0]?.slice(3, 7)}...` : "PUSHARY_API_KEY not set");
41
+ const settings = readJson(CLAUDE_SETTINGS);
42
+ if (settings) {
43
+ const mcpServers = settings.mcpServers;
44
+ const pusharyServer = mcpServers?.pushary;
45
+ check(!!pusharyServer, "Claude Code: MCP server configured");
46
+ if (pusharyServer) {
47
+ check(pusharyServer.type === "http", "Claude Code: MCP server type", pusharyServer.type ? String(pusharyServer.type) : 'missing \u2014 add type: "http"');
48
+ }
49
+ const hooks = settings.hooks;
50
+ const hasPreHook = JSON.stringify(hooks?.PreToolUse ?? []).includes("pushary-hook");
51
+ const hasPostHook = JSON.stringify(hooks?.PostToolUse ?? []).includes("pushary-post-hook");
52
+ const hasStopHook = JSON.stringify(hooks?.Stop ?? []).includes("pushary-stop-hook");
53
+ check(hasPreHook, "Claude Code: PreToolUse hook");
54
+ check(hasPostHook, "Claude Code: PostToolUse hook");
55
+ check(hasStopHook, "Claude Code: Stop hook");
56
+ const permissions = settings.permissions;
57
+ const hasWildcard = permissions?.allow?.some((r) => r === "MCP(pushary:*)") ?? false;
58
+ check(hasWildcard, "Claude Code: Pushary tools auto-allowed", hasWildcard ? "MCP(pushary:*)" : "missing");
59
+ const hasLegacyPerms = permissions?.allow?.some((r) => r.startsWith("mcp__pushary__")) ?? false;
60
+ if (hasLegacyPerms) {
61
+ console.log(` ${warn} Legacy individual permissions detected ${dim("(run pushary clean, then setup again)")}`);
62
+ }
63
+ } else {
64
+ check(false, "Claude Code: settings.json", "not found");
65
+ }
66
+ check(existsSync(SKILL_PATH), "Skill installed", existsSync(SKILL_PATH) ? SKILL_PATH : "not found");
67
+ let globalVersion = "";
68
+ try {
69
+ const { execSync } = await import("child_process");
70
+ globalVersion = execSync("npm list -g @pushary/agent-hooks --depth=0 2>/dev/null", { encoding: "utf-8" }).match(/@pushary\/agent-hooks@([\d.]+)/)?.[1] ?? "";
71
+ } catch {
72
+ }
73
+ check(!!globalVersion, "Global package installed", globalVersion || "not found");
74
+ console.log();
75
+ console.log(` ${dim("Connectivity")}`);
76
+ if (!apiKey) {
77
+ check(false, "MCP server reachable", "skipped \u2014 no API key");
78
+ check(false, "API key valid", "skipped");
79
+ check(false, "MCP handshake", "skipped");
80
+ } else {
81
+ let sessionId = "";
82
+ let toolCount = 0;
83
+ try {
84
+ const initRes = await fetch(MCP_URL, {
85
+ method: "POST",
86
+ headers: {
87
+ "Content-Type": "application/json",
88
+ "Accept": "application/json, text/event-stream",
89
+ "Authorization": `Bearer ${apiKey}`
90
+ },
91
+ body: JSON.stringify({
92
+ jsonrpc: "2.0",
93
+ id: 1,
94
+ method: "initialize",
95
+ params: {
96
+ protocolVersion: "2025-03-26",
97
+ capabilities: {},
98
+ clientInfo: { name: "pushary-doctor", version: "1.0" }
99
+ }
100
+ }),
101
+ signal: AbortSignal.timeout(1e4)
102
+ });
103
+ check(initRes.ok, "MCP server reachable", `${initRes.status} ${initRes.statusText}`);
104
+ sessionId = initRes.headers.get("mcp-session-id") ?? "";
105
+ check(!!sessionId, "Session ID returned", sessionId ? `${sessionId.slice(0, 8)}...` : "missing \u2014 update MCP SDK");
106
+ const initBody = await initRes.text();
107
+ const initMatch = initBody.match(/data: (.+)/);
108
+ if (initMatch) {
109
+ const initData = JSON.parse(initMatch[1]);
110
+ check(!!initData.result?.serverInfo, "API key valid", initData.result?.serverInfo?.name ?? "unknown server");
111
+ }
112
+ const toolsRes = await fetch(MCP_URL, {
113
+ method: "POST",
114
+ headers: {
115
+ "Content-Type": "application/json",
116
+ "Accept": "application/json, text/event-stream",
117
+ "Authorization": `Bearer ${apiKey}`,
118
+ ...sessionId ? { "Mcp-Session-Id": sessionId } : {}
119
+ },
120
+ body: JSON.stringify({
121
+ jsonrpc: "2.0",
122
+ id: 2,
123
+ method: "tools/list",
124
+ params: {}
125
+ }),
126
+ signal: AbortSignal.timeout(1e4)
127
+ });
128
+ const toolsBody = await toolsRes.text();
129
+ const toolsMatch = toolsBody.match(/data: (.+)/);
130
+ if (toolsMatch) {
131
+ const toolsData = JSON.parse(toolsMatch[1]);
132
+ toolCount = toolsData.result?.tools?.length ?? 0;
133
+ }
134
+ check(toolCount > 0, "MCP tools discovered", `${toolCount} tools`);
135
+ } catch (err) {
136
+ const msg = err instanceof Error ? err.message : "unknown error";
137
+ check(false, "MCP server reachable", msg);
138
+ }
139
+ console.log();
140
+ console.log(` ${dim("Notification Delivery")}`);
141
+ try {
142
+ const notifRes = await fetch("https://pushary.com/api/v1/server/send", {
143
+ method: "POST",
144
+ headers: {
145
+ "Content-Type": "application/json",
146
+ "Authorization": `Bearer ${apiKey}`
147
+ },
148
+ body: JSON.stringify({
149
+ title: "Pushary Doctor",
150
+ body: "If you see this, push notifications are working."
151
+ }),
152
+ signal: AbortSignal.timeout(1e4)
153
+ });
154
+ check(notifRes.ok, "Push notification sent", notifRes.ok ? "check your phone" : `${notifRes.status}`);
155
+ } catch (err) {
156
+ const msg = err instanceof Error ? err.message : "network error";
157
+ check(false, "Push notification sent", msg);
158
+ }
159
+ const testQuestion = await confirm({ message: "Test question roundtrip? (sends a push notification)", default: false });
160
+ if (testQuestion) {
161
+ console.log();
162
+ console.log(` ${dim("Question Roundtrip")}`);
163
+ try {
164
+ const askRes = await fetch(MCP_URL, {
165
+ method: "POST",
166
+ headers: {
167
+ "Content-Type": "application/json",
168
+ "Accept": "application/json, text/event-stream",
169
+ "Authorization": `Bearer ${apiKey}`
170
+ },
171
+ body: JSON.stringify({
172
+ jsonrpc: "2.0",
173
+ id: 3,
174
+ method: "tools/call",
175
+ params: {
176
+ name: "ask_user",
177
+ arguments: {
178
+ question: "Pushary Doctor: tap Yes to verify the roundtrip works.",
179
+ type: "confirm",
180
+ agentName: "Pushary Doctor"
181
+ }
182
+ }
183
+ }),
184
+ signal: AbortSignal.timeout(15e3)
185
+ });
186
+ const askBody = await askRes.text();
187
+ const askMatch = askBody.match(/data: (.+)/);
188
+ let correlationId = "";
189
+ if (askMatch) {
190
+ const askData = JSON.parse(askMatch[1]);
191
+ const content = askData.result?.content?.[0]?.text;
192
+ if (content) {
193
+ const parsed = JSON.parse(content);
194
+ correlationId = parsed.correlationId;
195
+ }
196
+ }
197
+ if (correlationId) {
198
+ console.log(` ${dim("\u2192")} Question sent, waiting for your answer...`);
199
+ const start = Date.now();
200
+ const waitRes = await fetch(MCP_URL, {
201
+ method: "POST",
202
+ headers: {
203
+ "Content-Type": "application/json",
204
+ "Accept": "application/json, text/event-stream",
205
+ "Authorization": `Bearer ${apiKey}`
206
+ },
207
+ body: JSON.stringify({
208
+ jsonrpc: "2.0",
209
+ id: 4,
210
+ method: "tools/call",
211
+ params: {
212
+ name: "wait_for_answer",
213
+ arguments: { correlationId, timeoutMs: 55e3 }
214
+ }
215
+ }),
216
+ signal: AbortSignal.timeout(6e4)
217
+ });
218
+ const waitBody = await waitRes.text();
219
+ const waitMatch = waitBody.match(/data: (.+)/);
220
+ if (waitMatch) {
221
+ const waitData = JSON.parse(waitMatch[1]);
222
+ const content = waitData.result?.content?.[0]?.text;
223
+ if (content) {
224
+ const parsed = JSON.parse(content);
225
+ const elapsed = ((Date.now() - start) / 1e3).toFixed(1);
226
+ check(parsed.answered === true, "Answer received", `"${parsed.value}" (${elapsed}s roundtrip)`);
227
+ } else {
228
+ check(false, "Answer received", "no response within timeout");
229
+ }
230
+ }
231
+ } else {
232
+ check(false, "Question sent", "failed to get correlationId");
233
+ }
234
+ } catch (err) {
235
+ const msg = err instanceof Error ? err.message : "unknown error";
236
+ check(false, "Question roundtrip", msg);
237
+ }
238
+ }
239
+ }
240
+ console.log();
241
+ const failed = results.filter((r) => !r.passed);
242
+ if (failed.length === 0) {
243
+ console.log(` ${green(bold("All checks passed."))}`);
244
+ } else {
245
+ console.log(` ${red(bold(`${failed.length} check${failed.length === 1 ? "" : "s"} failed:`))}`);
246
+ for (const f of failed) {
247
+ console.log(` ${fail} ${f.label}${f.detail ? ` \u2014 ${f.detail}` : ""}`);
248
+ }
249
+ console.log();
250
+ console.log(` ${dim("Run")} ${cyan("npx @pushary/agent-hooks@latest clean")} ${dim("then")} ${cyan("setup")} ${dim("to fix.")}`);
251
+ }
252
+ console.log();
253
+ };
254
+ main();
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@pushary/agent-hooks",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
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": {
8
8
  "type": "git",
9
- "url": "https://github.com/pushary/pushary.git",
9
+ "url": "git+https://github.com/pushary/pushary.git",
10
10
  "directory": "packages/agent-hooks"
11
11
  },
12
12
  "license": "MIT",
@@ -20,14 +20,19 @@
20
20
  "pushary-post-hook": "./dist/bin/pushary-post-hook.js",
21
21
  "pushary-stop-hook": "./dist/bin/pushary-stop-hook.js",
22
22
  "pushary-codex": "./dist/bin/pushary-codex.js",
23
- "pushary-setup": "./dist/bin/pushary-setup.js"
23
+ "pushary-setup": "./dist/bin/pushary-setup.js",
24
+ "pushary-clean": "./dist/bin/pushary-clean.js",
25
+ "pushary-doctor": "./dist/bin/pushary-doctor.js"
24
26
  },
25
27
  "files": [
26
28
  "dist"
27
29
  ],
28
30
  "scripts": {
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"
31
+ "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 bin/pushary-clean.ts bin/pushary-doctor.ts --format esm --dts --outDir dist",
32
+ "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 bin/pushary-clean.ts bin/pushary-doctor.ts --format esm --watch"
33
+ },
34
+ "dependencies": {
35
+ "@inquirer/prompts": "^8.4.2"
31
36
  },
32
37
  "devDependencies": {
33
38
  "tsup": "^8.0.0",