wormclaude 1.0.50 → 1.0.51
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/theme.js +1 -1
- package/dist/tui.js +69 -6
- package/package.json +1 -1
package/dist/theme.js
CHANGED
package/dist/tui.js
CHANGED
|
@@ -64,6 +64,8 @@ export async function runTui() {
|
|
|
64
64
|
];
|
|
65
65
|
const displayItems = [{ kind: 'banner' }];
|
|
66
66
|
let inputBuf = '', busy = false, streamChars = 0, spin = 0;
|
|
67
|
+
let streamPreview = ''; // canlı akış önizlemesi (footer'da)
|
|
68
|
+
const PREVIEW_LINES = 6; // akışta sabit önizleme satırı (yükseklik stabil → titreme yok)
|
|
67
69
|
const SPIN = ['·', '✢', '✳', '✶', '✻', '✽', '✶', '✳', '✢'];
|
|
68
70
|
// Giriş kutusunu genişliğe göre ÇOK SATIRA sar (uzun mesaj/kod sağa taşmaz, alta iner).
|
|
69
71
|
const MAX_INPUT_LINES = 10;
|
|
@@ -88,9 +90,14 @@ export async function runTui() {
|
|
|
88
90
|
const footerHeight = () => {
|
|
89
91
|
if (perm)
|
|
90
92
|
return 4;
|
|
93
|
+
if (ask)
|
|
94
|
+
return ask.options.length + 3; // çizgi + soru + seçenekler... aslında: line+q+opts+line
|
|
95
|
+
const il = inputBoxLines(Math.max(8, cols())).length;
|
|
96
|
+
if (busy && streamPreview)
|
|
97
|
+
return PREVIEW_LINES + 2 + il; // canlı akış önizlemesi
|
|
91
98
|
const m = cmdMatches();
|
|
92
99
|
const statusLines = m.length ? Math.min(8, m.length) : 1;
|
|
93
|
-
return statusLines + 2 +
|
|
100
|
+
return statusLines + 2 + il;
|
|
94
101
|
};
|
|
95
102
|
// Yükseklik değiştiyse scroll-region'ı + içeriği yeniden bas; değişmediyse sadece footer'ı çiz.
|
|
96
103
|
const refresh = () => { const fh = footerHeight(); if (fh !== prevFH)
|
|
@@ -98,8 +105,9 @@ export async function runTui() {
|
|
|
98
105
|
else
|
|
99
106
|
drawFooter(); };
|
|
100
107
|
setToolConfig(config); // araçlar (Write/Bash/Edit…) aynı config'i kullansın
|
|
101
|
-
// İzin (araç onayı) durumu
|
|
108
|
+
// İzin (araç onayı) + soru (AskUserQuestion) durumu
|
|
102
109
|
let perm = null;
|
|
110
|
+
let ask = null;
|
|
103
111
|
const allowAll = new Set(); // "Tümüne izin" denen araçlar (oturum boyu)
|
|
104
112
|
const inputHistory = []; // gönderilen mesajlar (↑/↓ ile geri çağrılır)
|
|
105
113
|
let histIdx = -1; // -1 = geçmişte gezinmiyor
|
|
@@ -182,10 +190,25 @@ export async function runTui() {
|
|
|
182
190
|
+ paint('[T] Tümüne izin', theme.grey) + paint(' · ', theme.greyDim) + paint('[H] Hayır', theme.grey);
|
|
183
191
|
body = [line, q, opts, line];
|
|
184
192
|
}
|
|
193
|
+
else if (ask) {
|
|
194
|
+
// Soru dialogu (AskUserQuestion): soru + numaralı seçenekler
|
|
195
|
+
const q = paint(' ? ', theme.redBright, true) + paint(ask.question, theme.white);
|
|
196
|
+
const opts = ask.options.map((o, i) => ' ' + paint((i === ask.sel ? '✶ ' : ' ') + (i + 1) + '. ' + o.label, i === ask.sel ? theme.redBright : theme.grey) + (o.description ? paint(' ' + o.description, theme.greyDim) : ''));
|
|
197
|
+
body = [line, q, ...opts, line];
|
|
198
|
+
}
|
|
185
199
|
else {
|
|
186
200
|
const inputLines = inputBoxLines(W); // çok-satırlı giriş (sarılmış)
|
|
187
201
|
const m = cmdMatches();
|
|
188
|
-
if (
|
|
202
|
+
if (busy && streamPreview) {
|
|
203
|
+
// CANLI akış önizlemesi (son PREVIEW_LINES satır, sabit yükseklik)
|
|
204
|
+
const pl = streamPreview.split('\n');
|
|
205
|
+
const tail = pl.slice(-PREVIEW_LINES);
|
|
206
|
+
while (tail.length < PREVIEW_LINES)
|
|
207
|
+
tail.push('');
|
|
208
|
+
const prev = tail.map((l, i) => (i === 0 ? paint('✶ ', theme.redBright, true) : ' ') + paint(l, theme.white));
|
|
209
|
+
body = [...prev, line, ...inputLines, line];
|
|
210
|
+
}
|
|
211
|
+
else if (m.length) {
|
|
189
212
|
// DİKEY slash menü — KAYAN pencere (8 satır, seçimi takip eder), seçili kırmızı.
|
|
190
213
|
const sel = Math.min(cmdSel, m.length - 1);
|
|
191
214
|
const WIN = 8;
|
|
@@ -229,15 +252,17 @@ export async function runTui() {
|
|
|
229
252
|
async function runTurn(userText, displayText) {
|
|
230
253
|
busy = true;
|
|
231
254
|
streamChars = 0;
|
|
255
|
+
streamPreview = '';
|
|
232
256
|
if (displayText !== undefined)
|
|
233
257
|
printItem({ kind: 'user', text: displayText }); // skill/@mention: gösterim farklı
|
|
234
258
|
history.push({ role: 'user', content: userText });
|
|
235
|
-
const timer = setInterval(() => { spin++; if (busy && !perm)
|
|
259
|
+
const timer = setInterval(() => { spin++; if (busy && !perm && !ask)
|
|
236
260
|
refresh(); }, 120);
|
|
237
261
|
let lastSig = '', sameCount = 0, usedWeb = false, lastAnswer = '';
|
|
238
262
|
try {
|
|
239
263
|
for (let iter = 0; iter < 25; iter++) {
|
|
240
264
|
streamChars = 0;
|
|
265
|
+
streamPreview = '';
|
|
241
266
|
// Oto-compact: bağlam eşiği aşılınca otomatik özetle (uzun sohbet patlamasın)
|
|
242
267
|
if (shouldAutoCompact(history)) {
|
|
243
268
|
try {
|
|
@@ -251,11 +276,11 @@ export async function runTui() {
|
|
|
251
276
|
let answer = '';
|
|
252
277
|
let toolCalls = [];
|
|
253
278
|
for await (const ev of streamChat(history, allToolSchemas(), config)) {
|
|
254
|
-
//
|
|
255
|
-
// streamChars güncellenir; footer'ı 120ms'lik spinTimer çizer; yazma anında keypress çizer.
|
|
279
|
+
// CANLI akış: answer biriktir + streamPreview güncelle. drawFooter'ı 120ms timer çizer (titreme yok).
|
|
256
280
|
if (ev.type === 'text') {
|
|
257
281
|
answer += ev.text;
|
|
258
282
|
streamChars = answer.length;
|
|
283
|
+
streamPreview = cleanModelText(answer);
|
|
259
284
|
}
|
|
260
285
|
else if (ev.type === 'done')
|
|
261
286
|
toolCalls = ev.toolCalls || [];
|
|
@@ -263,6 +288,7 @@ export async function runTui() {
|
|
|
263
288
|
answer += `\n[hata: ${ev.error}]`;
|
|
264
289
|
}
|
|
265
290
|
answer = cleanModelText(answer).trim();
|
|
291
|
+
streamPreview = ''; // canlı önizlemeyi kapat → footer küçülür, formatlı cevap içeriğe basılır
|
|
266
292
|
const am = { role: 'assistant', content: answer || '' };
|
|
267
293
|
if (toolCalls.length)
|
|
268
294
|
am.tool_calls = toolCalls.map((t) => ({ id: t.id, type: 'function', function: { name: t.name, arguments: t.args || '{}' } }));
|
|
@@ -292,6 +318,7 @@ export async function runTui() {
|
|
|
292
318
|
perm = { label: toolLabel(c.name, args), name: c.name, resolve };
|
|
293
319
|
refresh();
|
|
294
320
|
}),
|
|
321
|
+
ask: (q) => new Promise((resolve) => { ask = { question: q.question, options: q.options.length ? q.options : [{ label: 'Tamam' }], sel: 0, resolve }; refresh(); }),
|
|
295
322
|
onResult: (c, _i, res) => { if ((c.name === 'WebSearch' || c.name === 'WebFetch') && res.ok)
|
|
296
323
|
usedWeb = true; printItem({ kind: 'tool', label: toolLabel(c.name, res.args), result: sanitizeOutput(res.output), ok: res.ok }); },
|
|
297
324
|
});
|
|
@@ -305,6 +332,8 @@ export async function runTui() {
|
|
|
305
332
|
clearInterval(timer);
|
|
306
333
|
busy = false;
|
|
307
334
|
perm = null;
|
|
335
|
+
ask = null;
|
|
336
|
+
streamPreview = '';
|
|
308
337
|
refresh();
|
|
309
338
|
// Web-öğrenme: web'de arayıp cevap ürettiyse {soru→cevap}'ı eğitim datasına ekle
|
|
310
339
|
if (usedWeb && lastAnswer) {
|
|
@@ -339,6 +368,40 @@ export async function runTui() {
|
|
|
339
368
|
catch { } });
|
|
340
369
|
let ctrlcAt = 0;
|
|
341
370
|
process.stdin.on('keypress', (str, key) => {
|
|
371
|
+
// Soru dialogu (AskUserQuestion) aktifse: ↑↓ / 1-9 seç, Enter onayla, Esc/Ctrl+C ilk seçenek
|
|
372
|
+
if (ask) {
|
|
373
|
+
const n = ask.options.length;
|
|
374
|
+
if (key && key.name === 'up') {
|
|
375
|
+
ask.sel = (ask.sel - 1 + n) % n;
|
|
376
|
+
refresh();
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
if (key && key.name === 'down') {
|
|
380
|
+
ask.sel = (ask.sel + 1) % n;
|
|
381
|
+
refresh();
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (str && /^[1-9]$/.test(str) && +str <= n) {
|
|
385
|
+
ask.sel = +str - 1;
|
|
386
|
+
refresh();
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
if (key && key.name === 'return') {
|
|
390
|
+
const r = ask.resolve, v = ask.options[ask.sel]?.label || '';
|
|
391
|
+
ask = null;
|
|
392
|
+
r(v);
|
|
393
|
+
refresh();
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
if (key && (key.name === 'escape' || (key.ctrl && key.name === 'c'))) {
|
|
397
|
+
const r = ask.resolve, v = ask.options[0]?.label || '';
|
|
398
|
+
ask = null;
|
|
399
|
+
r(v);
|
|
400
|
+
refresh();
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
342
405
|
// İzin dialogu aktifse: E=Evet, T=Tümüne izin, H/Esc=Hayır (Ctrl+C de Hayır)
|
|
343
406
|
if (perm) {
|
|
344
407
|
const k = (str || '').toLowerCase();
|