@ikyyofc/gemini-cli 2.0.9 → 3.0.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.
- package/package.json +1 -1
- package/src/renderer.js +168 -233
package/package.json
CHANGED
package/src/renderer.js
CHANGED
|
@@ -1,328 +1,263 @@
|
|
|
1
|
-
// src/renderer.js
|
|
1
|
+
// src/renderer.js
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
|
|
4
4
|
const C = {
|
|
5
|
-
blue: "#4A9EFF",
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
red: "#FF5F7E",
|
|
11
|
-
green: "#50FA7B",
|
|
12
|
-
dim: "#4A4A5E",
|
|
13
|
-
dimmer: "#32323E",
|
|
14
|
-
muted: "#7A7A9A",
|
|
15
|
-
white: "#E8E8F0",
|
|
16
|
-
kw: "#79B8FF",
|
|
17
|
-
str: "#F0A070",
|
|
18
|
-
comment: "#6A9955",
|
|
19
|
-
num: "#B5CEA8",
|
|
20
|
-
fn: "#FFD080",
|
|
5
|
+
blue: "#4A9EFF", teal: "#00D4AA", purple: "#C586FF",
|
|
6
|
+
yellow: "#FFD080", orange:"#FF9060", red: "#FF5F7E",
|
|
7
|
+
dim: "#4A4A5E", dimmer:"#32323E", muted: "#7A7A9A",
|
|
8
|
+
white: "#E8E8F0", kw: "#79B8FF", str: "#F0A070",
|
|
9
|
+
comment: "#6A9955", num: "#B5CEA8", fn: "#FFD080",
|
|
21
10
|
};
|
|
22
11
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
12
|
+
const tw = () => Math.min(process.stdout.columns || 72, 84);
|
|
13
|
+
const bw = () => Math.min(tw() - 4, 68);
|
|
14
|
+
const vlen = s => s.replace(/\x1b\[[0-9;]*m/g, "").length;
|
|
15
|
+
|
|
16
|
+
function wrapText(text, maxW) {
|
|
17
|
+
if (vlen(text) <= maxW) return [text];
|
|
18
|
+
const words = text.split(" ");
|
|
19
|
+
const lines = [];
|
|
20
|
+
let cur = "";
|
|
21
|
+
for (const w of words) {
|
|
22
|
+
const adding = cur ? cur + " " + w : w;
|
|
23
|
+
if (vlen(adding) <= maxW) { cur = adding; continue; }
|
|
24
|
+
if (cur) lines.push(cur);
|
|
25
|
+
if (vlen(w) > maxW) {
|
|
26
|
+
for (let i = 0; i < w.length; i += maxW) lines.push(w.slice(i, i + maxW));
|
|
27
|
+
cur = "";
|
|
28
|
+
} else { cur = w; }
|
|
29
|
+
}
|
|
30
|
+
if (cur) lines.push(cur);
|
|
31
|
+
return lines.length ? lines : [""];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ─── Syntax highlight ────────────────────────────────────────────
|
|
35
|
+
// FIX: applyToRaw() ensures the number regex never matches digits
|
|
36
|
+
// inside existing \x00N\x00 placeholder markers (the root cause of
|
|
37
|
+
// garbage numbers appearing in rendered code).
|
|
26
38
|
const KW = {
|
|
27
39
|
js: /\b(const|let|var|function|return|if|else|for|while|do|switch|case|break|continue|new|this|class|extends|import|export|default|async|await|try|catch|finally|throw|typeof|instanceof|of|in|null|undefined|true|false|void|delete|yield|from|static|super)\b/g,
|
|
28
40
|
ts: /\b(const|let|var|function|return|if|else|for|while|switch|case|class|extends|import|export|default|async|await|try|catch|type|interface|enum|implements|declare|readonly|abstract|as|keyof|never|any|string|number|boolean|null|undefined|true|false)\b/g,
|
|
29
41
|
py: /\b(def|class|return|if|elif|else|for|while|import|from|as|with|try|except|finally|raise|pass|break|continue|and|or|not|in|is|None|True|False|lambda|yield|global|async|await)\b/g,
|
|
30
42
|
go: /\b(func|return|if|else|for|range|switch|var|const|type|struct|interface|import|package|defer|go|chan|map|make|new|nil|true|false)\b/g,
|
|
31
|
-
sh: /\b(if|then|else|elif|fi|for|while|do|done|case|esac|function|return|exit|export|echo|local|source|cd|mkdir|rm|cp|mv|sudo|
|
|
43
|
+
sh: /\b(if|then|else|elif|fi|for|while|do|done|case|esac|function|return|exit|export|echo|local|source|cd|mkdir|rm|cp|mv|sudo|npm|pip|git)\b/g,
|
|
32
44
|
rs: /\b(fn|let|mut|return|if|else|for|match|use|mod|pub|struct|enum|impl|trait|type|const|async|await|true|false|None|Some|Ok|Err)\b/g,
|
|
33
|
-
json: null,
|
|
34
45
|
};
|
|
35
46
|
const LANGMAP = {
|
|
36
47
|
javascript:"js", js:"js", typescript:"ts", ts:"ts",
|
|
37
48
|
python:"py", py:"py", go:"go", golang:"go",
|
|
38
49
|
rust:"rs", rs:"rs", bash:"sh", sh:"sh", shell:"sh", zsh:"sh", fish:"sh",
|
|
39
|
-
json:"json", jsonc:"json",
|
|
40
50
|
};
|
|
41
51
|
|
|
52
|
+
function applyToRaw(str, re, fn) {
|
|
53
|
+
return str.split(/(\x00\d+\x00)/).map((p, i) =>
|
|
54
|
+
i % 2 === 0 ? p.replace(re, fn) : p
|
|
55
|
+
).join("");
|
|
56
|
+
}
|
|
57
|
+
|
|
42
58
|
function highlight(code, lang = "") {
|
|
43
59
|
const l = LANGMAP[lang.toLowerCase()] || "";
|
|
44
|
-
if (!l
|
|
45
|
-
let r = code;
|
|
60
|
+
if (!l) return code;
|
|
46
61
|
const saved = [];
|
|
47
|
-
const save
|
|
48
|
-
r =
|
|
49
|
-
r = r
|
|
50
|
-
|
|
51
|
-
r = r
|
|
52
|
-
r = r
|
|
53
|
-
|
|
62
|
+
const save = s => { const id = `\x00${saved.length}\x00`; saved.push(s); return id; };
|
|
63
|
+
let r = code;
|
|
64
|
+
r = applyToRaw(r, /(\/\/.*$|#.*$|\/\*[\s\S]*?\*\/)/gm, m => save(chalk.hex(C.comment).italic(m)));
|
|
65
|
+
r = applyToRaw(r, /("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`)/g, m => save(chalk.hex(C.str)(m)));
|
|
66
|
+
if (KW[l]) { KW[l].lastIndex = 0; r = applyToRaw(r, KW[l], m => save(chalk.hex(C.kw).bold(m))); }
|
|
67
|
+
r = applyToRaw(r, /\b(\d+\.?\d*)\b/g, m => save(chalk.hex(C.num)(m)));
|
|
68
|
+
r = applyToRaw(r, /\b([a-zA-Z_$][a-zA-Z0-9_$]*)\s*(?=\()/g, m => save(chalk.hex(C.fn)(m)));
|
|
69
|
+
return r.replace(/\x00(\d+)\x00/g, (_, i) => saved[+i] ?? "");
|
|
54
70
|
}
|
|
55
71
|
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
export function renderMarkdown(text) {
|
|
72
|
+
// ─── Markdown renderer ───────────────────────────────────────────
|
|
73
|
+
export function renderMarkdown(text, contentW) {
|
|
74
|
+
const cw = contentW ?? bw() - 2;
|
|
60
75
|
let r = text;
|
|
61
76
|
|
|
62
|
-
// Code blocks
|
|
63
77
|
r = r.replace(/```(\w*)\n?([\s\S]*?)```/g, (_, lang, code) => {
|
|
64
78
|
const trimmed = code.trimEnd();
|
|
65
79
|
const lines = trimmed.split("\n");
|
|
66
80
|
const hl = highlight(trimmed, lang);
|
|
67
81
|
const hlLines = hl.split("\n");
|
|
68
82
|
const gw = String(lines.length).length;
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
83
|
+
const bw2 = Math.min(cw + 2, tw() - 6);
|
|
84
|
+
const lbl = lang ? chalk.hex(C.blue).bold(` ${lang} `) : "";
|
|
85
|
+
const lblLen = lang ? lang.length + 2 : 0;
|
|
86
|
+
const dashes = Math.max(2, bw2 - lblLen - 1);
|
|
87
|
+
const maxCode = bw2 - gw - 4;
|
|
88
|
+
|
|
89
|
+
const top = chalk.hex(C.dim)("┌─") + lbl + chalk.hex(C.dimmer)("─".repeat(dashes)) + chalk.hex(C.dim)("┐");
|
|
90
|
+
const bot = chalk.hex(C.dim)("└" + "─".repeat(bw2 + 1) + "┘");
|
|
91
|
+
const body = hlLines.map((hl_line, i) => {
|
|
92
|
+
const ln = chalk.hex(C.dimmer)(String(i + 1).padStart(gw));
|
|
93
|
+
const raw = lines[i] ?? "";
|
|
94
|
+
const disp = raw.length > maxCode ? hl_line.slice(0, maxCode * 3) + chalk.hex(C.dimmer)("…") : hl_line;
|
|
95
|
+
return chalk.hex(C.dim)("│") + chalk.hex(C.dimmer)(" " + ln + " ╎ ") + disp;
|
|
76
96
|
}).join("\n");
|
|
77
97
|
|
|
78
98
|
return `\n${top}\n${body}\n${bot}\n`;
|
|
79
99
|
});
|
|
80
100
|
|
|
81
|
-
|
|
82
|
-
r = r.replace(
|
|
83
|
-
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
// Headers
|
|
87
|
-
r = r.replace(/^### (.+)$/gm, (_, t) => "\n" + chalk.hex(C.yellow).bold(" ◈ " + t));
|
|
88
|
-
r = r.replace(/^## (.+)$/gm, (_, t) => "\n" + chalk.hex(C.blue).bold.underline(" " + t));
|
|
89
|
-
r = r.replace(/^# (.+)$/gm, (_, t) => "\n" + chalk.hex(C.teal).bold(" ◉ " + t.toUpperCase()));
|
|
90
|
-
|
|
91
|
-
// Bold / italic
|
|
101
|
+
r = r.replace(/`([^`\n]+)`/g, (_, c) => chalk.bgHex("#2A2A3E")(chalk.hex(C.orange)(" " + c + " ")));
|
|
102
|
+
r = r.replace(/^### (.+)$/gm, (_, t) => "\n" + chalk.hex(C.yellow).bold("◈ " + t));
|
|
103
|
+
r = r.replace(/^## (.+)$/gm, (_, t) => "\n" + chalk.hex(C.blue).bold.underline(t));
|
|
104
|
+
r = r.replace(/^# (.+)$/gm, (_, t) => "\n" + chalk.hex(C.teal).bold("◉ " + t.toUpperCase()));
|
|
92
105
|
r = r.replace(/\*\*\*(.+?)\*\*\*/g, (_, t) => chalk.bold.italic(t));
|
|
93
106
|
r = r.replace(/\*\*(.+?)\*\*/g, (_, t) => chalk.bold(t));
|
|
94
107
|
r = r.replace(/\*(.+?)\*/g, (_, t) => chalk.italic(t));
|
|
108
|
+
r = r.replace(/^> (.+)$/gm, (_, t) => chalk.hex(C.purple)("▎ ") + chalk.hex(C.muted).italic(t));
|
|
109
|
+
r = r.replace(/^(\s*)[*\-+] (.+)$/gm, (_, i, t) => i + chalk.hex(C.teal)("◆ ") + chalk.hex(C.white)(t));
|
|
110
|
+
r = r.replace(/^(\s*)(\d+)\. (.+)$/gm, (_, i, n, t) => i + chalk.hex(C.blue)(chalk.bold(n + ".") + " ") + chalk.hex(C.white)(t));
|
|
111
|
+
r = r.replace(/^---+$/gm, chalk.hex(C.dimmer)("╌".repeat(Math.min(cw, 48))));
|
|
112
|
+
return r;
|
|
113
|
+
}
|
|
95
114
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
115
|
+
// ─── Box printer ─────────────────────────────────────────────────
|
|
116
|
+
function printBox(contentLines, borderHex, label, extra = "") {
|
|
117
|
+
const W = bw();
|
|
118
|
+
const inner = W - 2;
|
|
119
|
+
const lblLen = vlen(label) + vlen(extra);
|
|
120
|
+
const dashes = Math.max(0, W - lblLen - 1);
|
|
100
121
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
122
|
+
process.stdout.write(
|
|
123
|
+
"\n" + chalk.hex(borderHex)("╭─") + label +
|
|
124
|
+
chalk.hex(C.dim)("─".repeat(dashes)) + extra + "\n"
|
|
125
|
+
);
|
|
104
126
|
|
|
105
|
-
|
|
106
|
-
|
|
127
|
+
for (const line of contentLines) {
|
|
128
|
+
if (line.includes("\x1b[")) {
|
|
129
|
+
// Already styled (code blocks, headers) — print as-is
|
|
130
|
+
process.stdout.write(chalk.hex(borderHex)("│ ") + line + "\n");
|
|
131
|
+
} else {
|
|
132
|
+
wrapText(line || " ", inner).forEach(wl =>
|
|
133
|
+
process.stdout.write(chalk.hex(borderHex)("│ ") + wl + "\n")
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
107
137
|
|
|
108
|
-
|
|
138
|
+
process.stdout.write(chalk.hex(borderHex)("╰" + "─".repeat(W + 1)) + "\n");
|
|
109
139
|
}
|
|
110
140
|
|
|
111
|
-
//
|
|
112
|
-
// User message
|
|
113
|
-
// ─────────────────────────────────────────────────────────────────
|
|
141
|
+
// ─── Messages ────────────────────────────────────────────────────
|
|
114
142
|
export function printUser(text) {
|
|
115
|
-
const lines
|
|
116
|
-
const
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
process.stdout.write(
|
|
121
|
-
"\n" +
|
|
122
|
-
chalk.hex(C.blue)(" ╭─") +
|
|
123
|
-
chalk.hex(C.blue).bold(" you ") +
|
|
124
|
-
chalk.hex(C.dim)("─".repeat(W - 5)) + "\n" +
|
|
125
|
-
chalk.hex(C.blue)(" │ ") + chalk.hex(C.white)(text) + "\n" +
|
|
126
|
-
chalk.hex(C.blue)(" ╰" + "─".repeat(W + 2)) + "\n"
|
|
127
|
-
);
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
process.stdout.write(
|
|
132
|
-
"\n" +
|
|
133
|
-
chalk.hex(C.blue)(" ╭─") +
|
|
134
|
-
chalk.hex(C.blue).bold(" you ") +
|
|
135
|
-
chalk.hex(C.dim)("─".repeat(W - 5)) +
|
|
136
|
-
chalk.hex(C.dim)(` (${lines.length} lines)`) + "\n"
|
|
137
|
-
);
|
|
138
|
-
lines.forEach(l =>
|
|
139
|
-
process.stdout.write(chalk.hex(C.blue)(" │ ") + chalk.hex(C.white)(l) + "\n")
|
|
140
|
-
);
|
|
141
|
-
process.stdout.write(chalk.hex(C.blue)(" ╰" + "─".repeat(W + 2)) + "\n");
|
|
143
|
+
const lines = text.split("\n");
|
|
144
|
+
const multi = lines.length > 1;
|
|
145
|
+
const label = chalk.hex(C.blue).bold(" you ");
|
|
146
|
+
const extra = multi ? chalk.hex(C.muted)(` (${lines.length} lines) `) : "";
|
|
147
|
+
printBox(lines, C.blue, label, extra);
|
|
142
148
|
}
|
|
143
149
|
|
|
144
|
-
// ─────────────────────────────────────────────────────────────────
|
|
145
|
-
// Gemini response
|
|
146
|
-
// ─────────────────────────────────────────────────────────────────
|
|
147
150
|
export function printAssistant(text) {
|
|
148
|
-
const
|
|
149
|
-
const rendered = renderMarkdown(text
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
process.stdout.write(
|
|
153
|
-
"\n" +
|
|
154
|
-
chalk.hex(C.teal)(" ╭─") +
|
|
155
|
-
chalk.hex(C.teal).bold(" gemini ") +
|
|
156
|
-
chalk.hex(C.dim)("─".repeat(W - 8)) + "\n"
|
|
157
|
-
);
|
|
158
|
-
lines.forEach(l =>
|
|
159
|
-
process.stdout.write(chalk.hex(C.teal)(" │") + " " + l + "\n")
|
|
160
|
-
);
|
|
161
|
-
process.stdout.write(
|
|
162
|
-
chalk.hex(C.teal)(" ╰" + "─".repeat(W + 2)) + "\n\n"
|
|
163
|
-
);
|
|
151
|
+
const inner = bw() - 2;
|
|
152
|
+
const rendered = renderMarkdown(text.trimEnd(), inner);
|
|
153
|
+
printBox(rendered.split("\n"), C.teal, chalk.hex(C.teal).bold(" gemini "));
|
|
154
|
+
process.stdout.write("\n");
|
|
164
155
|
}
|
|
165
156
|
|
|
166
|
-
//
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
const
|
|
172
|
-
const trail = chalk.hex(C.dim)("─".repeat(Math.max(2, 40 - label.length)));
|
|
157
|
+
// ─── Agent step blocks ───────────────────────────────────────────
|
|
158
|
+
export function printStepHeader(step) {
|
|
159
|
+
const W = bw();
|
|
160
|
+
const label = chalk.hex(C.yellow).bold(" working ");
|
|
161
|
+
const num = step > 1 ? chalk.hex(C.dim)(` step ${step} `) : " ";
|
|
162
|
+
const trail = Math.max(2, W - 9 - vlen(num));
|
|
173
163
|
process.stdout.write(
|
|
174
|
-
"\n" +
|
|
175
|
-
chalk.hex(C.
|
|
164
|
+
"\n" + chalk.hex(C.yellow)("╭─") + label +
|
|
165
|
+
chalk.hex(C.dim)("─".repeat(trail)) + num + "\n"
|
|
176
166
|
);
|
|
177
167
|
}
|
|
178
168
|
|
|
179
169
|
export function printStepFooter() {
|
|
180
|
-
process.stdout.write(
|
|
181
|
-
chalk.hex(C.yellow)(" ╰" + "─".repeat(50)) + "\n"
|
|
182
|
-
);
|
|
170
|
+
process.stdout.write(chalk.hex(C.yellow)("╰" + "─".repeat(bw() + 1)) + "\n");
|
|
183
171
|
}
|
|
184
172
|
|
|
185
173
|
export function printToolCall(name, args = {}) {
|
|
186
|
-
const argStr = Object.entries(args)
|
|
187
|
-
.
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
.join(" ");
|
|
192
|
-
|
|
174
|
+
const argStr = Object.entries(args).map(([k, v]) => {
|
|
175
|
+
const raw = String(v).replace(/\n/g, "↵");
|
|
176
|
+
const val = vlen(raw) > 42 ? raw.slice(0, 42) + "…" : raw;
|
|
177
|
+
return chalk.hex(C.muted)(k + ":") + chalk.hex(C.orange)(val);
|
|
178
|
+
}).join(" ");
|
|
193
179
|
process.stdout.write(
|
|
194
|
-
chalk.hex(C.yellow)("
|
|
195
|
-
chalk.hex(C.blue).bold(name) +
|
|
180
|
+
chalk.hex(C.yellow)("├─ ") + chalk.hex(C.blue).bold(name) +
|
|
196
181
|
(argStr ? " " + argStr : "") + "\n"
|
|
197
182
|
);
|
|
198
183
|
}
|
|
199
184
|
|
|
200
185
|
export function printToolResult(result) {
|
|
186
|
+
const W = bw() - 5;
|
|
201
187
|
const isErr = typeof result === "object" && result.error;
|
|
202
188
|
const text = typeof result === "object"
|
|
203
189
|
? (result.result ?? result.error ?? JSON.stringify(result, null, 2))
|
|
204
190
|
: String(result);
|
|
205
191
|
const color = isErr ? chalk.hex(C.red) : chalk.hex(C.muted);
|
|
206
|
-
const border =
|
|
192
|
+
const border = chalk.hex(C.dimmer)("│ ");
|
|
207
193
|
const lines = text.split("\n");
|
|
208
|
-
const shown = lines.slice(0,
|
|
209
|
-
const extra = lines.length
|
|
210
|
-
|
|
194
|
+
const shown = lines.slice(0, 10);
|
|
195
|
+
const extra = lines.length - 10;
|
|
211
196
|
shown.forEach(l =>
|
|
212
|
-
process.stdout.write(border
|
|
197
|
+
process.stdout.write(border + color(l.length > W ? l.slice(0, W) + "…" : l) + "\n")
|
|
213
198
|
);
|
|
214
|
-
if (extra > 0)
|
|
215
|
-
process.stdout.write(border(" │ ") + chalk.hex(C.dim)(`… +${extra} more lines`) + "\n");
|
|
199
|
+
if (extra > 0) process.stdout.write(border + chalk.hex(C.dim)(`… +${extra} more lines`) + "\n");
|
|
216
200
|
}
|
|
217
201
|
|
|
218
|
-
//
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
export function
|
|
222
|
-
|
|
223
|
-
"\n" +
|
|
224
|
-
chalk.hex(C.dim)(" ◌ ") +
|
|
225
|
-
chalk.hex(C.muted)("thinking") +
|
|
226
|
-
(step > 1 ? chalk.hex(C.dim)(` · step ${step}`) : "") +
|
|
227
|
-
chalk.hex(C.dim)(" …") + "\n"
|
|
228
|
-
);
|
|
229
|
-
}
|
|
202
|
+
// ─── Status ──────────────────────────────────────────────────────
|
|
203
|
+
export function printError(msg) { process.stdout.write("\n" + chalk.hex(C.red)("╳ ") + chalk.hex(C.red).bold("error ") + chalk.hex(C.muted)(msg) + "\n\n"); }
|
|
204
|
+
export function printInfo(msg) { process.stdout.write(chalk.hex(C.dim)("· ") + chalk.hex(C.white)(msg) + "\n"); }
|
|
205
|
+
export function printSuccess(msg) { process.stdout.write(chalk.hex(C.teal)("✓ ") + chalk.hex(C.teal)(msg) + "\n"); }
|
|
206
|
+
export function printWarning(msg) { process.stdout.write(chalk.hex(C.yellow)("⚠ ") + chalk.hex(C.yellow)(msg) + "\n"); }
|
|
230
207
|
|
|
231
|
-
|
|
232
|
-
process.stdout.write(
|
|
233
|
-
"\n" +
|
|
234
|
-
chalk.hex(C.red)(" ╳ ") +
|
|
235
|
-
chalk.hex(C.red).bold("error") +
|
|
236
|
-
chalk.hex(C.muted)(" " + msg) + "\n\n"
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
export function printInfo(msg) {
|
|
240
|
-
process.stdout.write(
|
|
241
|
-
chalk.hex(C.dim)(" · ") + chalk.hex(C.white)(msg) + "\n"
|
|
242
|
-
);
|
|
243
|
-
}
|
|
244
|
-
export function printSuccess(msg) {
|
|
245
|
-
process.stdout.write(
|
|
246
|
-
chalk.hex(C.teal)(" ✓ ") + chalk.hex(C.teal)(msg) + "\n"
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
export function printWarning(msg) {
|
|
250
|
-
process.stdout.write(
|
|
251
|
-
chalk.hex(C.yellow)(" ⚠ ") + chalk.hex(C.yellow)(msg) + "\n"
|
|
252
|
-
);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// ─────────────────────────────────────────────────────────────────
|
|
256
|
-
// Welcome
|
|
257
|
-
// ─────────────────────────────────────────────────────────────────
|
|
208
|
+
// ─── Welcome ─────────────────────────────────────────────────────
|
|
258
209
|
export function renderWelcome(memCount = 0, extCount = 0) {
|
|
210
|
+
const W = bw();
|
|
259
211
|
const stats = [
|
|
260
212
|
memCount ? `${memCount} context file${memCount > 1 ? "s" : ""}` : null,
|
|
261
213
|
extCount ? `${extCount} extension${extCount > 1 ? "s" : ""}` : null,
|
|
262
214
|
].filter(Boolean).join(" · ");
|
|
263
|
-
|
|
264
215
|
return [
|
|
265
216
|
"",
|
|
266
|
-
chalk.hex(C.dim)("
|
|
267
|
-
chalk.hex(C.dim)("
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
chalk.hex(C.dim)(" ") + chalk.hex(C.dim)("/help") + chalk.hex(C.dim)(" · ") + chalk.hex(C.dim)("/agent") + chalk.hex(C.dim)(" toggle tools · ") + chalk.hex(C.dim)("/yolo") + chalk.hex(C.dim)(" skip confirms"),
|
|
217
|
+
chalk.hex(C.dim)("┌" + "─".repeat(W + 1) + "┐"),
|
|
218
|
+
chalk.hex(C.dim)("│ ") + chalk.hex(C.teal).bold("Gemini") + chalk.hex(C.blue).bold(" CLI") +
|
|
219
|
+
chalk.hex(C.dim)(" ─ AI Agent ─ native function calling") + chalk.hex(C.dim)(" │"),
|
|
220
|
+
chalk.hex(C.dim)("└" + "─".repeat(W + 1) + "┘"),
|
|
221
|
+
stats ? chalk.hex(C.muted)(" " + stats) : "",
|
|
222
|
+
chalk.hex(C.dim)(" /help · /agent toggle · /yolo skip confirms"),
|
|
273
223
|
"",
|
|
274
224
|
].join("\n");
|
|
275
225
|
}
|
|
276
226
|
|
|
277
|
-
//
|
|
278
|
-
// Help
|
|
279
|
-
// ─────────────────────────────────────────────────────────────────
|
|
227
|
+
// ─── Help ────────────────────────────────────────────────────────
|
|
280
228
|
export function renderHelp(customCommands = {}) {
|
|
281
|
-
const sep = chalk.hex(C.dimmer)(" " + "─".repeat(52));
|
|
282
|
-
const row = (cmd, desc) =>
|
|
283
|
-
" " + chalk.hex(C.blue).bold(cmd.padEnd(26)) + chalk.hex(C.muted)(desc);
|
|
284
|
-
|
|
229
|
+
const sep = chalk.hex(C.dimmer)(" " + "─".repeat(Math.min(tw() - 4, 52)));
|
|
230
|
+
const row = (cmd, desc) => " " + chalk.hex(C.blue).bold(cmd.padEnd(24)) + chalk.hex(C.muted)(desc);
|
|
285
231
|
const lines = [
|
|
286
|
-
"",
|
|
287
|
-
|
|
288
|
-
sep,
|
|
289
|
-
row("/
|
|
290
|
-
row("/
|
|
291
|
-
sep,
|
|
292
|
-
row("/
|
|
293
|
-
row("/
|
|
294
|
-
row("/
|
|
295
|
-
|
|
296
|
-
row("/ext
|
|
297
|
-
row("/ext
|
|
298
|
-
row("/
|
|
299
|
-
row("/
|
|
300
|
-
row("/
|
|
301
|
-
|
|
302
|
-
row("/
|
|
303
|
-
row("/
|
|
304
|
-
row("/
|
|
305
|
-
row("/
|
|
306
|
-
row("/
|
|
307
|
-
|
|
308
|
-
row("/model", "Show model & config"),
|
|
309
|
-
row("/proxy [on|off]", "Proxy rotation status / toggle"),
|
|
310
|
-
row("/exit /quit", "Exit"),
|
|
311
|
-
sep,
|
|
232
|
+
"", chalk.hex(C.teal).bold(" Commands"), sep,
|
|
233
|
+
row("/agent", "Toggle agent ↔ chat mode"),
|
|
234
|
+
row("/yolo", "Skip all tool confirmations"), sep,
|
|
235
|
+
row("/memory show", "Show loaded GEMINI.md files"),
|
|
236
|
+
row("/memory reload", "Reload context from disk"),
|
|
237
|
+
row("/memory add <text>", "Append to ~/.gemini/GEMINI.md"), sep,
|
|
238
|
+
row("/ext list", "List extensions"),
|
|
239
|
+
row("/ext install <src>", "Install (path or git URL)"),
|
|
240
|
+
row("/ext uninstall <n>", "Uninstall extension"),
|
|
241
|
+
row("/ext enable <n>", "Enable extension"),
|
|
242
|
+
row("/ext disable <n>", "Disable extension"),
|
|
243
|
+
row("/ext update <n>", "Pull latest from git"), sep,
|
|
244
|
+
row("/file <path>", "Attach file to message"),
|
|
245
|
+
row("/system <text>", "Set system instruction"),
|
|
246
|
+
row("/history", "Show conversation turns"),
|
|
247
|
+
row("/export <file>", "Export history to JSON"),
|
|
248
|
+
row("/cd <path>", "Change working directory"),
|
|
249
|
+
row("/new /clear", "Reset conversation"),
|
|
250
|
+
row("/model", "Model & config info"),
|
|
251
|
+
row("/proxy [on|off]", "Proxy rotation status/toggle"),
|
|
252
|
+
row("/exit /quit", "Exit"), sep,
|
|
253
|
+
chalk.hex(C.dim)(" Ctrl+C interrupt · Ctrl+D exit"), "",
|
|
312
254
|
];
|
|
313
|
-
|
|
314
255
|
if (Object.keys(customCommands).length) {
|
|
315
|
-
lines.
|
|
316
|
-
|
|
317
|
-
|
|
256
|
+
lines.splice(-2, 0,
|
|
257
|
+
chalk.hex(C.purple).bold(" Extension Commands"), sep,
|
|
258
|
+
...Object.entries(customCommands).map(([k, c]) => row("/" + k, c.description ?? "")),
|
|
259
|
+
sep
|
|
318
260
|
);
|
|
319
|
-
lines.push(sep);
|
|
320
261
|
}
|
|
321
|
-
|
|
322
|
-
lines.push(
|
|
323
|
-
chalk.hex(C.dim)(" Paste multi-line code freely."),
|
|
324
|
-
chalk.hex(C.dim)(" Ctrl+C interrupt · Ctrl+D exit"),
|
|
325
|
-
"",
|
|
326
|
-
);
|
|
327
262
|
return lines.join("\n");
|
|
328
263
|
}
|