@ikyyofc/gemini-cli 1.0.5 → 1.0.6
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/index.js +13 -8
- package/package.json +1 -1
- package/src/agent.js +45 -46
package/index.js
CHANGED
|
@@ -81,13 +81,20 @@ function cleanup() {
|
|
|
81
81
|
disableBracketedPaste();
|
|
82
82
|
try { if (process.stdin.isTTY) process.stdin.setRawMode(false); } catch {}
|
|
83
83
|
}
|
|
84
|
-
process.on("exit",
|
|
84
|
+
process.on("exit", cleanup);
|
|
85
85
|
process.on("SIGTERM", () => { cleanup(); process.exit(0); });
|
|
86
86
|
|
|
87
|
+
// When terminal is resized (or focus returns on some terminals),
|
|
88
|
+
// only redraw prompt if we are NOT currently processing
|
|
89
|
+
process.on("SIGWINCH", () => { if (!processing) showPrompt(); });
|
|
90
|
+
|
|
87
91
|
// ─────────────────────────────────────────────────────────────────
|
|
88
92
|
// Prompt
|
|
89
93
|
// ─────────────────────────────────────────────────────────────────
|
|
90
94
|
function showPrompt() {
|
|
95
|
+
// Never redraw prompt while a request is in flight
|
|
96
|
+
if (processing) return;
|
|
97
|
+
|
|
91
98
|
const mode = agentMode ? chalk.hex("#4EC9B0")("agent") : chalk.dim("chat");
|
|
92
99
|
const yolo = autoApprove ? chalk.red(" yolo") : "";
|
|
93
100
|
const file = pendingFile ? chalk.yellow(` +${path.basename(pendingPath)}`) : "";
|
|
@@ -134,22 +141,20 @@ async function send(rawLine) {
|
|
|
134
141
|
history.push({ role: "assistant", content: res.finalResponse });
|
|
135
142
|
}
|
|
136
143
|
} else {
|
|
137
|
-
|
|
138
|
-
const sp = ora({
|
|
139
|
-
text: "thinking…", spinner: "dots", color: "cyan",
|
|
140
|
-
prefixText: " ", discardStdin: false
|
|
141
|
-
}).start();
|
|
144
|
+
process.stdout.write(chalk.hex("#555566")(" ⋯ ") + chalk.dim("thinking…") + "\n");
|
|
142
145
|
const msgs = [];
|
|
143
146
|
if (sysInstruction()) msgs.push({ role: "system", content: sysInstruction() });
|
|
144
147
|
msgs.push(...history, { role: "user", content: userText });
|
|
145
148
|
try {
|
|
146
149
|
const t0 = Date.now();
|
|
147
150
|
const reply = await chat(msgs, pendingFile || null);
|
|
148
|
-
|
|
151
|
+
// clear "thinking…" line, print done
|
|
152
|
+
if (process.stdout.isTTY) process.stdout.write("\x1b[1A\x1b[2K");
|
|
153
|
+
process.stdout.write(chalk.hex("#555566")(" ⋯ ") + chalk.dim(`done (${((Date.now()-t0)/1000).toFixed(1)}s)`) + "\n");
|
|
149
154
|
history.push({ role: "user", content: userText }, { role: "assistant", content: reply });
|
|
150
155
|
printAssistant(reply);
|
|
151
156
|
} catch (e) {
|
|
152
|
-
|
|
157
|
+
if (process.stdout.isTTY) process.stdout.write("\x1b[1A\x1b[2K");
|
|
153
158
|
printError(e.message);
|
|
154
159
|
}
|
|
155
160
|
}
|
package/package.json
CHANGED
package/src/agent.js
CHANGED
|
@@ -1,116 +1,115 @@
|
|
|
1
|
-
// src/agent.js — ReAct agent loop
|
|
1
|
+
// src/agent.js — ReAct agent loop, native Gemini function calling
|
|
2
2
|
import chalk from "chalk";
|
|
3
|
-
import ora from "ora";
|
|
4
3
|
import { callGemini } from "./gemini.js";
|
|
5
4
|
import { GEMINI_TOOLS, executeTool } from "./tools.js";
|
|
6
5
|
import { printAssistant, printError, printWarning, printToolCall, printToolResult } from "./renderer.js";
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
// ─────────────────────────────────────────────────────────────────
|
|
8
|
+
// Static progress line — write once, no continuous redraw
|
|
9
|
+
// Safe when terminal loses focus (no ANSI overwrite loops)
|
|
10
|
+
// ─────────────────────────────────────────────────────────────────
|
|
11
|
+
function printStep(n, label) {
|
|
12
|
+
process.stdout.write(
|
|
13
|
+
chalk.hex("#555566")(" ⋯ ") +
|
|
14
|
+
chalk.dim(label) +
|
|
15
|
+
(n > 1 ? chalk.hex("#555566")(` (step ${n})`) : "") +
|
|
16
|
+
"\n"
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function clearLastLine() {
|
|
21
|
+
// Move cursor up one line and clear it — only called right after printStep
|
|
22
|
+
// so we can replace "thinking…" with the actual tool section header
|
|
23
|
+
if (process.stdout.isTTY) {
|
|
24
|
+
process.stdout.write("\x1b[1A\x1b[2K");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
18
28
|
export async function runAgentLoop(userMessage, history, {
|
|
19
29
|
systemInstruction = null,
|
|
20
30
|
autoApprove = false,
|
|
21
31
|
maxIterations = 40,
|
|
22
32
|
} = {}) {
|
|
23
33
|
|
|
24
|
-
// Build initial message list
|
|
25
34
|
const messages = [
|
|
26
35
|
...history,
|
|
27
36
|
{ role: "user", content: userMessage }
|
|
28
37
|
];
|
|
29
38
|
|
|
30
|
-
let iteration
|
|
39
|
+
let iteration = 0;
|
|
40
|
+
let sectionOpen = false;
|
|
31
41
|
|
|
32
42
|
while (iteration < maxIterations) {
|
|
33
43
|
iteration++;
|
|
34
44
|
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
text: chalk.dim(iteration === 1 ? "thinking…" : `step ${iteration}…`),
|
|
38
|
-
spinner: "dots",
|
|
39
|
-
color: "cyan",
|
|
40
|
-
prefixText: " ",
|
|
41
|
-
discardStdin: false, // prevent ora from pausing stdin after stop
|
|
42
|
-
}).start();
|
|
45
|
+
// Print a static "thinking…" line — written once, not looping
|
|
46
|
+
printStep(iteration, iteration === 1 ? "thinking…" : "thinking…");
|
|
43
47
|
|
|
44
48
|
let parts;
|
|
45
49
|
try {
|
|
46
50
|
const res = await callGemini({ messages, tools: GEMINI_TOOLS, systemInstruction });
|
|
47
51
|
parts = res.parts;
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
// Clear the "thinking…" line now that we have a response
|
|
53
|
+
clearLastLine();
|
|
50
54
|
} catch (err) {
|
|
51
|
-
|
|
55
|
+
clearLastLine();
|
|
52
56
|
printError(err.message);
|
|
53
57
|
return null;
|
|
54
58
|
}
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
const textParts = parts.filter(p => p.text != null);
|
|
60
|
+
const textParts = parts.filter(p => p.text != null);
|
|
58
61
|
const callParts = parts.filter(p => p.functionCall != null);
|
|
59
62
|
|
|
60
|
-
//
|
|
63
|
+
// Model thinking aloud alongside tool calls
|
|
61
64
|
const textContent = textParts.map(p => p.text).join("").trim();
|
|
62
65
|
if (textContent && callParts.length > 0) {
|
|
63
66
|
process.stdout.write(
|
|
64
|
-
chalk.
|
|
67
|
+
chalk.hex("#555566")(" ┄ ") +
|
|
68
|
+
chalk.dim(textContent.split("\n")[0].slice(0, 80)) +
|
|
69
|
+
"\n"
|
|
65
70
|
);
|
|
66
71
|
}
|
|
67
72
|
|
|
68
|
-
// ──
|
|
73
|
+
// ── Final answer (no more tool calls) ─────────────────────
|
|
69
74
|
if (callParts.length === 0) {
|
|
70
75
|
const final = textParts.map(p => p.text).join("").trim();
|
|
71
|
-
|
|
72
|
-
if (iteration > 1) {
|
|
76
|
+
if (sectionOpen) {
|
|
73
77
|
process.stdout.write(
|
|
74
78
|
chalk.hex("#4A9EFF")(" ╰") +
|
|
75
79
|
chalk.hex("#555566")("─".repeat(47)) + "\n"
|
|
76
80
|
);
|
|
81
|
+
sectionOpen = false;
|
|
77
82
|
}
|
|
78
83
|
if (final) printAssistant(final);
|
|
79
84
|
return { finalResponse: final, iterations: iteration };
|
|
80
85
|
}
|
|
81
86
|
|
|
82
|
-
// ──
|
|
87
|
+
// ── Tool calls ─────────────────────────────────────────────
|
|
83
88
|
messages.push({ role: "model", parts });
|
|
84
89
|
|
|
85
|
-
|
|
86
|
-
if (iteration === 1) {
|
|
90
|
+
if (!sectionOpen) {
|
|
87
91
|
process.stdout.write(
|
|
88
92
|
"\n" + chalk.hex("#4A9EFF")(" ╭─ working") +
|
|
89
93
|
chalk.hex("#555566")(" " + "─".repeat(36)) + "\n"
|
|
90
94
|
);
|
|
95
|
+
sectionOpen = true;
|
|
91
96
|
}
|
|
92
97
|
|
|
93
98
|
const responseParts = [];
|
|
94
|
-
|
|
95
99
|
for (const part of callParts) {
|
|
96
100
|
const { name, args } = part.functionCall;
|
|
97
101
|
printToolCall(name, args);
|
|
98
|
-
|
|
99
102
|
const result = await executeTool(name, args ?? {}, { autoApprove });
|
|
100
103
|
printToolResult(result);
|
|
101
|
-
|
|
102
|
-
responseParts.push({
|
|
103
|
-
functionResponse: { name, response: result }
|
|
104
|
-
});
|
|
104
|
+
responseParts.push({ functionResponse: { name, response: result } });
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
messages.push({ role: "user", parts: responseParts });
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
if (sectionOpen) {
|
|
111
|
+
process.stdout.write(chalk.hex("#4A9EFF")(" ╰") + chalk.hex("#555566")("─".repeat(47)) + "\n");
|
|
112
|
+
}
|
|
113
|
+
printWarning(`max iterations (${maxIterations}) reached`);
|
|
111
114
|
return { finalResponse: null, iterations: iteration };
|
|
112
115
|
}
|
|
113
|
-
|
|
114
|
-
function clearLine() {
|
|
115
|
-
if (process.stdout.clearLine) { process.stdout.clearLine(0); process.stdout.cursorTo(0); }
|
|
116
|
-
}
|