wormclaude 1.0.115 → 1.0.117

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/compact.js CHANGED
@@ -7,7 +7,9 @@ import { approxTokens } from './usage.js';
7
7
  // Model tavanı değişirse bu değer de güncellenmeli (ya da WORMCLAUDE_CONTEXT_WINDOW ile override).
8
8
  const CONTEXT_WINDOW = Number(process.env.WORMCLAUDE_CONTEXT_WINDOW) || 32768;
9
9
  const SUMMARY_RESERVE = 4000; // özet çıktısı için rezerv (CC: ~20K büyük modellerde)
10
- const AUTOCOMPACT_BUFFER = 2000;
10
+ // Erken tetikle (~%69): geç tetiklenince tek bir turun büyük çıktısı (grep/curl) pencereyi
11
+ // taşırıp "token bitti → yazılmıyor"a sokuyordu. Erken tazeleme = kesilme yok.
12
+ const AUTOCOMPACT_BUFFER = 6000;
11
13
  export function autoCompactThreshold() {
12
14
  return CONTEXT_WINDOW - SUMMARY_RESERVE - AUTOCOMPACT_BUFFER;
13
15
  }
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.115';
19
+ export const VERSION = '1.0.117';
package/dist/tools.js CHANGED
@@ -1137,7 +1137,9 @@ export async function executeTool(name, args) {
1137
1137
  const showLineNo = args['-n'] !== false; // content modunda varsayılan true
1138
1138
  const after = Number(args['-A'] ?? args['-C'] ?? args.context ?? 0);
1139
1139
  const before = Number(args['-B'] ?? args['-C'] ?? args.context ?? 0);
1140
- const headLimit = args.head_limit === 0 ? Infinity : Number(args.head_limit) || 250;
1140
+ // Varsayılan 60 eşleşme: yüzlerce satırlık çıktı context'i şişirip modeli tekrar-döngüsüne
1141
+ // (sahte link üretimi) sokuyordu. Model gerekirse head_limit ile artırabilir.
1142
+ const headLimit = args.head_limit === 0 ? Infinity : Number(args.head_limit) || 60;
1141
1143
  const offset = Number(args.offset) || 0;
1142
1144
  const reset = () => { rx.lastIndex = 0; return rx; };
1143
1145
  const entries = [];
@@ -1206,7 +1208,7 @@ export async function executeTool(name, args) {
1206
1208
  if (!sliced.length)
1207
1209
  return { ok: true, output: '(no matches)' };
1208
1210
  const note = entries.length > sliced.length ? `\n(${entries.length - sliced.length} more, raise head_limit to see)` : '';
1209
- return { ok: true, output: sliced.join('\n').slice(0, 30000) + note + `\n\n[${fileCount} file(s) with matches]` };
1211
+ return { ok: true, output: sliced.join('\n').slice(0, 6000) + note + `\n\n[${fileCount} file(s) with matches]` };
1210
1212
  }
1211
1213
  if (name === 'WebFetch') {
1212
1214
  let url = String(args.url);
package/dist/tui.js CHANGED
@@ -11,15 +11,32 @@ import { sanitizeOutput } from './errorsan.js';
11
11
  import { itemAnsi, markdownAnsi } from './ansi.js';
12
12
  import { theme, VERSION } from './theme.js';
13
13
  import { cleanModelText } from './textclean.js';
14
+ import { stripInlineToolCalls } from './inlinetools.js';
14
15
  import { COMMANDS, runSlashCommand } from './commands.js';
15
- import { cmdDesc, t, setLang, loadLang } from './i18n.js';
16
+ import { cmdDesc, t, setLang, loadLang, getLang } from './i18n.js';
16
17
  import { getSkill, getSkills, buildSkillPrompt } from './skills.js';
17
18
  import { getExtCommand, getExtCommands, buildExtCommandPrompt } from './extensions.js';
18
19
  import { resolveAtMentions } from './atmention.js';
19
20
  import { loadMemoryContext, shouldExtract, triggerMemory } from './memory.js';
20
- import { shouldAutoCompact, runCompact } from './compact.js';
21
+ import { shouldAutoCompact, runCompact, isContextError } from './compact.js';
21
22
  import { recordLearned } from './learn.js';
22
23
  import { connectMcpServers } from './mcp.js';
24
+ // Komut çıktılarını context'e eklerken KIS: curl/scan gürültüsü (handshake, tüm header'lar)
25
+ // 32k pencereyi hızla doldurur → baş+son tut, ortayı at. Az token = uzun tarama. Read geniş kalır.
26
+ function fmtDur(ms) {
27
+ const s = Math.max(0, Math.floor(ms / 1000));
28
+ return s >= 60 ? `${Math.floor(s / 60)}m ${s % 60}s` : `${s}s`;
29
+ }
30
+ function capToolOut(name, out) {
31
+ const s = out || '';
32
+ const isCmd = name === 'Bash' || name === 'PowerShell';
33
+ const CAP = isCmd ? 2200 : 8000;
34
+ if (s.length <= CAP)
35
+ return s;
36
+ if (isCmd)
37
+ return s.slice(0, 1400) + `\n… [${s.length - 2000} karakter kısaltıldı] …\n` + s.slice(-600);
38
+ return s.slice(0, CAP) + `\n… [${s.length - CAP} karakter kısaltıldı]`;
39
+ }
23
40
  const RESET = '\x1b[0m';
24
41
  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` : ''; };
25
42
  const paint = (s, c, bold = false) => `${bold ? '\x1b[1m' : ''}${c ? hex(c) : ''}${s}${RESET}`;
@@ -65,6 +82,7 @@ export async function runTui() {
65
82
  ];
66
83
  const displayItems = [{ kind: 'banner' }];
67
84
  let inputBuf = '', inputCur = 0, busy = false, streamChars = 0, spin = 0;
85
+ let taskStart = 0; // görev başlangıç zamanı (spinner'da geçen süre için)
68
86
  // 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
87
  const SPIN = ['·', '✢', '✳', '✶', '✻', '✽', '✶', '✳', '✢'];
70
88
  // Canlı bağlam ölçer: son isteğin prompt_tokens'ı = o anki kullanılan bağlam (footer'da gösterilir).
@@ -227,7 +245,7 @@ export async function runTui() {
227
245
  else {
228
246
  const g = ctxUsed ? paint(' ' + ctxGauge(), theme.greyDim) : '';
229
247
  const status = busy
230
- ? paint(` ${SPIN[spin % SPIN.length]} ${t('tui.working')}${streamChars ? ' ' + streamChars + ' ' + t('tui.chars') : ''}`, theme.grey) + g
248
+ ? paint(` ${SPIN[spin % SPIN.length]} ${t('tui.working')}${taskStart ? ' · ' + fmtDur(Date.now() - taskStart) : ''}${streamChars ? ' · ' + Math.round(streamChars / 4) + ' tokens' : ''}`, theme.grey) + g
231
249
  : paint(' ' + t('tui.footerHint'), theme.greyDim) + g;
232
250
  body = [status, line, ...inputLines, line];
233
251
  }
@@ -262,12 +280,15 @@ export async function runTui() {
262
280
  async function runTurn(userText, displayText) {
263
281
  busy = true;
264
282
  streamChars = 0;
283
+ taskStart = Date.now();
265
284
  if (displayText !== undefined)
266
285
  printItem({ kind: 'user', text: displayText }); // skill/@mention: gösterim farklı
267
286
  history.push({ role: 'user', content: userText });
268
287
  const timer = setInterval(() => { spin++; if (busy && !perm && !ask)
269
288
  refresh(); }, 120);
270
289
  let lastSig = '', sameCount = 0, usedWeb = false, lastAnswer = '';
290
+ let consecFail = 0, totalFails = 0; // devre-kesici: olmayan araç/sözdizimi döngüsünü kır
291
+ let reactiveRetried = false; // bağlam taşmasında bir kez compact+retry
271
292
  try {
272
293
  for (let iter = 0; iter < 25; iter++) {
273
294
  streamChars = 0;
@@ -305,7 +326,9 @@ export async function runTui() {
305
326
  }
306
327
  if (cut <= committed)
307
328
  return;
308
- const chunk = cleanModelText(answer.slice(committed, cut)).replace(/\n+$/, '');
329
+ // Gömülü araç-çağrısı JSON'unu (```json {"name":...}```) stdout'a YAZMADAN gizle —
330
+ // stdout append-only, sonradan silinemez. Kesimler fence-güvenli → tam blok burada.
331
+ const chunk = stripInlineToolCalls(cleanModelText(answer.slice(committed, cut))).replace(/\n+$/, '');
309
332
  committed = cut;
310
333
  if (!chunk && !final)
311
334
  return;
@@ -315,6 +338,7 @@ export async function runTui() {
315
338
  process.stdout.write(out); // imleç içerik bölgesinde → aşağı akar, taşınca scrollback'e
316
339
  refresh(); // footer'ı dibe yeniden sabitle
317
340
  };
341
+ let gotCtxErr = false;
318
342
  for await (const ev of streamChat(history, allToolSchemas(), config)) {
319
343
  if (ev.type === 'text') {
320
344
  answer += ev.text;
@@ -328,12 +352,26 @@ export async function runTui() {
328
352
  ctxUsed = u.input;
329
353
  }
330
354
  else if (ev.type === 'error') {
355
+ if (isContextError(ev.error))
356
+ gotCtxErr = true;
331
357
  answer += `\n[hata: ${ev.error}]`;
332
358
  flushStream(false);
333
359
  }
334
360
  }
335
361
  flushStream(true); // kalan yarım satırı bas
336
- answer = cleanModelText(answer).trim();
362
+ // Reactive compact: bağlam taştıysa bir kez özetle ve turu tekrarla → "token bitti, yazılmıyor" olmaz.
363
+ if (gotCtxErr && !reactiveRetried) {
364
+ reactiveRetried = true;
365
+ printItem({ kind: 'note', text: t('tui.autoCompacted') });
366
+ try {
367
+ const { history: nh } = await runCompact(history, config);
368
+ history.length = 0;
369
+ history.push(...nh);
370
+ }
371
+ catch { }
372
+ continue; // tur sayılmaz, kaldığı yerden devam
373
+ }
374
+ answer = stripInlineToolCalls(cleanModelText(answer)).trim();
337
375
  const am = { role: 'assistant', content: answer || '' };
338
376
  if (toolCalls.length)
339
377
  am.tool_calls = toolCalls.map((t) => ({ id: t.id, type: 'function', function: { name: t.name, arguments: t.args || '{}' } }));
@@ -366,7 +404,20 @@ export async function runTui() {
366
404
  usedWeb = true; printItem({ kind: 'tool', label: toolLabel(c.name, res.args), result: sanitizeOutput(res.output), ok: res.ok }); },
367
405
  });
368
406
  for (let i = 0; i < toolCalls.length; i++)
369
- history.push({ role: 'tool', tool_call_id: toolCalls[i].id, content: (results[i].output || '').slice(0, 8000) });
407
+ history.push({ role: 'tool', tool_call_id: toolCalls[i].id, content: capToolOut(toolCalls[i].name, results[i].output || '') });
408
+ // Devre-kesici: olmayan araç/Unix sözdizimini (grep/openssl/hydra) tekrar deneyip
409
+ // döngüye girmesin. Üst üste hepsi fail (2 tur) VEYA toplam 4 başarısız → dur+özetle.
410
+ const _failed = results.filter((r) => !r.ok).length;
411
+ totalFails += _failed;
412
+ consecFail = (results.length > 0 && _failed === results.length) ? consecFail + 1 : 0;
413
+ if (consecFail >= 2 || totalFails >= 4) {
414
+ history.push({ role: 'user', content: getLang() === 'en'
415
+ ? 'Several commands failed — required tools/syntax are not available here (e.g. grep/openssl/hydra on Windows). STOP running commands now and give a SHORT summary of what you found so far. Do NOT call more tools, do NOT use grep/sed/awk.'
416
+ : 'Komutlar başarısız oldu — bu ortamda gerekli araç/sözdizim yok (Windows\'ta grep/openssl/hydra gibi). Komut çalıştırmayı ŞİMDİ BIRAK, şu ana kadarki bulguları KISA özetle. Başka araç çağırma, grep/sed/awk kullanma.' });
417
+ printItem({ kind: 'note', text: getLang() === 'en' ? 'Commands kept failing — wrapping up.' : 'Komutlar başarısız oldu — özetle bitiriliyor.' });
418
+ consecFail = 0;
419
+ totalFails = 0;
420
+ }
370
421
  }
371
422
  }
372
423
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormclaude",
3
- "version": "1.0.115",
3
+ "version": "1.0.117",
4
4
  "description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
5
5
  "type": "module",
6
6
  "bin": {