wormclaude 1.0.43 → 1.0.45
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 +4 -4
- package/dist/theme.js +1 -1
- package/dist/tui.js +118 -25
- package/package.json +1 -1
package/dist/ansi.js
CHANGED
|
@@ -145,17 +145,17 @@ export function itemAnsi(it, cols) {
|
|
|
145
145
|
if (it.kind === 'banner')
|
|
146
146
|
return '\n' + bannerAnsi(cols);
|
|
147
147
|
if (it.kind === 'user') {
|
|
148
|
-
// Kenarlıksız (kutu, küçültünce bozuluyordu) — sadece "
|
|
149
|
-
const body = wrap(it.text || '', W - 2).map((ln, i) => (i === 0 ? paint('
|
|
148
|
+
// Kenarlıksız (kutu, küçültünce bozuluyordu) — sadece "✶ metin", resize'da temiz sarılır.
|
|
149
|
+
const body = wrap(it.text || '', W - 2).map((ln, i) => (i === 0 ? paint('✶ ', theme.greyDim, true) : ' ') + paint(ln, theme.white));
|
|
150
150
|
return '\n' + body.join('\n');
|
|
151
151
|
}
|
|
152
152
|
if (it.kind === 'assistant') {
|
|
153
153
|
const md = markdownAnsi(it.text || '', cols).split('\n');
|
|
154
|
-
return '\n' + md.map((ln, i) => (i === 0 ? paint('
|
|
154
|
+
return '\n' + md.map((ln, i) => (i === 0 ? paint('✶ ', theme.redBright, true) + ln : ' ' + ln)).join('\n');
|
|
155
155
|
}
|
|
156
156
|
if (it.kind === 'tool') {
|
|
157
157
|
const n = (it.result || '').split('\n').length, chars = (it.result || '').length;
|
|
158
|
-
const head = paint('
|
|
158
|
+
const head = paint('✶ ', theme.redBright, true) + paint(it.label || '', theme.white);
|
|
159
159
|
const sub = paint(' ⎿ ', theme.greyDim) + (it.ok
|
|
160
160
|
? paint(`${n} ${t('common.lines') || 'satır'} (${chars})`, theme.grey)
|
|
161
161
|
: paint('✗ ' + (it.result || '').slice(0, 160), theme.errorRed));
|
package/dist/theme.js
CHANGED
package/dist/tui.js
CHANGED
|
@@ -11,6 +11,7 @@ import { sanitizeOutput } from './errorsan.js';
|
|
|
11
11
|
import { itemAnsi } from './ansi.js';
|
|
12
12
|
import { theme, VERSION } from './theme.js';
|
|
13
13
|
import { cleanModelText } from './textclean.js';
|
|
14
|
+
import { COMMANDS, runSlashCommand } from './commands.js';
|
|
14
15
|
const RESET = '\x1b[0m';
|
|
15
16
|
const hex = (h) => { const m = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(h); return m ? `\x1b[38;2;${parseInt(m[1], 16)};${parseInt(m[2], 16)};${parseInt(m[3], 16)}m` : ''; };
|
|
16
17
|
const paint = (s, c, bold = false) => `${bold ? '\x1b[1m' : ''}${c ? hex(c) : ''}${s}${RESET}`;
|
|
@@ -38,6 +39,7 @@ function fit(line, max) {
|
|
|
38
39
|
return out + RESET;
|
|
39
40
|
}
|
|
40
41
|
const vis = (s) => stringWidth(s.replace(/\x1b\[[0-9;]*m/g, ''));
|
|
42
|
+
const padVis = (s, w) => s + ' '.repeat(Math.max(0, w - vis(s))); // görünür genişliğe boşluk doldur
|
|
41
43
|
export async function runTui() {
|
|
42
44
|
const config = loadConfig();
|
|
43
45
|
let account = { plan: '', email: '', name: '' };
|
|
@@ -59,13 +61,59 @@ export async function runTui() {
|
|
|
59
61
|
const allowAll = new Set(); // "Tümüne izin" denen araçlar (oturum boyu)
|
|
60
62
|
const inputHistory = []; // gönderilen mesajlar (↑/↓ ile geri çağrılır)
|
|
61
63
|
let histIdx = -1; // -1 = geçmişte gezinmiyor
|
|
62
|
-
|
|
64
|
+
let cmdSel = 0; // slash menüde seçili komut
|
|
65
|
+
// Slash menü: "/" ile başlayan girişe uyan komutlar
|
|
66
|
+
const cmdMatches = () => {
|
|
67
|
+
if (busy || !inputBuf.startsWith('/'))
|
|
68
|
+
return [];
|
|
69
|
+
const tok = inputBuf.split(' ')[0];
|
|
70
|
+
return COMMANDS.filter((c) => c.name.startsWith(tok));
|
|
71
|
+
};
|
|
72
|
+
// Slash komutları için bağlam (cli.tsx ile aynı arayüz) — /clear,/config,/model,/memory,/program…
|
|
73
|
+
const cmdCtx = {
|
|
74
|
+
config,
|
|
75
|
+
getHistory: () => history,
|
|
76
|
+
setHistory: (h) => { history.length = 0; history.push(...h); },
|
|
77
|
+
note: (text) => printItem({ kind: 'note', text }),
|
|
78
|
+
assistant: (text) => printItem({ kind: 'assistant', text }),
|
|
79
|
+
clearConv: () => { history.length = 1; displayItems.length = 1; redrawAll(); }, // sistem msg + banner kalır
|
|
80
|
+
exit: () => quit(),
|
|
81
|
+
};
|
|
82
|
+
async function runCommand(v) {
|
|
83
|
+
busy = true;
|
|
84
|
+
drawFooter();
|
|
85
|
+
const timer = setInterval(() => { spin++; if (busy && !perm)
|
|
86
|
+
drawFooter(); }, 120);
|
|
87
|
+
try {
|
|
88
|
+
await runSlashCommand(v, cmdCtx);
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
printItem({ kind: 'note', text: 'Komut hatası: ' + (e?.message || e) });
|
|
92
|
+
}
|
|
93
|
+
clearInterval(timer);
|
|
94
|
+
busy = false;
|
|
95
|
+
drawFooter();
|
|
96
|
+
}
|
|
97
|
+
// ── İkonlu, 2-sütunlu bilgi başlığı (3 sol / 3 sağ) — responsive ──
|
|
63
98
|
function headerLines(W) {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
99
|
+
const ctx = (Number(process.env.WORMCLAUDE_CTX) || 12288).toLocaleString('tr-TR');
|
|
100
|
+
// [ikon, etiket, değer, renk]
|
|
101
|
+
const L = [
|
|
102
|
+
['◈', 'Version', 'v' + VERSION, theme.red],
|
|
103
|
+
['◆', 'Model', config.model, theme.redBright],
|
|
104
|
+
['★', 'Plan', (account.plan || '—').toUpperCase(), theme.white],
|
|
105
|
+
];
|
|
106
|
+
const R = [
|
|
107
|
+
['◉', 'Account', account.email || '—', theme.grey],
|
|
108
|
+
['◷', 'Context', ctx + ' tokens', theme.grey],
|
|
109
|
+
['▸', 'Workspace', process.cwd(), theme.grey],
|
|
110
|
+
];
|
|
111
|
+
const cell = ([ic, lb, val, col]) => ' ' + paint(ic + ' ', theme.red) + paint(lb.padEnd(9), theme.greyDim) + paint(val, col);
|
|
112
|
+
const colW = Math.max(28, Math.floor(W / 2)); // sol sütun genişliği
|
|
113
|
+
const narrow = W < 64;
|
|
114
|
+
if (narrow)
|
|
115
|
+
return [...L, ...R].map((r) => fit(cell(r), W)); // dar ekran → alt alta
|
|
116
|
+
return [0, 1, 2].map((i) => fit(padVis(cell(L[i]), colW) + cell(R[i]), W)); // geniş → 2 sütun
|
|
69
117
|
}
|
|
70
118
|
// ── Scroll region: üst = içerik (kayar), alt = sabit footer ──
|
|
71
119
|
function setRegion() {
|
|
@@ -90,11 +138,21 @@ export async function runTui() {
|
|
|
90
138
|
const avail = W - 3;
|
|
91
139
|
if (vis(shown) > avail)
|
|
92
140
|
shown = '…' + shown.slice(-(avail - 1));
|
|
93
|
-
const inputLine = paint('
|
|
94
|
-
// Durum satırı KUTUNUN ÜSTÜNDE
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
141
|
+
const inputLine = paint('✶ ', theme.redBright, true) + paint(shown, theme.white) + paint('▌', theme.greyDim);
|
|
142
|
+
// Durum satırı KUTUNUN ÜSTÜNDE: slash menü > spinner > ipucu.
|
|
143
|
+
const m = cmdMatches();
|
|
144
|
+
let status;
|
|
145
|
+
if (m.length) {
|
|
146
|
+
const sel = Math.min(cmdSel, m.length - 1);
|
|
147
|
+
const names = m.slice(0, 8).map((c, i) => i === sel ? paint(c.name, theme.redBright, true) : paint(c.name, theme.greyDim)).join(' ');
|
|
148
|
+
status = ' ' + names + paint(' ↹ tamamla · ↑↓ seç', theme.greyDim);
|
|
149
|
+
}
|
|
150
|
+
else if (busy) {
|
|
151
|
+
status = paint(` ${SPIN[spin % SPIN.length]} çalışıyor…${streamChars ? ' ' + streamChars + ' karakter' : ''}`, theme.grey);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
status = paint(' / komutlar · ↑↓ geçmiş · /kopyala · Ctrl+C çıkış', theme.greyDim);
|
|
155
|
+
}
|
|
98
156
|
body = [status, line, inputLine, line];
|
|
99
157
|
}
|
|
100
158
|
let out = '\x1b7'; // imleci kaydet
|
|
@@ -250,8 +308,14 @@ export async function runTui() {
|
|
|
250
308
|
if (key && key.ctrl && key.name === 'd') {
|
|
251
309
|
quit();
|
|
252
310
|
}
|
|
253
|
-
// ↑/↓ —
|
|
311
|
+
// ↑/↓ — slash menü açıksa komut seç, değilse geçmiş mesajlarda gezin
|
|
254
312
|
if (key && key.name === 'up') {
|
|
313
|
+
const m = cmdMatches();
|
|
314
|
+
if (m.length) {
|
|
315
|
+
cmdSel = (cmdSel - 1 + m.length) % m.length;
|
|
316
|
+
drawFooter();
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
255
319
|
if (inputHistory.length) {
|
|
256
320
|
histIdx = histIdx < 0 ? inputHistory.length - 1 : Math.max(0, histIdx - 1);
|
|
257
321
|
inputBuf = inputHistory[histIdx];
|
|
@@ -260,6 +324,12 @@ export async function runTui() {
|
|
|
260
324
|
return;
|
|
261
325
|
}
|
|
262
326
|
if (key && key.name === 'down') {
|
|
327
|
+
const m = cmdMatches();
|
|
328
|
+
if (m.length) {
|
|
329
|
+
cmdSel = (cmdSel + 1) % m.length;
|
|
330
|
+
drawFooter();
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
263
333
|
if (histIdx >= 0) {
|
|
264
334
|
histIdx++;
|
|
265
335
|
if (histIdx >= inputHistory.length) {
|
|
@@ -272,37 +342,59 @@ export async function runTui() {
|
|
|
272
342
|
}
|
|
273
343
|
return;
|
|
274
344
|
}
|
|
345
|
+
// Tab — seçili slash komutunu tamamla
|
|
346
|
+
if (key && key.name === 'tab') {
|
|
347
|
+
const m = cmdMatches();
|
|
348
|
+
if (m.length) {
|
|
349
|
+
inputBuf = m[Math.min(cmdSel, m.length - 1)].name + ' ';
|
|
350
|
+
cmdSel = 0;
|
|
351
|
+
drawFooter();
|
|
352
|
+
}
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
275
355
|
if (key && key.name === 'return') {
|
|
276
356
|
if (busy)
|
|
277
357
|
return; // tur sürerken Enter beklemede; yazılan metin durur (type-ahead)
|
|
278
|
-
|
|
358
|
+
let v = inputBuf.trim();
|
|
279
359
|
inputBuf = '';
|
|
280
360
|
histIdx = -1;
|
|
281
361
|
if (!v) {
|
|
282
362
|
drawFooter();
|
|
283
363
|
return;
|
|
284
364
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
if (
|
|
293
|
-
|
|
294
|
-
|
|
365
|
+
// Slash komutu: tam eşleşme yoksa menüde SEÇİLİ olanı kullan
|
|
366
|
+
if (v.startsWith('/')) {
|
|
367
|
+
const tok = v.split(' ')[0];
|
|
368
|
+
const matches = COMMANDS.filter((c) => c.name.startsWith(tok));
|
|
369
|
+
if (!COMMANDS.some((c) => c.name === tok) && matches.length)
|
|
370
|
+
v = matches[Math.min(cmdSel, matches.length - 1)].name;
|
|
371
|
+
cmdSel = 0;
|
|
372
|
+
if (v === '/cikis' || v === '/exit' || v === '/quit') {
|
|
373
|
+
quit();
|
|
374
|
+
return;
|
|
295
375
|
}
|
|
296
|
-
|
|
297
|
-
|
|
376
|
+
if (v === '/kopyala' || v === '/copy') {
|
|
377
|
+
const last = [...history].reverse().find((mm) => mm.role === 'assistant');
|
|
378
|
+
if (last) {
|
|
379
|
+
process.stdout.write(`\x1b]52;c;${Buffer.from(last.content, 'utf8').toString('base64')}\x07`);
|
|
380
|
+
printItem({ kind: 'note', text: `✓ Panoya kopyalandı (${last.content.length} karakter).` });
|
|
381
|
+
}
|
|
382
|
+
else
|
|
383
|
+
printItem({ kind: 'note', text: 'Kopyalanacak yanıt yok.' });
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
inputHistory.push(v);
|
|
387
|
+
runCommand(v);
|
|
298
388
|
return;
|
|
299
389
|
}
|
|
390
|
+
inputHistory.push(v); // geçmişe ekle (↑ ile geri çağrılır)
|
|
300
391
|
printItem({ kind: 'user', text: v });
|
|
301
392
|
runTurn(v);
|
|
302
393
|
return;
|
|
303
394
|
}
|
|
304
395
|
if (key && key.name === 'backspace') {
|
|
305
396
|
inputBuf = inputBuf.slice(0, -1);
|
|
397
|
+
cmdSel = 0;
|
|
306
398
|
drawFooter();
|
|
307
399
|
return;
|
|
308
400
|
}
|
|
@@ -314,6 +406,7 @@ export async function runTui() {
|
|
|
314
406
|
// sadece gerçek yazdırılabilir karakter (her zaman → cevap üretilirken bile type-ahead)
|
|
315
407
|
if (str && !key?.ctrl && !key?.meta && !str.startsWith('\x1b') && !/[\x00-\x1f]/.test(str)) {
|
|
316
408
|
inputBuf += str;
|
|
409
|
+
cmdSel = 0;
|
|
317
410
|
drawFooter();
|
|
318
411
|
}
|
|
319
412
|
});
|