wormclaude 1.0.140 → 1.0.142

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 CHANGED
@@ -16,4 +16,4 @@ export const theme = {
16
16
  synType: '#a78bfa', // tip/sınıf adları, sabitler
17
17
  synProp: '#e0e0e0', // özellik/anahtar adları
18
18
  };
19
- export const VERSION = '1.0.140';
19
+ export const VERSION = '1.0.142';
package/dist/tui.js CHANGED
@@ -28,6 +28,20 @@ function fmtDur(ms) {
28
28
  const s = Math.max(0, Math.floor(ms / 1000));
29
29
  return s >= 60 ? `${Math.floor(s / 60)}m ${s % 60}s` : `${s}s`;
30
30
  }
31
+ // Kullanıcı mesajının dilini tespit et → UI etiketleri (Oluşturulacak/Create file, Yazıldı/Wrote…)
32
+ // konuşma diline uysun. Belirsizse null döner (mevcut dili koru).
33
+ const _TR_HINT = /[çğışöüÇĞİŞÖÜ]|\b(bir|bu|ve|ile|için|nasıl|nedir|var|olan|bana|beni|merhaba|selam|tamam|evet|hayır|değil|çok|yap|yapar|oluştur|kur|yaz|dosya|çalıştır|göster|aç|sil|ekle|değiştir|düzelt|kod|site|uygulama|sunucu|güvenlik|tarama|anlat|nerede|neden|hangisi)\b/i;
34
+ const _EN_HINT = /^(write|make|create|build|fix|add|remove|update|show|run|test|the|what|how|why|where|can you|could you|please|i want|i need|give|generate|implement|explain|tell me|help me)\b/i;
35
+ function _detectMsgLang(text) {
36
+ const s = (text || '').trim();
37
+ if (!s)
38
+ return null;
39
+ if (_TR_HINT.test(s))
40
+ return 'tr';
41
+ if (_EN_HINT.test(s))
42
+ return 'en';
43
+ return null;
44
+ }
31
45
  // Dosya yolunu çalışma alanına göreli göster (Claude tarzı: "todo/index.html"), yoksa olduğu gibi.
