wormclaude 1.0.57 → 1.0.59

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/ansi.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // stdout'a BİR KEZ yazılır; ink yalnız canlı footer'ı yönetir. Böylece doğal kaydırma +
4
4
  // metin seçip kopyalama çalışır. Markdown + sözdizimi vurgusu burada ANSI'ye çevrilir.
5
5
  import { theme } from './theme.js';
6
- import { highlight } from './highlight.js';
6
+ import { highlight, isHighlightable } from './highlight.js';
7
7
  import { t } from './i18n.js';
8
8
  const RESET = '\x1b[0m';
9
9
  function hexAnsi(hex) {
@@ -90,8 +90,15 @@ export function markdownAnsi(text, cols) {
90
90
  const flushCode = () => {
91
91
  if (lang)
92
92
  out.push(paint(' ' + lang, theme.greyDim));
93
- for (const toks of highlight(code.join('\n'), lang)) {
94
- out.push(paint('│ ', theme.greyDim) + (toks.length ? toks.map((tk) => paint(tk.text, tk.color)).join('') : ' '));
93
+ if (isHighlightable(lang)) {
94
+ for (const toks of highlight(code.join('\n'), lang)) {
95
+ out.push(paint('│ ', theme.greyDim) + (toks.length ? toks.map((tk) => paint(tk.text, tk.color)).join('') : ' '));
96
+ }
97
+ }
98
+ else {
99
+ // Dilsiz/düz-metin blok: çubuk + nötr renk, sözdizimi-vurgusu YOK (saçma renk olmaz).
100
+ for (const ln of code)
101
+ out.push(paint('│ ', theme.greyDim) + paint(ln || ' ', theme.grey));
95
102
  }
96
103
  code = [];
97
104
  lang = '';
package/dist/highlight.js CHANGED
@@ -2,6 +2,13 @@
2
2
  // Kod bloklarını dile göre token'lara böler; her token'a tema rengi atar. Asla patlamaz —
3
3
  // tanımadığı dilde ortak kurallarla (string/sayı/yorum/anahtar kelime) renklendirir.
4
4
  import { theme } from './theme.js';
5
+ // Sözdizimi-vurgusu YALNIZ gerçek programlama dili etiketli bloklarda yapılır.
6
+ // Dil yoksa/düz-metin/markdown ise → renklendirme YOK (yoksa düz nesir "kod" sanılıp
7
+ // büyük-harfli kelimeler "tip", `in` gibi kelimeler "keyword" diye saçma renklenir).
8
+ const NON_CODE = new Set(['', 'text', 'txt', 'plain', 'plaintext', 'markdown', 'md', 'prose', 'none', 'output', 'log', 'console', 'raw']);
9
+ export function isHighlightable(lang) {
10
+ return !NON_CODE.has((lang || '').trim().toLowerCase());
11
+ }
5
12
  // Dil bazlı anahtar kelime setleri (ortak + spesifik).
6
13
  const KW = {
7
14
  js: ['const', 'let', 'var', 'function', 'return', 'if', 'else', 'for', 'while', 'do', 'switch', 'case', 'break', 'continue', 'new', 'class', 'extends', 'super', 'this', 'typeof', 'instanceof', 'in', 'of', 'await', 'async', 'yield', 'try', 'catch', 'finally', 'throw', 'import', 'export', 'from', 'default', 'delete', 'void', 'null', 'undefined', 'true', 'false'],
package/dist/i18n.js CHANGED
@@ -1,18 +1,24 @@
1
1
  // Çoklu dil (TR/EN) — arayüz metinleri. İlk açılışta dil seçilir, .wormclaude/settings.json'a yazılır.
2
2
  import * as fs from 'node:fs';
3
3
  import * as path from 'node:path';
4
- let current = 'tr';
4
+ import * as os from 'node:os';
5
+ let current = 'en'; // varsayılan: İngilizce (ilk kurulum). loadLang() kayıtlıysa onu uygular.
5
6
  export function setLang(l) { current = l; }
6
7
  export function getLang() { return current; }
7
- // Klasör bazlı ayar: her proje klasöründe bir kez sorulur (.wormclaude/settings.json)
8
- const SETTINGS = path.join(process.cwd(), '.wormclaude', 'settings.json');
8
+ // GLOBAL ayar: bir kez seçilince TÜM klasörlerde geçerli (~/.wormclaude/settings.json).
9
+ // (Önceden process.cwd()'ye yazılıyordu → her klasörde sıfırlanıyordu. Artık ev dizini.)
10
+ const SETTINGS = path.join(os.homedir(), '.wormclaude', 'settings.json');
11
+ // Geriye-uyum: eski proje-yerel ayar varsa onu da oku (yalnız global yoksa).
12
+ const LEGACY_SETTINGS = path.join(process.cwd(), '.wormclaude', 'settings.json');
9
13
  export function loadLang() {
10
- try {
11
- const j = JSON.parse(fs.readFileSync(SETTINGS, 'utf8'));
12
- if (j.lang === 'tr' || j.lang === 'en')
13
- return j.lang;
14
+ for (const p of [SETTINGS, LEGACY_SETTINGS]) {
15
+ try {
16
+ const j = JSON.parse(fs.readFileSync(p, 'utf8'));
17
+ if (j.lang === 'tr' || j.lang === 'en')
18
+ return j.lang;
19
+ }
20
+ catch { }
14
21
  }
15
- catch { }
16
22
  return null;
17
23
  }
18
24
  export function saveLang(l) {
@@ -67,6 +73,27 @@ const STR = {
67
73
  'mcp.errors': ' · {0} hata ({1})',
68
74
  'pill.running': '⏳ {0} çalışıyor',
69
75
  'pill.done': '✓ {0} görev bitti',
76
+ 'tui.footerHint': '/ komutlar · ↑↓ geçmiş · /kopyala · Ctrl+C çıkış',
77
+ 'tui.working': 'çalışıyor…',
78
+ 'tui.chars': 'karakter',
79
+ 'tui.pasteSummary': '…(+{0} satır · {1} karakter, Enter ile gönder)',
80
+ 'tui.permLabel': 'İZİN',
81
+ 'tui.permRun': 'çalıştırılsın mı?',
82
+ 'tui.permYes': '[E] Evet',
83
+ 'tui.permAll': '[T] Tümüne izin',
84
+ 'tui.permNo': '[H] Hayır',
85
+ 'tui.ok': 'Tamam',
86
+ 'tui.ctrlcExit': 'Çıkmak için tekrar Ctrl+C (veya /cikis). Kopyalama Ctrl+C\'yi etkilemez.',
87
+ 'tui.copied': '✓ Panoya kopyalandı ({0} karakter).',
88
+ 'tui.nothingCopy': 'Kopyalanacak yanıt yok.',
89
+ 'tui.mcpConnected': '🔌 {0} MCP sunucusu bağlandı',
90
+ 'tui.autoCompacted': '✎ bağlam otomatik özetlendi',
91
+ 'tui.loopStop': 'Aynı adım tekrarlandı, döngü önlemek için durduruldu.',
92
+ 'tui.connErr': '[bağlantı hatası: {0}]',
93
+ 'tui.learned': '✎ eğitim datasına eklendi',
94
+ 'tui.userCancel': 'kullanıcı iptal etti',
95
+ 'tui.cmdErr': 'Komut hatası: {0}',
96
+ 'tui.langSet': 'Dil değiştirildi: Türkçe',
70
97
  },
71
98
  en: {
72
99
  'lang.title': 'Select language / Dil seçin',
@@ -106,6 +133,27 @@ const STR = {
106
133
  'mcp.errors': ' · {0} error ({1})',
107
134
  'pill.running': '⏳ {0} running',
108
135
  'pill.done': '✓ {0} task(s) done',
136
+ 'tui.footerHint': '/ commands · ↑↓ history · /copy · Ctrl+C exit',
137
+ 'tui.working': 'working…',
138
+ 'tui.chars': 'chars',
139
+ 'tui.pasteSummary': '…(+{0} lines · {1} chars, Enter to send)',
140
+ 'tui.permLabel': 'PERMISSION',
141
+ 'tui.permRun': 'run it?',
142
+ 'tui.permYes': '[Y] Yes',
143
+ 'tui.permAll': '[A] Allow all',
144
+ 'tui.permNo': '[N] No',
145
+ 'tui.ok': 'OK',
146
+ 'tui.ctrlcExit': 'Press Ctrl+C again to exit (or /quit). Copying does not trigger Ctrl+C.',
147
+ 'tui.copied': '✓ Copied to clipboard ({0} chars).',
148
+ 'tui.nothingCopy': 'No response to copy.',
149
+ 'tui.mcpConnected': '🔌 {0} MCP server(s) connected',
150
+ 'tui.autoCompacted': '✎ context auto-summarized',
151
+ 'tui.loopStop': 'Same step repeated, stopped to avoid a loop.',
152
+ 'tui.connErr': '[connection error: {0}]',
153
+ 'tui.learned': '✎ added to training data',
154
+ 'tui.userCancel': 'user cancelled',
155
+ 'tui.cmdErr': 'Command error: {0}',
156
+ 'tui.langSet': 'Language changed: English',
109
157
  },
110
158
  };
111
159
  // Komut açıklamaları (slash menüsü + /help)
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.57';
19
+ export const VERSION = '1.0.59';
package/dist/tui.js CHANGED
@@ -12,7 +12,7 @@ import { itemAnsi, markdownAnsi } from './ansi.js';
12
12
  import { theme, VERSION } from './theme.js';
13
13
  import { cleanModelText } from './textclean.js';
14
14
  import { COMMANDS, runSlashCommand } from './commands.js';
15
- import { cmdDesc } from './i18n.js';
15
+ import { cmdDesc, t, setLang, loadLang } from './i18n.js';
16
16
  import { getSkill, getSkills, buildSkillPrompt } from './skills.js';
17
17
  import { getExtCommand, getExtCommands, buildExtCommandPrompt } from './extensions.js';
18
18
  import { resolveAtMentions } from './atmention.js';
@@ -49,6 +49,7 @@ function fit(line, max) {
49
49
  const vis = (s) => stringWidth(s.replace(/\x1b\[[0-9;]*m/g, ''));
50
50
  const padVis = (s, w) => s + ' '.repeat(Math.max(0, w - vis(s))); // görünür genişliğe boşluk doldur
51
51
  export async function runTui() {
52
+ setLang(loadLang() || 'en'); // kayıtlı dil varsa onu, yoksa İngilizce (ilk kurulum)
52
53
  const config = loadConfig();
53
54
  let account = { plan: '', email: '', name: '' };
54
55
  // Ortam bağlamı (Windows/cwd) — model DOĞRU yol/komut kullansın (yoksa /home/user gibi yanlış yol yazar).
@@ -92,7 +93,7 @@ export async function runTui() {
92
93
  // Çok uzun (büyük yapıştırma): son birkaç satır + üstte özet — footer'ı doldurmaz.
93
94
  const extra = wrapped.length - (MAX_INPUT_LINES - 1);
94
95
  const tail = wrapped.slice(-(MAX_INPUT_LINES - 1));
95
- const head = paint(`✶ (+${extra} satır · ${inputBuf.length} karakter, Enter ile gönder)`, theme.greyDim);
96
+ const head = paint('✶ ' + t('tui.pasteSummary', extra, inputBuf.length), theme.greyDim);
96
97
  return [head, ...tail.map((ln, i) => ' ' + paint(ln, theme.white) + (i === tail.length - 1 ? paint('▌', theme.greyDim) : ''))];
97
98
  };
98
99
  // Footer yüksekliği DİNAMİK: izin=4; değilse (durum/menü) + çizgi + giriş-satırları + çizgi.
@@ -146,7 +147,7 @@ export async function runTui() {
146
147
  await runSlashCommand(v, cmdCtx);
147
148
  }
148
149
  catch (e) {
149
- printItem({ kind: 'note', text: 'Komut hatası: ' + (e?.message || e) });
150
+ printItem({ kind: 'note', text: t('tui.cmdErr', e?.message || e) });
150
151
  }
151
152
  clearInterval(timer);
152
153
  busy = false;
@@ -186,9 +187,9 @@ export async function runTui() {
186
187
  let body;
187
188
  if (perm) {
188
189
  // İzin dialogu: araç adı + Evet/Tümü/Hayır
189
- const q = paint(' İZİN ', theme.redBright, true) + paint(perm.label, theme.white) + paint(' çalıştırılsın mı?', theme.grey);
190
- const opts = paint(' [E] Evet', theme.redBright, true) + paint(' · ', theme.greyDim)
191
- + paint('[T] Tümüne izin', theme.grey) + paint(' · ', theme.greyDim) + paint('[H] Hayır', theme.grey);
190
+ const q = paint(' ' + t('tui.permLabel') + ' ', theme.redBright, true) + paint(perm.label, theme.white) + paint(' ' + t('tui.permRun'), theme.grey);
191
+ const opts = paint(' ' + t('tui.permYes'), theme.redBright, true) + paint(' · ', theme.greyDim)
192
+ + paint(t('tui.permAll'), theme.grey) + paint(' · ', theme.greyDim) + paint(t('tui.permNo'), theme.grey);
192
193
  body = [line, q, opts, line];
193
194
  }
194
195
  else if (ask) {
@@ -215,8 +216,8 @@ export async function runTui() {
215
216
  else {
216
217
  const g = ctxUsed ? paint(' ' + ctxGauge(), theme.greyDim) : '';
217
218
  const status = busy
218
- ? paint(` ${SPIN[spin % SPIN.length]} çalışıyor…${streamChars ? ' ' + streamChars + ' karakter' : ''}`, theme.grey) + g
219
- : paint(' / komutlar · ↑↓ geçmiş · /kopyala · Ctrl+C çıkış', theme.greyDim) + g;
219
+ ? paint(` ${SPIN[spin % SPIN.length]} ${t('tui.working')}${streamChars ? ' ' + streamChars + ' ' + t('tui.chars') : ''}`, theme.grey) + g
220
+ : paint(' ' + t('tui.footerHint'), theme.greyDim) + g;
220
221
  body = [status, line, ...inputLines, line];
221
222
  }
222
223
  }
@@ -265,7 +266,7 @@ export async function runTui() {
265
266
  const { history: nh } = await runCompact(history, config);
266
267
  history.length = 0;
267
268
  history.push(...nh);
268
- printItem({ kind: 'note', text: '✎ bağlam otomatik özetlendi' });
269
+ printItem({ kind: 'note', text: t('tui.autoCompacted') });
269
270
  }
270
271
  catch { }
271
272
  }
@@ -339,7 +340,7 @@ export async function runTui() {
339
340
  lastSig = sig;
340
341
  }
341
342
  if (sameCount >= 2) {
342
- printItem({ kind: 'note', text: 'Aynı adım tekrarlandı, döngü önlemek için durduruldu.' });
343
+ printItem({ kind: 'note', text: t('tui.loopStop') });
343
344
  break;
344
345
  }
345
346
  const results = await executeToolCalls(toolCalls, {
@@ -349,7 +350,7 @@ export async function runTui() {
349
350
  perm = { label: toolLabel(c.name, args), name: c.name, resolve };
350
351
  refresh();
351
352
  }),
352
- ask: (q) => new Promise((resolve) => { ask = { question: q.question, options: q.options.length ? q.options : [{ label: 'Tamam' }], sel: 0, resolve }; refresh(); }),
353
+ ask: (q) => new Promise((resolve) => { ask = { question: q.question, options: q.options.length ? q.options : [{ label: t('tui.ok') }], sel: 0, resolve }; refresh(); }),
353
354
  onResult: (c, _i, res) => { if ((c.name === 'WebSearch' || c.name === 'WebFetch') && res.ok)
354
355
  usedWeb = true; printItem({ kind: 'tool', label: toolLabel(c.name, res.args), result: sanitizeOutput(res.output), ok: res.ok }); },
355
356
  });
@@ -358,7 +359,7 @@ export async function runTui() {
358
359
  }
359
360
  }
360
361
  catch (e) {
361
- printItem({ kind: 'note', text: `[bağlantı hatası: ${e?.message || e}]` });
362
+ printItem({ kind: 'note', text: t('tui.connErr', e?.message || e) });
362
363
  }
363
364
  clearInterval(timer);
364
365
  busy = false;
@@ -369,7 +370,7 @@ export async function runTui() {
369
370
  if (usedWeb && lastAnswer) {
370
371
  const sources = (lastAnswer.match(/https?:\/\/[^\s<>"')\]]+/g) || []).slice(0, 8);
371
372
  if (recordLearned(userText, lastAnswer, sources, config))
372
- printItem({ kind: 'note', text: '✎ eğitim datasına eklendi' });
373
+ printItem({ kind: 'note', text: t('tui.learned') });
373
374
  }
374
375
  // Oto-hafıza: eşik geçildiyse arka planda hafızayı güncelle
375
376
  if (shouldExtract(history))
@@ -390,7 +391,7 @@ export async function runTui() {
390
391
  redrawAll();
391
392
  } }).catch(() => { });
392
393
  connectMcpServers().then((srv) => { if (srv && srv.length)
393
- printItem({ kind: 'note', text: `🔌 ${srv.length} MCP sunucusu bağlandı` }); }).catch(() => { }); // MCP araçları (varsa)
394
+ printItem({ kind: 'note', text: t('tui.mcpConnected', srv.length) }); }).catch(() => { }); // MCP araçları (varsa)
394
395
  const quit = () => { process.stdout.write('\x1b[r\x1b[?25h\x1b[2J\x1b[3J\x1b[H'); process.exit(0); };
395
396
  process.on('exit', () => { try {
396
397
  process.stdout.write('\x1b[r\x1b[?25h');
@@ -438,26 +439,26 @@ export async function runTui() {
438
439
  const r = perm.resolve, nm = perm.name;
439
440
  if (key && key.ctrl && key.name === 'c') {
440
441
  perm = null;
441
- r({ deny: 'kullanıcı iptal etti' });
442
+ r({ deny: t('tui.userCancel') });
442
443
  refresh();
443
444
  return;
444
445
  }
445
- if (k === 'e' || k === '1' || (key && key.name === 'return')) {
446
+ if (k === 'e' || k === 'y' || k === '1' || (key && key.name === 'return')) {
446
447
  perm = null;
447
448
  r('allow');
448
449
  refresh();
449
- }
450
- else if (k === 't' || k === '2') {
450
+ } // Evet / Yes
451
+ else if (k === 't' || k === 'a' || k === '2') {
451
452
  allowAll.add(nm);
452
453
  perm = null;
453
454
  r('allow');
454
455
  refresh();
455
- }
456
- else if (k === 'h' || k === '3' || (key && key.name === 'escape')) {
456
+ } // Tümü / Allow all
457
+ else if (k === 'h' || k === 'n' || k === '3' || (key && key.name === 'escape')) {
457
458
  perm = null;
458
459
  r({ deny: '' });
459
460
  refresh();
460
- }
461
+ } // Hayır / No
461
462
  return;
462
463
  }
463
464
  if (key && key.ctrl && key.name === 'c') {
@@ -471,7 +472,7 @@ export async function runTui() {
471
472
  quit();
472
473
  }
473
474
  ctrlcAt = now;
474
- printItem({ kind: 'note', text: 'Çıkmak için tekrar Ctrl+C (veya /cikis). Kopyalama Ctrl+C\'yi etkilemez.' });
475
+ printItem({ kind: 'note', text: t('tui.ctrlcExit') });
475
476
  return;
476
477
  }
477
478
  if (key && key.ctrl && key.name === 'd') {
@@ -541,7 +542,7 @@ export async function runTui() {
541
542
  executeTool('Bash', { command: cmd }).then((res) => {
542
543
  printItem({ kind: 'tool', label: `! ${cmd.slice(0, 60)}`, result: sanitizeOutput(res.output), ok: res.ok });
543
544
  history.push({ role: 'user', content: `Şu shell komutunu çalıştırdım:\n\`\`\`\n${cmd}\n\`\`\`\nÇıktı:\n\`\`\`\n${(res.output || '').slice(0, 4000)}\n\`\`\`` });
544
- }).catch((e) => printItem({ kind: 'note', text: 'Komut hatası: ' + (e?.message || e) }))
545
+ }).catch((e) => printItem({ kind: 'note', text: t('tui.cmdErr', e?.message || e) }))
545
546
  .finally(() => { busy = false; refresh(); });
546
547
  return;
547
548
  }
@@ -563,10 +564,10 @@ export async function runTui() {
563
564
  const last = [...history].reverse().find((mm) => mm.role === 'assistant');
564
565
  if (last) {
565
566
  process.stdout.write(`\x1b]52;c;${Buffer.from(last.content, 'utf8').toString('base64')}\x07`);
566
- printItem({ kind: 'note', text: `✓ Panoya kopyalandı (${last.content.length} karakter).` });
567
+ printItem({ kind: 'note', text: t('tui.copied', last.content.length) });
567
568
  }
568
569
  else
569
- printItem({ kind: 'note', text: 'Kopyalanacak yanıt yok.' });
570
+ printItem({ kind: 'note', text: t('tui.nothingCopy') });
570
571
  return;
571
572
  }
572
573
  const builtin = COMMANDS.some((c) => c.name === tok);
@@ -582,6 +583,11 @@ export async function runTui() {
582
583
  runTurn(buildExtCommandPrompt(ext, a), `/${ext.name}${a ? ' ' + a : ''}`);
583
584
  return;
584
585
  }
586
+ // /lang|/dil: dil değişince banner alt-yazısı + footer yeni dilde olsun → tüm ekranı yeniden çiz
587
+ if (tok === '/lang') {
588
+ runCommand(v).then(() => redrawAll());
589
+ return;
590
+ }
585
591
  runCommand(v);
586
592
  return;
587
593
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormclaude",
3
- "version": "1.0.57",
3
+ "version": "1.0.59",
4
4
  "description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
5
5
  "type": "module",
6
6
  "bin": {