wormclaude 1.0.53 → 1.0.54
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 +1 -1
- package/dist/theme.js +1 -1
- package/dist/tui.js +42 -24
- package/package.json +1 -1
package/dist/ansi.js
CHANGED
|
@@ -81,7 +81,7 @@ export function bannerAnsi(cols) {
|
|
|
81
81
|
return body + '\n' + paint(' ' + t('banner.subtitle'), theme.greyDim);
|
|
82
82
|
}
|
|
83
83
|
// ── Markdown bloğu → ANSI (kod blokları sözdizimi-vurgulu) ──
|
|
84
|
-
function markdownAnsi(text, cols) {
|
|
84
|
+
export function markdownAnsi(text, cols) {
|
|
85
85
|
const W = Math.max(20, cols - 2);
|
|
86
86
|
const lines = text.split('\n');
|
|
87
87
|
const out = [];
|
package/dist/theme.js
CHANGED
package/dist/tui.js
CHANGED
|
@@ -8,7 +8,7 @@ import stringWidth from 'string-width';
|
|
|
8
8
|
import { loadConfig, streamChat, fetchAccount } from './api.js';
|
|
9
9
|
import { allToolSchemas, executeToolCalls, executeTool, toolLabel, setToolConfig } from './tools.js';
|
|
10
10
|
import { sanitizeOutput } from './errorsan.js';
|
|
11
|
-
import { itemAnsi } from './ansi.js';
|
|
11
|
+
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';
|
|
@@ -64,8 +64,7 @@ export async function runTui() {
|
|
|
64
64
|
];
|
|
65
65
|
const displayItems = [{ kind: 'banner' }];
|
|
66
66
|
let inputBuf = '', busy = false, streamChars = 0, spin = 0;
|
|
67
|
-
|
|
68
|
-
const PREVIEW_LINES = 6; // akışta sabit önizleme satırı (yükseklik stabil → titreme yok)
|
|
67
|
+
// 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.
|
|
69
68
|
const SPIN = ['·', '✢', '✳', '✶', '✻', '✽', '✶', '✳', '✢'];
|
|
70
69
|
// Giriş kutusunu genişliğe göre ÇOK SATIRA sar; çok uzunsa (yapıştırma) KISALTIP özet gösterir.
|
|
71
70
|
const MAX_INPUT_LINES = 6;
|
|
@@ -196,16 +195,7 @@ export async function runTui() {
|
|
|
196
195
|
else {
|
|
197
196
|
const inputLines = inputBoxLines(W); // çok-satırlı giriş (sarılmış)
|
|
198
197
|
const m = cmdMatches();
|
|
199
|
-
if (
|
|
200
|
-
// CANLI akış önizlemesi (son PREVIEW_LINES satır, sabit yükseklik)
|
|
201
|
-
const pl = streamPreview.split('\n');
|
|
202
|
-
const tail = pl.slice(-PREVIEW_LINES);
|
|
203
|
-
while (tail.length < PREVIEW_LINES)
|
|
204
|
-
tail.push('');
|
|
205
|
-
const prev = tail.map((l, i) => (i === 0 ? paint('✶ ', theme.redBright, true) : ' ') + paint(l, theme.white));
|
|
206
|
-
body = [...prev, line, ...inputLines, line];
|
|
207
|
-
}
|
|
208
|
-
else if (m.length) {
|
|
198
|
+
if (m.length) {
|
|
209
199
|
// DİKEY slash menü — KAYAN pencere (8 satır, seçimi takip eder), seçili kırmızı.
|
|
210
200
|
const sel = Math.min(cmdSel, m.length - 1);
|
|
211
201
|
const WIN = 8;
|
|
@@ -254,7 +244,6 @@ export async function runTui() {
|
|
|
254
244
|
async function runTurn(userText, displayText) {
|
|
255
245
|
busy = true;
|
|
256
246
|
streamChars = 0;
|
|
257
|
-
streamPreview = '';
|
|
258
247
|
if (displayText !== undefined)
|
|
259
248
|
printItem({ kind: 'user', text: displayText }); // skill/@mention: gösterim farklı
|
|
260
249
|
history.push({ role: 'user', content: userText });
|
|
@@ -264,7 +253,6 @@ export async function runTui() {
|
|
|
264
253
|
try {
|
|
265
254
|
for (let iter = 0; iter < 25; iter++) {
|
|
266
255
|
streamChars = 0;
|
|
267
|
-
streamPreview = '';
|
|
268
256
|
// Oto-compact: bağlam eşiği aşılınca otomatik özetle (uzun sohbet patlamasın)
|
|
269
257
|
if (shouldAutoCompact(history)) {
|
|
270
258
|
try {
|
|
@@ -277,28 +265,59 @@ export async function runTui() {
|
|
|
277
265
|
}
|
|
278
266
|
let answer = '';
|
|
279
267
|
let toolCalls = [];
|
|
268
|
+
// ── CANLI akış İÇERİK AKIŞINA (footer'a değil): tamamlanan satırları, mesajın altından
|
|
269
|
+
// aşağı doğru, formatlı (kod renkli) bas. Açık kod-bloğu kapanana dek bekle (yarım fence
|
|
270
|
+
// bozuk renklenmesin). ✶ öneki yalnız bu cevabın İLK satırına; gerisi " " ile hizalı. ──
|
|
271
|
+
let committed = 0, emittedFirst = false, leadEmitted = false;
|
|
272
|
+
const flushStream = (final) => {
|
|
273
|
+
const lines = answer.split('\n');
|
|
274
|
+
let cut;
|
|
275
|
+
if (final)
|
|
276
|
+
cut = answer.length;
|
|
277
|
+
else {
|
|
278
|
+
let pos = 0, fence = false, lastSafe = 0;
|
|
279
|
+
for (let k = 0; k < lines.length - 1; k++) { // son eleman = yarım satır (newline gelmedi)
|
|
280
|
+
pos += lines[k].length + 1;
|
|
281
|
+
if (/^ *(`{3,}|~{3,})/.test(lines[k]))
|
|
282
|
+
fence = !fence;
|
|
283
|
+
if (!fence)
|
|
284
|
+
lastSafe = pos;
|
|
285
|
+
}
|
|
286
|
+
cut = lastSafe;
|
|
287
|
+
}
|
|
288
|
+
if (cut <= committed)
|
|
289
|
+
return;
|
|
290
|
+
const chunk = cleanModelText(answer.slice(committed, cut)).replace(/\n+$/, '');
|
|
291
|
+
committed = cut;
|
|
292
|
+
if (!chunk && !final)
|
|
293
|
+
return;
|
|
294
|
+
const md = markdownAnsi(chunk, cols()).split('\n');
|
|
295
|
+
let out = leadEmitted ? '' : (leadEmitted = true, '\n'); // cevabın üstüne 1 ayraç satır
|
|
296
|
+
out += md.map((ln) => emittedFirst ? ' ' + ln : (emittedFirst = true, paint('✶ ', theme.redBright, true) + ln)).join('\n') + '\n';
|
|
297
|
+
process.stdout.write(out); // imleç içerik bölgesinde → aşağı akar, taşınca scrollback'e
|
|
298
|
+
refresh(); // footer'ı dibe yeniden sabitle
|
|
299
|
+
};
|
|
280
300
|
for await (const ev of streamChat(history, allToolSchemas(), config)) {
|
|
281
|
-
// CANLI akış: answer biriktir + streamPreview güncelle. drawFooter'ı 120ms timer çizer (titreme yok).
|
|
282
301
|
if (ev.type === 'text') {
|
|
283
302
|
answer += ev.text;
|
|
284
303
|
streamChars = answer.length;
|
|
285
|
-
|
|
304
|
+
flushStream(false);
|
|
286
305
|
}
|
|
287
306
|
else if (ev.type === 'done')
|
|
288
307
|
toolCalls = ev.toolCalls || [];
|
|
289
|
-
else if (ev.type === 'error')
|
|
308
|
+
else if (ev.type === 'error') {
|
|
290
309
|
answer += `\n[hata: ${ev.error}]`;
|
|
310
|
+
flushStream(false);
|
|
311
|
+
}
|
|
291
312
|
}
|
|
313
|
+
flushStream(true); // kalan yarım satırı bas
|
|
292
314
|
answer = cleanModelText(answer).trim();
|
|
293
|
-
streamPreview = ''; // canlı önizlemeyi kapat → footer küçülür, formatlı cevap içeriğe basılır
|
|
294
315
|
const am = { role: 'assistant', content: answer || '' };
|
|
295
316
|
if (toolCalls.length)
|
|
296
317
|
am.tool_calls = toolCalls.map((t) => ({ id: t.id, type: 'function', function: { name: t.name, arguments: t.args || '{}' } }));
|
|
297
318
|
history.push(am);
|
|
298
|
-
if (answer)
|
|
299
|
-
lastAnswer = answer;
|
|
300
|
-
printItem({ kind: 'assistant', text: answer });
|
|
301
|
-
}
|
|
319
|
+
if (answer)
|
|
320
|
+
lastAnswer = answer; // gösterim akışta yapıldı; tekrar printItem YOK (duplikasyon olmaz)
|
|
302
321
|
if (!toolCalls.length)
|
|
303
322
|
break;
|
|
304
323
|
// takılma koruması: aynı araç-çağrısı 3 kez üst üste → dur
|
|
@@ -335,7 +354,6 @@ export async function runTui() {
|
|
|
335
354
|
busy = false;
|
|
336
355
|
perm = null;
|
|
337
356
|
ask = null;
|
|
338
|
-
streamPreview = '';
|
|
339
357
|
refresh();
|
|
340
358
|
// Web-öğrenme: web'de arayıp cevap ürettiyse {soru→cevap}'ı eğitim datasına ekle
|
|
341
359
|
if (usedWeb && lastAnswer) {
|