32
46
  function relWs(fp) {
33
47
  try {
@@ -95,6 +109,7 @@ export async function runTui() {
95
109
  ];
96
110
  const displayItems = [{ kind: 'banner' }];
97
111
  let inputBuf = '', inputCur = 0, busy = false, streamChars = 0, spin = 0;
112
+ let turnAbort = null; // ESC ile çalışan turu durdurma
98
113
  let taskStart = 0; // görev başlangıç zamanı (spinner'da geçen süre için)
99
114
  // 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.
100
115
  const SPIN = ['·', '✢', '✳', '✶', '✻', '✽', '✶', '✳', '✢'];
@@ -300,6 +315,11 @@ export async function runTui() {
300
315
  busy = true;
301
316
  streamChars = 0;
302
317
  taskStart = Date.now();
318
+ turnAbort = new AbortController(); // ESC ile durdurulabilsin
319
+ // UI dili konuşma diline uysun (etiketler: Oluşturulacak/Create file, Yazıldı/Wrote…)
320
+ const _ml = _detectMsgLang(userText);
321
+ if (_ml && _ml !== getLang())
322
+ setLang(_ml);
303
323
  if (displayText !== undefined)
304
324
  printItem({ kind: 'user', text: displayText }); // skill/@mention: gösterim farklı
305
325
  history.push({ role: 'user', content: userText });
@@ -310,6 +330,8 @@ export async function runTui() {
310
330
  let reactiveRetried = false; // bağlam taşmasında bir kez compact+retry
311
331
  try {
312
332
  for (let iter = 0; iter < 25; iter++) {
333
+ if (turnAbort?.signal.aborted)
334
+ break; // ESC ile durduruldu
313
335
  streamChars = 0;
314
336
  // Oto-compact: bağlam eşiği aşılınca otomatik özetle (uzun sohbet patlamasın)
315
337
  if (shouldAutoCompact(history)) {
@@ -358,7 +380,7 @@ export async function runTui() {
358
380
  refresh(); // footer'ı dibe yeniden sabitle
359
381
  };
360
382
  let gotCtxErr = false;
361
- for await (const ev of streamChat(history, allToolSchemas(), config)) {
383
+ for await (const ev of streamChat(history, allToolSchemas(), config, turnAbort?.signal)) {
362
384
  if (ev.type === 'text') {
363
385
  answer += ev.text;
364
386
  streamChars = answer.length;
@@ -378,6 +400,8 @@ export async function runTui() {
378
400
  }
379
401
  }
380
402
  flushStream(true); // kalan yarım satırı bas
403
+ if (turnAbort?.signal.aborted)
404
+ break; // ESC → araçları çalıştırma, dur
381
405
  // Reactive compact: bağlam taştıysa bir kez özetle ve turu tekrarla → "token bitti, yazılmıyor" olmaz.
382
406
  if (gotCtxErr && !reactiveRetried) {
383
407
  reactiveRetried = true;
@@ -432,15 +456,16 @@ export async function runTui() {
432
456
  onResult: (c, _i, res) => {
433
457
  if ((c.name === 'WebSearch' || c.name === 'WebFetch') && res.ok)
434
458
  usedWeb = true;
435
- // Claude tarzı önizleme: Write/Edit dosya içeriğini özetli göster (ham JSON/uzun çıktı yerine).
436
- let preview;
437
- if (res.ok && c.name === 'Write' && res.args?.content != null) {
438
- preview = { verb: t('tui.wrote') || 'Yazıldı', file: relWs(res.args.file_path), lines: String(res.args.content).split('\n') };
439
- }
440
- else if (res.ok && c.name === 'Edit' && res.args?.new_string != null) {
441
- preview = { verb: t('tui.edited') || 'Düzenlendi', file: relWs(res.args.file_path), lines: String(res.args.new_string).split('\n') };
459
+ // İÇERİK İKİ KEZ BASILMASIN: Write/Edit içeriği onay anında (fileprev) tam gösterildi
460
+ // burada SADECE tek-satır özet ("Yazıldı N satır → X"), token/ekran israfı yok.
461
+ let result = sanitizeOutput(res.output);
462
+ if (res.ok && (c.name === 'Write' || c.name === 'Edit')) {
463
+ const _c = c.name === 'Write' ? res.args?.content : res.args?.new_string;
464
+ const _n = _c != null ? String(_c).split('\n').length : 0;
465
+ const _verb = c.name === 'Write' ? (t('tui.wrote') || 'Yazıldı') : (t('tui.edited') || 'Düzenlendi');
466
+ result = `${_verb} ${_n} ${t('tui.linesWord') || 'satır'} → ${relWs(res.args.file_path)}`;
442
467
  }
443
- printItem({ kind: 'tool', label: toolLabel(c.name, res.args), result: sanitizeOutput(res.output), ok: res.ok, preview });
468
+ printItem({ kind: 'tool', label: toolLabel(c.name, res.args), result, ok: res.ok });
444
469
  },
445
470
  });
446
471
  for (let i = 0; i < toolCalls.length; i++)
@@ -467,6 +492,7 @@ export async function runTui() {
467
492
  busy = false;
468
493
  perm = null;
469
494
  ask = null;
495
+ turnAbort = null;
470
496
  refresh();
471
497
  // Web-öğrenme: web'de arayıp cevap ürettiyse {soru→cevap}'ı eğitim datasına ekle
472
498
  if (usedWeb && lastAnswer) {
@@ -813,6 +839,12 @@ export async function runTui() {
813
839
  return;
814
840
  }
815
841
  if (key && key.name === 'escape') {
842
+ // Tur çalışıyorsa ESC = modeli DURDUR (akış/araç döngüsünü kes). Boştaysa input'u temizle.
843
+ if (busy && turnAbort) {
844
+ turnAbort.abort();
845
+ printItem({ kind: 'note', text: getLang() === 'en' ? '■ Stopped (Esc). You can type a new message.' : '■ Durduruldu (Esc). Yeni mesaj yazabilirsin.' });
846
+ return;
847
+ }
816
848
  inputBuf = '';
817
849
  inputCur = 0;
818
850
  refresh();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormclaude",
3
- "version": "1.0.140",
3
+ "version": "1.0.142",
4
4
  "description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
5
5
  "type": "module",
6
6
  "bin": {