@pushary/agent-hooks 0.18.3 → 0.19.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.
@@ -5,8 +5,9 @@ import {
5
5
  } from "../chunk-5MA3CPZB.js";
6
6
  import {
7
7
  execNpm,
8
- removeCodexHooks
9
- } from "../chunk-VC6U3QGF.js";
8
+ removeCodexHooks,
9
+ removeGeminiSettings
10
+ } from "../chunk-ZWBS3T7Q.js";
10
11
 
11
12
  // bin/pushary-clean.ts
12
13
  import { existsSync, readFileSync, writeFileSync, rmSync } from "fs";
@@ -134,6 +135,18 @@ var main = async () => {
134
135
  } else {
135
136
  console.log(` ${skip} Codex hooks ${dim("(not found)")}`);
136
137
  }
138
+ const geminiSettingsPath = join(homedir(), ".gemini", "settings.json");
139
+ const geminiSettings = readJson(geminiSettingsPath);
140
+ if (geminiSettings) {
141
+ if (removeGeminiSettings(geminiSettings)) {
142
+ writeJson(geminiSettingsPath, geminiSettings);
143
+ console.log(` ${check} Gemini CLI settings ${dim("(cleaned)")}`);
144
+ } else {
145
+ console.log(` ${skip} Gemini CLI settings ${dim("(no pushary entries)")}`);
146
+ }
147
+ } else {
148
+ console.log(` ${skip} Gemini CLI settings ${dim("(not found)")}`);
149
+ }
137
150
  for (const shellFile of SHELL_FILES) {
138
151
  try {
139
152
  const content = readFileSync(shellFile, "utf-8");
@@ -12,7 +12,7 @@ import {
12
12
  reportEvent,
13
13
  toCodexWire,
14
14
  toPolicyLookup
15
- } from "../chunk-Y633ZIJF.js";
15
+ } from "../chunk-QY4L6XHN.js";
16
16
  import {
17
17
  DEFAULT_SESSION,
18
18
  askUser,
@@ -25,8 +25,8 @@ import {
25
25
  savePendingQuestion,
26
26
  sendNotification,
27
27
  waitForAnswer
28
- } from "../chunk-2BE2IPMO.js";
29
- import "../chunk-RZLVE57X.js";
28
+ } from "../chunk-ACE77TKQ.js";
29
+ import "../chunk-USUCPCUC.js";
30
30
  import "../chunk-DWED7BS3.js";
31
31
  import {
32
32
  getApiKey
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  reportEvent
4
- } from "../chunk-Y633ZIJF.js";
4
+ } from "../chunk-QY4L6XHN.js";
5
5
  import {
6
6
  askUser,
7
7
  getMachineId,
8
8
  waitForAnswer
9
- } from "../chunk-2BE2IPMO.js";
10
- import "../chunk-RZLVE57X.js";
9
+ } from "../chunk-ACE77TKQ.js";
10
+ import "../chunk-USUCPCUC.js";
11
11
  import "../chunk-DWED7BS3.js";
