wormclaude 1.0.159 → 1.0.161

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/api.js CHANGED
@@ -111,6 +111,26 @@ async function fetchWithRetry(url, init) {
111
111
  }
112
112
  throw lastErr ?? new Error('retry exhausted');
113
113
  }
114
+ // Konuşmadaki EN SON URL/host'u bul (SecurityScan narration-recovery hedefi). Dosya adlarını
115
+ // (.js/.json/.html…) ELER ki "package.json" gibi şeyler hedef sanılmasın.
116
+ function _lastTargetFromMessages(messages) {
117
+ const urlRe = /https?:\/\/[^\s"'<>)\]]+/i;
118
+ const hostRe = /\b((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,24})\b/i;
119
+ const badExt = /\.(?:js|ts|tsx|jsx|json|html?|css|png|jpe?g|gif|svg|md|txt|py|sh|yml|yaml|lock|map|ico|woff2?|mjs|cjs)$/i;
120
+ for (let i = messages.length - 1; i >= 0; i--) {
121
+ const c = messages[i]?.content;
122
+ const s = typeof c === 'string' ? c : Array.isArray(c) ? c.map((x) => x?.text || '').join(' ') : '';
123
+ if (!s)
124
+ continue;
125
+ const u = s.match(urlRe);
126
+ if (u)
127
+ return u[0];
128
+ const h = s.match(hostRe);
129
+ if (h && !badExt.test(h[1]) && !/\.(localhost)$/i.test(h[1]))
130
+ return h[1];
131
+ }
132
+ return '';
133
+ }
114
134
  export async function* streamChat(messages, tools, config, signal) {
115
135
  const body = {
116
136
  model: config.model,
@@ -263,8 +283,9 @@ export async function* streamChat(messages, tools, config, signal) {
263
283
  args: safeJsonStringify(c.args),
264
284
  }));
265
285
  // Yedek: upstream yapısal tool_call vermediyse modelin metne gömdüğü çağrıyı kurtar.
286
+ // scanTarget: SecurityScan'i "anlatıp" çağırmayan 32B için hedefi konuşmadan al (en son URL/host).
266
287
  if (toolCalls.length === 0 && fullText) {
267
- const recovered = recoverInlineToolCalls(fullText);
288
+ const recovered = recoverInlineToolCalls(fullText, { scanTarget: _lastTargetFromMessages(messages) });
268
289
  if (recovered.length)
269
290
  toolCalls = recovered;
270
291
  }
package/dist/cli.js CHANGED
@@ -948,9 +948,13 @@ function App() {
948
948
  // başarısızlıklar birikir) toplam eşiği aşınca dur+özetle.
949
949
  const _failed = results.filter((r) => !r.ok).length;
950
950
  totalFails += _failed;
951
+ // Kurulum turu: model eksik aracı kuruyor (winget/choco/pip/apt/brew/npm -g…). Bu normal
952
+ // KURTARMA, "başarısızlık döngüsü" değil → ardışık-fail sayacını SIFIRLA ki uzun install
953
+ // (ya da install öncesi 'komut yok' hatası) devre-kesiciyi erken tetikleyip taramayı kesmesin.
954
+ const _installTurn = results.some((r) => /\b(?:winget|choco|scoop|apt(?:-get)?|dnf|yum|zypper|pacman|brew|pip3?|pipx|gem|cargo|go)\b[^|&;]*\b(?:install|-S|in)\b/i.test(String(r?.args?.command || '')));
951
955
  const _allFailed = results.length > 0 && _failed === results.length;
952
- consecFailTurns = _allFailed ? consecFailTurns + 1 : 0;
953
- if (consecFailTurns >= 2 || totalFails >= 4) {
956
+ consecFailTurns = (_allFailed && !_installTurn) ? consecFailTurns + 1 : 0;
957
+ if (consecFailTurns >= 2 || totalFails >= 5) {
954
958
  historyRef.current = [...historyRef.current, {
955
959
  role: 'user',
956
960
  content: getLang() === 'en'
@@ -232,11 +232,19 @@ function extractTopLevelJsonObjects(text) {
232
232
  }
233
233
  /** Metindeki gömülü araç çağrılarını kurtarır. Gürültüden kaçınmak için yalnız açık sarmalları
234
234
  * (<tool_call>, ```json) veya mesajın TAMAMI tek JSON çağrısıysa onu alır. */
235
- export function recoverInlineToolCalls(text) {
235
+ // SecurityScan'i ÇAĞIRMAYIP "anlatan" 32B için: tarama-ismi + aksiyon-fiili + hedef → gerçek çağrı.
236
+ // (Model "Recon işlemini başlatıyorum:" deyip takılıyordu; kullanıcı 'başla' deyip duruyordu.)
237
+ // Stem eşleşmesi (Türkçe ekleri için sondaki \b yok): "tarayacağım/tarıyorum", "keşfederek".
238
+ // tara(?!f) → "taraf/tarafından" YANLIŞ yakalanmaz; "keşif" (isim) + "keşf" (keşfet fiili) ayrı.
239
+ const _SCAN_NOUN_RE = /\b(?:recon|keşif|keşf|kesif|tar[aı](?!f)|scan|securityscan|zafiyet|enjeksiyon|injection|sqli|xss)/i;
240
+ const _SCAN_ACT_RE = /(başl|basl|çalıştır|calistir|gerçekleştir|gerceklestir|kullan|aca[gğ]|ece[gğ]|acak|ecek|[ıiuü]yor|start|run\b|launch|initiat|perform)/i;
241
+ function _scanIntent(s) { return _SCAN_NOUN_RE.test(s) && _SCAN_ACT_RE.test(s); }
242
+ export function recoverInlineToolCalls(text, opts) {
236
243
  const t = (text || '').trim();
237
- // JSON/prose/ToolName{…}/ToolName(…) çağrısı yoksa erken çık.
244
+ const scanTarget = (opts?.scanTarget || '').trim();
245
+ // JSON/prose/ToolName{…}/ToolName(…)/SecurityScan-niyeti çağrısı yoksa erken çık.
238
246
  // (Kod fence'i varsa çıkma — dosya-adı etiketli blok olabilir, adım 7 karar verir.)
239
- if (!t || (!t.includes('"name"') && !t.includes('"tool"') && !t.includes('"function"') && !/AskUserQuestion/i.test(t) && !TOOL_PREFIX_RE.test(t) && !TOOL_PAREN_RE.test(t) && !t.includes('```')))
247
+ if (!t || (!t.includes('"name"') && !t.includes('"tool"') && !t.includes('"function"') && !/AskUserQuestion/i.test(t) && !TOOL_PREFIX_RE.test(t) && !TOOL_PAREN_RE.test(t) && !t.includes('```') && !(scanTarget && _scanIntent(t))))
240
248
  return [];
241
249
  const out = [];
242
250
  const seen = new Set();
@@ -334,6 +342,20 @@ export function recoverInlineToolCalls(text) {
334
342
  }
335
343
  }
336
344
  }
345
+ // 6.5) SecurityScan NARRASYON → gerçek çağrı. 32B "recon başlatıyorum / XSS taraması yapacağım /
346
+ // SecurityScan ile tarayacağız" diye NİYET yazıp aracı çağırmıyor → takılıyordu. Hedef
347
+ // (konuşmadan) + niyet varsa SecurityScan'i kendimiz emit ediyoruz. Araç metinden seçilir.
348
+ if (!out.length && scanTarget && _scanIntent(t)) {
349
+ const low = t.toLowerCase();
350
+ let tool = 'recon'; // varsayılan: genel "tara" → önce keşif
351
+ if (/\bxss\b/.test(low))
352
+ tool = 'xss';
353
+ else if (/sql/.test(low))
354
+ tool = 'sqli';
355
+ else if (/(recon|keşif|keşf|kesif)/.test(low))
356
+ tool = 'recon';
357
+ push({ name: 'SecurityScan', arguments: { tool, target: scanTarget } });
358
+ }
337
359
  // 7) SON ÇARE: hiç çağrı kurtarılamadıysa, dosya-adı etiketli ```kod bloklarını
338
360
  // Write'a çevir (model build'de Write yerine kod yapıştırınca dosya kaybolmasın).
339
361
  // Adım 7, gerçek tool-call YOKKEN çalışır → "kod göster"i bozmaz (etiket gerekir).
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.159';
19
+ export const VERSION = '1.0.161';
package/dist/tools.js CHANGED
@@ -32,6 +32,16 @@ const DEFAULT_BASH_TIMEOUT_MS = 120000;
32
32
  // Bunları run_in_background istenmese bile OTOMATİK arka plana alıyoruz → CLI asla donmaz.
33
33
  const _DEV_SERVER_RE = /\b(?:npm|pnpm|yarn)\s+(?:run\s+)?(?:dev|start|serve|preview)\b|\b(?:next|nuxt|vite|gatsby)\s+(?:dev|develop|start)\b|\bng\s+serve\b|\breact-scripts\s+start\b|\bnodemon\b|\bhttp-server\b|(?:^|\s)serve(?:\s|$)|\bpython3?\s+-m\s+http\.server\b|\bflask\s+run\b|\buvicorn\b|\bgunicorn\b|\bphp\s+-S\b|\brails\s+s(?:erver)?\b|\bwebpack(?:-dev-server)?\s+serve\b/i;
34
34
  const MAX_BASH_TIMEOUT_MS = 600000;
35
+ // Paket KURULUM komutları (winget/choco/pip/apt/brew/npm -g …) yavaştır (indirme+derleme):
36
+ // 2 dk default timeout'u aşıp ÖLDÜRÜLÜYORLARDI → "install yarım kaldı" + devre-kesici tetikleniyordu.
37
+ // Bunlara otomatik MAX timeout (10 dk) verilir; model ayrıca süre belirtirse o kullanılır.
38
+ const _LONG_INSTALL_RE = /\b(?:winget\s+install|choco\s+install|scoop\s+install|apt(?:-get)?\s+install|dnf\s+install|yum\s+install|zypper\s+(?:in|install)|pacman\s+-S|brew\s+install|pip3?\s+install|pipx\s+install|gem\s+install|cargo\s+install|go\s+install|npm\s+(?:i|install)\b[^|&;]*-g)\b/i;
39
+ function _cmdTimeout(cmd, explicit) {
40
+ let t = Number(explicit) || (_LONG_INSTALL_RE.test(cmd) ? MAX_BASH_TIMEOUT_MS : DEFAULT_BASH_TIMEOUT_MS);
41
+ if (t > MAX_BASH_TIMEOUT_MS)
42
+ t = MAX_BASH_TIMEOUT_MS;
43
+ return t;
44
+ }
35
45
  // Bash çalışma dizini — oturum boyunca kalıcı. execSync her çağrıda taze shell açtığı için
36
46
  // `cd` normalde kaybolur; burada cwd'yi takip edip her komuta geçiriyoruz.
37
47
  let bashCwd;
@@ -1033,9 +1043,7 @@ export async function executeTool(name, args) {
1033
1043
  : '';
1034
1044
  return { ok: true, output: `Background task started: ${task.id}.${_note} Read output later with TaskOutput("${task.id}").` };
1035
1045
  }
1036
- let timeout = Number(args.timeout) || DEFAULT_BASH_TIMEOUT_MS;
1037
- if (timeout > MAX_BASH_TIMEOUT_MS)
1038
- timeout = MAX_BASH_TIMEOUT_MS;
1046
+ const timeout = _cmdTimeout(_cmd, args.timeout);
1039
1047
  const out = await runBashCapturingCwd(String(args.command), timeout);
1040
1048
  return { ok: true, output: (out || '(no output)').slice(0, 20000) };
1041
1049
  }
@@ -1389,9 +1397,7 @@ export async function executeTool(name, args) {
1389
1397
  return { ok: true, output: txt || '(boş)' };
1390
1398
  }
1391
1399
  if (name === 'PowerShell') {
1392
- let timeout = Number(args.timeout) || DEFAULT_BASH_TIMEOUT_MS;
1393
- if (timeout > MAX_BASH_TIMEOUT_MS)
1394
- timeout = MAX_BASH_TIMEOUT_MS;
1400
+ const timeout = _cmdTimeout(String(args.command), args.timeout);
1395
1401
  const cmd = String(args.command).replace(/"/g, '\\"');
1396
1402
  // ASYNC — event-loop'u bloklamaz (eski execSync donmaya sebep oluyordu).
1397
1403
  const { out, code, killed } = await _spawnAsync(`powershell -NoProfile -NonInteractive -Command "${cmd}"`, timeout, { shell: true, windowsHide: true, cwd: getBashCwd() });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormclaude",
3
- "version": "1.0.159",
3
+ "version": "1.0.161",
4
4
  "description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
5
5
  "type": "module",
6
6
  "bin": {