@danwahl/gemini-cli-mcp 0.1.6 → 0.1.8

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/dist/index.js CHANGED
@@ -42,6 +42,11 @@ server.registerTool("cli", {
42
42
  .string()
43
43
  .optional()
44
44
  .describe("Resume a previous Gemini session by ID. The session ID is returned in the structured output of each call."),
45
+ timeout: z
46
+ .number()
47
+ .optional()
48
+ .default(120)
49
+ .describe("Timeout in seconds. Default: 120. Increase for complex multi-step tasks."),
45
50
  },
46
51
  outputSchema: {
47
52
  sessionId: z.string().nullable().describe("Gemini CLI session ID"),
@@ -53,8 +58,8 @@ server.registerTool("cli", {
53
58
  readOnlyHint: false,
54
59
  openWorldHint: true,
55
60
  },
56
- }, async ({ prompt, cwd, model, sessionId }) => {
57
- const timeoutMs = 120_000;
61
+ }, async ({ prompt, cwd, model, sessionId, timeout }) => {
62
+ const timeoutMs = (timeout ?? 120) * 1000;
58
63
  const result = await runGemini(prompt, cwd, model, timeoutMs, sessionId);
59
64
  if (result.isError) {
60
65
  return {
package/dist/lib.js CHANGED
@@ -78,7 +78,7 @@ export function runGemini(prompt, cwd, model, timeoutMs, sessionId) {
78
78
  const args = buildGeminiArgs(prompt, model, sessionId);
79
79
  let child;
80
80
  try {
81
- child = spawn("gemini", args, { cwd, env: process.env });
81
+ child = spawn("gemini", args, { cwd, env: process.env, detached: true });
82
82
  }
83
83
  catch (err) {
84
84
  resolve({
@@ -90,18 +90,36 @@ export function runGemini(prompt, cwd, model, timeoutMs, sessionId) {
90
90
  }
91
91
  let stdout = "";
92
92
  let stderr = "";
93
- let timedOut = false;
93
+ let settled = false;
94
+ // Kill the entire process group (gemini + sandbox/tool grandchildren).
95
+ // Without this, grandchildren can keep stdio pipes open and `close` never fires.
96
+ const killGroup = (sig) => {
97
+ if (child.pid === undefined)
98
+ return;
99
+ try {
100
+ process.kill(-child.pid, sig);
101
+ }
102
+ catch {
103
+ // group already gone
104
+ }
105
+ };
106
+ const finish = (r) => {
107
+ if (settled)
108
+ return;
109
+ settled = true;
110
+ clearTimeout(timer);
111
+ resolve(r);
112
+ };
94
113
  const timer = setTimeout(() => {
95
- timedOut = true;
96
- child.kill("SIGTERM");
97
- setTimeout(() => {
98
- try {
99
- child.kill("SIGKILL");
100
- }
101
- catch {
102
- // already dead
103
- }
104
- }, 5000);
114
+ killGroup("SIGTERM");
115
+ setTimeout(() => killGroup("SIGKILL"), 5000).unref();
116
+ // Resolve immediately — don't wait for `close`, which may never fire
117
+ // if grandchildren keep stdio pipes open.
118
+ finish({
119
+ output: { sessionId: null, response: "" },
120
+ isError: true,
121
+ errorMessage: `gemini timed out after ${timeoutMs / 1000}s`,
122
+ });
105
123
  }, timeoutMs);
106
124
  child.stdout?.on("data", (chunk) => {
107
125
  stdout += chunk.toString();
@@ -110,10 +128,9 @@ export function runGemini(prompt, cwd, model, timeoutMs, sessionId) {
110
128
  stderr += chunk.toString();
111
129
  });
112
130
  child.on("error", (err) => {
113
- clearTimeout(timer);
114
131
  const isNotFound = err.code === "ENOENT" ||
115
132
  err.message.includes("ENOENT");
116
- resolve({
133
+ finish({
117
134
  output: { sessionId: null, response: "" },
118
135
  isError: true,
119
136
  errorMessage: isNotFound
@@ -122,25 +139,16 @@ export function runGemini(prompt, cwd, model, timeoutMs, sessionId) {
122
139
  });
123
140
  });
124
141
  child.on("close", (code) => {
125
- clearTimeout(timer);
126
- if (timedOut) {
127
- resolve({
128
- output: { sessionId: null, response: "" },
129
- isError: true,
130
- errorMessage: `gemini timed out after ${timeoutMs / 1000}s`,
131
- });
132
- return;
133
- }
134
142
  if (code !== 0) {
135
143
  const detail = stderr.trim() || stdout.trim() || `exit code ${code}`;
136
- resolve({
144
+ finish({
137
145
  output: { sessionId: null, response: "" },
138
146
  isError: true,
139
147
  errorMessage: `gemini exited with code ${code}: ${detail}`,
140
148
  });
141
149
  return;
142
150
  }
143
- resolve({
151
+ finish({
144
152
  output: parseGeminiOutput(stdout),
145
153
  isError: false,
146
154
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@danwahl/gemini-cli-mcp",
3
3
  "type": "module",
4
- "version": "0.1.6",
4
+ "version": "0.1.8",
5
5
  "description": "MCP server that exposes Gemini CLI as a single tool for Claude Code",
6
6
  "license": "MIT",
7
7
  "repository": {