@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 +7 -2
- package/dist/lib.js +33 -25
- package/package.json +1 -1
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 =
|
|
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
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
151
|
+
finish({
|
|
144
152
|
output: parseGeminiOutput(stdout),
|
|
145
153
|
isError: false,
|
|
146
154
|
});
|