wormclaude 1.0.43 → 1.0.44

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.43';
19
+ export const VERSION = '1.0.44';
package/dist/tui.js CHANGED
@@ -11,6 +11,7 @@ import { sanitizeOutput } from './errorsan.js';
11
11
  import { itemAnsi } from './ansi.js';
12
12
  import { theme, VERSION } from './theme.js';
13
13
  import { cleanModelText } from './textclean.js';
14
+ import { COMMANDS, runSlashCommand } from './commands.js';
14
15
  const RESET = '\x1b[0m';
15
16
  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` : ''; };
16
17
  const paint = (s, c, bold = false) => `${bold ? '\x1b[1m' : ''}${c ? hex(c) : ''}${s}${RESET}`;
@@ -59,13 +60,52 @@ export async function runTui() {
59
60
  const allowAll = new Set(); // "Tümüne izin" denen araçlar (oturum boyu)
60
61
  const inputHistory = []; // gönderilen mesajlar (↑/↓ ile geri çağrılır)
61
62
  let histIdx = -1; // -1 = geçmişte gezinmiyor
62
- // ── Claude tarzı başlık (model/plan/mail/cwd) responsive ──
63
+ let cmdSel = 0; // slash menüde seçili komut
64
+ // Slash menü: "/" ile başlayan girişe uyan komutlar
65
+ const cmdMatches = () => {
66
+ if (busy || !inputBuf.startsWith('/'))
67
+ return [];
68
+ const tok = inputBuf.split(' ')[0];
69
+ return COMMANDS.filter((c) => c.name.startsWith(tok));
70
+ };
71
+ // Slash komutları için bağlam (cli.tsx ile aynı arayüz) — /clear,/config,/model,/memory,/program…
72
+ const cmdCtx = {
73
+ config,
74
+ getHistory: () => history,
75
+ setHistory: (h) => { history.length = 0; history.push(...h); },
76
+ note: (text) => printItem({ kind: 'note', text }),
77
+ assistant: (text) => printItem({ kind: 'assistant', text }),
78
+ clearConv: () => { history.length = 1; displayItems.length = 1; redrawAll(); }, // sistem msg + banner kalır
79
+ exit: () => quit(),
80
+ };
81
+ async function runCommand(v) {
82
+ busy = true;
83
+ drawFooter();
84
+ const timer = setInterval(() => { spin++; if (busy && !perm)
85
+ drawFooter(); }, 120);
86
+ try {
87
+ await runSlashCommand(v, cmdCtx);
88
+ }
89
+ catch (e) {
90
+ printItem({ kind: 'note', text: 'Komut hatası: ' + (e?.message || e) });
91
+ }
92
+ clearInterval(timer);
93
+ busy = false;
94
+ drawFooter();
95
+ }
96
+ // ── Hizalı bilgi başlığı (Version/Model/Plan/Context/Workspace) — responsive ──
63
97
  function headerLines(W) {
64
- const a = paint(' WormClaude ', theme.greyDim) + paint('v' + VERSION, theme.red, true)
65
- + paint(' · model: ', theme.greyDim) + paint(config.model, theme.redBright)
66
- + (account.plan ? paint(' · plan: ', theme.greyDim) + paint(account.plan, theme.white) : '');
67
- const b = paint(' ' + (account.email ? account.email + ' · ' : '') + process.cwd(), theme.greyDim);
68
- return [a, b].map((l) => fit(l, W));
98
+ const ctx = (Number(process.env.WORMCLAUDE_CTX) || 12288).toLocaleString('tr-TR');
99
+ const rows = [
100
+ ['Version', 'v' + VERSION, theme.red],
101
+ ['Model', config.model, theme.redBright],
102
+ ['Plan', (account.plan || '—').toUpperCase(), theme.white],
103
+ ];
104
+ if (account.email)
105
+ rows.push(['Account', account.email, theme.grey]);
106
+ rows.push(['Context', ctx + ' tokens', theme.grey]);
107
+ rows.push(['Workspace', process.cwd(), theme.grey]);
108
+ return rows.map(([label, val, col]) => fit(' ' + paint(label.padEnd(11), theme.greyDim) + paint(val, col), W));
69
109
  }
70
110
  // ── Scroll region: üst = içerik (kayar), alt = sabit footer ──
71
111
  function setRegion() {
@@ -91,10 +131,20 @@ export async function runTui() {
91
131
  if (vis(shown) > avail)
92
132
  shown = '…' + shown.slice(-(avail - 1));
93
133
  const inputLine = paint('❯ ', theme.redBright, true) + paint(shown, theme.white) + paint('▌', theme.greyDim);
94
- // Durum satırı KUTUNUN ÜSTÜNDE (en altta değil): çalışırken spinner, boştayken ipucu.
95
- const status = busy
96
- ? paint(` ${SPIN[spin % SPIN.length]} çalışıyor…${streamChars ? ' ' + streamChars + ' karakter' : ''}`, theme.grey)
97
- : paint(' /kopyala · /help komutlar · ↑↓ geçmiş · Ctrl+C çıkış', theme.greyDim);
134
+ // Durum satırı KUTUNUN ÜSTÜNDE: slash menü > spinner > ipucu.
135
+ const m = cmdMatches();
136
+ let status;
137
+ if (m.length) {
138
+ const sel = Math.min(cmdSel, m.length - 1);
139
+ const names = m.slice(0, 8).map((c, i) => i === sel ? paint(c.name, theme.redBright, true) : paint(c.name, theme.greyDim)).join(' ');
140
+ status = ' ' + names + paint(' ↹ tamamla · ↑↓ seç', theme.greyDim);
141
+ }
142
+ else if (busy) {
143
+ status = paint(` ${SPIN[spin % SPIN.length]} çalışıyor…${streamChars ? ' ' + streamChars + ' karakter' : ''}`, theme.grey);
144
+ }
145
+ else {
146
+ status = paint(' / komutlar · ↑↓ geçmiş · /kopyala · Ctrl+C çıkış', theme.greyDim);
147
+ }
98
148
  body = [status, line, inputLine, line];
99
149
  }
100
150
  let out = '\x1b7'; // imleci kaydet
@@ -250,8 +300,14 @@ export async function runTui() {
250
300
  if (key && key.ctrl && key.name === 'd') {
251
301
  quit();
252
302
  }
253
- // ↑/↓ — geçmiş mesajlarda gezin (shell tarzı komut geçmişi)
303
+ // ↑/↓ — slash menü açıksa komut seç, değilse geçmiş mesajlarda gezin
254
304
  if (key && key.name === 'up') {
305
+ const m = cmdMatches();
306
+ if (m.length) {
307
+ cmdSel = (cmdSel - 1 + m.length) % m.length;
308
+ drawFooter();
309
+ return;
310
+ }
255
311
  if (inputHistory.length) {
256
312
  histIdx = histIdx < 0 ? inputHistory.length - 1 : Math.max(0, histIdx - 1);
257
313
  inputBuf = inputHistory[histIdx];
@@ -260,6 +316,12 @@ export async function runTui() {
260
316
  return;
261
317
  }
262
318
  if (key && key.name === 'down') {
319
+ const m = cmdMatches();
320
+ if (m.length) {
321
+ cmdSel = (cmdSel + 1) % m.length;
322
+ drawFooter();
323
+ return;
324
+ }
263
325
  if (histIdx >= 0) {
264
326
  histIdx++;
265
327
  if (histIdx >= inputHistory.length) {
@@ -272,37 +334,59 @@ export async function runTui() {
272
334
  }
273
335
  return;
274
336
  }
337
+ // Tab — seçili slash komutunu tamamla
338
+ if (key && key.name === 'tab') {
339
+ const m = cmdMatches();
340
+ if (m.length) {
341
+ inputBuf = m[Math.min(cmdSel, m.length - 1)].name + ' ';
342
+ cmdSel = 0;
343
+ drawFooter();
344
+ }
345
+ return;
346
+ }
275
347
  if (key && key.name === 'return') {
276
348
  if (busy)
277
349
  return; // tur sürerken Enter beklemede; yazılan metin durur (type-ahead)
278
- const v = inputBuf.trim();
350
+ let v = inputBuf.trim();
279
351
  inputBuf = '';
280
352
  histIdx = -1;
281
353
  if (!v) {
282
354
  drawFooter();
283
355
  return;
284
356
  }
285
- if (v)
286
- inputHistory.push(v); // geçmişe ekle (↑ ile geri çağrılır)
287
- if (v === '/cikis' || v === '/exit' || v === '/quit') {
288
- quit();
289
- }
290
- if (v === '/kopyala' || v === '/copy') {
291
- const last = [...history].reverse().find((m) => m.role === 'assistant');
292
- if (last) {
293
- process.stdout.write(`\x1b]52;c;${Buffer.from(last.content, 'utf8').toString('base64')}\x07`);
294
- printItem({ kind: 'note', text: `✓ Panoya kopyalandı (${last.content.length} karakter).` });
357
+ // Slash komutu: tam eşleşme yoksa menüde SEÇİLİ olanı kullan
358
+ if (v.startsWith('/')) {
359
+ const tok = v.split(' ')[0];
360
+ const matches = COMMANDS.filter((c) => c.name.startsWith(tok));
361
+ if (!COMMANDS.some((c) => c.name === tok) && matches.length)
362
+ v = matches[Math.min(cmdSel, matches.length - 1)].name;
363
+ cmdSel = 0;
364
+ if (v === '/cikis' || v === '/exit' || v === '/quit') {
365
+ quit();
366
+ return;
295
367
  }
296
- else
297
- printItem({ kind: 'note', text: 'Kopyalanacak yanıt yok.' });
368
+ if (v === '/kopyala' || v === '/copy') {
369
+ const last = [...history].reverse().find((mm) => mm.role === 'assistant');
370
+ if (last) {
371
+ process.stdout.write(`\x1b]52;c;${Buffer.from(last.content, 'utf8').toString('base64')}\x07`);
372
+ printItem({ kind: 'note', text: `✓ Panoya kopyalandı (${last.content.length} karakter).` });
373
+ }
374
+ else
375
+ printItem({ kind: 'note', text: 'Kopyalanacak yanıt yok.' });
376
+ return;
377
+ }
378
+ inputHistory.push(v);
379
+ runCommand(v);
298
380
  return;
299
381
  }
382
+ inputHistory.push(v); // geçmişe ekle (↑ ile geri çağrılır)
300
383
  printItem({ kind: 'user', text: v });
301
384
  runTurn(v);
302
385
  return;
303
386
  }
304
387
  if (key && key.name === 'backspace') {
305
388
  inputBuf = inputBuf.slice(0, -1);
389
+ cmdSel = 0;
306
390
  drawFooter();
307
391
  return;
308
392
  }
@@ -314,6 +398,7 @@ export async function runTui() {
314
398
  // sadece gerçek yazdırılabilir karakter (her zaman → cevap üretilirken bile type-ahead)
315
399
  if (str && !key?.ctrl && !key?.meta && !str.startsWith('\x1b') && !/[\x00-\x1f]/.test(str)) {
316
400
  inputBuf += str;
401
+ cmdSel = 0;
317
402
  drawFooter();
318
403
  }
319
404
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormclaude",
3
- "version": "1.0.43",
3
+ "version": "1.0.44",
4
4
  "description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
5
5
  "type": "module",
6
6
  "bin": {