wormclaude 1.0.151 → 1.0.153
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/api.js +1 -0
- package/dist/auth.js +22 -24
- package/dist/cli.js +8 -4
- package/dist/commands.js +30 -1
- package/dist/i18n.js +2 -0
- package/dist/theme.js +1 -1
- package/dist/tui.js +11 -1
- package/package.json +1 -1
package/dist/api.js
CHANGED
|
@@ -151,6 +151,7 @@ export async function* streamChat(messages, tools, config, signal) {
|
|
|
151
151
|
method: 'POST',
|
|
152
152
|
headers: {
|
|
153
153
|
'Content-Type': 'application/json',
|
|
154
|
+
'X-WormClaude-Client': 'cli', // gateway: CLI kullanımı abonelik kovasından düşer (çıplak API = API cüzdanı)
|
|
154
155
|
...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}),
|
|
155
156
|
...(getTrace() ? { 'X-WC-Trace': getTrace(), 'X-WC-Session': getSession() } : {}),
|
|
156
157
|
},
|
package/dist/auth.js
CHANGED
|
@@ -4,6 +4,9 @@ import * as path from 'node:path';
|
|
|
4
4
|
import * as os from 'node:os';
|
|
5
5
|
import * as readline from 'node:readline';
|
|
6
6
|
import { spawn } from 'node:child_process';
|
|
7
|
+
import { getLang } from './i18n.js';
|
|
8
|
+
// Kullanıcıya gösterilen metin: VARSAYILAN İngilizce; yalnız dil 'tr' ise Türkçe.
|
|
9
|
+
const tt = (en, tr) => (getLang() === 'tr' ? tr : en);
|
|
7
10
|
export const CONFIG_DIR = path.join(os.homedir(), '.wormclaude');
|
|
8
11
|
export const CONFIG_PATH = path.join(CONFIG_DIR, 'config.json');
|
|
9
12
|
// Müşteriler bunu değiştirmesin diye varsayılan public API.
|
|
@@ -36,24 +39,26 @@ export function clearStored() {
|
|
|
36
39
|
export async function loginWithKey(rawKey) {
|
|
37
40
|
const key = (rawKey || '').trim();
|
|
38
41
|
if (!key) {
|
|
39
|
-
process.stdout.write('\n Anahtar boş. Kullanım: wormclaude login --key <ANAHTAR
|
|
42
|
+
process.stdout.write('\n ' + tt('Empty key. Usage: wormclaude login --key <KEY>', 'Anahtar boş. Kullanım: wormclaude login --key <ANAHTAR>') + '\n\n');
|
|
40
43
|
process.exit(1);
|
|
41
44
|
}
|
|
42
45
|
const base = process.env.WORMCLAUDE_BASE_URL || DEFAULT_BASE_URL;
|
|
43
|
-
process.stdout.write(' Anahtar doğrulanıyor...');
|
|
46
|
+
process.stdout.write(' ' + tt('Validating key...', 'Anahtar doğrulanıyor...'));
|
|
44
47
|
try {
|
|
45
48
|
const r = await fetch(`${base}/account`, { headers: { Authorization: `Bearer ${key}` } });
|
|
46
49
|
if (!r.ok) {
|
|
47
|
-
process.stdout.write('\n\n \x1b[31m✗ Anahtar geçersiz\x1b[0m (HTTP ' + r.status + ').
|
|
50
|
+
process.stdout.write('\n\n \x1b[31m' + tt('✗ Invalid key', '✗ Anahtar geçersiz') + '\x1b[0m (HTTP ' + r.status + '). ' +
|
|
51
|
+
tt('Copy the correct key from web Settings → API.', 'Web Ayarlar → API\'den doğru anahtarı kopyala.') + '\n\n');
|
|
48
52
|
process.exit(1);
|
|
49
53
|
}
|
|
50
54
|
}
|
|
51
55
|
catch (e) {
|
|
52
|
-
process.stdout.write('\n\n Sunucuya ulaşılamadı: ' + (e?.message || e) + '\n\n');
|
|
56
|
+
process.stdout.write('\n\n ' + tt('Could not reach the server: ', 'Sunucuya ulaşılamadı: ') + (e?.message || e) + '\n\n');
|
|
53
57
|
process.exit(1);
|
|
54
58
|
}
|
|
55
59
|
saveStored({ baseUrl: base, apiKey: key, model: 'wormclaude-v2' });
|
|
56
|
-
process.stdout.write('\n\n \x1b[32m✓ Giriş başarıl
|
|
60
|
+
process.stdout.write('\n\n \x1b[32m' + tt('✓ Signed in!', '✓ Giriş başarılı!') + '\x1b[0m ' +
|
|
61
|
+
tt('You can now use `wormclaude`.', 'Artık `wormclaude` yazarak kullanabilirsiniz.') + '\n\n');
|
|
57
62
|
}
|
|
58
63
|
// baseUrl ".../v1" → device endpoint'leri için kök (".../v1" olmadan)
|
|
59
64
|
function apiOrigin(baseUrl) {
|
|
@@ -135,8 +140,8 @@ export function runUpdate() {
|
|
|
135
140
|
// ↑/↓ ok tuşlarıyla gezin, Enter ile seç. (1/2 tuşları da çalışır.)
|
|
136
141
|
export function promptLoginMenu() {
|
|
137
142
|
const items = [
|
|
138
|
-
{ label: 'Giriş yap', value: 'login' },
|
|
139
|
-
{ label: 'Çıkış', value: 'exit' },
|
|
143
|
+
{ label: tt('Log in', 'Giriş yap'), value: 'login' },
|
|
144
|
+
{ label: tt('Exit', 'Çıkış'), value: 'exit' },
|
|
140
145
|
];
|
|
141
146
|
return new Promise((resolve) => {
|
|
142
147
|
const stdin = process.stdin;
|
|
@@ -148,7 +153,7 @@ export function promptLoginMenu() {
|
|
|
148
153
|
}
|
|
149
154
|
let idx = 0;
|
|
150
155
|
process.stdout.write('\n \x1b[1mWormClaude\x1b[0m\n');
|
|
151
|
-
process.stdout.write(' \x1b[2m↑/↓ ile seç · Enter ile onayla\x1b[0m\n\n');
|
|
156
|
+
process.stdout.write(' \x1b[2m' + tt('↑/↓ to select · Enter to confirm', '↑/↓ ile seç · Enter ile onayla') + '\x1b[0m\n\n');
|
|
152
157
|
const draw = (first) => {
|
|
153
158
|
if (!first)
|
|
154
159
|
process.stdout.write(`\x1b[${items.length}A`); // imleci listenin başına al
|
|
@@ -217,17 +222,17 @@ export async function deviceLogin() {
|
|
|
217
222
|
start = await r.json();
|
|
218
223
|
}
|
|
219
224
|
catch (e) {
|
|
220
|
-
process.stderr.write('Giriş başlatılamadı: ' + (e?.message || e) + '\n');
|
|
225
|
+
process.stderr.write(tt('Could not start login: ', 'Giriş başlatılamadı: ') + (e?.message || e) + '\n');
|
|
221
226
|
process.exit(1);
|
|
222
227
|
}
|
|
223
228
|
const url = start.verification_uri_complete || start.verification_uri;
|
|
224
229
|
const deviceCode = start.device_code;
|
|
225
230
|
openBrowser(url);
|
|
226
|
-
process.stdout.write('\n Tarayıcıda Google ile giriş yapın
|
|
227
|
-
process.stdout.write(' \x1b[2m(tarayıcı açılmadıysa: ' + url + ')\x1b[0m\n\n');
|
|
231
|
+
process.stdout.write('\n ' + tt('Sign in with Google in your browser...', 'Tarayıcıda Google ile giriş yapın...') + '\n');
|
|
232
|
+
process.stdout.write(' \x1b[2m(' + tt('if the browser did not open: ', 'tarayıcı açılmadıysa: ') + url + ')\x1b[0m\n\n');
|
|
228
233
|
const pollMs = Math.max(2, Number(start.interval) || 3) * 1000;
|
|
229
234
|
const deadline = Date.now() + (Number(start.expires_in) || 600) * 1000;
|
|
230
|
-
process.stdout.write(' Bekleniyor');
|
|
235
|
+
process.stdout.write(' ' + tt('Waiting', 'Bekleniyor'));
|
|
231
236
|
while (Date.now() < deadline) {
|
|
232
237
|
await sleep(pollMs);
|
|
233
238
|
process.stdout.write('.');
|
|
@@ -240,28 +245,21 @@ export async function deviceLogin() {
|
|
|
240
245
|
continue; // geçici ağ hatası — tekrar dene
|
|
241
246
|
}
|
|
242
247
|
if (d.status === 'approved') {
|
|
243
|
-
//
|
|
244
|
-
// verilemez (hash'li saklanır) → kullanıcı Ayarlar'dan anahtarını yapıştırmalı.
|
|
245
|
-
if (d.existing && !d.api_key) {
|
|
246
|
-
process.stdout.write('\n\n \x1b[33mHesabında zaten bir API anahtarı var.\x1b[0m (' + (d.prefix || 'wc_live_…') + '…)\n' +
|
|
247
|
-
' Güvenlik gereği mevcut anahtar tekrar gösterilemez. Şunlardan birini yap:\n' +
|
|
248
|
-
' 1) Anahtarını web Ayarlar → API\'den kopyala, sonra: \x1b[36mwormclaude login --key <ANAHTAR>\x1b[0m\n' +
|
|
249
|
-
' 2) Web Ayarlar → API\'de \x1b[36mSıfırla\x1b[0m de (yeni anahtar üretir; eski geçersiz olur), sonra tekrar gir.\n\n');
|
|
250
|
-
process.exit(1);
|
|
251
|
-
}
|
|
248
|
+
// Gateway onayda anahtarı CLI'ye bağlar (yoksa oluşturur, varsa yeniler) → api_key hep dolu.
|
|
252
249
|
saveStored({
|
|
253
250
|
baseUrl: d.base_url || base,
|
|
254
251
|
apiKey: d.api_key,
|
|
255
252
|
model: d.model || 'wormclaude-v2',
|
|
256
253
|
});
|
|
257
|
-
process.stdout.write('\n\n \x1b[32m✓ Giriş başarıl
|
|
254
|
+
process.stdout.write('\n\n \x1b[32m' + tt('✓ Signed in!', '✓ Giriş başarılı!') + '\x1b[0m ' +
|
|
255
|
+
tt('You can now use `wormclaude`.', 'Artık `wormclaude` yazarak kullanabilirsiniz.') + '\n\n');
|
|
258
256
|
return;
|
|
259
257
|
}
|
|
260
258
|
if (d.status === 'expired') {
|
|
261
|
-
process.stdout.write('\n\n Kodun süresi doldu. Tekrar deneyin: wormclaude login\n\n');
|
|
259
|
+
process.stdout.write('\n\n ' + tt('Code expired. Try again: wormclaude login', 'Kodun süresi doldu. Tekrar deneyin: wormclaude login') + '\n\n');
|
|
262
260
|
process.exit(1);
|
|
263
261
|
}
|
|
264
262
|
}
|
|
265
|
-
process.stdout.write('\n\n Süre doldu. Tekrar deneyin: wormclaude login\n\n');
|
|
263
|
+
process.stdout.write('\n\n ' + tt('Timed out. Try again: wormclaude login', 'Süre doldu. Tekrar deneyin: wormclaude login') + '\n\n');
|
|
266
264
|
process.exit(1);
|
|
267
265
|
}
|
package/dist/cli.js
CHANGED
|
@@ -61,11 +61,15 @@ import { shouldAutoCompact, runCompact, isContextError } from './compact.js';
|
|
|
61
61
|
import { shouldExtract, triggerMemory, loadMemoryContext } from './memory.js';
|
|
62
62
|
// --- WORMCLAUDE SUBCOMMANDS (TUI oncesi) ---
|
|
63
63
|
const _arg = (process.argv[2] || '').toLowerCase();
|
|
64
|
+
// Dil: VARSAYILAN İngilizce; kayıtlı dil varsa onu uygula. TÜM yollardan (subcommand + TUI) ÖNCE
|
|
65
|
+
// ayarla ki login/whoami/hata mesajları da doğru dilde olsun (eskiden subcommand'lar default'a düşüyordu).
|
|
66
|
+
setLang(loadLang() ?? 'en');
|
|
67
|
+
const _tt = (en, tr) => (getLang() === 'tr' ? tr : en);
|
|
64
68
|
// Headless mod: wormclaude -p "<görev>" → TUI'siz çalıştır, stdout'a yaz, çık (scriptlenebilir + test).
|
|
65
69
|
if (_arg === '-p' || _arg === '--print') {
|
|
66
70
|
const _prompt = process.argv.slice(3).join(' ').trim();
|
|
67
71
|
if (!_prompt) {
|
|
68
|
-
console.error('Kullanım: wormclaude -p "<görev>"');
|
|
72
|
+
console.error(_tt('Usage: wormclaude -p "<task>"', 'Kullanım: wormclaude -p "<görev>"'));
|
|
69
73
|
process.exit(1);
|
|
70
74
|
}
|
|
71
75
|
const { runHeadless } = await import('./headless.js');
|
|
@@ -84,11 +88,11 @@ if (_arg === 'login' || _arg === 'logout' || _arg === 'whoami' || _arg === '--ve
|
|
|
84
88
|
}
|
|
85
89
|
else if (_arg === 'logout') {
|
|
86
90
|
auth.clearStored();
|
|
87
|
-
console.log('
|
|
91
|
+
console.log(_tt('Logged out.', 'Çıkış yapıldı.'));
|
|
88
92
|
}
|
|
89
93
|
else if (_arg === 'whoami') {
|
|
90
94
|
const c = auth.loadStored();
|
|
91
|
-
console.log(c.apiKey ? ('
|
|
95
|
+
console.log(c.apiKey ? (_tt('Logged in (', 'Giriş yapıldı (') + (c.baseUrl || '') + ')') : _tt('Not logged in - wormclaude login', 'Giriş yapılmadı - wormclaude login'));
|
|
92
96
|
}
|
|
93
97
|
else if (_arg === 'update') {
|
|
94
98
|
await auth.runUpdate();
|
|
@@ -168,7 +172,7 @@ if (_needLogin) {
|
|
|
168
172
|
setToolConfig(config); // Agent/alt-agent araçları aynı config'i kullanır
|
|
169
173
|
setCheckpointStore(process.cwd()); // rewind deposu (/rewind, /checkpoints)
|
|
170
174
|
const MAX_TURNS = Number(process.env.WORMCLAUDE_MAX_TURNS) || 90; // tur limiti
|
|
171
|
-
setLang(loadLang() ?? '
|
|
175
|
+
setLang(loadLang() ?? 'en'); // kayıtlı dili yükle (yoksa İngilizce)
|
|
172
176
|
loadSkills(); // .wormclaude/skills/*.md yükle
|
|
173
177
|
loadExtensions(); // extensions/<ad>/ (gömülü + kullanıcı + proje) yükle
|
|
174
178
|
// Kalıcı hafıza: açılışta .wormclaude/memory.md + WORMCLAUDE.md'yi context'e yükle
|
package/dist/commands.js
CHANGED
|
@@ -164,6 +164,25 @@ function formatFinding(x) {
|
|
|
164
164
|
return JSON.stringify(x);
|
|
165
165
|
}
|
|
166
166
|
// /recon /scan /xss /sqli — ince runner'ı sürer. Zorunlu yetki onayı + trust 3+ teaser.
|
|
167
|
+
// Slash'sız komut tespiti: kullanıcı "recon target.com" (slash'sız) yazınca "/recon target.com" öner.
|
|
168
|
+
// FALSE-POZİTİF guard: ilk kelime tam komut adı + argüman var + soru DEĞİL ("recon nedir?" tetiklemez).
|
|
169
|
+
const _BARE_CMDS = new Set(['recon', 'scan', 'xss', 'sqli', 'exploit', 'harden', 'agent', 'agents']);
|
|
170
|
+
const _QUESTION_WORDS = new Set(['nedir', 'ne', 'nasıl', 'nasil', 'neden', 'mi', 'mu', 'mı', 'mü', 'what', 'how', 'why', 'is', 'are', 'about', 'açıkla', 'acikla', 'explain', 'hakkında', 'hakkinda', 'anlat']);
|
|
171
|
+
export function detectBareCommand(input) {
|
|
172
|
+
const s = (input || '').trim();
|
|
173
|
+
if (!s || s.startsWith('/') || s.includes('?') || s.includes('\n'))
|
|
174
|
+
return null;
|
|
175
|
+
const parts = s.split(/\s+/);
|
|
176
|
+
if (parts.length < 2)
|
|
177
|
+
return null; // tek kelime → düz mesaj olabilir
|
|
178
|
+
const first = parts[0].toLowerCase();
|
|
179
|
+
if (!_BARE_CMDS.has(first))
|
|
180
|
+
return null;
|
|
181
|
+
if (_QUESTION_WORDS.has(parts[1].toLowerCase()))
|
|
182
|
+
return null; // "recon nedir" → komut değil
|
|
183
|
+
const cmd = first === 'agents' ? 'agent' : (first === 'scan' ? 'scan' : first);
|
|
184
|
+
return '/' + cmd + ' ' + parts.slice(1).join(' ');
|
|
185
|
+
}
|
|
167
186
|
async function pentestCmd(tool, arg, ctx) {
|
|
168
187
|
if (tool === 'scan')
|
|
169
188
|
tool = 'recon'; // genel tarama = keşif+başlıklar
|
|
@@ -173,7 +192,17 @@ async function pentestCmd(tool, arg, ctx) {
|
|
|
173
192
|
scopeAck = true;
|
|
174
193
|
parts.pop();
|
|
175
194
|
}
|
|
176
|
-
|
|
195
|
+
// Ana sayfadaki kozmetik flag'leri (--scope authorized, --cve X, --emit yara,sigma) yok say → hedef temiz kalsın
|
|
196
|
+
const cleaned = [];
|
|
197
|
+
for (let i = 0; i < parts.length; i++) {
|
|
198
|
+
if (parts[i].startsWith('-')) {
|
|
199
|
+
if (parts[i + 1] && !parts[i + 1].startsWith('-'))
|
|
200
|
+
i++;
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
cleaned.push(parts[i]);
|
|
204
|
+
}
|
|
205
|
+
const target = cleaned.join(' ').trim();
|
|
177
206
|
const label = PT_LABELS[tool] || tool;
|
|
178
207
|
if (!target) {
|
|
179
208
|
ctx.note(`${label}\nKullanım: /${tool} <hedef>\nÖrnek: /${tool} https://test.com/sayfa?id=1`);
|
package/dist/i18n.js
CHANGED
|
@@ -100,6 +100,7 @@ const STR = {
|
|
|
100
100
|
'tui.userCancel': 'kullanıcı iptal etti',
|
|
101
101
|
'tui.cmdErr': 'Komut hatası: {0}',
|
|
102
102
|
'tui.langSet': 'Dil değiştirildi: Türkçe',
|
|
103
|
+
'tui.useSlash': 'Komutlar / ile başlar. Şunu mu demek istediniz: {0} · çalıştırmak için Enter\'a bas',
|
|
103
104
|
},
|
|
104
105
|
en: {
|
|
105
106
|
'lang.title': 'Select language / Dil seçin',
|
|
@@ -166,6 +167,7 @@ const STR = {
|
|
|
166
167
|
'tui.userCancel': 'user cancelled',
|
|
167
168
|
'tui.cmdErr': 'Command error: {0}',
|
|
168
169
|
'tui.langSet': 'Language changed: English',
|
|
170
|
+
'tui.useSlash': 'Commands start with /. Did you mean: {0} · press Enter to run',
|
|
169
171
|
},
|
|
170
172
|
};
|
|
171
173
|
// Komut açıklamaları (slash menüsü + /help)
|
package/dist/theme.js
CHANGED
package/dist/tui.js
CHANGED
|
@@ -15,7 +15,7 @@ import { itemAnsi, markdownAnsi } from './ansi.js';
|
|
|
15
15
|
import { theme, VERSION } from './theme.js';
|
|
16
16
|
import { cleanModelText } from './textclean.js';
|
|
17
17
|
import { stripInlineToolCalls, stripEchoBlocks } from './inlinetools.js';
|
|
18
|
-
import { COMMANDS, runSlashCommand, getPendingPentestCommand, buildExploitPrompt, buildHardenPrompt } from './commands.js';
|
|
18
|
+
import { COMMANDS, runSlashCommand, getPendingPentestCommand, buildExploitPrompt, buildHardenPrompt, detectBareCommand } from './commands.js';
|
|
19
19
|
import { cmdDesc, t, setLang, loadLang, getLang } from './i18n.js';
|
|
20
20
|
import { getSkill, getSkills, buildSkillPrompt } from './skills.js';
|
|
21
21
|
import { getExtCommand, getExtCommands, buildExtCommandPrompt } from './extensions.js';
|
|
@@ -878,6 +878,16 @@ export async function runTui() {
|
|
|
878
878
|
runCommand(v);
|
|
879
879
|
return;
|
|
880
880
|
}
|
|
881
|
+
// Slash'sız komut mu? ("recon target.com" → "/recon target.com" öner, slash kullanımına yönlendir)
|
|
882
|
+
const _bare = detectBareCommand(v);
|
|
883
|
+
if (_bare) {
|
|
884
|
+
printItem({ kind: 'note', text: t('tui.useSlash', _bare) });
|
|
885
|
+
inputBuf = _bare;
|
|
886
|
+
inputCur = _bare.length;
|
|
887
|
+
cmdSel = 0;
|
|
888
|
+
refresh();
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
881
891
|
// 🖼 Görsel sürükle-bırak — girdide resim yolu varsa VL modeline gönder (vision turu)
|
|
882
892
|
const _vis = extractImages(v);
|
|
883
893
|
if (_vis.images.length) {
|