@ikyyofc/gemini-cli 4.0.7 → 4.0.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.
Files changed (3) hide show
  1. package/index.js +9 -51
  2. package/package.json +1 -1
  3. package/src/agent.js +44 -74
package/index.js CHANGED
@@ -4,7 +4,7 @@ import fs from "fs";
4
4
  import path from "path";
5
5
  import chalk from "chalk";
6
6
 
7
- import { chat, callGeminiStream } from "./src/gemini.js";
7
+ import { chat } from "./src/gemini.js";
8
8
  import { runAgentLoop } from "./src/agent.js";
9
9
  import {
10
10
  loadMemory, buildContextString, memoryShow, memoryAdd, ensureGlobalDir, GLOBAL_DIR
@@ -163,62 +163,20 @@ async function send(rawLine) {
163
163
  history.push({ role: "assistant", content: res.finalResponse });
164
164
  }
165
165
  } else {
166
- // Chat mode — streaming
166
+ // Chat mode — non-streaming
167
+ const sp = new Spinner();
167
168
  const msgs = [];
168
169
  if (sysInstruction()) msgs.push({ role: "system", content: sysInstruction() });
169
170
  msgs.push(...history, { role: "user", content: userText });
170
-
171
- const W = bw();
172
- const prefix = chalk.hex("#00D4AA")(" │ ");
173
- let started = false;
174
- let fullText = "";
175
- let thinkText = "";
176
-
177
- const sp = new Spinner();
178
171
  sp.start("thinking…", "#4A9EFF");
179
-
180
172
  try {
181
- await callGeminiStream({
182
- messages: msgs,
183
- fileBuffer: pendingFile || null,
184
- onThought: (chunk) => {
185
- thinkText += chunk;
186
- },
187
- onText: (chunk) => {
188
- if (!started) {
189
- sp.stop();
190
- // Show thinking first if any
191
- if (thinkText.trim()) {
192
- process.stdout.write(
193
- "\n" + chalk.hex("#2A2A40")(" ╭─ thinking " + "─".repeat(Math.max(2, W - 13))) + "\n"
194
- );
195
- thinkText.trim().split("\n").forEach(line =>
196
- process.stdout.write(chalk.hex("#2A2A40")(" │ ") + chalk.hex("#4A4A6A").italic(line) + "\n")
197
- );
198
- process.stdout.write(chalk.hex("#2A2A40")(" ╰" + "─".repeat(W + 1)) + "\n\n");
199
- }
200
- process.stdout.write(
201
- "\n" + chalk.hex("#00D4AA")(" ╭─") +
202
- chalk.hex("#00D4AA").bold(" gemini ") +
203
- chalk.hex("#4A4A5E")("─".repeat(Math.max(0, W - 10))) + "\n"
204
- );
205
- started = true;
206
- }
207
- fullText += chunk;
208
- process.stdout.write(prefix + chunk.replace(/\n/g, "\n" + prefix));
209
- },
210
- onDone: () => {
211
- if (!started) sp.stop();
212
- }
213
- });
214
-
215
- if (started) {
216
- process.stdout.write("\n" + chalk.hex("#00D4AA")(" ╰" + "─".repeat(W + 1)) + "\n\n");
217
- }
218
-
219
- history.push({ role: "user", content: userText }, { role: "assistant", content: fullText });
173
+ const t0 = Date.now();
174
+ const reply = await chat(msgs, pendingFile || null);
175
+ sp.succeed(`done ${((Date.now()-t0)/1000).toFixed(1)}s`);
176
+ history.push({ role: "user", content: userText }, { role: "assistant", content: reply });
177
+ printAssistant(reply);
220
178
  } catch (e) {
221
- sp.stop();
179
+ sp.fail(e.message);
222
180
  printError(e.message);
223
181
  }
224
182
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ikyyofc/gemini-cli",
3
- "version": "4.0.7",
3
+ "version": "4.0.8",
4
4
  "description": "AI Agent CLI — native function calling · GEMINI.md context · extensions",
5
5
  "type": "module",
6
6
  "bin": { "gemini": "./index.js" },
package/src/agent.js CHANGED
@@ -1,6 +1,6 @@
1
- // src/agent.js — ReAct agent loop with streaming final answer
1
+ // src/agent.js — ReAct agent loop
2
2
  import chalk from "chalk";
3
- import { callGemini, callGeminiStream } from "./gemini.js";
3
+ import { callGemini } from "./gemini.js";
4
4
  import { GEMINI_TOOLS, FUNCTION_DECLARATIONS, executeTool } from "./tools.js";
5
5
  import { Spinner } from "./utils/spinner.js";
6
6
  import { loadSkills, SKILLS_DIR } from "./skills.js";
@@ -16,52 +16,66 @@ const TIMEOUT_MS = 10 * 60 * 1000;
16
16
  // System prompt
17
17
  // ─────────────────────────────────────────────────────────────────
18
18
  function buildSystemPrompt(extra = "") {
19
- const toolList = FUNCTION_DECLARATIONS.map(t => `- ${t.name}: ${t.description}`).join("\n");
20
- const skills = loadSkills();
21
- const skillIndex = skills.length
22
- ? skills.map(s => {
23
- const firstLine = s.content.split("\n").find(l => l.trim() && !l.startsWith("#")) ?? "";
24
- return ` - ${s.slug}: ${firstLine.slice(0, 80)}`;
25
- }).join("\n")
26
- : null;
19
+ const toolList = FUNCTION_DECLARATIONS.map(t => `- ${t.name}: ${t.description}`).join("\n");
20
+ const skills = loadSkills();
27
21
 
28
22
  const now = new Date();
29
23
  const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
30
24
  const datetime = now.toLocaleString("id-ID", { timeZone: tz, dateStyle: "full", timeStyle: "long" });
31
25
 
26
+ // Build skill section
27
+ let skillSection = "";
28
+ if (skills.length) {
29
+ const index = skills.map(s => {
30
+ const desc = s.content.split("\n").find(l => l.trim() && !l.startsWith("#")) ?? "";
31
+ return ` - ${s.slug}: ${desc.slice(0, 80)}`;
32
+ }).join("\n");
33
+
34
+ skillSection = `
35
+ ## SKILLS — MANDATORY
36
+ You have skills installed. Skills contain expert instructions for specific tasks.
37
+
38
+ **RULE: You MUST read the relevant skill file BEFORE starting any task.**
39
+ Do NOT proceed with a task until you have read the applicable skill(s).
40
+
41
+ Steps:
42
+ 1. Look at the installed skills below
43
+ 2. Identify which skill(s) apply to the current task
44
+ 3. Use read_file to load the skill: read_file("${SKILLS_DIR}/<slug>/SKILL.md")
45
+ 4. Follow the skill's instructions exactly
46
+ 5. Only then proceed with the task
47
+
48
+ Installed skills:
49
+ ${index}
50
+
51
+ Skills directory: ${SKILLS_DIR}`;
52
+ }
53
+
32
54
  return `You are an autonomous AI coding agent running in the user's terminal.
33
55
 
34
56
  ## CURRENT TIME
35
57
  ${datetime} (${tz})
58
+ ${skillSection}
36
59
 
37
60
  ## CORE RULE — NEVER ASK, ALWAYS ACT
38
61
  Use tools to complete every task. Never instruct the user to do anything themselves.
39
62
 
40
63
  ## WORKFLOW
41
- 1. CHECK SKILLS — if skills are available, read the relevant one FIRST before starting
42
- 2. EXPLOREunderstand the project structure
43
- 3. ACTcomplete the task fully using tools
44
- 4. VERIFYtest after changes
45
- 5. REPORT — brief summary
64
+ ${skills.length ? "0. READ SKILL load the relevant SKILL.md first if applicable\n" : ""}1. EXPLORE understand the project structure
65
+ 2. ACTcomplete the task fully using tools
66
+ 3. VERIFYtest after changes
67
+ 4. REPORTbrief summary
46
68
 
47
69
  ## TOOLS
48
70
  ${toolList}
49
71
 
50
- ${skillIndex ? `## AVAILABLE SKILLS
51
- You have skills installed. ALWAYS check if a skill is relevant before starting a task.
52
- If relevant, read it first: read_file("${SKILLS_DIR}/<slug>/SKILL.md")
53
-
54
- Installed:
55
- ${skillIndex}` : ""}
56
-
57
72
  ## RULES
58
- - Always read files before editing
59
- - Use patch_file for targeted edits
73
+ - Always read files before editing them
74
+ - Use patch_file for targeted edits (safer than full rewrite)
60
75
  - Verify code works after changes
61
76
  - If a command fails, diagnose and retry
62
77
  - Platform: ${process.platform} | CWD: ${process.cwd()}
63
-
64
- ${extra ? `## EXTRA\n${extra}` : ""}`.trim();
78
+ ${extra ? `\n## EXTRA\n${extra}` : ""}`.trim();
65
79
  }
66
80
 
67
81
  // ─────────────────────────────────────────────────────────────────
@@ -125,16 +139,13 @@ export async function runAgentLoop(userMessage, history, {
125
139
  // Show thinking
126
140
  printThinkBlock(thinkContent);
127
141
 
128
- // ── Final answer — stream it ───────────────────────────────
142
+ // ── Final answer ───────────────────────────────────────────
129
143
  if (callParts.length === 0) {
130
- if (textContent) {
131
- // Stream the final answer for better UX
132
- await streamFinalAnswer(messages, fullSystem, thinkContent);
133
- }
144
+ if (textContent) printAssistant(textContent);
134
145
  return { finalResponse: textContent, iterations: iteration };
135
146
  }
136
147
 
137
- // Show reasoning text before tool block
148
+ // Reasoning text before tool block
138
149
  if (textContent) {
139
150
  textContent.split("\n").forEach((line, i) =>
140
151
  process.stdout.write(
@@ -145,7 +156,7 @@ export async function runAgentLoop(userMessage, history, {
145
156
  }
146
157
 
147
158
  // ── Tool calls ─────────────────────────────────────────────
148
- // Include ALL parts (thinking + text + calls) in history for continuity
159
+ // Push ALL parts (including thinking) into history for context continuity
149
160
  messages.push({ role: "model", parts });
150
161
 
151
162
  printStepHeader(iteration);
@@ -164,44 +175,3 @@ export async function runAgentLoop(userMessage, history, {
164
175
  messages.push({ role: "user", parts: responseParts });
165
176
  }
166
177
  }
167
-
168
- // ─────────────────────────────────────────────────────────────────
169
- // Stream the final answer with live typing effect
170
- // ─────────────────────────────────────────────────────────────────
171
- async function streamFinalAnswer(messages, systemInstruction, prevThink) {
172
- const W = bw();
173
- const prefix = chalk.hex("#00D4AA")(" │ ");
174
- let started = false;
175
- let thinkAcc = "";
176
-
177
- const printHeader = () => {
178
- process.stdout.write(
179
- "\n" + chalk.hex("#00D4AA")(" ╭─") +
180
- chalk.hex("#00D4AA").bold(" gemini ") +
181
- chalk.hex("#4A4A5E")("─".repeat(Math.max(0, W - 10))) + "\n"
182
- );
183
- started = true;
184
- };
185
-
186
- await callGeminiStream({
187
- messages,
188
- systemInstruction,
189
- onThought: (chunk) => {
190
- thinkAcc += chunk;
191
- },
192
- onText: (chunk) => {
193
- if (!started) printHeader();
194
- process.stdout.write(prefix + chunk.replace(/\n/g, "\n" + prefix));
195
- },
196
- onDone: (parts) => {
197
- // Show thinking if new thinking arrived in final answer
198
- if (thinkAcc.trim() && thinkAcc !== prevThink) {
199
- printThinkBlock(thinkAcc);
200
- }
201
- }
202
- });
203
-
204
- if (started) {
205
- process.stdout.write("\n" + chalk.hex("#00D4AA")(" ╰" + "─".repeat(W + 1)) + "\n\n");
206
- }
207
- }