12
12
  import {
13
13
  getApiKey
@@ -1,9 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ GEMINI_HOOK_BINARY,
3
4
  execNpm,
4
5
  hasCodexHooks,
5
- missingCodexHookEvents
6
- } from "../chunk-VC6U3QGF.js";
6
+ hasGeminiHooks,
7
+ missingCodexHookEvents,
8
+ missingGeminiHookEvents
9
+ } from "../chunk-ZWBS3T7Q.js";
7
10
  import {
8
11
  callMcpTool,
9
12
  sendMcpRequest
@@ -187,6 +190,30 @@ var main = async () => {
187
190
  const codexSkillPath = join(homedir(), ".codex", "skills", "pushary", "SKILL.md");
188
191
  check(existsSync(codexSkillPath), "Codex: skill installed");
189
192
  }
193
+ const geminiSettingsPath = join(homedir(), ".gemini", "settings.json");
194
+ const geminiSettings = readJson(geminiSettingsPath);
195
+ if (geminiSettings) {
196
+ const geminiServers = geminiSettings.mcpServers ?? {};
197
+ const geminiPushary = geminiServers.pushary;
198
+ check(!!geminiPushary, "Gemini CLI: MCP server configured");
199
+ if (geminiPushary) {
200
+ check(typeof geminiPushary.httpUrl === "string", "Gemini CLI: MCP transport", geminiPushary.httpUrl ? String(geminiPushary.httpUrl) : "missing \u2014 add httpUrl");
201
+ check(geminiPushary.trust === true, "Gemini CLI: tools auto-allowed", geminiPushary.trust === true ? "trust: true" : "missing \u2014 MCP calls will prompt for confirmation");
202
+ }
203
+ const geminiHooksInstalled = hasGeminiHooks(geminiSettings);
204
+ if (geminiHooksInstalled) {
205
+ const missingEvents = missingGeminiHookEvents(geminiSettings);
206
+ check(missingEvents.length === 0, "Gemini CLI: native hooks installed", missingEvents.length === 0 ? "all 5 events" : `missing ${missingEvents.join(", ")}, re-run setup`);
207
+ const geminiHooks = geminiSettings.hooks;
208
+ const hookCommand = extractHookCommand(geminiHooks?.BeforeTool, GEMINI_HOOK_BINARY);
209
+ if (hookCommand) {
210
+ const resolves = commandResolves(hookCommand);
211
+ check(resolves, "Gemini CLI: hook command resolves", resolves ? hookCommand : `not on PATH: ${hookCommand}`);
212
+ }
213
+ } else {
214
+ check(false, "Gemini CLI: native hooks installed", "no Pushary hooks in ~/.gemini/settings.json \u2014 re-run setup");
215
+ }
216
+ }
190
217
  const cursorPluginDir = join(homedir(), ".cursor", "plugins", "local", "pushary");
191
218
  if (existsSync(cursorPluginDir)) {
192
219
  const cursorUserHooks = join(homedir(), ".cursor", "hooks.json");
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,246 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ handlePostToolUse,
4
+ handleStop,
5
+ handleUserPrompt,
6
+ reportEvent
7
+ } from "../chunk-QY4L6XHN.js";
8
+ import {
9
+ DEFAULT_SESSION,
10
+ askUser,
11
+ deriveToolTarget,
12
+ describeToolCall,
13
+ fetchModeState,
14
+ getMachineId,
15
+ getPolicy,
16
+ resolvePolicy,
17
+ savePendingQuestion,
18
+ sendNotification,
19
+ waitForAnswer
20
+ } from "../chunk-ACE77TKQ.js";
21
+ import "../chunk-USUCPCUC.js";
22
+ import "../chunk-DWED7BS3.js";
23
+ import {
24
+ getApiKey
25
+ } from "../chunk-NKXSILEW.js";
26
+
27
+ // bin/pushary-gemini-hook.ts
28
+ import { basename } from "path";
29
+
30
+ // src/gemini-adapter.ts
31
+ var GEMINI_AGENT = { type: "gemini_cli", label: "Gemini CLI" };
32
+ var GEMINI_TOOL_MAP = {
33
+ run_shell_command: "Bash",
34
+ write_file: "Write",
35
+ replace: "Edit",
36
+ read_file: "Read"
37
+ };
38
+ var firstString = (...values) => values.find((v) => typeof v === "string" && v.length > 0);
39
+ var toGeminiPolicyLookup = (toolName, toolInput) => {
40
+ const canonical = GEMINI_TOOL_MAP[toolName];
41
+ if (!canonical) return { tool: toolName, input: toolInput };
42
+ if (canonical === "Bash") {
43
+ const command = firstString(toolInput.command);
44
+ return { tool: "Bash", input: command ? { command } : {} };
45
+ }
46
+ const filePath = firstString(toolInput.file_path, toolInput.absolute_path, toolInput.path);
47
+ return { tool: canonical, input: filePath ? { file_path: filePath } : {} };
48
+ };
49
+ var geminiAllow = () => ({ kind: "allow" });
50
+ var geminiDeny = (reason) => ({ kind: "deny", reason });
51
+ var geminiPass = () => ({ kind: "pass" });
52
+ var toGeminiWire = (decision) => {
53
+ if (decision.kind === "allow") return { decision: "allow" };
54
+ if (decision.kind === "deny") return { decision: "deny", reason: decision.reason };
55
+ return null;
56
+ };
57
+ var geminiTimeoutDecision = (timeoutAction, denyReason = "No response within timeout") => {
58
+ if (timeoutAction === "approve") return geminiAllow();
59
+ if (timeoutAction === "deny") return geminiDeny(denyReason);
60
+ return geminiPass();
61
+ };
62
+
63
+ // bin/pushary-gemini-hook.ts
64
+ var KILL_REASON = "Stopped by user: this agent was halted from Pushary";
65
+ var MAX_WAIT_SECONDS = 170;
66
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
67
+ var denyReasonFrom = (value) => value && value !== "no" && value !== "yes" ? `Denied from your phone: ${value}` : "Denied via push notification";
68
+ var pollForAnswer = async (apiKey, correlationId, deadlineMs, pollInterval = 2e3) => {
69
+ while (Date.now() < deadlineMs) {
70
+ const remaining = Math.min(Math.max(deadlineMs - Date.now(), 1e3), 3e4);
71
+ let answer;
72
+ try {
73
+ answer = await waitForAnswer(apiKey, correlationId, remaining);
74
+ } catch {
75
+ if (Date.now() + pollInterval >= deadlineMs) break;
76
+ await sleep(pollInterval);
77
+ continue;
78
+ }
79
+ if (answer.answered) return answer;
80
+ if (Date.now() + pollInterval >= deadlineMs) break;
81
+ await sleep(pollInterval);
82
+ }
83
+ return { answered: false };
84
+ };
85
+ var agentNameFor = (input) => `${GEMINI_AGENT.label} - ${basename(input.cwd ?? process.cwd())}`;
86
+ var pushQuestion = async (apiKey, input, lookup, waitSeconds, pollInterval = 2e3) => {
87
+ const projectName = basename(input.cwd ?? process.cwd());
88
+ const description = describeToolCall(lookup.tool, lookup.input, "hook");
89
+ const result = await askUser(apiKey, {
90
+ question: `Allow ${description}?`,
91
+ type: "confirm",
92
+ context: `Agent wants to run this in ${projectName}`,
93
+ agentName: agentNameFor(input),
94
+ sessionId: input.session_id,
95
+ machineId: getMachineId(),
96
+ toolName: lookup.tool,
97
+ toolTarget: deriveToolTarget(lookup.tool, lookup.input)
98
+ });
99
+ const deadline = Date.now() + Math.min(waitSeconds, MAX_WAIT_SECONDS) * 1e3;
100
+ const answer = await pollForAnswer(apiKey, result.correlationId, deadline, pollInterval);
101
+ return { answer, correlationId: result.correlationId };
102
+ };
103
+ var notifyApprovalNeeded = async (apiKey, input, lookup) => {
104
+ try {
105
+ await sendNotification(apiKey, {
106
+ title: "Agent needs approval",
107
+ body: describeToolCall(lookup.tool, lookup.input, "hook"),
108
+ agentName: agentNameFor(input),
109
+ sessionId: input.session_id,
110
+ machineId: getMachineId()
111
+ });
112
+ } catch {
113
+ }
114
+ };
115
+ var handlePushOnly = async (apiKey, input, lookup, timeoutSeconds, timeoutAction) => {
116
+ let pushed;
117
+ try {
118
+ pushed = await pushQuestion(apiKey, input, lookup, timeoutSeconds);
119
+ } catch {
120
+ return geminiTimeoutDecision(timeoutAction, "Push notification failed, denying per policy");
121
+ }
122
+ const { answer, correlationId } = pushed;
123
+ if (answer.answered) {
124
+ return answer.value === "yes" ? geminiAllow() : geminiDeny(denyReasonFrom(answer.value));
125
+ }
126
+ savePendingQuestion(input.session_id || DEFAULT_SESSION, correlationId);
127
+ return geminiTimeoutDecision(timeoutAction);
128
+ };
129
+ var handlePushFirst = async (apiKey, input, lookup, pushFirstSeconds) => {
130
+ let pushed;
131
+ try {
132
+ pushed = await pushQuestion(apiKey, input, lookup, pushFirstSeconds, 1500);
133
+ } catch {
134
+ return geminiPass();
135
+ }
136
+ const { answer, correlationId } = pushed;
137
+ if (answer.answered) {
138
+ return answer.value === "yes" ? geminiAllow() : geminiDeny(denyReasonFrom(answer.value));
139
+ }
140
+ savePendingQuestion(input.session_id || DEFAULT_SESSION, correlationId);
141
+ return geminiPass();
142
+ };
143
+ var decideBeforeTool = async (input) => {
144
+ try {
145
+ const apiKey = getApiKey();
146
+ const modeState = await fetchModeState(apiKey, input.session_id);
147
+ if (modeState.kill) return geminiDeny(KILL_REASON);
148
+ const lookup = toGeminiPolicyLookup(input.tool_name ?? "", input.tool_input ?? {});
149
+ const policy = await getPolicy(apiKey, modeState.policyVersion);
150
+ const toolPolicy = resolvePolicy(policy, lookup.tool, modeState.mode, lookup.input);
151
+ if (toolPolicy.timeoutSeconds === 0 && toolPolicy.timeoutAction === "approve") return geminiAllow();
152
+ if (toolPolicy.timeoutSeconds === 0 && toolPolicy.timeoutAction === "deny") {
153
+ return geminiDeny(`Denied by policy for ${toolPolicy.tool}`);
154
+ }
155
+ switch (toolPolicy.mode) {
156
+ case "push_only":
157
+ return handlePushOnly(apiKey, input, lookup, toolPolicy.timeoutSeconds, toolPolicy.timeoutAction);
158
+ case "terminal_only":
159
+ return geminiPass();
160
+ case "push_first":
161
+ return handlePushFirst(apiKey, input, lookup, toolPolicy.pushFirstSeconds);
162
+ case "notify_only":
163
+ await notifyApprovalNeeded(apiKey, input, lookup);
164
+ return geminiPass();
165
+ default:
166
+ return handlePushFirst(apiKey, input, lookup, toolPolicy.pushFirstSeconds);
167
+ }
168
+ } catch {
169
+ return geminiPass();
170
+ }
171
+ };
172
+ var reportSessionStart = async (input) => {
173
+ try {
174
+ await reportEvent({
175
+ event: "session_begin",
176
+ agentType: GEMINI_AGENT.type,
177
+ agentName: agentNameFor(input),
178
+ action: "Session started",
179
+ sessionId: input.session_id
180
+ }, { maxAttempts: 1, timeoutMs: 5e3 });
181
+ } catch {
182
+ }
183
+ };
184
+ var toCanonicalResult = (toolResponse) => {
185
+ if (!toolResponse || typeof toolResponse !== "object" || Array.isArray(toolResponse)) return void 0;
186
+ const error = toolResponse.error;
187
+ return error ? { error } : {};
188
+ };
189
+ var emit = (wire) => {
190
+ if (wire) process.stdout.write(JSON.stringify(wire));
191
+ };
192
+ var main = async () => {
193
+ let rawInput = "";
194
+ for await (const chunk of process.stdin) {
195
+ rawInput += chunk;
196
+ }
197
+ if (!rawInput.trim()) {
198
+ process.exit(0);
199
+ }
200
+ let input;
201
+ try {
202
+ input = JSON.parse(rawInput);
203
+ } catch {
204
+ process.exit(0);
205
+ }
206
+ try {
207
+ switch (input.hook_event_name) {
208
+ case "BeforeTool":
209
+ emit(toGeminiWire(await decideBeforeTool(input)));
210
+ break;
211
+ case "AfterTool": {
212
+ const lookup = toGeminiPolicyLookup(input.tool_name ?? "", input.tool_input ?? {});
213
+ await handlePostToolUse({
214
+ tool_name: lookup.tool,
215
+ tool_input: lookup.input,
216
+ tool_result: toCanonicalResult(input.tool_response),
217
+ cwd: input.cwd,
218
+ session_id: input.session_id,
219
+ transcript_path: input.transcript_path
220
+ }, GEMINI_AGENT);
221
+ break;
222
+ }
223
+ case "BeforeAgent":
224
+ await handleUserPrompt({
225
+ prompt: input.prompt,
226
+ cwd: input.cwd,
227
+ session_id: input.session_id
228
+ }, GEMINI_AGENT);
229
+ break;
230
+ case "SessionEnd":
231
+ await handleStop({
232
+ cwd: input.cwd,
233
+ session_id: input.session_id,
234
+ transcript_path: input.transcript_path
235
+ }, GEMINI_AGENT);
236
+ break;
237
+ case "SessionStart":
238
+ await reportSessionStart(input);
239
+ break;
240
+ default:
241
+ break;
242
+ }
243
+ } catch {
244
+ }
245
+ };
246
+ main();
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePreToolUse
4
- } from "../chunk-DKZVKEOW.js";
5
- import "../chunk-2BE2IPMO.js";
6
- import "../chunk-RZLVE57X.js";
4
+ } from "../chunk-SDREQWNI.js";
5
+ import "../chunk-ACE77TKQ.js";
6
+ import "../chunk-USUCPCUC.js";
7
7
  import "../chunk-DWED7BS3.js";
