wormclaude 1.0.20 → 1.0.21
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/cli.js +14 -59
- package/dist/highlight.js +132 -0
- package/dist/markdown.js +17 -3
- package/dist/theme.js +9 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import React, { useState, useRef, useEffect } from 'react';
|
|
3
|
-
import { render, Box, Text, useApp, useInput } from 'ink';
|
|
3
|
+
import { render, Box, Text, Static, useApp, useInput } from 'ink';
|
|
4
4
|
import TextInput from 'ink-text-input';
|
|
5
5
|
import * as path from 'node:path';
|
|
6
6
|
import { theme, VERSION } from './theme.js';
|
|
@@ -85,18 +85,10 @@ const _initHistory = () => {
|
|
|
85
85
|
sys.push({ role: 'system', content: _memCtx });
|
|
86
86
|
return sys;
|
|
87
87
|
};
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
// ?1049h alt-screen
|
|
91
|
-
|
|
92
|
-
process.stdout.write('\x1b[?1049h\x1b[?1007h\x1b[2J\x1b[H');
|
|
93
|
-
}
|
|
94
|
-
catch { }
|
|
95
|
-
const _leaveAlt = () => { try {
|
|
96
|
-
process.stdout.write('\x1b[?1007l\x1b[?1049l');
|
|
97
|
-
}
|
|
98
|
-
catch { } };
|
|
99
|
-
process.on('exit', _leaveAlt);
|
|
88
|
+
// NORMAL buffer (alt-screen YOK) — transcript <Static> ile gerçek terminal scrollback'ine
|
|
89
|
+
// basılır. Böylece terminalin doğal kaydırması (fare tekerleği / Shift+PageUp) ve metin
|
|
90
|
+
// seçip kopyalama tam çalışır. Eskiden ?1049h alt-screen kullanılıyordu; o, scrollback'i ve
|
|
91
|
+
// kopyalamayı engelliyordu — kaldırıldı.
|
|
100
92
|
function useDimensions() {
|
|
101
93
|
const [d, setD] = useState({
|
|
102
94
|
cols: process.stdout.columns || 80,
|
|
@@ -448,25 +440,9 @@ function App() {
|
|
|
448
440
|
else if (key.downArrow)
|
|
449
441
|
setCmdSel((s) => (s + 1) % n);
|
|
450
442
|
});
|
|
451
|
-
//
|
|
452
|
-
//
|
|
453
|
-
|
|
454
|
-
if (!started || perm || ask || lang === null)
|
|
455
|
-
return;
|
|
456
|
-
// satır-temelli; üst sınır render'da off=min(scroll,maxScroll) ile kırpılır
|
|
457
|
-
if (key.pageUp)
|
|
458
|
-
setScroll((s) => s + 10);
|
|
459
|
-
else if (key.pageDown)
|
|
460
|
-
setScroll((s) => Math.max(0, s - 10));
|
|
461
|
-
else if (input === '' && !busy) {
|
|
462
|
-
if (key.upArrow)
|
|
463
|
-
setScroll((s) => s + 3);
|
|
464
|
-
else if (key.downArrow)
|
|
465
|
-
setScroll((s) => Math.max(0, s - 3));
|
|
466
|
-
}
|
|
467
|
-
});
|
|
468
|
-
// Yeni mesaj gelince en alta dön
|
|
469
|
-
useEffect(() => { setScroll(0); }, [items.length]);
|
|
443
|
+
// NOT: Transcript artık <Static> ile terminal scrollback'ine basılıyor; kaydırma
|
|
444
|
+
// terminalin kendi işi (fare tekerleği / Shift+PageUp). Tuşları YAKALAMIYORUZ ki
|
|
445
|
+
// doğal kaydırma + metin seçip kopyalama bozulmasın.
|
|
470
446
|
// Başlangıçta güven seviyesini (Doğrulanmış Araştırmacı Programı) çek → StatusLine rozeti
|
|
471
447
|
useEffect(() => {
|
|
472
448
|
if (!started)
|
|
@@ -856,33 +832,12 @@ function App() {
|
|
|
856
832
|
React.createElement(Box, { flexGrow: 1 }),
|
|
857
833
|
React.createElement(StatusLine, { model: config.model, ctxTokens: 0 })));
|
|
858
834
|
}
|
|
859
|
-
return (React.createElement(Box, { flexDirection: "column",
|
|
860
|
-
React.createElement(
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
const maxScroll = Math.max(0, all.length - avail);
|
|
866
|
-
const off = Math.min(scroll, maxScroll); // alttan kaç satır yukarı
|
|
867
|
-
const startLine = Math.max(0, all.length - avail - off);
|
|
868
|
-
const view = all.slice(startLine, startLine + avail);
|
|
869
|
-
return (React.createElement(React.Fragment, null,
|
|
870
|
-
startLine > 0 ? React.createElement(Text, { color: theme.greyDim },
|
|
871
|
-
" \u2191 ",
|
|
872
|
-
startLine,
|
|
873
|
-
" sat\u0131r \u00B7 PageUp") : null,
|
|
874
|
-
view.map((segs, i) => (React.createElement(Text, { key: i }, segs.length === 0
|
|
875
|
-
? ' '
|
|
876
|
-
: segs.map((s, j) => (React.createElement(Text, { key: j, color: s.dim ? theme.greyDim : s.color, bold: s.bold }, linkify(s.text))))))),
|
|
877
|
-
off > 0 ? React.createElement(Text, { color: theme.greyDim },
|
|
878
|
-
" \u2193 ",
|
|
879
|
-
off,
|
|
880
|
-
" sat\u0131r \u00B7 PageDown / Son") : null,
|
|
881
|
-
streaming && off === 0 ? (React.createElement(Box, { flexDirection: "row" },
|
|
882
|
-
React.createElement(Text, { color: theme.redBright, bold: true }, "\u23FA "),
|
|
883
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
884
|
-
React.createElement(Text, { color: theme.white }, streaming)))) : null));
|
|
885
|
-
})()),
|
|
835
|
+
return (React.createElement(Box, { flexDirection: "column", width: cols },
|
|
836
|
+
React.createElement(Static, { items: items }, (item, i) => React.createElement(RenderItem, { key: i, item: item })),
|
|
837
|
+
streaming ? (React.createElement(Box, { marginTop: 1, flexDirection: "row" },
|
|
838
|
+
React.createElement(Text, { color: theme.redBright, bold: true }, "\u23FA "),
|
|
839
|
+
React.createElement(Box, { flexDirection: "column", flexGrow: 1 },
|
|
840
|
+
React.createElement(MarkdownDisplay, { text: streaming })))) : null,
|
|
886
841
|
perm ? (React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.red, paddingX: 1, marginTop: 1 },
|
|
887
842
|
React.createElement(Text, { color: theme.redBright, bold: true }, t('perm.title', perm.label)),
|
|
888
843
|
permMode === 'feedback' ? (React.createElement(React.Fragment, null,
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// Bağımlılıksız terminal sözdizimi vurgusu (lowlight/highlight.js yerine hafif tokenizer).
|
|
2
|
+
// Kod bloklarını dile göre token'lara böler; her token'a tema rengi atar. Asla patlamaz —
|
|
3
|
+
// tanımadığı dilde ortak kurallarla (string/sayı/yorum/anahtar kelime) renklendirir.
|
|
4
|
+
import { theme } from './theme.js';
|
|
5
|
+
// Dil bazlı anahtar kelime setleri (ortak + spesifik).
|
|
6
|
+
const KW = {
|
|
7
|
+
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'],
|
|
8
|
+
ts: ['interface', 'type', 'enum', 'implements', 'public', 'private', 'protected', 'readonly', 'abstract', 'namespace', 'declare', 'as', 'keyof', 'infer', 'satisfies'],
|
|
9
|
+
py: ['def', 'class', 'return', 'if', 'elif', 'else', 'for', 'while', 'break', 'continue', 'import', 'from', 'as', 'with', 'try', 'except', 'finally', 'raise', 'lambda', 'yield', 'global', 'nonlocal', 'pass', 'assert', 'del', 'in', 'is', 'not', 'and', 'or', 'None', 'True', 'False', 'self', 'async', 'await'],
|
|
10
|
+
bash: ['if', 'then', 'else', 'elif', 'fi', 'for', 'while', 'do', 'done', 'case', 'esac', 'function', 'in', 'return', 'export', 'local', 'echo', 'cd', 'source', 'set', 'unset'],
|
|
11
|
+
go: ['func', 'package', 'import', 'var', 'const', 'type', 'struct', 'interface', 'map', 'chan', 'go', 'defer', 'return', 'if', 'else', 'for', 'range', 'switch', 'case', 'select', 'break', 'continue', 'nil', 'true', 'false'],
|
|
12
|
+
rust: ['fn', 'let', 'mut', 'const', 'struct', 'enum', 'impl', 'trait', 'pub', 'use', 'mod', 'match', 'if', 'else', 'for', 'while', 'loop', 'return', 'self', 'Self', 'where', 'async', 'await', 'move', 'ref', 'true', 'false'],
|
|
13
|
+
java: ['public', 'private', 'protected', 'class', 'interface', 'extends', 'implements', 'static', 'final', 'void', 'new', 'return', 'if', 'else', 'for', 'while', 'switch', 'case', 'break', 'continue', 'try', 'catch', 'finally', 'throw', 'throws', 'import', 'package', 'this', 'super', 'null', 'true', 'false'],
|
|
14
|
+
css: ['important', 'inherit', 'initial', 'auto', 'none', 'flex', 'grid', 'block', 'inline'],
|
|
15
|
+
};
|
|
16
|
+
function langKeywords(lang) {
|
|
17
|
+
const l = (lang || '').toLowerCase();
|
|
18
|
+
const base = [];
|
|
19
|
+
if (l === 'ts' || l === 'tsx' || l === 'typescript')
|
|
20
|
+
base.push(...KW.js, ...KW.ts);
|
|
21
|
+
else if (l === 'js' || l === 'jsx' || l === 'javascript' || l === 'json' || l === 'node')
|
|
22
|
+
base.push(...KW.js);
|
|
23
|
+
else if (l === 'py' || l === 'python')
|
|
24
|
+
base.push(...KW.py);
|
|
25
|
+
else if (l === 'sh' || l === 'bash' || l === 'shell' || l === 'zsh')
|
|
26
|
+
base.push(...KW.bash);
|
|
27
|
+
else if (l === 'go' || l === 'golang')
|
|
28
|
+
base.push(...KW.go);
|
|
29
|
+
else if (l === 'rs' || l === 'rust')
|
|
30
|
+
base.push(...KW.rust);
|
|
31
|
+
else if (l === 'java')
|
|
32
|
+
base.push(...KW.java);
|
|
33
|
+
else if (l === 'css' || l === 'scss')
|
|
34
|
+
base.push(...KW.css);
|
|
35
|
+
else
|
|
36
|
+
base.push(...KW.js, ...KW.py); // bilinmeyen dil → en yaygın iki set
|
|
37
|
+
return new Set(base);
|
|
38
|
+
}
|
|
39
|
+
const lineComment = (lang) => {
|
|
40
|
+
const l = (lang || '').toLowerCase();
|
|
41
|
+
if (['py', 'python', 'sh', 'bash', 'shell', 'zsh', 'yaml', 'yml', 'rb', 'ruby', 'toml'].includes(l))
|
|
42
|
+
return '#';
|
|
43
|
+
return '//';
|
|
44
|
+
};
|
|
45
|
+
// Bir satırı token'lara böl. Basit ama sağlam bir durum makinesi.
|
|
46
|
+
function tokenizeLine(line, kw, lc) {
|
|
47
|
+
const toks = [];
|
|
48
|
+
let i = 0;
|
|
49
|
+
const n = line.length;
|
|
50
|
+
const push = (text, color) => { if (text)
|
|
51
|
+
toks.push({ text, color }); };
|
|
52
|
+
while (i < n) {
|
|
53
|
+
const ch = line[i];
|
|
54
|
+
// satır yorumu (// veya #)
|
|
55
|
+
if (line.startsWith(lc, i)) {
|
|
56
|
+
push(line.slice(i), theme.synComment);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
// dizgi: " ' `
|
|
60
|
+
if (ch === '"' || ch === "'" || ch === '`') {
|
|
61
|
+
let j = i + 1;
|
|
62
|
+
while (j < n && line[j] !== ch) {
|
|
63
|
+
if (line[j] === '\\')
|
|
64
|
+
j++;
|
|
65
|
+
j++;
|
|
66
|
+
}
|
|
67
|
+
push(line.slice(i, Math.min(j + 1, n)), theme.synString);
|
|
68
|
+
i = j + 1;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
// sayı
|
|
72
|
+
if (/[0-9]/.test(ch) && (i === 0 || !/[A-Za-z_]/.test(line[i - 1]))) {
|
|
73
|
+
let j = i;
|
|
74
|
+
while (j < n && /[0-9a-fA-FxX._]/.test(line[j]))
|
|
75
|
+
j++;
|
|
76
|
+
push(line.slice(i, j), theme.synNumber);
|
|
77
|
+
i = j;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
// tanımlayıcı / anahtar kelime
|
|
81
|
+
if (/[A-Za-z_$@]/.test(ch)) {
|
|
82
|
+
let j = i;
|
|
83
|
+
while (j < n && /[A-Za-z0-9_$]/.test(line[j]))
|
|
84
|
+
j++;
|
|
85
|
+
const word = line.slice(i, j);
|
|
86
|
+
const after = line[j];
|
|
87
|
+
if (kw.has(word))
|
|
88
|
+
push(word, theme.synKeyword);
|
|
89
|
+
else if (after === '(')
|
|
90
|
+
push(word, theme.synFunc); // fonksiyon çağrısı
|
|
91
|
+
else if (/^[A-Z]/.test(word))
|
|
92
|
+
push(word, theme.synType); // Tip/Sınıf
|
|
93
|
+
else
|
|
94
|
+
push(word); // düz
|
|
95
|
+
i = j;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
// tek karakter (operatör/noktalama) — düz
|
|
99
|
+
push(ch);
|
|
100
|
+
i++;
|
|
101
|
+
}
|
|
102
|
+
return toks;
|
|
103
|
+
}
|
|
104
|
+
/** Kodu satır-satır token dizilerine çevirir. Her satır Tok[]. */
|
|
105
|
+
export function highlight(code, lang = '') {
|
|
106
|
+
try {
|
|
107
|
+
const kw = langKeywords(lang);
|
|
108
|
+
const lc = lineComment(lang);
|
|
109
|
+
let blockComment = false; // /* ... */ için
|
|
110
|
+
return code.split('\n').map((line) => {
|
|
111
|
+
// çok-satırlı /* */ yorum bloğu (basit destek)
|
|
112
|
+
if (blockComment) {
|
|
113
|
+
const end = line.indexOf('*/');
|
|
114
|
+
if (end === -1)
|
|
115
|
+
return [{ text: line, color: theme.synComment }];
|
|
116
|
+
blockComment = false;
|
|
117
|
+
const rest = tokenizeLine(line.slice(end + 2), kw, lc);
|
|
118
|
+
return [{ text: line.slice(0, end + 2), color: theme.synComment }, ...rest];
|
|
119
|
+
}
|
|
120
|
+
const start = line.indexOf('/*');
|
|
121
|
+
if (start !== -1 && line.indexOf('*/', start) === -1) {
|
|
122
|
+
blockComment = true;
|
|
123
|
+
const pre = tokenizeLine(line.slice(0, start), kw, lc);
|
|
124
|
+
return [...pre, { text: line.slice(start), color: theme.synComment }];
|
|
125
|
+
}
|
|
126
|
+
return tokenizeLine(line, kw, lc);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return code.split('\n').map((l) => [{ text: l, color: theme.synString }]);
|
|
131
|
+
}
|
|
132
|
+
}
|
package/dist/markdown.js
CHANGED
|
@@ -4,6 +4,18 @@ import React from 'react';
|
|
|
4
4
|
import { Text, Box } from 'ink';
|
|
5
5
|
import stringWidth from 'string-width';
|
|
6
6
|
import { theme } from './theme.js';
|
|
7
|
+
import { highlight } from './highlight.js';
|
|
8
|
+
// Kod bloğunu sözdizimi-vurgulu render eder (sol kenarda ince kırmızı çubuk + dil etiketi).
|
|
9
|
+
function CodeBlock({ code, lang }) {
|
|
10
|
+
const hl = highlight(code.join('\n'), lang);
|
|
11
|
+
return (React.createElement(Box, { flexDirection: "column", marginY: 1 },
|
|
12
|
+
lang ? React.createElement(Text, { color: theme.greyDim },
|
|
13
|
+
' ',
|
|
14
|
+
lang) : null,
|
|
15
|
+
hl.map((toks, i) => (React.createElement(Box, { key: i },
|
|
16
|
+
React.createElement(Text, { color: theme.greyDim }, "\u2502 "),
|
|
17
|
+
React.createElement(Text, null, toks.length ? toks.map((tk, j) => React.createElement(Text, { key: j, color: tk.color }, tk.text)) : ' '))))));
|
|
18
|
+
}
|
|
7
19
|
// ── Inline markdown: **bold** *italik* ~~strike~~ `code` [text](url) <u>u</u> url ──
|
|
8
20
|
const INLINE_RE = /(\*\*.*?\*\*|\*.*?\*|_.*?_|~~.*?~~|\[.*?\]\(.*?\)|`+.+?`+|<u>.*?<\/u>|https?:\/\/\S+)/g;
|
|
9
21
|
export function RenderInline({ text }) {
|
|
@@ -122,7 +134,7 @@ export function MarkdownDisplay({ text, width }) {
|
|
|
122
134
|
const blocks = [];
|
|
123
135
|
let key = 0;
|
|
124
136
|
const push = (n) => blocks.push(React.createElement(React.Fragment, { key: key++ }, n));
|
|
125
|
-
let inCode = false, codeFence = '', codeLines = [];
|
|
137
|
+
let inCode = false, codeFence = '', codeLang = '', codeLines = [];
|
|
126
138
|
let inTable = false, tHeaders = [], tRows = [];
|
|
127
139
|
const flushTable = () => { if (tHeaders.length)
|
|
128
140
|
push(React.createElement(Table, { headers: tHeaders, rows: tRows, width: W })); inTable = false; tHeaders = []; tRows = []; };
|
|
@@ -137,9 +149,10 @@ export function MarkdownDisplay({ text, width }) {
|
|
|
137
149
|
if (inCode) {
|
|
138
150
|
const fm = line.match(fenceRe);
|
|
139
151
|
if (fm && fm[1][0] === codeFence[0] && fm[1].length >= codeFence.length) {
|
|
140
|
-
push(React.createElement(
|
|
152
|
+
push(React.createElement(CodeBlock, { code: codeLines, lang: codeLang }));
|
|
141
153
|
inCode = false;
|
|
142
154
|
codeFence = '';
|
|
155
|
+
codeLang = '';
|
|
143
156
|
codeLines = [];
|
|
144
157
|
}
|
|
145
158
|
else
|
|
@@ -153,6 +166,7 @@ export function MarkdownDisplay({ text, width }) {
|
|
|
153
166
|
flushTable();
|
|
154
167
|
inCode = true;
|
|
155
168
|
codeFence = fm[1];
|
|
169
|
+
codeLang = (fm[2] || '').trim();
|
|
156
170
|
return;
|
|
157
171
|
}
|
|
158
172
|
if (rm && !inTable) {
|
|
@@ -214,7 +228,7 @@ export function MarkdownDisplay({ text, width }) {
|
|
|
214
228
|
React.createElement(RenderInline, { text: line })));
|
|
215
229
|
});
|
|
216
230
|
if (inCode)
|
|
217
|
-
push(React.createElement(
|
|
231
|
+
push(React.createElement(CodeBlock, { code: codeLines, lang: codeLang }));
|
|
218
232
|
if (inTable)
|
|
219
233
|
flushTable();
|
|
220
234
|
return React.createElement(Box, { flexDirection: "column" }, blocks);
|
package/dist/theme.js
CHANGED
|
@@ -7,5 +7,13 @@ export const theme = {
|
|
|
7
7
|
greyDim: '#666666',
|
|
8
8
|
green: '#4ade80',
|
|
9
9
|
errorRed: '#ff6b6b',
|
|
10
|
+
// ── Sözdizimi vurgusu (kod blokları) ──
|
|
11
|
+
synKeyword: '#ff5c5c', // anahtar kelimeler (if, function, def…) — marka kırmızısı
|
|
12
|
+
synString: '#4ade80', // dizgiler "…" '…' `…`
|
|
13
|
+
synNumber: '#f0b429', // sayılar
|
|
14
|
+
synComment: '#666666', // yorumlar
|
|
15
|
+
synFunc: '#4fc3f7', // fonksiyon/metot adları
|
|
16
|
+
synType: '#a78bfa', // tip/sınıf adları, sabitler
|
|
17
|
+
synProp: '#e0e0e0', // özellik/anahtar adları
|
|
10
18
|
};
|
|
11
|
-
export const VERSION = '1.0.
|
|
19
|
+
export const VERSION = '1.0.21';
|