wormclaude 1.0.48 → 1.0.50
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 +1 -1
- package/dist/tui.js +100 -23
- package/package.json +1 -1
package/dist/theme.js
CHANGED
package/dist/tui.js
CHANGED
|
@@ -6,13 +6,20 @@
|
|
|
6
6
|
import readline from 'node:readline';
|
|
7
7
|
import stringWidth from 'string-width';
|
|
8
8
|
import { loadConfig, streamChat, fetchAccount } from './api.js';
|
|
9
|
-
import { allToolSchemas, executeToolCalls, toolLabel, setToolConfig } from './tools.js';
|
|
9
|
+
import { allToolSchemas, executeToolCalls, executeTool, toolLabel, setToolConfig } from './tools.js';
|
|
10
10
|
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
14
|
import { COMMANDS, runSlashCommand } from './commands.js';
|
|
15
15
|
import { cmdDesc } from './i18n.js';
|
|
16
|
+
import { getSkill, getSkills, buildSkillPrompt } from './skills.js';
|
|
17
|
+
import { getExtCommand, getExtCommands, buildExtCommandPrompt } from './extensions.js';
|
|
18
|
+
import { resolveAtMentions } from './atmention.js';
|
|
19
|
+
import { loadMemoryContext, shouldExtract, triggerMemory } from './memory.js';
|
|
20
|
+
import { shouldAutoCompact, runCompact } from './compact.js';
|
|
21
|
+
import { recordLearned } from './learn.js';
|
|
22
|
+
import { connectMcpServers } from './mcp.js';
|
|
16
23
|
const RESET = '\x1b[0m';
|
|
17
24
|
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` : ''; };
|
|
18
25
|
const paint = (s, c, bold = false) => `${bold ? '\x1b[1m' : ''}${c ? hex(c) : ''}${s}${RESET}`;
|
|
@@ -49,8 +56,11 @@ export async function runTui() {
|
|
|
49
56
|
const _winNote = process.platform === 'win32'
|
|
50
57
|
? ' This is WINDOWS. Write files to the CURRENT directory (relative paths) or under C:\\Users\\... — NEVER use /home/user or other Unix paths. The Bash tool runs via cmd.exe (use Windows commands).'
|
|
51
58
|
: ' Use POSIX paths.';
|
|
59
|
+
const _memCtx = loadMemoryContext(); // WORMCLAUDE.md + .wormclaude/memory.md
|
|
60
|
+
const _sysCount = _memCtx ? 2 : 1; // başlangıç sistem mesajı sayısı (clear bunları korur)
|
|
52
61
|
const history = [
|
|
53
62
|
{ role: 'system', content: `ENVIRONMENT: The user machine runs ${_plat}. Current working directory: ${process.cwd()}.${_winNote}` },
|
|
63
|
+
...(_memCtx ? [{ role: 'system', content: _memCtx }] : []),
|
|
54
64
|
];
|
|
55
65
|
const displayItems = [{ kind: 'banner' }];
|
|
56
66
|
let inputBuf = '', busy = false, streamChars = 0, spin = 0;
|
|
@@ -94,12 +104,18 @@ export async function runTui() {
|
|
|
94
104
|
const inputHistory = []; // gönderilen mesajlar (↑/↓ ile geri çağrılır)
|
|
95
105
|
let histIdx = -1; // -1 = geçmişte gezinmiyor
|
|
96
106
|
let cmdSel = 0; // slash menüde seçili komut
|
|
107
|
+
// Tüm komutlar: yerleşik + skill + extension
|
|
108
|
+
const allCmds = () => [
|
|
109
|
+
...COMMANDS,
|
|
110
|
+
...getSkills().map((s) => ({ name: '/' + s.name, desc: s.description })),
|
|
111
|
+
...getExtCommands().map((c) => ({ name: '/' + c.name, desc: c.description })),
|
|
112
|
+
];
|
|
97
113
|
// Slash menü: "/" ile başlayan girişe uyan komutlar
|
|
98
114
|
const cmdMatches = () => {
|
|
99
115
|
if (busy || !inputBuf.startsWith('/'))
|
|
100
116
|
return [];
|
|
101
117
|
const tok = inputBuf.split(' ')[0];
|
|
102
|
-
return
|
|
118
|
+
return allCmds().filter((c) => c.name.startsWith(tok));
|
|
103
119
|
};
|
|
104
120
|
// Slash komutları için bağlam (cli.tsx ile aynı arayüz) — /clear,/config,/model,/memory,/program…
|
|
105
121
|
const cmdCtx = {
|
|
@@ -108,7 +124,7 @@ export async function runTui() {
|
|
|
108
124
|
setHistory: (h) => { history.length = 0; history.push(...h); },
|
|
109
125
|
note: (text) => printItem({ kind: 'note', text }),
|
|
110
126
|
assistant: (text) => printItem({ kind: 'assistant', text }),
|
|
111
|
-
clearConv: () => { history.length =
|
|
127
|
+
clearConv: () => { history.length = _sysCount; displayItems.length = 1; redrawAll(); }, // sistem mesajları + banner kalır
|
|
112
128
|
exit: () => quit(),
|
|
113
129
|
};
|
|
114
130
|
async function runCommand(v) {
|
|
@@ -170,11 +186,13 @@ export async function runTui() {
|
|
|
170
186
|
const inputLines = inputBoxLines(W); // çok-satırlı giriş (sarılmış)
|
|
171
187
|
const m = cmdMatches();
|
|
172
188
|
if (m.length) {
|
|
173
|
-
// DİKEY slash menü (
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
const
|
|
177
|
-
|
|
189
|
+
// DİKEY slash menü — KAYAN pencere (8 satır, seçimi takip eder), seçili kırmızı.
|
|
190
|
+
const sel = Math.min(cmdSel, m.length - 1);
|
|
191
|
+
const WIN = 8;
|
|
192
|
+
const start = Math.max(0, Math.min(sel - 3, m.length - WIN));
|
|
193
|
+
const view = m.slice(start, start + WIN);
|
|
194
|
+
const menu = view.map((c, i) => {
|
|
195
|
+
const on = (start + i) === sel;
|
|
178
196
|
return ' ' + paint((on ? '✶ ' : ' ') + c.name.padEnd(13), on ? theme.redBright : theme.grey) + paint(cmdDesc(c.name) || c.desc || '', theme.greyDim);
|
|
179
197
|
});
|
|
180
198
|
body = [...menu, line, ...inputLines, line];
|
|
@@ -208,16 +226,28 @@ export async function runTui() {
|
|
|
208
226
|
const printItem = (it) => { displayItems.push(it); process.stdout.write(itemAnsi(it, cols()) + '\n'); refresh(); };
|
|
209
227
|
// ── Agent döngüsü (M2: araçlar + izin). Model tool çağırırsa izin sorulup çalıştırılır,
|
|
210
228
|
// sonuç geçmişe eklenip döngü devam eder; tool yoksa biter. ──
|
|
211
|
-
async function runTurn(userText) {
|
|
229
|
+
async function runTurn(userText, displayText) {
|
|
212
230
|
busy = true;
|
|
213
231
|
streamChars = 0;
|
|
232
|
+
if (displayText !== undefined)
|
|
233
|
+
printItem({ kind: 'user', text: displayText }); // skill/@mention: gösterim farklı
|
|
214
234
|
history.push({ role: 'user', content: userText });
|
|
215
235
|
const timer = setInterval(() => { spin++; if (busy && !perm)
|
|
216
236
|
refresh(); }, 120);
|
|
217
|
-
let lastSig = '', sameCount = 0;
|
|
237
|
+
let lastSig = '', sameCount = 0, usedWeb = false, lastAnswer = '';
|
|
218
238
|
try {
|
|
219
239
|
for (let iter = 0; iter < 25; iter++) {
|
|
220
240
|
streamChars = 0;
|
|
241
|
+
// Oto-compact: bağlam eşiği aşılınca otomatik özetle (uzun sohbet patlamasın)
|
|
242
|
+
if (shouldAutoCompact(history)) {
|
|
243
|
+
try {
|
|
244
|
+
const { history: nh } = await runCompact(history, config);
|
|
245
|
+
history.length = 0;
|
|
246
|
+
history.push(...nh);
|
|
247
|
+
printItem({ kind: 'note', text: '✎ bağlam otomatik özetlendi' });
|
|
248
|
+
}
|
|
249
|
+
catch { }
|
|
250
|
+
}
|
|
221
251
|
let answer = '';
|
|
222
252
|
let toolCalls = [];
|
|
223
253
|
for await (const ev of streamChat(history, allToolSchemas(), config)) {
|
|
@@ -237,8 +267,10 @@ export async function runTui() {
|
|
|
237
267
|
if (toolCalls.length)
|
|
238
268
|
am.tool_calls = toolCalls.map((t) => ({ id: t.id, type: 'function', function: { name: t.name, arguments: t.args || '{}' } }));
|
|
239
269
|
history.push(am);
|
|
240
|
-
if (answer)
|
|
270
|
+
if (answer) {
|
|
271
|
+
lastAnswer = answer;
|
|
241
272
|
printItem({ kind: 'assistant', text: answer });
|
|
273
|
+
}
|
|
242
274
|
if (!toolCalls.length)
|
|
243
275
|
break;
|
|
244
276
|
// takılma koruması: aynı araç-çağrısı 3 kez üst üste → dur
|
|
@@ -260,7 +292,8 @@ export async function runTui() {
|
|
|
260
292
|
perm = { label: toolLabel(c.name, args), name: c.name, resolve };
|
|
261
293
|
refresh();
|
|
262
294
|
}),
|
|
263
|
-
onResult: (c, _i, res) =>
|
|
295
|
+
onResult: (c, _i, res) => { if ((c.name === 'WebSearch' || c.name === 'WebFetch') && res.ok)
|
|
296
|
+
usedWeb = true; printItem({ kind: 'tool', label: toolLabel(c.name, res.args), result: sanitizeOutput(res.output), ok: res.ok }); },
|
|
264
297
|
});
|
|
265
298
|
for (let i = 0; i < toolCalls.length; i++)
|
|
266
299
|
history.push({ role: 'tool', tool_call_id: toolCalls[i].id, content: (results[i].output || '').slice(0, 8000) });
|
|
@@ -273,6 +306,15 @@ export async function runTui() {
|
|
|
273
306
|
busy = false;
|
|
274
307
|
perm = null;
|
|
275
308
|
refresh();
|
|
309
|
+
// Web-öğrenme: web'de arayıp cevap ürettiyse {soru→cevap}'ı eğitim datasına ekle
|
|
310
|
+
if (usedWeb && lastAnswer) {
|
|
311
|
+
const sources = (lastAnswer.match(/https?:\/\/[^\s<>"')\]]+/g) || []).slice(0, 8);
|
|
312
|
+
if (recordLearned(userText, lastAnswer, sources, config))
|
|
313
|
+
printItem({ kind: 'note', text: '✎ eğitim datasına eklendi' });
|
|
314
|
+
}
|
|
315
|
+
// Oto-hafıza: eşik geçildiyse arka planda hafızayı güncelle
|
|
316
|
+
if (shouldExtract(history))
|
|
317
|
+
triggerMemory(history, config);
|
|
276
318
|
}
|
|
277
319
|
// ── Kurulum ──
|
|
278
320
|
readline.emitKeypressEvents(process.stdin);
|
|
@@ -288,6 +330,8 @@ export async function runTui() {
|
|
|
288
330
|
account = a;
|
|
289
331
|
redrawAll();
|
|
290
332
|
} }).catch(() => { });
|
|
333
|
+
connectMcpServers().then((srv) => { if (srv && srv.length)
|
|
334
|
+
printItem({ kind: 'note', text: `🔌 ${srv.length} MCP sunucusu bağlandı` }); }).catch(() => { }); // MCP araçları (varsa)
|
|
291
335
|
const quit = () => { process.stdout.write('\x1b[r\x1b[?25h\x1b[2J\x1b[3J\x1b[H'); process.exit(0); };
|
|
292
336
|
process.on('exit', () => { try {
|
|
293
337
|
process.stdout.write('\x1b[r\x1b[?25h');
|
|
@@ -394,18 +438,35 @@ export async function runTui() {
|
|
|
394
438
|
refresh();
|
|
395
439
|
return;
|
|
396
440
|
}
|
|
397
|
-
|
|
441
|
+
inputHistory.push(v);
|
|
442
|
+
// ! shell modu — LLM'siz doğrudan shell komutu; çıktıyı modele bağlam olarak ekle
|
|
443
|
+
if (v.startsWith('!') && v.length > 1) {
|
|
444
|
+
const cmd = v.slice(1).trim();
|
|
445
|
+
printItem({ kind: 'user', text: v });
|
|
446
|
+
busy = true;
|
|
447
|
+
refresh();
|
|
448
|
+
executeTool('Bash', { command: cmd }).then((res) => {
|
|
449
|
+
printItem({ kind: 'tool', label: `! ${cmd.slice(0, 60)}`, result: sanitizeOutput(res.output), ok: res.ok });
|
|
450
|
+
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\`\`\`` });
|
|
451
|
+
}).catch((e) => printItem({ kind: 'note', text: 'Komut hatası: ' + (e?.message || e) }))
|
|
452
|
+
.finally(() => { busy = false; refresh(); });
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
398
455
|
if (v.startsWith('/')) {
|
|
399
|
-
const
|
|
400
|
-
|
|
401
|
-
if (!
|
|
402
|
-
|
|
456
|
+
const tok0 = v.split(' ')[0];
|
|
457
|
+
// tam eşleşme yoksa menüde SEÇİLİ olanı kullan (skill/ext dahil), argümanları koru
|
|
458
|
+
if (!allCmds().some((c) => c.name === tok0)) {
|
|
459
|
+
const ms = allCmds().filter((c) => c.name.startsWith(tok0));
|
|
460
|
+
if (ms.length)
|
|
461
|
+
v = ms[Math.min(cmdSel, ms.length - 1)].name + v.slice(tok0.length);
|
|
462
|
+
}
|
|
403
463
|
cmdSel = 0;
|
|
404
|
-
|
|
464
|
+
const tok = v.split(' ')[0];
|
|
465
|
+
if (tok === '/cikis' || tok === '/exit' || tok === '/quit') {
|
|
405
466
|
quit();
|
|
406
467
|
return;
|
|
407
468
|
}
|
|
408
|
-
if (
|
|
469
|
+
if (tok === '/kopyala' || tok === '/copy') {
|
|
409
470
|
const last = [...history].reverse().find((mm) => mm.role === 'assistant');
|
|
410
471
|
if (last) {
|
|
411
472
|
process.stdout.write(`\x1b]52;c;${Buffer.from(last.content, 'utf8').toString('base64')}\x07`);
|
|
@@ -415,13 +476,29 @@ export async function runTui() {
|
|
|
415
476
|
printItem({ kind: 'note', text: 'Kopyalanacak yanıt yok.' });
|
|
416
477
|
return;
|
|
417
478
|
}
|
|
418
|
-
|
|
479
|
+
const builtin = COMMANDS.some((c) => c.name === tok);
|
|
480
|
+
const skill = !builtin ? getSkill(tok.slice(1)) : undefined;
|
|
481
|
+
if (skill) {
|
|
482
|
+
const a = v.slice(tok.length).trim();
|
|
483
|
+
runTurn(buildSkillPrompt(skill, a), `/${skill.name}${a ? ' ' + a : ''}`);
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
const ext = (!builtin && !skill) ? getExtCommand(tok.slice(1)) : undefined;
|
|
487
|
+
if (ext) {
|
|
488
|
+
const a = v.slice(tok.length).trim();
|
|
489
|
+
runTurn(buildExtCommandPrompt(ext, a), `/${ext.name}${a ? ' ' + a : ''}`);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
419
492
|
runCommand(v);
|
|
420
493
|
return;
|
|
421
494
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
495
|
+
// @dosya mention — referanslanan dosya içeriğini modele enjekte et, kullanıcıya orijinali göster
|
|
496
|
+
const at = resolveAtMentions(v);
|
|
497
|
+
if (at.files.length) {
|
|
498
|
+
runTurn(at.augmented, v);
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
runTurn(v, v);
|
|
425
502
|
return;
|
|
426
503
|
}
|
|
427
504
|
if (key && key.name === 'backspace') {
|