8
8
  import "../chunk-NKXSILEW.js";
9
9
 
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handlePostToolUse
4
- } from "../chunk-Y633ZIJF.js";
5
- import "../chunk-2BE2IPMO.js";
6
- import "../chunk-RZLVE57X.js";
4
+ } from "../chunk-QY4L6XHN.js";
5
+ import "../chunk-ACE77TKQ.js";
6
+ import "../chunk-USUCPCUC.js";
7
7
  import "../chunk-DWED7BS3.js";
8
8
  import "../chunk-NKXSILEW.js";
9
9
 
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleUserPrompt
4
- } from "../chunk-Y633ZIJF.js";
5
- import "../chunk-2BE2IPMO.js";
6
- import "../chunk-RZLVE57X.js";
4
+ } from "../chunk-QY4L6XHN.js";
5
+ import "../chunk-ACE77TKQ.js";
6
+ import "../chunk-USUCPCUC.js";
7
7
  import "../chunk-DWED7BS3.js";
8
8
  import "../chunk-NKXSILEW.js";
9
9
 
@@ -5,14 +5,17 @@ import {
5
5
  addPusharyToolPermissions
6
6
  } from "../chunk-5MA3CPZB.js";
7
7
  import {
8
+ GEMINI_HOOK_BINARY,
8
9
  addCodexHookTrust,
9
10
  addCodexHooks,
11
+ addGeminiHooks,
12
+ addGeminiMcpServer,
10
13
  execNpm,
11
14
  npmErrorMessage
12
- } from "../chunk-VC6U3QGF.js";
15
+ } from "../chunk-ZWBS3T7Q.js";
13
16
  import {
14
17
  isValidApiKey
15
- } from "../chunk-RZLVE57X.js";
18
+ } from "../chunk-USUCPCUC.js";
16
19
 
