wormclaude 1.0.220 → 1.0.222

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/i18n.js CHANGED
@@ -95,6 +95,7 @@ const STR = {
95
95
  'tui.mcpConnected': '🔌 {0} MCP sunucusu bağlandı',
96
96
  'tui.autoCompacted': '✎ bağlam otomatik özetlendi',
97
97
  'tui.loopStop': 'Aynı adım tekrarlandı, döngü önlemek için durduruldu.',
98
+ 'tui.userStopped': '■ durduruldu (Esc).',
98
99
  'tui.connErr': '[bağlantı hatası: {0}]',
99
100
  'tui.learned': '✎ eğitim datasına eklendi',
100
101
  'tui.userCancel': 'kullanıcı iptal etti',
@@ -162,6 +163,7 @@ const STR = {
162
163
  'tui.mcpConnected': '🔌 {0} MCP server(s) connected',
163
164
  'tui.autoCompacted': '✎ context auto-summarized',
164
165
  'tui.loopStop': 'Same step repeated, stopped to avoid a loop.',
166
+ 'tui.userStopped': '■ stopped (Esc).',
165
167
  'tui.connErr': '[connection error: {0}]',
166
168
  'tui.learned': '',
167
169
  'tui.userCancel': 'user cancelled',
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.220';
19
+ export const VERSION = '1.0.222';
package/dist/tools.js CHANGED
@@ -183,7 +183,8 @@ const BASH_DESCRIPTION = `Run a shell command and return its output. Working dir
183
183
  - Quote paths with spaces. Chain dependent commands with && in ONE call; use ; if you do not care about failures; no newlines between commands.
184
184
  - timeout: optional ms (max ${MAX_BASH_TIMEOUT_MS}, default ${DEFAULT_BASH_TIMEOUT_MS}). run_in_background: true for long or never-exiting commands (returns a task id; read later with TaskOutput).
185
185
  - git: commit only when asked; avoid destructive ops (reset --hard, push --force) unless clearly best.`;
186
- const READ_DESCRIPTION = `Read a file from the local filesystem. file_path must be ABSOLUTE. Returns content with line numbers (cat -n format), up to ${MAX_LINES_TO_READ} lines; optional offset/limit for long files. Cannot read directories (use ls via Bash). A missing file returns an error.`;
186
+ const READ_DESCRIPTION = `Read a file from the local filesystem. file_path must be ABSOLUTE. Returns content with line numbers (cat -n format), up to ${MAX_LINES_TO_READ} lines; optional offset/limit for long files. Cannot read directories (use ls via Bash). A missing file returns an error. For STRUCTURED DATA (.csv, .xlsx, .json, .pdf, ...) use ReadDataFile instead — Read garbles binary spreadsheets.`;
187
+ const READ_DATA_DESCRIPTION = `Read and PARSE a structured-data file (.csv, .tsv, .json, .jsonl, .txt, .xlsx, .xls, .pdf) into clean text/rows. You MUST use THIS (not Read) for spreadsheets and data files — Read mangles binary .xlsx/.pdf. CSV/TSV/XLSX → table rows (first row = headers); JSON/JSONL → pretty JSON; PDF → text extracted page by page; TXT → raw text. Use offset/max_rows to paginate large files. For real ANALYSIS, read the structure here then write a Python/JS script that processes the WHOLE file (never just the sample shown).`;
187
188
  const WRITE_DESCRIPTION = `Writes a file to the local filesystem.
188
189
 
189
190
  Usage:
@@ -192,7 +193,11 @@ Usage:
192
193
  - Prefer the Edit tool for modifying existing files — it only sends the diff. Only use this tool to create new files or for complete rewrites.
193
194
  - NEVER create documentation files (*.md) or README files unless explicitly requested by the User.
194
195
  - Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.`;
195
- const EDIT_DESCRIPTION = `Exact string replacement in a file. You MUST Read the file at least once first (errors otherwise). old_string must be UNIQUE in the file - include enough surrounding context, or use replace_all to change every occurrence (e.g. renaming a variable). Preserve exact indentation from the file; do NOT include the line-number prefix from Read output.`;
196
+ const EDIT_DESCRIPTION = `Exact string replacement in a file. You MUST Read the file at least once first (errors otherwise).
197
+ - old_string MUST be the EXACT literal text from the file — including all whitespace, indentation and newlines. Do NOT include the line-number prefix from Read output, and NEVER escape characters (escaping breaks the literal match and the edit fails).
198
+ - old_string MUST uniquely identify the SINGLE place to change: include at least 3 lines of context BEFORE and AFTER the target, matching indentation precisely. If it matches multiple places or does not match exactly, the edit fails.
199
+ - To change EVERY occurrence (e.g. renaming a variable), set replace_all: true.
200
+ - new_string is the exact replacement text (also exact whitespace/indentation); ensure the result is correct and idiomatic.`;
196
201
  const GLOB_DESCRIPTION = `- Fast file pattern matching tool that works with any codebase size
197
202
  - Supports glob patterns like "**/*.js" or "src/**/*.ts"
198
203
  - Returns matching file paths sorted by modification time
@@ -325,6 +330,22 @@ export const toolSchemas = [
325
330
  },
326
331
  },
327
332
  },
333
+ {
334
+ type: 'function',
335
+ function: {
336
+ name: 'ReadDataFile',
337
+ description: READ_DATA_DESCRIPTION,
338
+ parameters: {
339
+ type: 'object',
340
+ properties: {
341
+ file_path: { type: 'string', description: 'Absolute path to the structured-data file (.csv, .tsv, .json, .jsonl, .txt, .xlsx, .xls, .pdf).' },
342
+ max_rows: { type: 'number', description: 'Optional: max rows/pages to DISPLAY (default 100 for tables, 10 for PDF). Only limits the sample shown.' },
343
+ offset: { type: 'number', description: 'Optional: 0-based row/page to start from (pagination through large files).' },
344
+ },
345
+ required: ['file_path'],
346
+ },
347
+ },
348
+ },
328
349
  {
329
350
  type: 'function',
330
351
  function: {
@@ -708,7 +729,7 @@ const computerToolSchemas = [
708
729
  // Bu yüzden modele YALNIZ sade, build+güvenlik çekirdeğini veriyoruz → araçları gerçekten
709
730
  // çağırıp işi yapar, planı ekrana basmaz. (Gerekirse buraya yeni araç eklenir.)
710
731
  const CORE_TOOLS = new Set([
711
- 'Bash', 'PowerShell', 'Read', 'Write', 'Edit', 'Glob', 'Grep',
732
+ 'Bash', 'PowerShell', 'Read', 'ReadDataFile', 'Write', 'Edit', 'Glob', 'Grep',
712
733
  'WebFetch', 'WebSearch', 'CloneSite', 'Sleep', 'SecurityScan', 'CodeAudit', 'JwtAudit', 'CreateDocument',
713
734
  'TaskOutput', // uzun komutları arka planda çalıştırıp bitişini yoklamak için (run_in_background)
714
735
  'AskUserQuestion', // GERİ EKLENDİ: FLAT şema (options: string[]) ile 32B temiz çağrı üretiyor
@@ -738,6 +759,7 @@ export function allToolSchemas() {
738
759
  }
739
760
  const TOOL_META = {
740
761
  Read: { readOnly: true, concurrencySafe: true, validate: (a) => (a && a.file_path && String(a.file_path) !== 'undefined' ? null : 'file_path gerekli (geçerli bir dosya yolu ver)') },
762
+ ReadDataFile: { readOnly: true, concurrencySafe: true, validate: (a) => (a && a.file_path ? null : 'file_path gerekli') },
741
763
  Glob: { readOnly: true, concurrencySafe: true },
742
764
  Grep: { readOnly: true, concurrencySafe: true },
743
765
  WebFetch: { readOnly: true, validate: (a) => (a && a.url ? null : 'url gerekli') },
@@ -1241,6 +1263,8 @@ export function toolLabel(name, args) {
1241
1263
  return `Bash(${String(args.command).slice(0, 80)})`;
1242
1264
  if (name === 'Read')
1243
1265
  return `Read(${args.file_path})`;
1266
+ if (name === 'ReadDataFile')
1267
+ return `📊 ReadDataFile(${args.file_path})`;
1244
1268
  if (name === 'Write')
1245
1269
  return `Write(${args.file_path})`;
1246
1270
  if (name === 'Edit')
@@ -1457,6 +1481,47 @@ function syntaxWarn(fp, content) {
1457
1481
  const err = syntaxCheck(fp, content);
1458
1482
  return err ? `\n⚠️ SYNTAX HATASI bu düzenlemeden sonra: ${err}\nDosya yazıldı ama BOZUK — bu hatayı şimdi düzelt (doğru sözdizimiyle tekrar Edit et).` : '';
1459
1483
  }
1484
+ // CSV/TSV ayrıştırıcı — tırnak içi ayraç/satırsonu ve "" kaçışını doğru işler.
1485
+ function parseCSV(text, sep) {
1486
+ const rows = [];
1487
+ let row = [];
1488
+ let field = '';
1489
+ let inQ = false;
1490
+ for (let i = 0; i < text.length; i++) {
1491
+ const c = text[i];
1492
+ if (inQ) {
1493
+ if (c === '"') {
1494
+ if (text[i + 1] === '"') {
1495
+ field += '"';
1496
+ i++;
1497
+ }
1498
+ else
1499
+ inQ = false;
1500
+ }
1501
+ else
1502
+ field += c;
1503
+ }
1504
+ else if (c === '"')
1505
+ inQ = true;
1506
+ else if (c === sep) {
1507
+ row.push(field);
1508
+ field = '';
1509
+ }
1510
+ else if (c === '\n') {
1511
+ row.push(field);
1512
+ rows.push(row);
1513
+ row = [];
1514
+ field = '';
1515
+ }
1516
+ else if (c !== '\r')
1517
+ field += c;
1518
+ }
1519
+ if (field.length || row.length) {
1520
+ row.push(field);
1521
+ rows.push(row);
1522
+ }
1523
+ return rows.filter((r) => r.length > 1 || (r.length === 1 && r[0] !== ''));
1524
+ }
1460
1525
  export async function executeTool(name, args) {
1461
1526
  try {
1462
1527
  if (name === 'See') {
@@ -1594,6 +1659,67 @@ export async function executeTool(name, args) {
1594
1659
  .join('\n');
1595
1660
  return { ok: true, output: numbered.slice(0, 40000) };
1596
1661
  }
1662
+ if (name === 'ReadDataFile') {
1663
+ const fp = resolveWs(args.file_path);
1664
+ if (!fs.existsSync(fp))
1665
+ return { ok: false, output: `Error: file does not exist: ${fp}` };
1666
+ if (fs.statSync(fp).isDirectory())
1667
+ return { ok: false, output: 'Error: path is a directory.' };
1668
+ const ext = path.extname(fp).toLowerCase();
1669
+ const maxRows = Number(args.max_rows) || (ext === '.pdf' ? 10 : 100);
1670
+ const off = Math.max(0, Number(args.offset) || 0);
1671
+ readFiles.add(norm(fp));
1672
+ const tbl = (head, body) => [head.join(' | '), head.map(() => '---').join(' | '), ...body.map((r) => r.map((c) => (c == null ? '' : String(c))).join(' | '))].join('\n');
1673
+ try {
1674
+ if (ext === '.csv' || ext === '.tsv') {
1675
+ const rows = parseCSV(fs.readFileSync(fp, 'utf8'), ext === '.tsv' ? '\t' : ',');
1676
+ const head = rows[0] || [];
1677
+ const body = rows.slice(1 + off, 1 + off + maxRows);
1678
+ return { ok: true, output: `[${ext.slice(1).toUpperCase()} — ${fp}] ${Math.max(0, rows.length - 1)} satır × ${head.length} sütun (${off + 1}–${off + body.length} gösteriliyor)\n\n${tbl(head, body).slice(0, 30000)}` };
1679
+ }
1680
+ if (ext === '.json') {
1681
+ const data = JSON.parse(fs.readFileSync(fp, 'utf8'));
1682
+ return { ok: true, output: `[JSON — ${fp}]\n${JSON.stringify(data, null, 2).slice(0, 30000)}` };
1683
+ }
1684
+ if (ext === '.jsonl' || ext === '.ndjson') {
1685
+ const items = fs.readFileSync(fp, 'utf8').split(/\r?\n/).filter(Boolean).map((l) => { try {
1686
+ return JSON.parse(l);
1687
+ }
1688
+ catch {
1689
+ return l;
1690
+ } });
1691
+ const slice = items.slice(off, off + maxRows);
1692
+ return { ok: true, output: `[JSONL — ${fp}] ${items.length} kayıt (${off + 1}–${off + slice.length})\n${JSON.stringify(slice, null, 2).slice(0, 30000)}` };
1693
+ }
1694
+ if (ext === '.txt' || ext === '.log' || ext === '.md') {
1695
+ return { ok: true, output: `[TXT — ${fp}]\n${fs.readFileSync(fp, 'utf8').slice(0, 40000)}` };
1696
+ }
1697
+ if (ext === '.xlsx' || ext === '.xls') {
1698
+ const ExcelJS = await import('exceljs');
1699
+ const wb = new (ExcelJS.default || ExcelJS).Workbook();
1700
+ await wb.xlsx.readFile(fp);
1701
+ const parts = [];
1702
+ wb.eachSheet((ws) => {
1703
+ const rows = [];
1704
+ ws.eachRow((row) => rows.push((row.values || []).slice(1).map((v) => (v && (v.text ?? v.result)) ?? v)));
1705
+ const head = rows[0] || [];
1706
+ const body = rows.slice(1 + off, 1 + off + maxRows);
1707
+ parts.push(`### Sayfa: ${ws.name} (${Math.max(0, rows.length - 1)} satır × ${head.length} sütun)\n${tbl(head, body)}`);
1708
+ });
1709
+ return { ok: true, output: `[XLSX — ${fp}]\n${(parts.join('\n\n') || '(boş)').slice(0, 30000)}` };
1710
+ }
1711
+ if (ext === '.pdf') {
1712
+ const { PDFParse } = await import('pdf-parse');
1713
+ const r = await new PDFParse({ data: fs.readFileSync(fp) }).getText();
1714
+ const txt = String(r?.text || '').trim();
1715
+ return { ok: true, output: txt ? `[PDF — ${fp}]\n${txt.slice(0, 40000)}` : 'PDF metin çıkmadı (taranmış/görsel olabilir).' };
1716
+ }
1717
+ return { ok: false, output: `Desteklenmeyen veri tipi: ${ext}. Düz metin/kod için Read kullan.` };
1718
+ }
1719
+ catch (e) {
1720
+ return { ok: false, output: 'Veri dosyası okuma hatası: ' + (e?.message || e) };
1721
+ }
1722
+ }
1597
1723
  if (name === 'Write') {
1598
1724
  const fp = resolveWs(args.file_path);
1599
1725
  const _existed = fs.existsSync(fp);
package/dist/tui.js CHANGED
@@ -795,6 +795,14 @@ export async function runTui() {
795
795
  } // Hayır / No
796
796
  return;
797
797
  }
