wormclaude 1.0.48 → 1.0.49
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 +93 -18
- 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) {
|
|
@@ -208,16 +224,28 @@ export async function runTui() {
|
|
|
208
224
|
const printItem = (it) => { displayItems.push(it); process.stdout.write(itemAnsi(it, cols()) + '\n'); refresh(); };
|
|
209
225
|
// ── Agent döngüsü (M2: araçlar + izin). Model tool çağırırsa izin sorulup çalıştırılır,
|
|
210
226
|
// sonuç geçmişe eklenip döngü devam eder; tool yoksa biter. ──
|
|
211
|
-
async function runTurn(userText) {
|
|
227
|
+
async function runTurn(userText, displayText) {
|
|
212
228
|
busy = true;
|
|
213
229
|
streamChars = 0;
|
|
230
|
+
if (displayText !== undefined)
|
|
231
|
+
printItem({ kind: 'user', text: displayText }); // skill/@mention: gösterim farklı
|
|
214
232
|
history.push({ role: 'user', content: userText });
|
|
215
233
|
const timer = setInterval(() => { spin++; if (busy && !perm)
|
|
216
234
|
refresh(); }, 120);
|
|
217
|
-
let lastSig = '', sameCount = 0;
|
|
235
|
+
let lastSig = '', sameCount = 0, usedWeb = false, lastAnswer = '';
|
|
218
236
|
try {
|
|
219
237
|
for (let iter = 0; iter < 25; iter++) {
|
|
220
238
|
streamChars = 0;
|
|
239
|
+
// Oto-compact: bağlam eşiği aşılınca otomatik özetle (uzun sohbet patlamasın)
|
|
240
|
+
if (shouldAutoCompact(history)) {
|
|
241
|
+
try {
|
|
242
|
+
const { history: nh } = await runCompact(history, config);
|
|
243
|
+
history.length = 0;
|
|
244
|
+
history.push(...nh);
|
|
245
|
+
printItem({ kind: 'note', text: '✎ bağlam otomatik özetlendi' });
|
|
246
|
+
}
|
|
247
|
+
catch { }
|
|
248
|
+
}
|
|
221
249
|
let answer = '';
|
|
222
250
|
let toolCalls = [];
|
|
223
251
|
for await (const ev of streamChat(history, allToolSchemas(), config)) {
|
|
@@ -237,8 +265,10 @@ export async function runTui() {
|
|
|
237
265
|
if (toolCalls.length)
|
|
238
266
|
am.tool_calls = toolCalls.map((t) => ({ id: t.id, type: 'function', function: { name: t.name, arguments: t.args || '{}' } }));
|
|
239
267
|
history.push(am);
|
|
240
|
-
if (answer)
|
|
268
|
+
if (answer) {
|
|
269
|
+
lastAnswer = answer;
|
|
241
270
|
printItem({ kind: 'assistant', text: answer });
|
|
271
|
+
}
|
|
242
272
|
if (!toolCalls.length)
|
|
243
273
|
break;
|
|
244
274
|
// takılma koruması: aynı araç-çağrısı 3 kez üst üste → dur
|
|
@@ -260,7 +290,8 @@ export async function runTui() {
|
|
|
260
290
|
perm = { label: toolLabel(c.name, args), name: c.name, resolve };
|
|
261
291
|
refresh();
|
|
262
292
|
}),
|
|
263
|
-
onResult: (c, _i, res) =>
|
|
293
|
+
onResult: (c, _i, res) => { if ((c.name === 'WebSearch' || c.name === 'WebFetch') && res.ok)
|
|
294
|
+
usedWeb = true; printItem({ kind: 'tool', label: toolLabel(c.name, res.args), result: sanitizeOutput(res.output), ok: res.ok }); },
|
|
264
295
|
});
|
|
265
296
|
for (let i = 0; i < toolCalls.length; i++)
|
|
266
297
|
history.push({ role: 'tool', tool_call_id: toolCalls[i].id, content: (results[i].output || '').slice(0, 8000) });
|
|
@@ -273,6 +304,15 @@ export async function runTui() {
|
|
|
273
304
|
busy = false;
|
|
274
305
|
perm = null;
|
|
275
306
|
refresh();
|
|
307
|
+
// Web-öğrenme: web'de arayıp cevap ürettiyse {soru→cevap}'ı eğitim datasına ekle
|
|
308
|
+
if (usedWeb && lastAnswer) {
|
|
309
|
+
const sources = (lastAnswer.match(/https?:\/\/[^\s<>"')\]]+/g) || []).slice(0, 8);
|
|
310
|
+
if (recordLearned(userText, lastAnswer, sources, config))
|
|
311
|
+
printItem({ kind: 'note', text: '✎ eğitim datasına eklendi' });
|
|
312
|
+
}
|
|
313
|
+
// Oto-hafıza: eşik geçildiyse arka planda hafızayı güncelle
|
|
314
|
+
if (shouldExtract(history))
|
|
315
|
+
triggerMemory(history, config);
|
|
276
316
|
}
|
|
277
317
|
// ── Kurulum ──
|
|
278
318
|
readline.emitKeypressEvents(process.stdin);
|
|
@@ -288,6 +328,8 @@ export async function runTui() {
|
|
|
288
328
|
account = a;
|
|
289
329
|
redrawAll();
|
|
290
330
|
} }).catch(() => { });
|
|
331
|
+
connectMcpServers().then((srv) => { if (srv && srv.length)
|
|
332
|
+
printItem({ kind: 'note', text: `🔌 ${srv.length} MCP sunucusu bağlandı` }); }).catch(() => { }); // MCP araçları (varsa)
|
|
291
333
|
const quit = () => { process.stdout.write('\x1b[r\x1b[?25h\x1b[2J\x1b[3J\x1b[H'); process.exit(0); };
|
|
292
334
|
process.on('exit', () => { try {
|
|
293
335
|
process.stdout.write('\x1b[r\x1b[?25h');
|
|
@@ -394,18 +436,35 @@ export async function runTui() {
|
|
|
394
436
|
refresh();
|
|
395
437
|
return;
|
|
396
438
|
}
|
|
397
|
-
|
|
439
|
+
inputHistory.push(v);
|
|
440
|
+
// ! shell modu — LLM'siz doğrudan shell komutu; çıktıyı modele bağlam olarak ekle
|
|
441
|
+
if (v.startsWith('!') && v.length > 1) {
|
|
442
|
+
const cmd = v.slice(1).trim();
|
|
443
|
+
printItem({ kind: 'user', text: v });
|
|
444
|
+
busy = true;
|
|
445
|
+
refresh();
|
|
446
|
+
executeTool('Bash', { command: cmd }).then((res) => {
|
|
447
|
+
printItem({ kind: 'tool', label: `! ${cmd.slice(0, 60)}`, result: sanitizeOutput(res.output), ok: res.ok });
|
|
448
|
+
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\`\`\`` });
|
|
449
|
+
}).catch((e) => printItem({ kind: 'note', text: 'Komut hatası: ' + (e?.message || e) }))
|
|
450
|
+
.finally(() => { busy = false; refresh(); });
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
398
453
|
if (v.startsWith('/')) {
|
|
399
|
-
const
|
|
400
|
-
|
|
401
|
-
if (!
|
|
402
|
-
|
|
454
|
+
const tok0 = v.split(' ')[0];
|
|
455
|
+
// tam eşleşme yoksa menüde SEÇİLİ olanı kullan (skill/ext dahil), argümanları koru
|
|
456
|
+
if (!allCmds().some((c) => c.name === tok0)) {
|
|
457
|
+
const ms = allCmds().filter((c) => c.name.startsWith(tok0));
|
|
458
|
+
if (ms.length)
|
|
459
|
+
v = ms[Math.min(cmdSel, ms.length - 1)].name + v.slice(tok0.length);
|
|
460
|
+
}
|
|
403
461
|
cmdSel = 0;
|
|
404
|
-
|
|
462
|
+
const tok = v.split(' ')[0];
|
|
463
|
+
if (tok === '/cikis' || tok === '/exit' || tok === '/quit') {
|
|
405
464
|
quit();
|
|
406
465
|
return;
|
|
407
466
|
}
|
|
408
|
-
if (
|
|
467
|
+
if (tok === '/kopyala' || tok === '/copy') {
|
|
409
468
|
const last = [...history].reverse().find((mm) => mm.role === 'assistant');
|
|
410
469
|
if (last) {
|
|
411
470
|
process.stdout.write(`\x1b]52;c;${Buffer.from(last.content, 'utf8').toString('base64')}\x07`);
|
|
@@ -415,13 +474,29 @@ export async function runTui() {
|
|
|
415
474
|
printItem({ kind: 'note', text: 'Kopyalanacak yanıt yok.' });
|
|
416
475
|
return;
|
|
417
476
|
}
|
|
418
|
-
|
|
477
|
+
const builtin = COMMANDS.some((c) => c.name === tok);
|
|
478
|
+
const skill = !builtin ? getSkill(tok.slice(1)) : undefined;
|
|
479
|
+
if (skill) {
|
|
480
|
+
const a = v.slice(tok.length).trim();
|
|
481
|
+
runTurn(buildSkillPrompt(skill, a), `/${skill.name}${a ? ' ' + a : ''}`);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
const ext = (!builtin && !skill) ? getExtCommand(tok.slice(1)) : undefined;
|
|
485
|
+
if (ext) {
|
|
486
|
+
const a = v.slice(tok.length).trim();
|
|
487
|
+
runTurn(buildExtCommandPrompt(ext, a), `/${ext.name}${a ? ' ' + a : ''}`);
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
419
490
|
runCommand(v);
|
|
420
491
|
return;
|
|
421
492
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
493
|
+
// @dosya mention — referanslanan dosya içeriğini modele enjekte et, kullanıcıya orijinali göster
|
|
494
|
+
const at = resolveAtMentions(v);
|
|
495
|
+
if (at.files.length) {
|
|
496
|
+
runTurn(at.augmented, v);
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
runTurn(v, v);
|
|
425
500
|
return;
|
|
426
501
|
}
|
|
427
502
|
if (key && key.name === 'backspace') {
|