17
20
  // bin/pushary-setup.ts
18
21
  import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync, cpSync, rmSync, chmodSync } from "fs";
@@ -300,6 +303,7 @@ var CURSOR_USER_HOOKS = join(homedir(), ".cursor", "hooks.json");
300
303
  var CLAUDE_SKILL_DIR = join(homedir(), ".claude", "skills", "pushary");
301
304
  var CODEX_HOME = process.env.CODEX_HOME?.trim() || join(homedir(), ".codex");
302
305
  var CODEX_SKILL_DIR = join(CODEX_HOME, "skills", "pushary");
306
+ var GEMINI_SETTINGS = join(homedir(), ".gemini", "settings.json");
303
307
  var PUSHARY_CONFIG_DIR = join(homedir(), ".pushary");
304
308
  var PUSHARY_CONFIG_FILE = join(PUSHARY_CONFIG_DIR, "config.json");
305
309
  var SHELL_FILES = [".zshrc", ".zprofile", ".bashrc", ".bash_profile"].map((f) => join(homedir(), f));
@@ -799,9 +803,44 @@ var setupCustom = async (_apiKey) => {
799
803
  console.log();
800
804
  console.log(` ${dim2("Full guide:")} ${cyan2("https://pushary.com/docs/agents/connect-any-agent")}`);
801
805
  };
