wormclaude 1.0.24 → 1.0.26

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
@@ -72,9 +72,9 @@ const CLAUDE_ROWS = [
72
72
  ];
73
73
  /** Banner'ı ANSI olarak üretir (dar ekranda tek kelime, geniş ekranda yan yana). */
74
74
  export function bannerAnsi(cols) {
75
- if (cols < 46)
75
+ if (cols < 64)
76
76
  return paint('WORMCLAUDE', theme.red, true) + '\n' + paint(' ' + t('banner.subtitle'), theme.greyDim);
77
- const rows = cols >= 88 ? WORM_ROWS.map((w, i) => w + CLAUDE_ROWS[i]) : [...WORM_ROWS, ...CLAUDE_ROWS];
77
+ const rows = cols >= 100 ? WORM_ROWS.map((w, i) => w + CLAUDE_ROWS[i]) : [...WORM_ROWS, ...CLAUDE_ROWS];
78
78
  return rows.map((r) => paint(r, theme.red, true)).join('\n') + '\n' + paint(' ' + t('banner.subtitle'), theme.greyDim);
79
79
  }
80
80
  // ── Markdown bloğu → ANSI (kod blokları sözdizimi-vurgulu) ──
package/dist/cli.js CHANGED
@@ -254,9 +254,15 @@ function buildLines(items, cols) {
254
254
  for (const it of items) {
255
255
  lines.push([]); // üstte boşluk
256
256
  if (it.kind === 'banner') {
257
- const rows = cols >= 88 ? WORM_ROWS.map((w, i) => w + CLAUDE_ROWS[i]) : [...WORM_ROWS, ...CLAUDE_ROWS];
258
- for (const r of rows)
259
- lines.push([{ text: r, color: red, bold: true }]);
257
+ // Dar terminalde (<64) ASCII art sarıp bozulur temiz tek-kelime kullan.
258
+ if (cols < 64) {
259
+ lines.push([{ text: 'WORMCLAUDE', color: red, bold: true }]);
260
+ }
261
+ else {
262
+ const rows = cols >= 100 ? WORM_ROWS.map((w, i) => w + CLAUDE_ROWS[i]) : [...WORM_ROWS, ...CLAUDE_ROWS];
263
+ for (const r of rows)
264
+ lines.push([{ text: r, color: red, bold: true }]);
265
+ }
260
266
  lines.push([{ text: ' ' + t('banner.subtitle'), dim: true }]);
261
267
  }
262
268
  else if (it.kind === 'user') {
@@ -287,14 +293,14 @@ function buildLines(items, cols) {
287
293
  function Banner() {
288
294
  const { cols } = useDimensions();
289
295
  const RED = theme.red; // WORM + CLAUDE tek renk (kan kırmızısı)
290
- // Çok dar: temiz tek kelime (kırpılır, asla bozulmaz)
291
- if (cols < 46) {
296
+ // Dar terminal (<64): temiz tek kelime (ASCII art sarıp bozulmaz)
297
+ if (cols < 64) {
292
298
  return (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
293
299
  React.createElement(Text, { color: RED, bold: true, wrap: "truncate" }, "WORMCLAUDE"),
294
300
  React.createElement(Text, { color: theme.greyDim, wrap: "truncate" }, t('banner.subtitle'))));
295
301
  }
296
302
  // Geniş ekran: tek satır WORMCLAUDE (WORM + CLAUDE yan yana, tek renk → düzgün kırpılır)
297
- if (cols >= 88) {
303
+ if (cols >= 100) {
298
304
  return (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
299
305
  WORM_ROWS.map((w, i) => React.createElement(Text, { key: i, color: RED, bold: true, wrap: "truncate" }, w + CLAUDE_ROWS[i])),
300
306
  React.createElement(Text, { color: theme.greyDim, wrap: "truncate" }, ` ${t('banner.subtitle')}`)));
@@ -368,7 +374,8 @@ function StatusLine({ model, ctxTokens, trust = 0 }) {
368
374
  const barColor = pct > 85 ? theme.errorRed : pct > 60 ? theme.redBright : theme.grey;
369
375
  const cwd = path.basename(process.cwd()) || process.cwd();
370
376
  const badge = tier(trust).badge;
371
- return (React.createElement(Box, null,
377
+ // Tek satır + truncate → dar terminalde "WormClaud4" gibi taşma/wrap olmaz.
378
+ return (React.createElement(Text, { wrap: "truncate" },
372
379
  React.createElement(Text, { color: theme.greyDim },
373
380
  ' ',
374
381
  "WormClaude "),
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.24';
19
+ export const VERSION = '1.0.26';
package/dist/tui.js CHANGED
@@ -4,6 +4,7 @@
4
4
  // Renkli kod + markdown: ansi.ts (itemAnsi). WORMCLAUDE_TUI=1 ile çalışır; ink sürümü dokunulmadan kalır.
5
5
  import readline from 'node:readline';
6
6
  import logUpdate from 'log-update';
7
+ import stringWidth from 'string-width';
7
8
  import { loadConfig, streamChat } from './api.js';
8
9
  import { itemAnsi, bannerAnsi } from './ansi.js';
9
10
  import { theme, VERSION } from './theme.js';
@@ -12,6 +13,31 @@ const RESET = '\x1b[0m';
12
13
  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` : ''; };
13
14
  const paint = (s, c, bold = false) => `${bold ? '\x1b[1m' : ''}${c ? hex(c) : ''}${s}${RESET}`;
14
15
  const cols = () => process.stdout.columns || 80;
16
+ // Footer satırını terminal genişliğine ANSI-korumalı kırp (otomatik sarmayı önler → log-update
17
+ // satır sayımı şaşmaz, küçük terminalde bozulmaz). ANSI escape'leri genişliğe saymaz, korur.
18
+ function fit(line, max) {
19
+ let out = '', w = 0, i = 0;
20
+ while (i < line.length) {
21
+ if (line[i] === '\x1b') {
22
+ const m = /^\x1b\[[0-9;]*m/.exec(line.slice(i));
23
+ if (m) {
24
+ out += m[0];
25
+ i += m[0].length;
26
+ continue;
27
+ }
28
+ }
29
+ const ch = line[i];
30
+ const cw = stringWidth(ch) || 1;
31
+ if (w + cw > max)
32
+ break;
33
+ out += ch;
34
+ w += cw;
35
+ i++;
36
+ }
37
+ return out + RESET;
38
+ }
39
+ // Görünür (ANSI'siz) genişlik
40
+ const vis = (s) => stringWidth(s.replace(/\x1b\[[0-9;]*m/g, ''));
15
41
  export async function runTui() {
16
42
  const config = loadConfig();
17
43
  const history = []; // model bağlamı {role, content}
@@ -24,19 +50,28 @@ export async function runTui() {
24
50
  const printItem = (it) => { logUpdate.clear(); process.stdout.write(itemAnsi(it, cols()) + '\n'); renderFooter(); };
25
51
  // ── Canlı footer (log-update yönetir) ──
26
52
  function renderFooter() {
53
+ const W = Math.max(8, cols());
27
54
  const lines = [];
28
55
  if (busy && !streamPreview)
29
56
  lines.push(paint(`${SPIN[spin % SPIN.length]} `, theme.red) + paint('yanıt bekleniyor…', theme.grey));
30
57
  if (streamPreview) {
31
- const tail = streamPreview.split('\n').slice(-12); // footer'ı sınırla (uzun akışta taşmasın)
58
+ const maxTail = Math.max(2, Math.min(12, (process.stdout.rows || 24) - 4)); // ekran boyunu aşma
59
+ const tail = streamPreview.split('\n').slice(-maxTail);
32
60
  lines.push(paint('⏺ ', theme.redBright, true) + paint(tail.shift() || '', theme.white));
33
61
  for (const l of tail)
34
62
  lines.push(' ' + paint(l, theme.white));
35
63
  }
36
64
  lines.push('');
37
- lines.push(paint('❯ ', theme.redBright, true) + inputBuf + (busy ? '' : paint('▌', theme.greyDim)));
38
- lines.push(paint(' /kopyala panoya · Ctrl+C çıkış', theme.greyDim));
39
- logUpdate(lines.join('\n'));
65
+ // Giriş satırı: uzunsa SONU göster (yazdıkça imleç görünür kalsın)
66
+ const prompt = paint(' ', theme.redBright, true);
67
+ let shown = inputBuf;
68
+ const avail = W - 3; // "❯ " + imleç payı
69
+ if (vis(shown) > avail)
70
+ shown = '…' + shown.slice(-(avail - 1));
71
+ lines.push(prompt + shown + (busy ? '' : paint('▌', theme.greyDim)));
72
+ lines.push(paint('/kopyala panoya · Ctrl+C çıkış', theme.greyDim));
73
+ // HER satırı genişliğe kırp → küçük terminalde sarma/bozulma olmaz
74
+ logUpdate(lines.map((l) => fit(l, W)).join('\n'));
40
75
  }
41
76
  // ── Bir sohbet turu (Milestone 1: araç yok, saf metin) ──
42
77
  async function runTurn(userText) {
@@ -78,8 +113,27 @@ export async function runTui() {
78
113
  process.stdout.write(bannerAnsi(cols()) + '\n');
79
114
  process.stdout.write(paint(' uncensored security + code', theme.greyDim) + paint(' · WormClaude ', theme.greyDim) + paint('v' + VERSION, theme.red, true) + paint(' · özel renderer (deneysel)', theme.greyDim) + '\n\n');
80
115
  renderFooter();
116
+ let ctrlcAt = 0;
81
117
  process.stdin.on('keypress', (str, key) => {
118
+ // Ctrl+C tek başına ÇIKMAZ (Windows'ta seçimi Ctrl+C ile kopyalarken uygulama kapanmasın).
119
+ // Giriş varsa temizler; boşsa 2 sn içinde ikinci Ctrl+C ile çıkar.
82
120
  if (key && key.ctrl && key.name === 'c') {
121
+ if (inputBuf) {
122
+ inputBuf = '';
123
+ renderFooter();
124
+ return;
125
+ }
126
+ const now = Date.now();
127
+ if (now - ctrlcAt < 2000) {
128
+ logUpdate.clear();
129
+ process.stdout.write('\n');
130
+ process.exit(0);
131
+ }
132
+ ctrlcAt = now;
133
+ printItem({ kind: 'note', text: 'Çıkmak için tekrar Ctrl+C (veya /cikis). Kopyalama Ctrl+C\'yi etkilemez.' });
134
+ return;
135
+ }
136
+ if (key && key.ctrl && key.name === 'd') {
83
137
  logUpdate.clear();
84
138
  process.stdout.write('\n');
85
139
  process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormclaude",
3
- "version": "1.0.24",
3
+ "version": "1.0.26",
4
4
  "description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
5
5
  "type": "module",
6
6
  "bin": {