wormclaude 1.0.56 → 1.0.58
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/ansi.js +10 -3
- package/dist/highlight.js +7 -0
- package/dist/i18n.js +43 -1
- package/dist/theme.js +1 -1
- package/dist/tui.js +44 -28
- package/package.json +1 -1
package/dist/ansi.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// stdout'a BİR KEZ yazılır; ink yalnız canlı footer'ı yönetir. Böylece doğal kaydırma +
|
|
4
4
|
// metin seçip kopyalama çalışır. Markdown + sözdizimi vurgusu burada ANSI'ye çevrilir.
|
|
5
5
|
import { theme } from './theme.js';
|
|
6
|
-
import { highlight } from './highlight.js';
|
|
6
|
+
import { highlight, isHighlightable } from './highlight.js';
|
|
7
7
|
import { t } from './i18n.js';
|
|
8
8
|
const RESET = '\x1b[0m';
|
|
9
9
|
function hexAnsi(hex) {
|
|
@@ -90,8 +90,15 @@ export function markdownAnsi(text, cols) {
|
|
|
90
90
|
const flushCode = () => {
|
|
91
91
|
if (lang)
|
|
92
92
|
out.push(paint(' ' + lang, theme.greyDim));
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
if (isHighlightable(lang)) {
|
|
94
|
+
for (const toks of highlight(code.join('\n'), lang)) {
|
|
95
|
+
out.push(paint('│ ', theme.greyDim) + (toks.length ? toks.map((tk) => paint(tk.text, tk.color)).join('') : ' '));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
// Dilsiz/düz-metin blok: çubuk + nötr renk, sözdizimi-vurgusu YOK (saçma renk olmaz).
|
|
100
|
+
for (const ln of code)
|
|
101
|
+
out.push(paint('│ ', theme.greyDim) + paint(ln || ' ', theme.grey));
|
|
95
102
|
}
|
|
96
103
|
code = [];
|
|
97
104
|
lang = '';
|
package/dist/highlight.js
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
// Kod bloklarını dile göre token'lara böler; her token'a tema rengi atar. Asla patlamaz —
|
|
3
3
|
// tanımadığı dilde ortak kurallarla (string/sayı/yorum/anahtar kelime) renklendirir.
|
|
4
4
|
import { theme } from './theme.js';
|
|
5
|
+
// Sözdizimi-vurgusu YALNIZ gerçek programlama dili etiketli bloklarda yapılır.
|
|
6
|
+
// Dil yoksa/düz-metin/markdown ise → renklendirme YOK (yoksa düz nesir "kod" sanılıp
|
|
7
|
+
// büyük-harfli kelimeler "tip", `in` gibi kelimeler "keyword" diye saçma renklenir).
|
|
8
|
+
const NON_CODE = new Set(['', 'text', 'txt', 'plain', 'plaintext', 'markdown', 'md', 'prose', 'none', 'output', 'log', 'console', 'raw']);
|
|
9
|
+
export function isHighlightable(lang) {
|
|
10
|
+
return !NON_CODE.has((lang || '').trim().toLowerCase());
|
|
11
|
+
}
|
|
5
12
|
// Dil bazlı anahtar kelime setleri (ortak + spesifik).
|
|
6
13
|
const KW = {
|
|
7
14
|
js: ['const', 'let', 'var', 'function', 'return', 'if', 'else', 'for', 'while', 'do', 'switch', 'case', 'break', 'continue', 'new', 'class', 'extends', 'super', 'this', 'typeof', 'instanceof', 'in', 'of', 'await', 'async', 'yield', 'try', 'catch', 'finally', 'throw', 'import', 'export', 'from', 'default', 'delete', 'void', 'null', 'undefined', 'true', 'false'],
|
package/dist/i18n.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Çoklu dil (TR/EN) — arayüz metinleri. İlk açılışta dil seçilir, .wormclaude/settings.json'a yazılır.
|
|
2
2
|
import * as fs from 'node:fs';
|
|
3
3
|
import * as path from 'node:path';
|
|
4
|
-
let current = '
|
|
4
|
+
let current = 'en'; // varsayılan: İngilizce (ilk kurulum). loadLang() kayıtlıysa onu uygular.
|
|
5
5
|
export function setLang(l) { current = l; }
|
|
6
6
|
export function getLang() { return current; }
|
|
7
7
|
// Klasör bazlı ayar: her proje klasöründe bir kez sorulur (.wormclaude/settings.json)
|
|
@@ -67,6 +67,27 @@ const STR = {
|
|
|
67
67
|
'mcp.errors': ' · {0} hata ({1})',
|
|
68
68
|
'pill.running': '⏳ {0} çalışıyor',
|
|
69
69
|
'pill.done': '✓ {0} görev bitti',
|
|
70
|
+
'tui.footerHint': '/ komutlar · ↑↓ geçmiş · /kopyala · Ctrl+C çıkış',
|
|
71
|
+
'tui.working': 'çalışıyor…',
|
|
72
|
+
'tui.chars': 'karakter',
|
|
73
|
+
'tui.pasteSummary': '…(+{0} satır · {1} karakter, Enter ile gönder)',
|
|
74
|
+
'tui.permLabel': 'İZİN',
|
|
75
|
+
'tui.permRun': 'çalıştırılsın mı?',
|
|
76
|
+
'tui.permYes': '[E] Evet',
|
|
77
|
+
'tui.permAll': '[T] Tümüne izin',
|
|
78
|
+
'tui.permNo': '[H] Hayır',
|
|
79
|
+
'tui.ok': 'Tamam',
|
|
80
|
+
'tui.ctrlcExit': 'Çıkmak için tekrar Ctrl+C (veya /cikis). Kopyalama Ctrl+C\'yi etkilemez.',
|
|
81
|
+
'tui.copied': '✓ Panoya kopyalandı ({0} karakter).',
|
|
82
|
+
'tui.nothingCopy': 'Kopyalanacak yanıt yok.',
|
|
83
|
+
'tui.mcpConnected': '🔌 {0} MCP sunucusu bağlandı',
|
|
84
|
+
'tui.autoCompacted': '✎ bağlam otomatik özetlendi',
|
|
85
|
+
'tui.loopStop': 'Aynı adım tekrarlandı, döngü önlemek için durduruldu.',
|
|
86
|
+
'tui.connErr': '[bağlantı hatası: {0}]',
|
|
87
|
+
'tui.learned': '✎ eğitim datasına eklendi',
|
|
88
|
+
'tui.userCancel': 'kullanıcı iptal etti',
|
|
89
|
+
'tui.cmdErr': 'Komut hatası: {0}',
|
|
90
|
+
'tui.langSet': 'Dil değiştirildi: Türkçe',
|
|
70
91
|
},
|
|
71
92
|
en: {
|
|
72
93
|
'lang.title': 'Select language / Dil seçin',
|
|
@@ -106,6 +127,27 @@ const STR = {
|
|
|
106
127
|
'mcp.errors': ' · {0} error ({1})',
|
|
107
128
|
'pill.running': '⏳ {0} running',
|
|
108
129
|
'pill.done': '✓ {0} task(s) done',
|
|
130
|
+
'tui.footerHint': '/ commands · ↑↓ history · /copy · Ctrl+C exit',
|
|
131
|
+
'tui.working': 'working…',
|
|
132
|
+
'tui.chars': 'chars',
|
|
133
|
+
'tui.pasteSummary': '…(+{0} lines · {1} chars, Enter to send)',
|
|
134
|
+
'tui.permLabel': 'PERMISSION',
|
|
135
|
+
'tui.permRun': 'run it?',
|
|
136
|
+
'tui.permYes': '[Y] Yes',
|
|
137
|
+
'tui.permAll': '[A] Allow all',
|
|
138
|
+
'tui.permNo': '[N] No',
|
|
139
|
+
'tui.ok': 'OK',
|
|
140
|
+
'tui.ctrlcExit': 'Press Ctrl+C again to exit (or /quit). Copying does not trigger Ctrl+C.',
|
|
141
|
+
'tui.copied': '✓ Copied to clipboard ({0} chars).',
|
|
142
|
+
'tui.nothingCopy': 'No response to copy.',
|
|
143
|
+
'tui.mcpConnected': '🔌 {0} MCP server(s) connected',
|
|
144
|
+
'tui.autoCompacted': '✎ context auto-summarized',
|
|
145
|
+
'tui.loopStop': 'Same step repeated, stopped to avoid a loop.',
|
|
146
|
+
'tui.connErr': '[connection error: {0}]',
|
|
147
|
+
'tui.learned': '✎ added to training data',
|
|
148
|
+
'tui.userCancel': 'user cancelled',
|
|
149
|
+
'tui.cmdErr': 'Command error: {0}',
|
|
150
|
+
'tui.langSet': 'Language changed: English',
|
|
109
151
|
},
|
|
110
152
|
};
|
|
111
153
|
// Komut açıklamaları (slash menüsü + /help)
|
package/dist/theme.js
CHANGED
package/dist/tui.js
CHANGED
|
@@ -12,7 +12,7 @@ import { itemAnsi, markdownAnsi } from './ansi.js';
|
|
|
12
12
|
import { theme, VERSION } from './theme.js';
|
|
13
13
|
import { cleanModelText } from './textclean.js';
|
|
14
14
|
import { COMMANDS, runSlashCommand } from './commands.js';
|
|
15
|
-
import { cmdDesc } from './i18n.js';
|
|
15
|
+
import { cmdDesc, t, setLang, loadLang } from './i18n.js';
|
|
16
16
|
import { getSkill, getSkills, buildSkillPrompt } from './skills.js';
|
|
17
17
|
import { getExtCommand, getExtCommands, buildExtCommandPrompt } from './extensions.js';
|
|
18
18
|
import { resolveAtMentions } from './atmention.js';
|
|
@@ -49,6 +49,7 @@ function fit(line, max) {
|
|
|
49
49
|
const vis = (s) => stringWidth(s.replace(/\x1b\[[0-9;]*m/g, ''));
|
|
50
50
|
const padVis = (s, w) => s + ' '.repeat(Math.max(0, w - vis(s))); // görünür genişliğe boşluk doldur
|
|
51
51
|
export async function runTui() {
|
|
52
|
+
setLang(loadLang() || 'en'); // kayıtlı dil varsa onu, yoksa İngilizce (ilk kurulum)
|
|
52
53
|
const config = loadConfig();
|
|
53
54
|
let account = { plan: '', email: '', name: '' };
|
|
54
55
|
// Ortam bağlamı (Windows/cwd) — model DOĞRU yol/komut kullansın (yoksa /home/user gibi yanlış yol yazar).
|
|
@@ -66,6 +67,11 @@ export async function runTui() {
|
|
|
66
67
|
let inputBuf = '', busy = false, streamChars = 0, spin = 0;
|
|
67
68
|
// Canlı akış artık FOOTER'da DEĞİL — içerik akışına (mesajın altından aşağı) satır-satır basılır.
|
|
68
69
|
const SPIN = ['·', '✢', '✳', '✶', '✻', '✽', '✶', '✳', '✢'];
|
|
70
|
+
// Canlı bağlam ölçer: son isteğin prompt_tokens'ı = o anki kullanılan bağlam (footer'da gösterilir).
|
|
71
|
+
const CTX_MAX = Number(process.env.WORMCLAUDE_CTX) || 12288;
|
|
72
|
+
let ctxUsed = 0;
|
|
73
|
+
const _k = (n) => (n >= 1000 ? (n / 1000).toFixed(1).replace(/\.0$/, '') + 'k' : String(n));
|
|
74
|
+
const ctxGauge = () => `◷ ${_k(ctxUsed)}/${_k(CTX_MAX)} (%${Math.min(100, Math.round((ctxUsed / CTX_MAX) * 100))})`;
|
|
69
75
|
// Giriş kutusunu genişliğe göre ÇOK SATIRA sar; çok uzunsa (yapıştırma) KISALTIP özet gösterir.
|
|
70
76
|
const MAX_INPUT_LINES = 6;
|
|
71
77
|
const inputBoxLines = (W) => {
|
|
@@ -87,7 +93,7 @@ export async function runTui() {
|
|
|
87
93
|
// Çok uzun (büyük yapıştırma): son birkaç satır + üstte özet — footer'ı doldurmaz.
|
|
88
94
|
const extra = wrapped.length - (MAX_INPUT_LINES - 1);
|
|
89
95
|
const tail = wrapped.slice(-(MAX_INPUT_LINES - 1));
|
|
90
|
-
const head = paint(
|
|
96
|
+
const head = paint('✶ ' + t('tui.pasteSummary', extra, inputBuf.length), theme.greyDim);
|
|
91
97
|
return [head, ...tail.map((ln, i) => ' ' + paint(ln, theme.white) + (i === tail.length - 1 ? paint('▌', theme.greyDim) : ''))];
|
|
92
98
|
};
|
|
93
99
|
// Footer yüksekliği DİNAMİK: izin=4; değilse (durum/menü) + çizgi + giriş-satırları + çizgi.
|
|
@@ -141,7 +147,7 @@ export async function runTui() {
|
|
|
141
147
|
await runSlashCommand(v, cmdCtx);
|
|
142
148
|
}
|
|
143
149
|
catch (e) {
|
|
144
|
-
printItem({ kind: 'note', text: '
|
|
150
|
+
printItem({ kind: 'note', text: t('tui.cmdErr', e?.message || e) });
|
|
145
151
|
}
|
|
146
152
|
clearInterval(timer);
|
|
147
153
|
busy = false;
|
|
@@ -149,7 +155,7 @@ export async function runTui() {
|
|
|
149
155
|
}
|
|
150
156
|
// ── İkonlu, 2-sütunlu bilgi başlığı (3 sol / 3 sağ) — responsive ──
|
|
151
157
|
function headerLines(W) {
|
|
152
|
-
const ctx =
|
|
158
|
+
const ctx = CTX_MAX.toLocaleString('tr-TR');
|
|
153
159
|
// [ikon, etiket, değer, renk]
|
|
154
160
|
const L = [
|
|
155
161
|
['◈', 'Version', 'v' + VERSION, theme.red],
|
|
@@ -158,7 +164,7 @@ export async function runTui() {
|
|
|
158
164
|
];
|
|
159
165
|
const R = [
|
|
160
166
|
['◉', 'Account', account.email || '—', theme.grey],
|
|
161
|
-
['◷', 'Context', ctx + '
|
|
167
|
+
['◷', 'Context', ctx + ' tok (pencere)', theme.grey],
|
|
162
168
|
['▸', 'Workspace', process.cwd(), theme.grey],
|
|
163
169
|
];
|
|
164
170
|
const cell = ([ic, lb, val, col]) => ' ' + paint(ic + ' ', theme.red) + paint(lb.padEnd(11), theme.greyDim) + paint(val, col);
|
|
@@ -181,9 +187,9 @@ export async function runTui() {
|
|
|
181
187
|
let body;
|
|
182
188
|
if (perm) {
|
|
183
189
|
// İzin dialogu: araç adı + Evet/Tümü/Hayır
|
|
184
|
-
const q = paint('
|
|
185
|
-
const opts = paint('
|
|
186
|
-
+ paint('
|
|
190
|
+
const q = paint(' ' + t('tui.permLabel') + ' ', theme.redBright, true) + paint(perm.label, theme.white) + paint(' ' + t('tui.permRun'), theme.grey);
|
|
191
|
+
const opts = paint(' ' + t('tui.permYes'), theme.redBright, true) + paint(' · ', theme.greyDim)
|
|
192
|
+
+ paint(t('tui.permAll'), theme.grey) + paint(' · ', theme.greyDim) + paint(t('tui.permNo'), theme.grey);
|
|
187
193
|
body = [line, q, opts, line];
|
|
188
194
|
}
|
|
189
195
|
else if (ask) {
|
|
@@ -208,9 +214,10 @@ export async function runTui() {
|
|
|
208
214
|
body = [...menu, line, ...inputLines, line];
|
|
209
215
|
}
|
|
210
216
|
else {
|
|
217
|
+
const g = ctxUsed ? paint(' ' + ctxGauge(), theme.greyDim) : '';
|
|
211
218
|
const status = busy
|
|
212
|
-
? paint(` ${SPIN[spin % SPIN.length]}
|
|
213
|
-
: paint('
|
|
219
|
+
? paint(` ${SPIN[spin % SPIN.length]} ${t('tui.working')}${streamChars ? ' ' + streamChars + ' ' + t('tui.chars') : ''}`, theme.grey) + g
|
|
220
|
+
: paint(' ' + t('tui.footerHint'), theme.greyDim) + g;
|
|
214
221
|
body = [status, line, ...inputLines, line];
|
|
215
222
|
}
|
|
216
223
|
}
|
|
@@ -259,7 +266,7 @@ export async function runTui() {
|
|
|
259
266
|
const { history: nh } = await runCompact(history, config);
|
|
260
267
|
history.length = 0;
|
|
261
268
|
history.push(...nh);
|
|
262
|
-
printItem({ kind: 'note', text: '
|
|
269
|
+
printItem({ kind: 'note', text: t('tui.autoCompacted') });
|
|
263
270
|
}
|
|
264
271
|
catch { }
|
|
265
272
|
}
|
|
@@ -303,8 +310,12 @@ export async function runTui() {
|
|
|
303
310
|
streamChars = answer.length;
|
|
304
311
|
flushStream(false);
|
|
305
312
|
}
|
|
306
|
-
else if (ev.type === 'done')
|
|
313
|
+
else if (ev.type === 'done') {
|
|
307
314
|
toolCalls = ev.toolCalls || [];
|
|
315
|
+
const u = ev.usage;
|
|
316
|
+
if (u && u.input)
|
|
317
|
+
ctxUsed = u.input;
|
|
318
|
+
}
|
|
308
319
|
else if (ev.type === 'error') {
|
|
309
320
|
answer += `\n[hata: ${ev.error}]`;
|
|
310
321
|
flushStream(false);
|
|
@@ -329,7 +340,7 @@ export async function runTui() {
|
|
|
329
340
|
lastSig = sig;
|
|
330
341
|
}
|
|
331
342
|
if (sameCount >= 2) {
|
|
332
|
-
printItem({ kind: 'note', text: '
|
|
343
|
+
printItem({ kind: 'note', text: t('tui.loopStop') });
|
|
333
344
|
break;
|
|
334
345
|
}
|
|
335
346
|
const results = await executeToolCalls(toolCalls, {
|
|
@@ -339,7 +350,7 @@ export async function runTui() {
|
|
|
339
350
|
perm = { label: toolLabel(c.name, args), name: c.name, resolve };
|
|
340
351
|
refresh();
|
|
341
352
|
}),
|
|
342
|
-
ask: (q) => new Promise((resolve) => { ask = { question: q.question, options: q.options.length ? q.options : [{ label: '
|
|
353
|
+
ask: (q) => new Promise((resolve) => { ask = { question: q.question, options: q.options.length ? q.options : [{ label: t('tui.ok') }], sel: 0, resolve }; refresh(); }),
|
|
343
354
|
onResult: (c, _i, res) => { if ((c.name === 'WebSearch' || c.name === 'WebFetch') && res.ok)
|
|
344
355
|
usedWeb = true; printItem({ kind: 'tool', label: toolLabel(c.name, res.args), result: sanitizeOutput(res.output), ok: res.ok }); },
|
|
345
356
|
});
|
|
@@ -348,7 +359,7 @@ export async function runTui() {
|
|
|
348
359
|
}
|
|
349
360
|
}
|
|
350
361
|
catch (e) {
|
|
351
|
-
printItem({ kind: 'note', text:
|
|
362
|
+
printItem({ kind: 'note', text: t('tui.connErr', e?.message || e) });
|
|
352
363
|
}
|
|
353
364
|
clearInterval(timer);
|
|
354
365
|
busy = false;
|
|
@@ -359,7 +370,7 @@ export async function runTui() {
|
|
|
359
370
|
if (usedWeb && lastAnswer) {
|
|
360
371
|
const sources = (lastAnswer.match(/https?:\/\/[^\s<>"')\]]+/g) || []).slice(0, 8);
|
|
361
372
|
if (recordLearned(userText, lastAnswer, sources, config))
|
|
362
|
-
printItem({ kind: 'note', text: '
|
|
373
|
+
printItem({ kind: 'note', text: t('tui.learned') });
|
|
363
374
|
}
|
|
364
375
|
// Oto-hafıza: eşik geçildiyse arka planda hafızayı güncelle
|
|
365
376
|
if (shouldExtract(history))
|
|
@@ -380,7 +391,7 @@ export async function runTui() {
|
|
|
380
391
|
redrawAll();
|
|
381
392
|
} }).catch(() => { });
|
|
382
393
|
connectMcpServers().then((srv) => { if (srv && srv.length)
|
|
383
|
-
printItem({ kind: 'note', text:
|
|
394
|
+
printItem({ kind: 'note', text: t('tui.mcpConnected', srv.length) }); }).catch(() => { }); // MCP araçları (varsa)
|
|
384
395
|
const quit = () => { process.stdout.write('\x1b[r\x1b[?25h\x1b[2J\x1b[3J\x1b[H'); process.exit(0); };
|
|
385
396
|
process.on('exit', () => { try {
|
|
386
397
|
process.stdout.write('\x1b[r\x1b[?25h');
|
|
@@ -428,26 +439,26 @@ export async function runTui() {
|
|
|
428
439
|
const r = perm.resolve, nm = perm.name;
|
|
429
440
|
if (key && key.ctrl && key.name === 'c') {
|
|
430
441
|
perm = null;
|
|
431
|
-
r({ deny: '
|
|
442
|
+
r({ deny: t('tui.userCancel') });
|
|
432
443
|
refresh();
|
|
433
444
|
return;
|
|
434
445
|
}
|
|
435
|
-
if (k === 'e' || k === '1' || (key && key.name === 'return')) {
|
|
446
|
+
if (k === 'e' || k === 'y' || k === '1' || (key && key.name === 'return')) {
|
|
436
447
|
perm = null;
|
|
437
448
|
r('allow');
|
|
438
449
|
refresh();
|
|
439
|
-
}
|
|
440
|
-
else if (k === 't' || k === '2') {
|
|
450
|
+
} // Evet / Yes
|
|
451
|
+
else if (k === 't' || k === 'a' || k === '2') {
|
|
441
452
|
allowAll.add(nm);
|
|
442
453
|
perm = null;
|
|
443
454
|
r('allow');
|
|
444
455
|
refresh();
|
|
445
|
-
}
|
|
446
|
-
else if (k === 'h' || k === '3' || (key && key.name === 'escape')) {
|
|
456
|
+
} // Tümü / Allow all
|
|
457
|
+
else if (k === 'h' || k === 'n' || k === '3' || (key && key.name === 'escape')) {
|
|
447
458
|
perm = null;
|
|
448
459
|
r({ deny: '' });
|
|
449
460
|
refresh();
|
|
450
|
-
}
|
|
461
|
+
} // Hayır / No
|
|
451
462
|
return;
|
|
452
463
|
}
|
|
453
464
|
if (key && key.ctrl && key.name === 'c') {
|
|
@@ -461,7 +472,7 @@ export async function runTui() {
|
|
|
461
472
|
quit();
|
|
462
473
|
}
|
|
463
474
|
ctrlcAt = now;
|
|
464
|
-
printItem({ kind: 'note', text:
|
|
475
|
+
printItem({ kind: 'note', text: t('tui.ctrlcExit') });
|
|
465
476
|
return;
|
|
466
477
|
}
|
|
467
478
|
if (key && key.ctrl && key.name === 'd') {
|
|
@@ -531,7 +542,7 @@ export async function runTui() {
|
|
|
531
542
|
executeTool('Bash', { command: cmd }).then((res) => {
|
|
532
543
|
printItem({ kind: 'tool', label: `! ${cmd.slice(0, 60)}`, result: sanitizeOutput(res.output), ok: res.ok });
|
|
533
544
|
history.push({ role: 'user', content: `Şu shell komutunu çalıştırdım:\n\`\`\`\n${cmd}\n\`\`\`\nÇıktı:\n\`\`\`\n${(res.output || '').slice(0, 4000)}\n\`\`\`` });
|
|
534
|
-
}).catch((e) => printItem({ kind: 'note', text: '
|
|
545
|
+
}).catch((e) => printItem({ kind: 'note', text: t('tui.cmdErr', e?.message || e) }))
|
|
535
546
|
.finally(() => { busy = false; refresh(); });
|
|
536
547
|
return;
|
|
537
548
|
}
|
|
@@ -553,10 +564,10 @@ export async function runTui() {
|
|
|
553
564
|
const last = [...history].reverse().find((mm) => mm.role === 'assistant');
|
|
554
565
|
if (last) {
|
|
555
566
|
process.stdout.write(`\x1b]52;c;${Buffer.from(last.content, 'utf8').toString('base64')}\x07`);
|
|
556
|
-
printItem({ kind: 'note', text:
|
|
567
|
+
printItem({ kind: 'note', text: t('tui.copied', last.content.length) });
|
|
557
568
|
}
|
|
558
569
|
else
|
|
559
|
-
printItem({ kind: 'note', text: '
|
|
570
|
+
printItem({ kind: 'note', text: t('tui.nothingCopy') });
|
|
560
571
|
return;
|
|
561
572
|
}
|
|
562
573
|
const builtin = COMMANDS.some((c) => c.name === tok);
|
|
@@ -572,6 +583,11 @@ export async function runTui() {
|
|
|
572
583
|
runTurn(buildExtCommandPrompt(ext, a), `/${ext.name}${a ? ' ' + a : ''}`);
|
|
573
584
|
return;
|
|
574
585
|
}
|
|
586
|
+
// /lang|/dil: dil değişince banner alt-yazısı + footer yeni dilde olsun → tüm ekranı yeniden çiz
|
|
587
|
+
if (tok === '/lang') {
|
|
588
|
+
runCommand(v).then(() => redrawAll());
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
575
591
|
runCommand(v);
|
|
576
592
|
return;
|
|
577
593
|
}
|