806
+ var setupGemini = async (apiKey) => {
807
+ console.log(`
808
+ ${bold2("Setting up Gemini CLI")}
809
+ `);
810
+ if (!isInstalled("gemini")) {
811
+ console.log(` ${yellow2("!")} Gemini CLI not found. Skipping.`);
812
+ console.log(` ${dim2("Install Gemini CLI and re-run setup to configure.")}`);
813
+ return;
814
+ }
815
+ await installGlobally();
816
+ const settings = readJson(GEMINI_SETTINGS);
817
+ await spinner("Adding MCP server (~/.gemini/settings.json)", async () => {
818
+ addGeminiMcpServer(settings, apiKey);
819
+ });
820
+ await spinner("Adding hooks (BeforeTool, AfterTool, BeforeAgent, SessionStart, SessionEnd)", async () => {
821
+ let hookCommand = GEMINI_HOOK_BINARY;
822
+ try {
823
+ const candidate = join(execNpm("prefix -g --no-workspaces", { timeout: 5e3 }).toString().trim(), "bin", GEMINI_HOOK_BINARY);
824
+ if (existsSync(candidate)) hookCommand = candidate;
825
+ } catch {
826
+ }
827
+ addGeminiHooks(settings, hookCommand);
828
+ });
829
+ await spinner(`Writing ${GEMINI_SETTINGS}`, async () => {
830
+ writeJson(GEMINI_SETTINGS, settings);
831
+ });
832
+ console.log();
833
+ console.log(` ${dim2("What this configured:")}`);
834
+ console.log(` ${dim2("\u2022")} MCP server: Gemini can send notifications and ask questions`);
835
+ console.log(` ${dim2("\u2022")} Hooks: phone approvals, policy enforcement, kill switch, session tracking`);
836
+ console.log(` ${dim2("\u2022")} Gate covers ${bold2("run_shell_command")}, ${bold2("write_file")}, and ${bold2("replace")}`);
837
+ console.log(` ${dim2("\u2022")} Auto-allowed tools: Pushary MCP calls run without a confirmation prompt`);
838
+ console.log(` ${dim2("Restart Gemini CLI to load the new config.")}`);
839
+ };
802
840
  var AGENT_SETUP = {
803
841
  claude_code: setupClaudeCode,
804
842
  codex: setupCodex,
843
+ gemini_cli: setupGemini,
805
844
  hermes: setupHermes,
806
845
  cursor: setupCursor,
807
846
  custom: setupCustom
@@ -865,6 +904,7 @@ var main = async () => {
865
904
  const detected = {
866
905
  claude_code: isInstalled("claude"),
867
906
  codex: isInstalled("codex"),
907
+ gemini_cli: isInstalled("gemini"),
868
908
  hermes: isInstalled("hermes"),
869
909
  cursor: isInstalled("cursor"),
870
910
  custom: false
@@ -875,6 +915,7 @@ var main = async () => {
875
915
  choices: [
876
916
  { name: `Claude Code ${dim2("MCP + hooks + auto-allowed tools")}`, value: "claude_code", checked: detected.claude_code },
877
917
  { name: `Codex ${dim2("MCP + native hooks + auto-allowed tools")}`, value: "codex", checked: detected.codex },
918
+ { name: `Gemini CLI ${dim2("MCP + native hooks + auto-allowed tools")}`, value: "gemini_cli", checked: detected.gemini_cli },
878
919
  { name: `Hermes ${dim2("native plugin + auto-error notifications")}`, value: "hermes", checked: detected.hermes },
879
920
  { name: `Cursor ${dim2("plugin + permission gate")}`, value: "cursor", checked: detected.cursor },
880
921
  { name: `Other ${dim2("any MCP or HTTP agent (Windsurf, n8n, custom)")}`, value: "custom", checked: false }
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleStop
4
- } from "../chunk-Y633ZIJF.js";
5
- import "../chunk-2BE2IPMO.js";
6
- import "../chunk-RZLVE57X.js";
4
+ } from "../chunk-QY4L6XHN.js";
5
+ import "../chunk-ACE77TKQ.js";
6
+ import "../chunk-USUCPCUC.js";
7
7
  import "../chunk-DWED7BS3.js";
8
8
  import "../chunk-NKXSILEW.js";
9
9
 
@@ -17,7 +17,7 @@ if (command === "setup") {
17
17
  Pushary Agent Hooks
18
18
 
19
19
  Commands:
20
- setup Configure Claude Code, Codex, Hermes, or Cursor with Pushary
20
+ setup Configure Claude Code, Codex, Gemini CLI, Hermes, or Cursor with Pushary
21
21
  doctor Verify your Pushary installation is working
22
22
  clean Remove all Pushary configuration
23
23
  mode Switch approval mode (push_only, push_first, terminal_only)