798
+ // ÇALIŞAN TURU DURDUR: perm/ask dialogu YOKKEN Esc → uçuştaki isteği kes (app'i kapatma).
799
+ // Altyapı (turnAbort→signal→api.ts reader.cancel + loop break) hazırdı ama bu dal eksikti:
800
+ // model çok dosya okuyup takıldığında Esc'in hiçbir etkisi olmuyordu.
801
+ if (busy && turnAbort && key && key.name === 'escape') {
802
+ turnAbort.abort();
803
+ printItem({ kind: 'note', text: t('tui.userStopped') });
804
+ return;
805
+ }
798
806
  if (key && key.ctrl && key.name === 'c') {
799
807
  if (inputBuf) {
800
808
  inputBuf = '';
@@ -802,6 +810,12 @@ export async function runTui() {
802
810
  refresh();
803
811
  return;
804
812
  }
813
+ // Tur çalışıyorsa ilk Ctrl+C turu durdurur (app'i kapatmaz); boştayken çift-C çıkış.
814
+ if (busy && turnAbort) {
815
+ turnAbort.abort();
816
+ printItem({ kind: 'note', text: t('tui.userStopped') });
817
+ return;
818
+ }
805
819
  const now = Date.now();
806
820
  if (now - ctrlcAt < 2000) {
807
821
  quit();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormclaude",
3
- "version": "1.0.220",
3
+ "version": "1.0.222",
4
4
  "description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
5
5
  "type": "module",
6
6
  "bin": {