wormclaude 1.0.21 → 1.0.22
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 +166 -0
- package/dist/cli.js +6 -12
- package/dist/theme.js +1 -1
- package/package.json +1 -1
package/dist/ansi.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// Geçmiş öğelerini doğrudan terminal scrollback'ine yazmak için ANSI string üreticisi.
|
|
2
|
+
// ink <Static> resize'da her şeyi yeniden bastığından (kademe/çift banner), geçmiş artık
|
|
3
|
+
// stdout'a BİR KEZ yazılır; ink yalnız canlı footer'ı yönetir. Böylece doğal kaydırma +
|
|
4
|
+
// metin seçip kopyalama çalışır. Markdown + sözdizimi vurgusu burada ANSI'ye çevrilir.
|
|
5
|
+
import { theme } from './theme.js';
|
|
6
|
+
import { highlight } from './highlight.js';
|
|
7
|
+
import { t } from './i18n.js';
|
|
8
|
+
const RESET = '\x1b[0m';
|
|
9
|
+
function hexAnsi(hex) {
|
|
10
|
+
if (!hex)
|
|
11
|
+
return '';
|
|
12
|
+
const m = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(hex);
|
|
13
|
+
if (!m)
|
|
14
|
+
return '';
|
|
15
|
+
return `\x1b[38;2;${parseInt(m[1], 16)};${parseInt(m[2], 16)};${parseInt(m[3], 16)}m`;
|
|
16
|
+
}
|
|
17
|
+
const paint = (s, hex, bold = false, dim = false, italic = false) => `${bold ? '\x1b[1m' : ''}${dim ? '\x1b[2m' : ''}${italic ? '\x1b[3m' : ''}${hexAnsi(hex)}${s}${RESET}`;
|
|
18
|
+
// ── Satır kaydırma (görsel genişliğe göre basit sarma) ──
|
|
19
|
+
function wrap(text, width) {
|
|
20
|
+
const out = [];
|
|
21
|
+
for (const para of String(text).split('\n')) {
|
|
22
|
+
if (!para) {
|
|
23
|
+
out.push('');
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
let line = '';
|
|
27
|
+
for (const word of para.split(' ')) {
|
|
28
|
+
const cand = line ? line + ' ' + word : word;
|
|
29
|
+
if (cand.length <= width) {
|
|
30
|
+
line = cand;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (line)
|
|
34
|
+
out.push(line);
|
|
35
|
+
if (word.length > width) {
|
|
36
|
+
let w = word;
|
|
37
|
+
while (w.length > width) {
|
|
38
|
+
out.push(w.slice(0, width));
|
|
39
|
+
w = w.slice(width);
|
|
40
|
+
}
|
|
41
|
+
line = w;
|
|
42
|
+
}
|
|
43
|
+
else
|
|
44
|
+
line = word;
|
|
45
|
+
}
|
|
46
|
+
out.push(line);
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
// ── Inline markdown → ANSI (**bold** `code` *italik* [t](u)) ──
|
|
51
|
+
function inlineAnsi(text) {
|
|
52
|
+
return text
|
|
53
|
+
.replace(/`([^`]+)`/g, (_m, c) => paint(c, theme.green))
|
|
54
|
+
.replace(/\*\*([^*]+)\*\*/g, (_m, c) => paint(c, undefined, true))
|
|
55
|
+
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, a, b) => `${a}${paint(' (' + b + ')', theme.redBright)}`);
|
|
56
|
+
}
|
|
57
|
+
const WORM_ROWS = [
|
|
58
|
+
'██╗ ██╗ ██████╗ ██████╗ ███╗ ███╗',
|
|
59
|
+
'██║ ██║██╔═══██╗██╔══██╗████╗ ████║',
|
|
60
|
+
'██║ █╗ ██║██║ ██║██████╔╝██╔████╔██║',
|
|
61
|
+
'██║███╗██║██║ ██║██╔══██╗██║╚██╔╝██║',
|
|
62
|
+
'╚███╔███╔╝╚██████╔╝██║ ██║██║ ╚═╝ ██║',
|
|
63
|
+
' ╚══╝╚══╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝',
|
|
64
|
+
];
|
|
65
|
+
const CLAUDE_ROWS = [
|
|
66
|
+
' ██████╗██╗ █████╗ ██╗ ██╗██████╗ ███████╗',
|
|
67
|
+
'██╔════╝██║ ██╔══██╗██║ ██║██╔══██╗██╔════╝',
|
|
68
|
+
'██║ ██║ ███████║██║ ██║██║ ██║█████╗ ',
|
|
69
|
+
'██║ ██║ ██╔══██║██║ ██║██║ ██║██╔══╝ ',
|
|
70
|
+
'╚██████╗███████╗██║ ██║╚██████╔╝██████╔╝███████╗',
|
|
71
|
+
' ╚═════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝',
|
|
72
|
+
];
|
|
73
|
+
/** Banner'ı ANSI olarak üretir (dar ekranda tek kelime, geniş ekranda yan yana). */
|
|
74
|
+
export function bannerAnsi(cols) {
|
|
75
|
+
if (cols < 46)
|
|
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];
|
|
78
|
+
return rows.map((r) => paint(r, theme.red, true)).join('\n') + '\n' + paint(' ' + t('banner.subtitle'), theme.greyDim);
|
|
79
|
+
}
|
|
80
|
+
// ── Markdown bloğu → ANSI (kod blokları sözdizimi-vurgulu) ──
|
|
81
|
+
function markdownAnsi(text, cols) {
|
|
82
|
+
const W = Math.max(20, cols - 2);
|
|
83
|
+
const lines = text.split('\n');
|
|
84
|
+
const out = [];
|
|
85
|
+
let inCode = false, fence = '', lang = '', code = [];
|
|
86
|
+
const fenceRe = /^ *(`{3,}|~{3,}) *(\w*)? *$/;
|
|
87
|
+
const flushCode = () => {
|
|
88
|
+
if (lang)
|
|
89
|
+
out.push(paint(' ' + lang, theme.greyDim));
|
|
90
|
+
for (const toks of highlight(code.join('\n'), lang)) {
|
|
91
|
+
out.push(paint('│ ', theme.greyDim) + (toks.length ? toks.map((tk) => paint(tk.text, tk.color)).join('') : ' '));
|
|
92
|
+
}
|
|
93
|
+
code = [];
|
|
94
|
+
lang = '';
|
|
95
|
+
fence = '';
|
|
96
|
+
};
|
|
97
|
+
for (const line of lines) {
|
|
98
|
+
if (inCode) {
|
|
99
|
+
const fm = line.match(fenceRe);
|
|
100
|
+
if (fm && fm[1][0] === fence[0] && fm[1].length >= fence.length) {
|
|
101
|
+
inCode = false;
|
|
102
|
+
flushCode();
|
|
103
|
+
}
|
|
104
|
+
else
|
|
105
|
+
code.push(line);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const fm = line.match(fenceRe);
|
|
109
|
+
if (fm) {
|
|
110
|
+
inCode = true;
|
|
111
|
+
fence = fm[1];
|
|
112
|
+
lang = (fm[2] || '').trim();
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const hm = line.match(/^ *(#{1,4}) +(.*)/);
|
|
116
|
+
const um = line.match(/^([ \t]*)([-*+]) +(.*)/);
|
|
117
|
+
const om = line.match(/^([ \t]*)(\d+)\. +(.*)/);
|
|
118
|
+
if (hm) {
|
|
119
|
+
const lvl = hm[1].length, inner = inlineAnsi(hm[2]);
|
|
120
|
+
out.push(lvl <= 2 ? paint(inner, theme.redBright, true) : lvl === 3 ? paint(inner, theme.white, true) : paint(inner, theme.grey, false, false, true));
|
|
121
|
+
}
|
|
122
|
+
else if (um || om) {
|
|
123
|
+
const [, ws, marker, itemText] = (um || om);
|
|
124
|
+
const prefix = om ? `${marker}. ` : '• ';
|
|
125
|
+
out.push(' '.repeat(ws.length) + paint(prefix, theme.grey) + inlineAnsi(itemText));
|
|
126
|
+
}
|
|
127
|
+
else if (line.trim() === '') {
|
|
128
|
+
out.push('');
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
for (const w of wrap(line, W))
|
|
132
|
+
out.push(inlineAnsi(w));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (inCode)
|
|
136
|
+
flushCode();
|
|
137
|
+
return out.join('\n');
|
|
138
|
+
}
|
|
139
|
+
/** Bir geçmiş öğesini scrollback'e yazılacak ANSI string'e çevirir (üstte 1 boş satır). */
|
|
140
|
+
export function itemAnsi(it, cols) {
|
|
141
|
+
const W = Math.max(24, cols - 2);
|
|
142
|
+
if (it.kind === 'banner')
|
|
143
|
+
return '\n' + bannerAnsi(cols);
|
|
144
|
+
if (it.kind === 'user') {
|
|
145
|
+
const inner = W - 4;
|
|
146
|
+
const top = paint('╭' + '─'.repeat(W - 2) + '╮', theme.greyDim);
|
|
147
|
+
const bot = paint('╰' + '─'.repeat(W - 2) + '╯', theme.greyDim);
|
|
148
|
+
const body = wrap('› ' + (it.text || ''), inner).map((ln) => paint('│ ', theme.greyDim) + paint(ln.padEnd(inner), theme.white) + paint(' │', theme.greyDim));
|
|
149
|
+
return '\n' + [top, ...body, bot].join('\n');
|
|
150
|
+
}
|
|
151
|
+
if (it.kind === 'assistant') {
|
|
152
|
+
const md = markdownAnsi(it.text || '', cols).split('\n');
|
|
153
|
+
return '\n' + md.map((ln, i) => (i === 0 ? paint('⏺ ', theme.redBright, true) + ln : ' ' + ln)).join('\n');
|
|
154
|
+
}
|
|
155
|
+
if (it.kind === 'tool') {
|
|
156
|
+
const n = (it.result || '').split('\n').length, chars = (it.result || '').length;
|
|
157
|
+
const head = paint('⏺ ', theme.redBright, true) + paint(it.label || '', theme.white);
|
|
158
|
+
const sub = paint(' ⎿ ', theme.greyDim) + (it.ok
|
|
159
|
+
? paint(`${n} ${t('common.lines') || 'satır'} (${chars})`, theme.grey)
|
|
160
|
+
: paint('✗ ' + (it.result || '').slice(0, 160), theme.errorRed));
|
|
161
|
+
return '\n' + head + '\n' + sub;
|
|
162
|
+
}
|
|
163
|
+
if (it.kind === 'note')
|
|
164
|
+
return '\n' + wrap(it.text || '', W).map((ln) => paint(ln, theme.greyDim)).join('\n');
|
|
165
|
+
return '';
|
|
166
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -788,10 +788,9 @@ function App() {
|
|
|
788
788
|
runAgent(v);
|
|
789
789
|
}
|
|
790
790
|
const { cols, rows } = useDimensions();
|
|
791
|
-
// İlk açılış: dil seçimi
|
|
791
|
+
// İlk açılış: dil seçimi (banner stdout'a basıldı; burada yalnız seçim footer'ı)
|
|
792
792
|
if (lang === null) {
|
|
793
|
-
return (React.createElement(Box, { flexDirection: "column",
|
|
794
|
-
React.createElement(Banner, null),
|
|
793
|
+
return (React.createElement(Box, { flexDirection: "column", width: cols },
|
|
795
794
|
React.createElement(Box, { flexDirection: "column", marginTop: 1, paddingX: 1 },
|
|
796
795
|
React.createElement(Text, { color: theme.redBright, bold: true }, t('lang.title')),
|
|
797
796
|
React.createElement(Box, { flexDirection: "column", marginTop: 1 },
|
|
@@ -803,14 +802,11 @@ function App() {
|
|
|
803
802
|
t('lang.en'))),
|
|
804
803
|
React.createElement(Text, { color: theme.greyDim },
|
|
805
804
|
" ",
|
|
806
|
-
t('lang.hint')))
|
|
807
|
-
React.createElement(Box, { flexGrow: 1 }),
|
|
808
|
-
React.createElement(StatusLine, { model: config.model, ctxTokens: 0 })));
|
|
805
|
+
t('lang.hint')))));
|
|
809
806
|
}
|
|
810
|
-
// Açılış: klasöre güven sorusu (
|
|
807
|
+
// Açılış: klasöre güven sorusu (banner stdout'ta; burada yalnız soru footer'ı)
|
|
811
808
|
if (!started) {
|
|
812
|
-
return (React.createElement(Box, { flexDirection: "column",
|
|
813
|
-
React.createElement(Banner, null),
|
|
809
|
+
return (React.createElement(Box, { flexDirection: "column", width: cols },
|
|
814
810
|
React.createElement(Box, { flexDirection: "column", marginTop: 1, paddingX: 1 },
|
|
815
811
|
React.createElement(Text, { color: theme.redBright, bold: true }, t('trust.accessing')),
|
|
816
812
|
React.createElement(Text, null, " "),
|
|
@@ -828,9 +824,7 @@ function App() {
|
|
|
828
824
|
t('trust.no'))),
|
|
829
825
|
React.createElement(Text, { color: theme.greyDim },
|
|
830
826
|
" ",
|
|
831
|
-
t('trust.hint')))
|
|
832
|
-
React.createElement(Box, { flexGrow: 1 }),
|
|
833
|
-
React.createElement(StatusLine, { model: config.model, ctxTokens: 0 })));
|
|
827
|
+
t('trust.hint')))));
|
|
834
828
|
}
|
|
835
829
|
return (React.createElement(Box, { flexDirection: "column", width: cols },
|
|
836
830
|
React.createElement(Static, { items: items }, (item, i) => React.createElement(RenderItem, { key: i, item: item })),
|
package/dist/theme.js
CHANGED