@noobdemon/noob-cli 1.9.11 → 1.10.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/repl.js +41 -9
- package/src/tui.js +1 -0
package/package.json
CHANGED
package/src/repl.js
CHANGED
|
@@ -150,6 +150,15 @@ export async function startRepl(opts = {}) {
|
|
|
150
150
|
};
|
|
151
151
|
const tokenMeter = new TokenMeter();
|
|
152
152
|
|
|
153
|
+
// Set terminal title bar — hiện trên CMD/PowerShell.
|
|
154
|
+
const updateTitle = () => {
|
|
155
|
+
const name = session?.title
|
|
156
|
+
? session.title.slice(0, 40) + (session.title.length > 40 ? "…" : "")
|
|
157
|
+
: state.model.name;
|
|
158
|
+
process.title = `noob — ${name}`;
|
|
159
|
+
};
|
|
160
|
+
updateTitle();
|
|
161
|
+
|
|
153
162
|
// Prompt = dòng trạng thái sống. Luôn phản ánh yolo + version theo thời gian
|
|
154
163
|
// thực (vẽ lại mỗi lượt và ngay khi Shift+Tab), nên không cần gõ /status.
|
|
155
164
|
const promptStr = (lead = true) => {
|
|
@@ -306,6 +315,7 @@ export async function startRepl(opts = {}) {
|
|
|
306
315
|
const m = findModel(s.model);
|
|
307
316
|
if (m) state.model = m;
|
|
308
317
|
}
|
|
318
|
+
updateTitle();
|
|
309
319
|
// Re-arm /loop nếu phiên cũ đang chạy loop (timer/running không serialize được).
|
|
310
320
|
if (s.loop && s.loop.task && s.loop.intervalMs) {
|
|
311
321
|
state.loop = {
|
|
@@ -1237,6 +1247,11 @@ NGUYÊN TẮC:
|
|
|
1237
1247
|
? text + `\n\n[File người dùng nhắc tới bằng @: ${files.join(", ")} — đọc bằng read_file nếu cần.]`
|
|
1238
1248
|
: text;
|
|
1239
1249
|
state.history.push({ role: "user", content });
|
|
1250
|
+
// Update terminal title với session name (trích từ message đầu).
|
|
1251
|
+
if (session && !session.title) {
|
|
1252
|
+
session.title = content.replace(/\s+/g, " ").trim().slice(0, 60);
|
|
1253
|
+
updateTitle();
|
|
1254
|
+
}
|
|
1240
1255
|
// Tính context tokens realtime — đếm system prompt + history trước khi gửi.
|
|
1241
1256
|
tokenMeter.setContext(countMessages(state.history));
|
|
1242
1257
|
if (process.stdin.isTTY && !state.steerHintShown) {
|
|
@@ -1790,6 +1805,7 @@ NGUYÊN TẮC:
|
|
|
1790
1805
|
state.model = m;
|
|
1791
1806
|
state.mode = "chat";
|
|
1792
1807
|
config.setModel(m.id);
|
|
1808
|
+
updateTitle();
|
|
1793
1809
|
console.log(c.ok(" " + t.switchTo + " ") + modelBadge(m));
|
|
1794
1810
|
if (m.provider === "openai" || m.provider === "google")
|
|
1795
1811
|
console.log(c.dim(" ") + c.tool(t.providerRefuses(PROVIDERS[m.provider].name)));
|
|
@@ -1800,21 +1816,37 @@ NGUYÊN TẮC:
|
|
|
1800
1816
|
s.mode === "merge" ? c.tool("Merge AI") : s.mode === "search" ? c.accent("Tìm web") : modelBadge(s.model);
|
|
1801
1817
|
const key = config.apiKey ? c.ok(" 🔑") : c.err(" 🔒");
|
|
1802
1818
|
const yolo = s.yolo ? c.err(" ⚡ yolo: BẬT") : c.dim(" yolo: tắt");
|
|
1803
|
-
//
|
|
1804
|
-
const
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
const
|
|
1809
|
-
|
|
1810
|
-
|
|
1819
|
+
// Context % — dùng token meter nếu có data, fallback chars.
|
|
1820
|
+
const ctxPct = tokenMeter.contextPct();
|
|
1821
|
+
const ctxColor = ctxPct !== null
|
|
1822
|
+
? (ctxPct >= 80 ? c.err : ctxPct >= 60 ? c.accent : ctxPct >= 40 ? c.tool : c.dim)
|
|
1823
|
+
: c.dim;
|
|
1824
|
+
const ctxLabel = ctxPct !== null
|
|
1825
|
+
? ctxColor(` ctx: ${ctxPct}%`)
|
|
1826
|
+
: c.dim(" ctx: —");
|
|
1827
|
+
// Token usage.
|
|
1828
|
+
const tokLabel = c.dim(` ↑${fmtK(tokenMeter.input)} ↓${fmtK(tokenMeter.output)} (${fmtK(tokenMeter.total)})`);
|
|
1829
|
+
// Todo progress.
|
|
1830
|
+
const todos = s.todos || [];
|
|
1831
|
+
let todoLabel = "";
|
|
1832
|
+
if (todos.length) {
|
|
1833
|
+
const done = todos.filter((t) => t.done).length;
|
|
1834
|
+
todoLabel = c.ok(` ✓ ${done}/${todos.length}`);
|
|
1835
|
+
}
|
|
1836
|
+
// Session ID.
|
|
1837
|
+
const sidLabel = session?.id ? c.dim(` 📋 ${session.id}`) : "";
|
|
1838
|
+
// CWD.
|
|
1839
|
+
const cwdLabel = c.dim(" 📁 " + shortCwd());
|
|
1811
1840
|
console.log(
|
|
1812
|
-
|
|
1841
|
+
` ${mode}${key}${yolo}${ctxLabel}${tokLabel}${todoLabel}\n ${c.dim("v" + CURRENT)}${sidLabel}${cwdLabel}`,
|
|
1813
1842
|
);
|
|
1814
1843
|
}
|
|
1815
1844
|
}
|
|
1816
1845
|
|
|
1817
1846
|
// ── presentation helpers ───────────────────────────────────────────────────
|
|
1847
|
+
function fmtK(n) {
|
|
1848
|
+
return n >= 1000000 ? (n / 1000000).toFixed(1) + "M" : n >= 1000 ? (n / 1000).toFixed(1) + "k" : String(n);
|
|
1849
|
+
}
|
|
1818
1850
|
function printAnswer(text, name, color) {
|
|
1819
1851
|
if (!text?.trim()) return;
|
|
1820
1852
|
console.log("\n" + chalk.hex(color).bold(" ● " + name));
|
package/src/tui.js
CHANGED
|
@@ -581,6 +581,7 @@ export function createTui({ onLine, onInterrupt, onEOF, onShiftTab, completer }
|
|
|
581
581
|
}
|
|
582
582
|
if (ch === "\x7f" || ch === "\b") { backspace(); refreshMenu(); draw(); i++; continue; } // Backspace
|
|
583
583
|
if (ch === "\x03") { onInterrupt?.(); i++; continue; } // Ctrl+C
|
|
584
|
+
if (ch === "\x0c") { console.clear(); draw(); i++; continue; } // Ctrl+L: clear screen
|
|
584
585
|
if (ch === "\x01") { cur = 0; draw(); i++; continue; } // Ctrl+A → đầu dòng
|
|
585
586
|
if (ch === "\x05") { cur = cells.length; draw(); i++; continue; } // Ctrl+E → cuối dòng
|
|
586
587
|
if (ch === "\x15") { cells = cells.slice(cur); cur = 0; histPos = null; refreshMenu(); draw(); i++; continue; } // Ctrl+U: xoá tới đầu dòng
|