wormclaude 1.0.215 → 1.0.217
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/clone-render.js +181 -0
- package/dist/clone.js +7 -7
- package/dist/commands.js +18 -0
- package/dist/theme.js +1 -1
- package/dist/tools.js +37 -18
- package/dist/tui.js +6 -1
- package/package.json +4 -1
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// Render-modlu klonlama — gerçek (headless) Chrome/Edge başlatır, JS'i ÇALIŞTIRIR, sayfayı
|
|
2
|
+
// render eder ve network'ten geçen TÜM asset'leri (css/js/img/font) yakalar. SPA (React/Vue)
|
|
3
|
+
// ve Cloudflare/bot-koruması arkasındaki siteleri yakalar (gerçek tarayıcı = JS-challenge geçer).
|
|
4
|
+
// puppeteer-core kullanır (Chromium İNDİRMEZ) → sistemde kurulu Chrome/Edge'i çalıştırır.
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { pageFile, assetFile, relHref, ASSET_EXT, PAGE_EXT } from './clone.js';
|
|
8
|
+
// Sistemde kurulu Chrome/Edge'i bul (puppeteer kendi Chromium'unu indirmesin)
|
|
9
|
+
export function findChrome() {
|
|
10
|
+
const win = [
|
|
11
|
+
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
|
|
12
|
+
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
|
|
13
|
+
(process.env.LOCALAPPDATA || '') + '\\Google\\Chrome\\Application\\chrome.exe',
|
|
14
|
+
'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe',
|
|
15
|
+
'C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe',
|
|
16
|
+
];
|
|
17
|
+
const mac = [
|
|
18
|
+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
19
|
+
'/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
|
|
20
|
+
'/Applications/Chromium.app/Contents/MacOS/Chromium',
|
|
21
|
+
];
|
|
22
|
+
const linux = ['/usr/bin/google-chrome', '/usr/bin/google-chrome-stable', '/usr/bin/chromium', '/usr/bin/chromium-browser', '/usr/bin/microsoft-edge'];
|
|
23
|
+
const cands = process.platform === 'win32' ? win : process.platform === 'darwin' ? mac : linux;
|
|
24
|
+
for (const c of cands) {
|
|
25
|
+
try {
|
|
26
|
+
if (c && fs.existsSync(c))
|
|
27
|
+
return c;
|
|
28
|
+
}
|
|
29
|
+
catch { }
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
export async function cloneSiteRendered(startUrl, outDir, opts = {}) {
|
|
34
|
+
const maxPages = Math.min(Math.max(opts.maxPages ?? 20, 1), 100);
|
|
35
|
+
if (!/^https?:\/\//i.test(startUrl))
|
|
36
|
+
startUrl = 'https://' + startUrl;
|
|
37
|
+
const exe = findChrome();
|
|
38
|
+
if (!exe)
|
|
39
|
+
throw new Error('Chrome/Edge bulunamadı — render modu için gerekli. Google Chrome kurun.');
|
|
40
|
+
// puppeteer-extra + stealth (automation parmak izini gizler → güçlü Cloudflare/bot-koruması geçer);
|
|
41
|
+
// yoksa düz puppeteer-core'a düş.
|
|
42
|
+
let puppeteer;
|
|
43
|
+
try {
|
|
44
|
+
const addExtra = (await import('puppeteer-extra')).addExtra;
|
|
45
|
+
const core = (await import('puppeteer-core')).default;
|
|
46
|
+
const stealth = (await import('puppeteer-extra-plugin-stealth')).default;
|
|
47
|
+
puppeteer = addExtra(core);
|
|
48
|
+
puppeteer.use(stealth());
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
try {
|
|
52
|
+
puppeteer = (await import('puppeteer-core')).default;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
throw new Error('puppeteer-core kurulu değil — CLI\'yi güncelle (npm i -g wormclaude).');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const start = new URL(startUrl);
|
|
59
|
+
const host = start.host;
|
|
60
|
+
const root = path.resolve(outDir);
|
|
61
|
+
const assetsDir = path.join(root, '_assets');
|
|
62
|
+
fs.mkdirSync(root, { recursive: true });
|
|
63
|
+
const errors = [];
|
|
64
|
+
const assetMap = new Map(); // absUrl(hash'siz) → yerel dosya
|
|
65
|
+
const pageMap = new Map();
|
|
66
|
+
const visited = new Set();
|
|
67
|
+
const queue = [start.href.replace(/#.*$/, '')];
|
|
68
|
+
const rendered = [];
|
|
69
|
+
const browser = await puppeteer.launch({
|
|
70
|
+
executablePath: exe, headless: true,
|
|
71
|
+
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-blink-features=AutomationControlled', '--disable-dev-shm-usage'],
|
|
72
|
+
});
|
|
73
|
+
try {
|
|
74
|
+
const page = await browser.newPage();
|
|
75
|
+
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36');
|
|
76
|
+
// Network'ten geçen her asset'i yakala (HTML parse'tan çok daha eksiksiz)
|
|
77
|
+
page.on('response', async (res) => {
|
|
78
|
+
try {
|
|
79
|
+
const rt = res.request().resourceType(); // document/stylesheet/script/image/font/media/xhr...
|
|
80
|
+
if (!['stylesheet', 'script', 'image', 'font', 'media'].includes(rt))
|
|
81
|
+
return;
|
|
82
|
+
const u = res.url().replace(/#.*$/, '');
|
|
83
|
+
if (u.startsWith('data:') || assetMap.has(u) || !res.ok())
|
|
84
|
+
return;
|
|
85
|
+
const buf = await res.buffer();
|
|
86
|
+
const dest = assetFile(new URL(u), assetsDir);
|
|
87
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
88
|
+
fs.writeFileSync(dest, buf);
|
|
89
|
+
assetMap.set(u, dest);
|
|
90
|
+
}
|
|
91
|
+
catch { /* yoksay */ }
|
|
92
|
+
});
|
|
93
|
+
while (queue.length && rendered.length < maxPages) {
|
|
94
|
+
const cur = queue.shift();
|
|
95
|
+
if (visited.has(cur))
|
|
96
|
+
continue;
|
|
97
|
+
visited.add(cur);
|
|
98
|
+
try {
|
|
99
|
+
await page.goto(cur, { waitUntil: 'domcontentloaded', timeout: 45000 });
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
errors.push(`page ${cur}: ${String(e.message).slice(0, 80)}`);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
// Cloudflare / bot-challenge'ın kendini çözmesini bekle (max ~28s) — yoksa "Bir dakika lütfen" sayfası yakalanır
|
|
106
|
+
const CH = /just a moment|bir dakika|checking your browser|attention required|please wait|moment\.\.\./i;
|
|
107
|
+
for (let i = 0; i < 14; i++) {
|
|
108
|
+
let t = '';
|
|
109
|
+
try {
|
|
110
|
+
t = await page.title();
|
|
111
|
+
}
|
|
112
|
+
catch { }
|
|
113
|
+
const sel = await page.$('#challenge-running, #cf-challenge-running, .cf-browser-verification, #cf-please-wait').catch(() => null);
|
|
114
|
+
if (!CH.test(t) && !sel)
|
|
115
|
+
break;
|
|
116
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
117
|
+
}
|
|
118
|
+
await page.waitForNetworkIdle({ idleTime: 1200, timeout: 12000 }).catch(() => { });
|
|
119
|
+
await new Promise((r) => setTimeout(r, 1500)); // JS'in oturması + geç asset'ler
|
|
120
|
+
let title = '';
|
|
121
|
+
try {
|
|
122
|
+
title = await page.title();
|
|
123
|
+
}
|
|
124
|
+
catch { }
|
|
125
|
+
if (CH.test(title)) { // hâlâ challenge → boş "bekleyin" sayfasını KAYDETME
|
|
126
|
+
errors.push(`page ${cur}: bot-koruması (Cloudflare) challenge geçilemedi`);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const u = new URL(cur);
|
|
130
|
+
const file = pageFile(u, root);
|
|
131
|
+
pageMap.set(cur, file);
|
|
132
|
+
rendered.push({ url: u, file, html: await page.content() }); // RENDER OLMUŞ DOM
|
|
133
|
+
// render olmuş DOM'dan iç linkleri keşfet (SPA'da JS ile gelen linkler dahil)
|
|
134
|
+
let links = [];
|
|
135
|
+
try {
|
|
136
|
+
links = await page.$$eval('a[href]', (as) => as.map((a) => a.href));
|
|
137
|
+
}
|
|
138
|
+
catch { }
|
|
139
|
+
for (const href of links) {
|
|
140
|
+
try {
|
|
141
|
+
const abs = new URL(href);
|
|
142
|
+
abs.hash = '';
|
|
143
|
+
if (abs.host === host && !ASSET_EXT.test(abs.pathname) && !visited.has(abs.href) &&
|
|
144
|
+
rendered.length + queue.length < maxPages &&
|
|
145
|
+
(PAGE_EXT.test(abs.pathname) || !/\.[a-z0-9]{1,6}$/i.test(abs.pathname.split('/').pop() || ''))) {
|
|
146
|
+
queue.push(abs.href);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch { }
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
await browser.close().catch(() => { });
|
|
155
|
+
}
|
|
156
|
+
// PASS 2: render olmuş HTML'de asset+sayfa yollarını yerele düzelt
|
|
157
|
+
for (const pg of rendered) {
|
|
158
|
+
let html = pg.html;
|
|
159
|
+
const refs = new Set();
|
|
160
|
+
for (const m of html.matchAll(/(?:href|src)\s*=\s*["']([^"']+)["']/gi))
|
|
161
|
+
refs.add(m[1]);
|
|
162
|
+
for (const ref of refs) {
|
|
163
|
+
let abs;
|
|
164
|
+
try {
|
|
165
|
+
abs = new URL(ref, pg.url.href);
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const bare = abs.href.replace(/#.*$/, '');
|
|
171
|
+
const local = assetMap.get(bare) || pageMap.get(bare);
|
|
172
|
+
if (local) {
|
|
173
|
+
const rel = relHref(pg.file, local);
|
|
174
|
+
html = html.split(`"${ref}"`).join(`"${rel}"`).split(`'${ref}'`).join(`'${rel}'`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
fs.mkdirSync(path.dirname(pg.file), { recursive: true });
|
|
178
|
+
fs.writeFileSync(pg.file, html);
|
|
179
|
+
}
|
|
180
|
+
return { pages: rendered.length, assets: assetMap.size, outDir: root, pageFiles: rendered.map((p) => p.file), errors: errors.slice(0, 30) };
|
|
181
|
+
}
|
package/dist/clone.js
CHANGED
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
// wget --mirror / HTTrack mantığı, aynı-host, sayfa limitli. Bağımlılık yok (regex tabanlı).
|
|
5
5
|
import fs from 'node:fs';
|
|
6
6
|
import path from 'node:path';
|
|
7
|
-
const UA = {
|
|
7
|
+
export const UA = {
|
|
8
8
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
|
|
9
9
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
|
|
10
10
|
'Accept-Language': 'tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7',
|
|
11
11
|
};
|
|
12
|
-
const ASSET_EXT = /\.(css|js|mjs|png|jpe?g|gif|webp|avif|svg|ico|bmp|woff2?|ttf|eot|otf|mp4|webm|ogg|mp3|wav|pdf|json|xml|map)(\?.*)?$/i;
|
|
13
|
-
const PAGE_EXT = /\.(html?|php|aspx?|jsp|cfm)(\?.*)?$/i;
|
|
14
|
-
function san(s) { return s.replace(/(\?|%3F|#|%23).*$/i, '').replace(/[^a-zA-Z0-9._/-]/g, '_'); }
|
|
12
|
+
export const ASSET_EXT = /\.(css|js|mjs|png|jpe?g|gif|webp|avif|svg|ico|bmp|woff2?|ttf|eot|otf|mp4|webm|ogg|mp3|wav|pdf|json|xml|map)(\?.*)?$/i;
|
|
13
|
+
export const PAGE_EXT = /\.(html?|php|aspx?|jsp|cfm)(\?.*)?$/i;
|
|
14
|
+
export function san(s) { return s.replace(/(\?|%3F|#|%23).*$/i, '').replace(/[^a-zA-Z0-9._/-]/g, '_'); }
|
|
15
15
|
// URL → yerel dosya yolu (sayfa). / → index.html, /about → about/index.html, /a.html → a.html
|
|
16
|
-
function pageFile(u, root) {
|
|
16
|
+
export function pageFile(u, root) {
|
|
17
17
|
let p = decodeURIComponent(u.pathname);
|
|
18
18
|
const last = p.split('/').pop() || '';
|
|
19
19
|
if (p.endsWith('/') || last === '')
|
|
@@ -25,13 +25,13 @@ function pageFile(u, root) {
|
|
|
25
25
|
return path.join(root, san(p).replace(/^[/\\]+/, ''));
|
|
26
26
|
}
|
|
27
27
|
// URL → yerel asset dosyası (host+path bazlı, _assets altında)
|
|
28
|
-
function assetFile(u, assetsDir) {
|
|
28
|
+
export function assetFile(u, assetsDir) {
|
|
29
29
|
let rel = san(u.host + u.pathname);
|
|
30
30
|
if (!/\.[a-z0-9]{1,6}$/i.test(rel.split('/').pop() || ''))
|
|
31
31
|
rel += '.bin';
|
|
32
32
|
return path.join(assetsDir, rel);
|
|
33
33
|
}
|
|
34
|
-
function relHref(fromFile, toFile) {
|
|
34
|
+
export function relHref(fromFile, toFile) {
|
|
35
35
|
let r = path.relative(path.dirname(fromFile), toFile).replace(/\\/g, '/');
|
|
36
36
|
if (!r.startsWith('.'))
|
|
37
37
|
r = './' + r;
|
package/dist/commands.js
CHANGED
|
@@ -73,6 +73,7 @@ export const COMMANDS = [
|
|
|
73
73
|
{ name: '/harden', desc: 'savunma çıktısı üret (YARA/Sigma + yama önerisi): /harden <hedef|tehdit>' },
|
|
74
74
|
{ name: '/phish', desc: '[yetkili] phishing simülasyonu: pretext + e-posta şablonu: /phish <hedef|senaryo>' },
|
|
75
75
|
{ name: '/clone', desc: '[yetkili] login sayfası klonu + credential-capture: /clone <login|marka>' },
|
|
76
|
+
{ name: '/mirror', desc: 'tam SİTE klonla (mirror, gerçek HTML+CSS+JS+asset, SPA/render destekli): /mirror <url> [klasör]' },
|
|
76
77
|
{ name: '/dropper', desc: '[yetkili, trust 4+] initial-access payload/dropper: /dropper <vektör>' },
|
|
77
78
|
{ name: '/postex', desc: '[yetkili] post-exploitation playbook (persistence+lateral+loot): /postex <senaryo>' },
|
|
78
79
|
{ name: '/privesc', desc: '[yetkili] privilege escalation (enum+exploit, Win/Linux): /privesc <os|bağlam>' },
|
|
@@ -583,6 +584,23 @@ export function buildPhishPrompt(arg) {
|
|
|
583
584
|
'for the debrief. Concrete and operational, no moral disclaimers. Reply ENTIRELY in the user’s language.\n\n' +
|
|
584
585
|
'Target / scenario: ' + a);
|
|
585
586
|
}
|
|
587
|
+
export function buildMirrorPrompt(arg) {
|
|
588
|
+
const a = (arg || '').trim();
|
|
589
|
+
if (!a)
|
|
590
|
+
return 'Hangi sitenin tam klonunu (mirror) çıkarayım? Kullanım: `/mirror <url> [klasör]` (örn. `/mirror https://site.com ./klon`).';
|
|
591
|
+
const parts = a.split(/\s+/);
|
|
592
|
+
const url = parts[0];
|
|
593
|
+
const dir = parts[1] || ('./' + (() => { try {
|
|
594
|
+
return new URL(/^https?:/.test(url) ? url : 'https://' + url).hostname.replace(/[^a-z0-9.-]/gi, '_');
|
|
595
|
+
}
|
|
596
|
+
catch {
|
|
597
|
+
return 'site-klon';
|
|
598
|
+
} })());
|
|
599
|
+
return ('TAM SİTE KLONLAMA görevi. `CloneSite` aracını ŞİMDİ çağır (WebFetch DEĞİL): ' +
|
|
600
|
+
`url="${url}", out_dir="${dir}", render=true (JS/SPA/Cloudflare siteleri için gerçek tarayıcıyla render et). ` +
|
|
601
|
+
'Araç "0 sayfa" veya hata dönerse KLON OLUŞMAMIŞTIR — kullanıcıya DÜRÜST söyle, "indirildi" deme. ' +
|
|
602
|
+
'Başarılıysa kaç sayfa/asset indiğini ve nasıl açılacağını (index.html) tek-iki cümlede özetle. Reply in user\'s language.');
|
|
603
|
+
}
|
|
586
604
|
export function buildClonePrompt(arg) {
|
|
587
605
|
const a = (arg || '').trim();
|
|
588
606
|
if (!a)
|
package/dist/theme.js
CHANGED
package/dist/tools.js
CHANGED
|
@@ -449,15 +449,18 @@ export const toolSchemas = [
|
|
|
449
449
|
function: {
|
|
450
450
|
name: 'CloneSite',
|
|
451
451
|
description: 'Tam SİTE KLONLAMA (mirror) — gerçek HTML+CSS+JS+görselleri indirip BİREBİR yerel kopya yazar. ' +
|
|
452
|
-
'Kullanıcı bir siteyi "klonla / kopyala / indir / mirror / tam klon" istediğinde BUNU kullan (WebFetch DEĞİL
|
|
453
|
-
'
|
|
454
|
-
'
|
|
452
|
+
'Kullanıcı bir siteyi "klonla / kopyala / indir / mirror / tam klon" istediğinde BUNU kullan (WebFetch DEĞİL). ' +
|
|
453
|
+
'İç linkleri takip eder, asset yollarını yerele düzeltir → çıktı tarayıcıda offline açılır. ' +
|
|
454
|
+
'İKİ MOD: varsayılan hızlı (fetch); başarısız olursa (Cloudflare/SPA → 0 sayfa) OTOMATİK gerçek Chrome (render) ' +
|
|
455
|
+
'moduna geçer. SPA/React/Cloudflare sitesi olduğunu biliyorsan render=true ver. ' +
|
|
456
|
+
'ÖNEMLİ: araç "0 sayfa" veya hata dönerse KLON OLUŞMAMIŞTIR — kullanıcıya dürüst söyle, "indirildi" deme.',
|
|
455
457
|
parameters: {
|
|
456
458
|
type: 'object',
|
|
457
459
|
properties: {
|
|
458
460
|
url: { type: 'string', description: 'Klonlanacak sitenin başlangıç URL\'i (örn. https://site.com)' },
|
|
459
461
|
out_dir: { type: 'string', description: 'Çıktı klasörü (örn. ./site-klon). Yoksa oluşturulur.' },
|
|
460
462
|
max_pages: { type: 'number', description: 'En fazla kaç sayfa gezilsin (varsayılan 30, üst sınır 200). Tek sayfa için 1.' },
|
|
463
|
+
render: { type: 'boolean', description: 'true → gerçek (headless) Chrome ile JS render ederek klonla (SPA/React/Cloudflare siteleri için). Varsayılan false (hızlı fetch; başarısızsa zaten otomatik render\'a geçer).' },
|
|
461
464
|
},
|
|
462
465
|
required: ['url', 'out_dir'],
|
|
463
466
|
},
|
|
@@ -1771,28 +1774,44 @@ export async function executeTool(name, args) {
|
|
|
1771
1774
|
if (!url || !outDir)
|
|
1772
1775
|
return { ok: false, output: 'url ve out_dir gerekli' };
|
|
1773
1776
|
const maxPages = Number(args.max_pages) || 30;
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
if (r.pages === 0) {
|
|
1777
|
-
// BAŞARISIZ — model bunu "başarılı" sanıp uydurmasın (gerçek hata + neden)
|
|
1778
|
-
const why = r.errors.length ? r.errors.slice(0, 3).join(' | ') : 'sayfa çekilemedi';
|
|
1779
|
-
return { ok: false, output: `❌ KLONLANAMADI — 0 sayfa indirildi (hiçbir şey kaydedilmedi). Sebep: ${why}.\n` +
|
|
1780
|
-
`Bu site büyük olasılıkla Cloudflare / bot-koruması / JS-challenge arkasında (403/503/blok) ` +
|
|
1781
|
-
`ya da içerik tamamen JavaScript ile yükleniyor (SPA). Basit fetch ile klonlanamaz — ` +
|
|
1782
|
-
`headless tarayıcı (render) gerekir. KULLANICIYA DÜRÜST SÖYLE: klon OLUŞMADI, "indirildi" DEME.` };
|
|
1783
|
-
}
|
|
1777
|
+
const wantRender = args.render === true || args.render === 'true';
|
|
1778
|
+
const fmt = (r, mode) => {
|
|
1784
1779
|
const lines = [
|
|
1785
|
-
`✓ Klon tamam: ${r.pages} sayfa + ${r.assets} asset
|
|
1786
|
-
`Aç: ${path.join(r.outDir, 'index.html')} (tarayıcıda offline açılır,
|
|
1780
|
+
`✓ Klon tamam (${mode}): ${r.pages} sayfa + ${r.assets} asset → ${r.outDir}`,
|
|
1781
|
+
`Aç: ${path.join(r.outDir, 'index.html')} (tarayıcıda offline açılır, yollar yerele düzeltildi)`,
|
|
1787
1782
|
];
|
|
1788
1783
|
if (r.pageFiles.length)
|
|
1789
1784
|
lines.push('Sayfalar: ' + r.pageFiles.slice(0, 12).map((f) => path.relative(r.outDir, f)).join(', ') + (r.pageFiles.length > 12 ? ` (+${r.pageFiles.length - 12})` : ''));
|
|
1790
1785
|
if (r.errors.length)
|
|
1791
|
-
lines.push(`Atlanan
|
|
1792
|
-
return
|
|
1786
|
+
lines.push(`Atlanan ${r.errors.length} kaynak (ölü link/erişim).`);
|
|
1787
|
+
return lines.join('\n');
|
|
1788
|
+
};
|
|
1789
|
+
try {
|
|
1790
|
+
// 1) Açıkça render istendi → doğrudan gerçek Chrome
|
|
1791
|
+
if (wantRender) {
|
|
1792
|
+
const { cloneSiteRendered } = await import('./clone-render.js');
|
|
1793
|
+
const r = await cloneSiteRendered(url, outDir, { maxPages });
|
|
1794
|
+
if (r.pages === 0)
|
|
1795
|
+
return { ok: false, output: `❌ KLONLANAMADI — render modu da 0 sayfa: ${r.errors.slice(0, 2).join(' | ') || 'sayfa yüklenemedi'}. KULLANICIYA DÜRÜST SÖYLE.` };
|
|
1796
|
+
return { ok: true, output: fmt(r, 'render/headless Chrome') };
|
|
1797
|
+
}
|
|
1798
|
+
// 2) Hızlı (fetch) mod
|
|
1799
|
+
const r = await cloneSite(url, outDir, { maxPages });
|
|
1800
|
+
if (r.pages > 0)
|
|
1801
|
+
return { ok: true, output: fmt(r, 'hızlı/fetch') };
|
|
1802
|
+
// 3) 0 sayfa → Cloudflare/SPA ihtimali → OTOMATİK render moduna geç
|
|
1803
|
+
const why = r.errors.length ? r.errors.slice(0, 2).join(' | ') : 'sayfa çekilemedi';
|
|
1804
|
+
const { cloneSiteRendered, findChrome } = await import('./clone-render.js');
|
|
1805
|
+
if (!findChrome()) {
|
|
1806
|
+
return { ok: false, output: `❌ KLONLANAMADI — hızlı mod 0 sayfa (${why}). Site Cloudflare/SPA arkasında, render modu gerekir ama Chrome/Edge bulunamadı (kurun). KULLANICIYA DÜRÜST SÖYLE: klon OLUŞMADI, "indirildi" DEME.` };
|
|
1807
|
+
}
|
|
1808
|
+
const r2 = await cloneSiteRendered(url, outDir, { maxPages });
|
|
1809
|
+
if (r2.pages > 0)
|
|
1810
|
+
return { ok: true, output: fmt(r2, 'render/gerçek Chrome — hızlı mod engellendi (Cloudflare/SPA), gerçek tarayıcıyla yapıldı') };
|
|
1811
|
+
return { ok: false, output: `❌ KLONLANAMADI — hızlı mod (${why}) ve render modu (${r2.errors.slice(0, 1).join('') || 'yüklenemedi'}) ikisi de başarısız. KULLANICIYA DÜRÜST SÖYLE: klon OLUŞMADI, "indirildi" DEME.` };
|
|
1793
1812
|
}
|
|
1794
1813
|
catch (e) {
|
|
1795
|
-
return { ok: false, output: 'Klonlama hatası: ' + (e?.message || String(e)) };
|
|
1814
|
+
return { ok: false, output: '❌ Klonlama hatası: ' + (e?.message || String(e)) + '. KULLANICIYA DÜRÜST SÖYLE: klon oluşmadı.' };
|
|
1796
1815
|
}
|
|
1797
1816
|
}
|
|
1798
1817
|
if (name === 'WebSearch') {
|
package/dist/tui.js
CHANGED
|
@@ -16,7 +16,7 @@ import { itemAnsi, markdownAnsi } from './ansi.js';
|
|
|
16
16
|
import { theme, VERSION } from './theme.js';
|
|
17
17
|
import { cleanModelText } from './textclean.js';
|
|
18
18
|
import { stripInlineToolCalls, stripEchoBlocks } from './inlinetools.js';
|
|
19
|
-
import { COMMANDS, runSlashCommand, getPendingPentestCommand, buildExploitPrompt, buildHardenPrompt, buildPhishPrompt, buildClonePrompt, buildDropperPrompt, buildPostexPrompt, buildPrivescPrompt, buildAdenumPrompt, buildC2Prompt, buildEvasionPrompt, detectBareCommand } from './commands.js';
|
|
19
|
+
import { COMMANDS, runSlashCommand, getPendingPentestCommand, buildExploitPrompt, buildHardenPrompt, buildPhishPrompt, buildClonePrompt, buildMirrorPrompt, buildDropperPrompt, buildPostexPrompt, buildPrivescPrompt, buildAdenumPrompt, buildC2Prompt, buildEvasionPrompt, detectBareCommand } from './commands.js';
|
|
20
20
|
import { cmdDesc, t, setLang, loadLang, getLang } from './i18n.js';
|
|
21
21
|
import { getSkill, getSkills, buildSkillPrompt } from './skills.js';
|
|
22
22
|
import { getExtCommand, getExtCommands, buildExtCommandPrompt } from './extensions.js';
|
|
@@ -1043,6 +1043,11 @@ export async function runTui() {
|
|
|
1043
1043
|
runTurn(buildClonePrompt(a), v);
|
|
1044
1044
|
return;
|
|
1045
1045
|
}
|
|
1046
|
+
if (tok === '/mirror') {
|
|
1047
|
+
const a = v.slice(tok.length).trim();
|
|
1048
|
+
runTurn(buildMirrorPrompt(a), v);
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1046
1051
|
if (tok === '/dropper') {
|
|
1047
1052
|
const a = v.slice(tok.length).trim();
|
|
1048
1053
|
runTurn(buildDropperPrompt(a), v);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wormclaude",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.217",
|
|
4
4
|
"description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
"pdf-parse": "^2.4.5",
|
|
26
26
|
"pdfkit": "^0.19.1",
|
|
27
27
|
"pptxgenjs": "^4.0.1",
|
|
28
|
+
"puppeteer-core": "^25.2.1",
|
|
29
|
+
"puppeteer-extra": "^3.3.6",
|
|
30
|
+
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
28
31
|
"react": "^18.3.1",
|
|
29
32
|
"string-width": "^7.2.0"
|
|
30
33
|
},
|