wormclaude 1.0.131 → 1.0.133

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.131';
19
+ export const VERSION = '1.0.133';
package/dist/tools.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // OpenAI function şemaları + Node executor'ları. Açıklamalar ve davranışlar
3
3
  // WormClaude'un gerçek prompt.ts/şemalarından alınmıştır; sadece marka adı ve
4
4
  // WormClaude'da bulunmayan araç referansları (Agent tool, sandbox) uyarlandı.
5
- import { execSync, spawn, spawnSync } from 'node:child_process';
5
+ import { spawn } from 'node:child_process';
6
6
  import * as fs from 'node:fs';
7
7
  import * as os from 'node:os';
8
8
  import * as path from 'node:path';
@@ -51,18 +51,47 @@ export function resolveWs(fp) {
51
51
  const _webFetchCache = new Map();
52
52
  // Komutu çalıştırır ve sonrasında cwd değişikliğini (cd) yakalayıp bashCwd'yi günceller.
53
53
  // POSIX: pwd'yi temp dosyaya yazan, çıkış kodunu KORUYAN sarmalayıcı (hata propagasyonu bozulmaz).
54
+ // ── ASYNC shell çalıştırıcı — KRİTİK: event-loop'u BLOKLAMAZ ────────────────
55
+ // Eskiden spawnSync/execSync (SENKRON) kullanılıyordu → uzun komut (npm install vb.)
56
+ // boyunca tüm Node event-loop'u kilitleniyor, spinner+girdi DAHİL her şey donuyordu
57
+ // ("8 saattir donma" şikayetinin kök sebebi buydu). spawn (async) ile komut arkada
58
+ // çalışırken UI canlı kalır. stdout+stderr ayrı yakalanır (curl progress sızmaz).
59
+ const _SHELL_CAP = 10 * 1024 * 1024;
60
+ function _spawnAsync(command, timeout, spawnOpts) {
61
+ return new Promise((resolve, reject) => {
62
+ let child;
63
+ try {
64
+ child = spawn(command, spawnOpts);
65
+ }
66
+ catch (e) {
67
+ return reject(e);
68
+ }
69
+ let out = '';
70
+ let killed = false;
71
+ const to = setTimeout(() => { killed = true; try {
72
+ child.kill();
73
+ }
74
+ catch { /* */ } }, timeout);
75
+ const onData = (d) => { if (out.length < _SHELL_CAP)
76
+ out += d.toString(); };
77
+ child.stdout?.on('data', onData);
78
+ child.stderr?.on('data', onData);
79
+ child.on('error', (e) => { clearTimeout(to); reject(e); });
80
+ child.on('close', (code) => { clearTimeout(to); resolve({ out, code, killed }); });
81
+ });
82
+ }
83
+ function _timeoutErr(out, timeout) {
84
+ const e = new Error((out ? out + '\n' : '') +
85
+ `[Komut ${Math.round(timeout / 1000)}sn icinde bitmedi ve durduruldu — uzun sureli/sunucu komutuysa run_in_background ile arka planda calistir.]`);
86
+ e.stdout = out;
87
+ e.timedOut = true;
88
+ return e;
89
+ }
54
90
  // Windows: komutu olduğu gibi çalıştır, sonra baştaki `cd <hedef>`'i regex ile yakala (best-effort).
55
- function runBashCapturingCwd(command, timeout) {
91
+ async function runBashCapturingCwd(command, timeout) {
56
92
  const cwd = getBashCwd();
57
- const opts = { encoding: 'utf8', timeout, maxBuffer: 10 * 1024 * 1024, windowsHide: true, cwd };
58
93
  if (process.platform === 'win32') {
59
- // spawnSync: stdout+stderr'i AYRI yakalar (komutu DEĞİŞTİRMEDEN) curl'ün "% Total" progress
60
- // meter'ı terminale sızmaz. execSync stderr'i inherit ederdi; `2>&1` ise zincirli (A && B)
61
- // komutlarda yalnız SON komutun stderr'ini yakalıyordu (ilkininki sızıyordu).
62
- const r = spawnSync(command, { ...opts, shell: true });
63
- if (r.error)
64
- throw r.error;
65
- const out = (r.stdout || '') + (r.stderr || '');
94
+ const { out, code, killed } = await _spawnAsync(command, timeout, { shell: true, windowsHide: true, cwd });
66
95
  // best-effort: "cd <hedef>" / "cd /d <hedef>" (zincirsiz tek komut)
67
96
  const m = /^\s*cd\s+(?:\/d\s+)?"?([^"&|<>]+?)"?\s*$/i.exec(command);
68
97
  if (m) {
@@ -73,10 +102,12 @@ function runBashCapturingCwd(command, timeout) {
73
102
  }
74
103
  catch { /* yok say */ }
75
104
  }
76
- if (typeof r.status === 'number' && r.status !== 0) {
77
- const e = new Error(out || `Command failed (exit ${r.status})`);
105
+ if (killed)
106
+ throw _timeoutErr(out, timeout);
107
+ if (typeof code === 'number' && code !== 0) {
108
+ const e = new Error(out || `Command failed (exit ${code})`);
78
109
  e.stdout = out;
79
- e.status = r.status;
110
+ e.status = code;
80
111
  throw e;
81
112
  }
82
113
  return out;
@@ -85,7 +116,16 @@ function runBashCapturingCwd(command, timeout) {
85
116
  const pwdFile = path.join(os.tmpdir(), `wc_pwd_${process.pid}_${Date.now()}.tmp`);
86
117
  const wrapped = `{ ${command}\n}; __wc=$?; pwd > '${pwdFile}' 2>/dev/null; exit $__wc`;
87
118
  try {
88
- return execSync(wrapped, { ...opts, shell: '/bin/sh' });
119
+ const { out, code, killed } = await _spawnAsync(wrapped, timeout, { shell: '/bin/sh', cwd });
120
+ if (killed)
121
+ throw _timeoutErr(out, timeout);
122
+ if (typeof code === 'number' && code !== 0) {
123
+ const e = new Error(out || `Command failed (exit ${code})`);
124
+ e.stdout = out;
125
+ e.status = code;
126
+ throw e;
127
+ }
128
+ return out;
89
129
  }
90
130
  finally {
91
131
  try {
@@ -998,7 +1038,7 @@ export async function executeTool(name, args) {
998
1038
  let timeout = Number(args.timeout) || DEFAULT_BASH_TIMEOUT_MS;
999
1039
  if (timeout > MAX_BASH_TIMEOUT_MS)
1000
1040
  timeout = MAX_BASH_TIMEOUT_MS;
1001
- const out = runBashCapturingCwd(String(args.command), timeout);
1041
+ const out = await runBashCapturingCwd(String(args.command), timeout);
1002
1042
  return { ok: true, output: (out || '(no output)').slice(0, 20000) };
1003
1043
  }
1004
1044
  if (name === 'Agent') {
@@ -1081,9 +1121,11 @@ export async function executeTool(name, args) {
1081
1121
  }
1082
1122
  if (name === 'Write') {
1083
1123
  const fp = resolveWs(args.file_path);
1084
- if (fs.existsSync(fp) && !readFiles.has(norm(fp)))
1085
- return { ok: false, output: 'Error: existing file must be read first. Use the Read tool before overwriting.' };
1086
- fs.mkdirSync(path.dirname(path.resolve(fp)), { recursive: true });
1124
+ const _existed = fs.existsSync(fp);
1125
+ // ESKİDEN: var olan dosya Read edilmemişse HARD-BLOCK ediliyordu. Zayıf 32B güvenilir Read
1126
+ // yapmadığı için bu, build'leri öldürüyordu (create-react-app dosyayı oluşturur → model
1127
+ // Read etmeden Write eder → bloklanır → proje yarıda kalır). ÇÖZÜM: bloklama; eski içeriği
1128
+ // OKU (diffStat'te ne değiştiği görünür, veri sessizce kaybolmaz), readFiles'a ekle, yaz.
1087
1129
  const _wnew = args.content ?? '';
1088
1130
  const _wold = (() => { try {
1089
1131
  return fs.readFileSync(fp, 'utf8');
@@ -1091,9 +1133,11 @@ export async function executeTool(name, args) {
1091
1133
  catch {
1092
1134
  return '';
1093
1135
  } })();
1136
+ fs.mkdirSync(path.dirname(path.resolve(fp)), { recursive: true });
1094
1137
  fs.writeFileSync(fp, _wnew);
1095
1138
  readFiles.add(norm(fp));
1096
- return { ok: true, output: `Wrote ${fp} (${_wnew.length} chars)${diffStat(_wold, _wnew)}` };
1139
+ const _ovr = (_existed && _wold !== _wnew) ? ' (uzerine yazildi)' : '';
1140
+ return { ok: true, output: `Wrote ${fp} (${_wnew.length} chars)${_ovr}${diffStat(_wold, _wnew)}` };
1097
1141
  }
1098
1142
  if (name === 'Edit') {
1099
1143
  const fp = resolveWs(args.file_path);
@@ -1349,9 +1393,12 @@ export async function executeTool(name, args) {
1349
1393
  if (timeout > MAX_BASH_TIMEOUT_MS)
1350
1394
  timeout = MAX_BASH_TIMEOUT_MS;
1351
1395
  const cmd = String(args.command).replace(/"/g, '\\"');
1352
- const out = execSync(`powershell -NoProfile -NonInteractive -Command "${cmd}"`, {
1353
- encoding: 'utf8', timeout, maxBuffer: 10 * 1024 * 1024, windowsHide: true,
1354
- });
1396
+ // ASYNC event-loop'u bloklamaz (eski execSync donmaya sebep oluyordu).
1397
+ const { out, code, killed } = await _spawnAsync(`powershell -NoProfile -NonInteractive -Command "${cmd}"`, timeout, { shell: true, windowsHide: true, cwd: getBashCwd() });
1398
+ if (killed)
1399
+ return { ok: false, output: _timeoutErr(out, timeout).message };
1400
+ if (typeof code === 'number' && code !== 0)
1401
+ return { ok: false, output: out || `PowerShell failed (exit ${code})` };
1355
1402
  return { ok: true, output: (out || '(no output)').slice(0, 20000) };
1356
1403
  }
1357
1404
  if (name === 'NotebookEdit') {
@@ -1390,7 +1437,11 @@ export async function executeTool(name, args) {
1390
1437
  fs.writeFileSync(tmp, String(args.code || ''));
1391
1438
  try {
1392
1439
  const cmd = lang === 'python' ? `python "${tmp}"` : `node "${tmp}"`;
1393
- const out = execSync(cmd, { encoding: 'utf8', timeout: 60000, maxBuffer: 10 * 1024 * 1024, windowsHide: true });
1440
+ const { out, code, killed } = await _spawnAsync(cmd, 60000, { shell: true, windowsHide: true, cwd: getBashCwd() });
1441
+ if (killed)
1442
+ return { ok: false, output: _timeoutErr(out, 60000).message };
1443
+ if (typeof code === 'number' && code !== 0)
1444
+ return { ok: false, output: (out || `exit ${code}`).slice(0, 15000) };
1394
1445
  return { ok: true, output: (out || '(no output)').slice(0, 15000) };
1395
1446
  }
1396
1447
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormclaude",
3
- "version": "1.0.131",
3
+ "version": "1.0.133",
4
4
  "description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
5
5
  "type": "module",
6
6
  "bin": {