wormclaude 1.0.204 → 1.0.206

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/commands.js CHANGED
@@ -66,6 +66,7 @@ export const COMMANDS = [
66
66
  { name: '/audit', desc: 'kaynak kod güvenlik denetimi (SAST — sır/açık/CVE, yerel): /audit [klasör]' },
67
67
  { name: '/jwt', desc: 'JWT token güvenlik analizi (alg=none/zayıf-secret/expiry/claim, yerel): /jwt <token>' },
68
68
  { name: '/computer', desc: 'ekran kontrolünü aç/kapa (screenshot + tıkla/yaz, trust3+): See/Click/Type' },
69
+ { name: '/loop', desc: 'görevi belirli aralıkla tekrarla: /loop 5dk <görev> · durdur: /loop off' },
69
70
  { name: '/spray', desc: 'login formuna parola-spray (yetkili test, trust 3+): /spray <login-url> [kullanıcı]' },
70
71
  { name: '/defaultcreds', desc: 'login\'e varsayılan kimlik denemesi (admin/admin vb, trust 3+): /defaultcreds <login-url>' },
71
72
  { name: '/exploit', desc: 'yetkili testte doğrulanmış PoC üret: /exploit <cve|açıklama>' },
package/dist/docs.js ADDED
@@ -0,0 +1,97 @@
1
+ // Döküman üretimi — saf-JS kütüphaneleriyle (kullanıcının Python'una gerek YOK; CLI kendi
2
+ // node_modules'ıyla üretir). xlsx=exceljs, docx=docx, pdf=pdfkit, pptx=pptxgenjs.
3
+ import * as fs from 'node:fs';
4
+ async function makeXlsx(spec) {
5
+ const ExcelJS = (await import('exceljs')).default;
6
+ const wb = new ExcelJS.Workbook();
7
+ const ws = wb.addWorksheet((spec.title || 'Sayfa1').slice(0, 31));
8
+ const rows = spec.rows || [];
9
+ rows.forEach((r, i) => {
10
+ const row = ws.addRow(r);
11
+ if (i === 0)
12
+ row.font = { bold: true };
13
+ });
14
+ ws.columns.forEach((c) => { c.width = 18; });
15
+ await wb.xlsx.writeFile(spec.path);
16
+ }
17
+ async function makeDocx(spec) {
18
+ const D = await import('docx');
19
+ const children = [];
20
+ if (spec.title)
21
+ children.push(new D.Paragraph({ text: spec.title, heading: D.HeadingLevel.TITLE }));
22
+ for (const s of (spec.sections || [])) {
23
+ if (s.heading)
24
+ children.push(new D.Paragraph({ text: s.heading, heading: D.HeadingLevel.HEADING_1 }));
25
+ if (s.text)
26
+ for (const line of String(s.text).split('\n'))
27
+ children.push(new D.Paragraph(line));
28
+ }
29
+ if (spec.rows && spec.rows.length) {
30
+ children.push(new D.Table({
31
+ rows: spec.rows.map((r) => new D.TableRow({
32
+ children: r.map((cell) => new D.TableCell({ children: [new D.Paragraph(String(cell))] })),
33
+ })),
34
+ }));
35
+ }
36
+ const doc = new D.Document({ sections: [{ children }] });
37
+ const buf = await D.Packer.toBuffer(doc);
38
+ fs.writeFileSync(spec.path, buf);
39
+ }
40
+ async function makePdf(spec) {
41
+ const PDFDocument = (await import('pdfkit')).default;
42
+ await new Promise((resolve, reject) => {
43
+ const doc = new PDFDocument({ margin: 50 });
44
+ const stream = fs.createWriteStream(spec.path);
45
+ stream.on('finish', () => resolve());
46
+ stream.on('error', reject);
47
+ doc.pipe(stream);
48
+ if (spec.title)
49
+ doc.fontSize(20).text(spec.title).moveDown();
50
+ for (const s of (spec.sections || [])) {
51
+ if (s.heading)
52
+ doc.fontSize(15).fillColor('#222').text(s.heading).moveDown(0.3);
53
+ if (s.text)
54
+ doc.fontSize(11).fillColor('#000').text(s.text).moveDown(0.6);
55
+ }
56
+ for (const r of (spec.rows || []))
57
+ doc.fontSize(11).text(r.map((c) => String(c)).join(' | '));
58
+ doc.end();
59
+ });
60
+ }
61
+ async function makePptx(spec) {
62
+ const pptxgen = (await import('pptxgenjs')).default;
63
+ const pptx = new pptxgen();
64
+ const slides = spec.slides && spec.slides.length ? spec.slides
65
+ : [{ title: spec.title || 'Slayt', bullets: (spec.sections || []).map((s) => s.heading || s.text || '') }];
66
+ for (const sl of slides) {
67
+ const slide = pptx.addSlide();
68
+ slide.addText(sl.title || '', { x: 0.5, y: 0.3, w: 9, h: 1, fontSize: 28, bold: true });
69
+ const bullets = (sl.bullets || []).filter(Boolean);
70
+ if (bullets.length)
71
+ slide.addText(bullets.map((b) => ({ text: b, options: { bullet: true } })), { x: 0.7, y: 1.4, w: 8.5, h: 4.5, fontSize: 16 });
72
+ }
73
+ await pptx.writeFile({ fileName: spec.path });
74
+ }
75
+ /** Yapısal spec'ten dosya üret → {ok, path, size}. */
76
+ export async function createDocument(spec) {
77
+ try {
78
+ if (!spec || !spec.path)
79
+ return { ok: false, error: 'path gerekli' };
80
+ const t = (spec.type || '').toLowerCase();
81
+ if (t === 'xlsx')
82
+ await makeXlsx(spec);
83
+ else if (t === 'docx')
84
+ await makeDocx(spec);
85
+ else if (t === 'pdf')
86
+ await makePdf(spec);
87
+ else if (t === 'pptx')
88
+ await makePptx(spec);
89
+ else
90
+ return { ok: false, error: 'type xlsx|docx|pdf|pptx olmalı' };
91
+ const size = fs.statSync(spec.path).size;
92
+ return { ok: true, path: spec.path, size };
93
+ }
94
+ catch (e) {
95
+ return { ok: false, error: e?.message || String(e) };
96
+ }
97
+ }
package/dist/theme.js CHANGED
@@ -16,4 +16,4 @@ export const theme = {
16
16
  synType: '#a78bfa', // tip/sınıf adları, sabitler
17
17
  synProp: '#e0e0e0', // özellik/anahtar adları
18
18
  };
19
- export const VERSION = '1.0.204';
19
+ export const VERSION = '1.0.206';
package/dist/tools.js CHANGED
@@ -256,6 +256,25 @@ export const toolSchemas = [
256
256
  },
257
257
  },
258
258
  },
259
+ {
260
+ type: 'function',
261
+ function: {
262
+ name: 'CreateDocument',
263
+ description: "Create an Office/PDF document (Excel .xlsx, Word .docx, PDF, PowerPoint .pptx) NATIVELY — no Python needed. Use when the user asks to make/generate a spreadsheet, report, document, slides, or PDF (\"excel oluştur\", \"rapor hazırla\", \"word/pdf/sunum yap\", \"tabloyu .xlsx olarak ver\"). The CLI generates the real file with bundled libraries. Provide structured data: for xlsx use 'rows' (2D array, first row = headers); for docx/pdf use 'sections' (heading+text blocks) and/or 'rows' (a table); for pptx use 'slides' (title + bullets).",
264
+ parameters: {
265
+ type: 'object',
266
+ properties: {
267
+ type: { type: 'string', enum: ['xlsx', 'docx', 'pdf', 'pptx'], description: 'Document format.' },
268
+ path: { type: 'string', description: 'Output file path, e.g. "rapor.xlsx".' },
269
+ title: { type: 'string', description: 'Document/sheet title (optional).' },
270
+ rows: { type: 'array', description: 'For xlsx (table rows, first = header) or docx/pdf (a table). 2D array.', items: { type: 'array', items: {} } },
271
+ sections: { type: 'array', description: 'For docx/pdf: blocks. Each {heading?, text?}.', items: { type: 'object', properties: { heading: { type: 'string' }, text: { type: 'string' } } } },
272
+ slides: { type: 'array', description: 'For pptx: each {title, bullets:[...]}.', items: { type: 'object', properties: { title: { type: 'string' }, bullets: { type: 'array', items: { type: 'string' } } } } },
273
+ },
274
+ required: ['type', 'path'],
275
+ },
276
+ },
277
+ },
259
278
  {
260
279
  type: 'function',
261
280
  function: {
@@ -654,7 +673,7 @@ const computerToolSchemas = [
654
673
  // çağırıp işi yapar, planı ekrana basmaz. (Gerekirse buraya yeni araç eklenir.)
655
674
  const CORE_TOOLS = new Set([
656
675
  'Bash', 'PowerShell', 'Read', 'Write', 'Edit', 'Glob', 'Grep',
657
- 'WebFetch', 'WebSearch', 'Sleep', 'SecurityScan', 'CodeAudit', 'JwtAudit',
676
+ 'WebFetch', 'WebSearch', 'Sleep', 'SecurityScan', 'CodeAudit', 'JwtAudit', 'CreateDocument',
658
677
  'TaskOutput', // uzun komutları arka planda çalıştırıp bitişini yoklamak için (run_in_background)
659
678
  'AskUserQuestion', // GERİ EKLENDİ: FLAT şema (options: string[]) ile 32B temiz çağrı üretiyor
660
679
  // (test edildi). Eski degenere NESTED şemadandı ([{label,description}]). Handler string→{label}
@@ -699,6 +718,7 @@ const TOOL_META = {
699
718
  WebSearch: { readOnly: true, validate: (a) => (a && a.query ? null : 'query gerekli') },
700
719
  CodeAudit: { readOnly: true, concurrencySafe: true },
701
720
  JwtAudit: { readOnly: true, concurrencySafe: true, validate: (a) => (a && a.token ? null : 'token gerekli') },
721
+ CreateDocument: { needsPermission: true, validate: (a) => (a && a.type && a.path ? null : 'type ve path gerekli') },
702
722
  TodoWrite: { readOnly: true, validate: (a) => (a && Array.isArray(a.todos) ? null : 'todos dizisi gerekli') },
703
723
  SaveMemory: { validate: (a) => (a && a.fact && String(a.fact).trim() ? null : 'fact gerekli') },
704
724
  PowerShell: { needsPermission: true, validate: (a) => (a && a.command ? null : 'command gerekli') },
@@ -1039,6 +1059,20 @@ async function execOne(call, hooks) {
1039
1059
  return { ok: false, output: 'JWT analizi hatası: ' + (e?.message || e), args };
1040
1060
  }
1041
1061
  }
1062
+ // 3.47) Döküman üretimi (xlsx/docx/pdf/pptx) — CLI native (Python gerekmez)
1063
+ if (call.name === 'CreateDocument') {
1064
+ try {
1065
+ const { createDocument } = await import('./docs.js');
1066
+ const fp = resolveWs(String(args?.path || ''));
1067
+ const r = await createDocument({ ...(args || {}), path: fp });
1068
+ if (!r.ok)
1069
+ return { ok: false, output: 'Döküman oluşturulamadı: ' + (r.error || 'hata'), args };
1070
+ return { ok: true, output: `${String(args?.type).toUpperCase()} dosyası oluşturuldu → ${r.path} (${Math.round((r.size || 0) / 1024)} KB). [doc-done] Kullanıcıya dosyanın yolunu ve nasıl açacağını kısaca söyle.`, args };
1071
+ }
1072
+ catch (e) {
1073
+ return { ok: false, output: 'Döküman hatası: ' + (e?.message || e), args };
1074
+ }
1075
+ }
1042
1076
  // 3.5) Komut güvenliği (Bash/PowerShell) — cmdsec: deny→blokla, allow→izinsiz, confirm→izin akışı
1043
1077
  if ((call.name === 'Bash' || call.name === 'PowerShell') && args && args.command) {
1044
1078
  const chk = checkCommand(String(args.command), { shell: call.name === 'PowerShell' ? 'powershell' : 'bash' });
@@ -1193,6 +1227,8 @@ export function toolLabel(name, args) {
1193
1227
  return `🛡️ Kod denetimi (SAST): ${String(args.path || '.').slice(0, 50)}`;
1194
1228
  if (name === 'JwtAudit')
1195
1229
  return `🎫 JWT analizi`;
1230
+ if (name === 'CreateDocument')
1231
+ return `📄 ${String(args.type || '').toUpperCase()} oluştur: ${String(args.path || '').slice(0, 40)}`;
1196
1232
  if (name === 'TodoWrite')
1197
1233
  return `TodoWrite(${(args.todos || []).length} öğe)`;
1198
1234
  if (name === 'PowerShell')
package/dist/tui.js CHANGED
@@ -164,6 +164,10 @@ export async function runTui() {
164
164
  let inputBuf = '', inputCur = 0, busy = false, streamChars = 0, spin = 0;
165
165
  let turnAbort = null; // ESC ile çalışan turu durdurma
166
166
  let taskStart = 0; // görev başlangıç zamanı (spinner'da geçen süre için)
167
+ // /loop — oturum-içi zamanlanmış görev tekrarı (CLI açıkken belirli aralıkla çalışır)
168
+ let loopPrompt = '', loopIntervalMs = 0, loopTimer = null, loopCount = 0;
169
+ function stopLoop() { if (loopTimer)
170
+ clearTimeout(loopTimer); loopTimer = null; loopPrompt = ''; }
167
171
  // Canlı akış artık FOOTER'da DEĞİL — içerik akışına (mesajın altından aşağı) satır-satır basılır.
168
172
  const SPIN = ['·', '✢', '✳', '✶', '✻', '✽', '✶', '✳', '✢'];
169
173
  // Canlı bağlam ölçer: son isteğin prompt_tokens'ı = o anki kullanılan bağlam (footer'da gösterilir).
@@ -620,6 +624,15 @@ export async function runTui() {
620
624
  lastFbQ = userText;
621
625
  lastFbA = lastAnswer;
622
626
  }
627
+ // /loop — aktifse ve bu tur loop görevinin kendisiyse, aralık sonra tekrar çalıştır
628
+ if (loopPrompt && displayText === '__loop__') {
629
+ const _m = Math.round(loopIntervalMs / 1000);
630
+ printItem({ kind: 'note', text: `🔁 Sonraki tekrar ${_m >= 60 ? Math.round(_m / 60) + ' dk' : _m + ' sn'} sonra (#${loopCount}). Durdurmak: /loop off` });
631
+ loopTimer = setTimeout(() => { if (loopPrompt) {
632
+ loopCount++;
633
+ runTurn(loopPrompt, '__loop__');
634
+ } }, loopIntervalMs);
635
+ }
623
636
  // Oto-hafıza: eşik geçildiyse arka planda hafızayı güncelle
624
637
  if (shouldExtract(history))
625
638
  triggerMemory(history, config);
@@ -932,6 +945,34 @@ export async function runTui() {
932
945
  runTurn(`CodeAudit aracıyla şu yolu kaynak kod güvenliği için tara (SAST): ${a}. Bulguları severity-sıralı özetle + öncelikli düzeltmeler.`, v);
933
946
  return;
934
947
  }
948
+ // /loop — oturum-içi zamanlanmış görev tekrarı: /loop <aralık> <görev> · /loop off
949
+ if (tok === '/loop') {
950
+ const rest = v.slice(tok.length).trim();
951
+ if (/^(off|stop|dur|kapat)$/i.test(rest)) {
952
+ stopLoop();
953
+ printItem({ kind: 'note', text: '🔁 Loop durduruldu.' });
954
+ return;
955
+ }
956
+ const im = rest.match(/^(\d+)\s*(sn|s|saniye|dk|m|dakika|sa|h|saat)\b/i);
957
+ if (!im) {
958
+ printItem({ kind: 'note', text: 'Kullanım: /loop <aralık> <görev> (örn: /loop 5dk git status) · durdur: /loop off' });
959
+ return;
960
+ }
961
+ const n = parseInt(im[1]);
962
+ const unit = im[2].toLowerCase();
963
+ const mult = /^(sa|h|saat)/.test(unit) ? 3600 : /^(dk|m|dakika)/.test(unit) ? 60 : 1;
964
+ loopIntervalMs = Math.max(10, n * mult) * 1000;
965
+ loopPrompt = rest.slice(im[0].length).trim();
966
+ if (!loopPrompt) {
967
+ loopPrompt = '';
968
+ printItem({ kind: 'note', text: 'Görev belirt: /loop 5dk <yapılacak iş>' });
969
+ return;
970
+ }
971
+ loopCount = 1;
972
+ printItem({ kind: 'note', text: `🔁 Loop başladı: her ${n} ${unit} → "${loopPrompt.slice(0, 50)}". Durdurmak: /loop off (ya da Esc).` });
973
+ runTurn(loopPrompt, '__loop__');
974
+ return;
975
+ }
935
976
  // /computer — ekran kontrolü (See/Click/Type) aç-kapa
936
977
  if (tok === '/computer') {
937
978
  setComputerUse(!isComputerUse());
@@ -1102,6 +1143,10 @@ export async function runTui() {
1102
1143
  return;
1103
1144
  }
1104
1145
  if (key && key.name === 'escape') {
1146
+ if (loopPrompt) {
1147
+ stopLoop();
1148
+ printItem({ kind: 'note', text: '🔁 Loop durduruldu (Esc).' });
1149
+ }
1105
1150
  // Tur çalışıyorsa ESC = modeli DURDUR (akış/araç döngüsünü kes). Boştaysa input'u temizle.
1106
1151
  if (busy && turnAbort) {
1107
1152
  turnAbort.abort();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormclaude",
3
- "version": "1.0.204",
3
+ "version": "1.0.206",
4
4
  "description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,10 +16,14 @@
16
16
  "@modelcontextprotocol/sdk": "^1.29.0",
17
17
  "@types/diff": "^7.0.2",
18
18
  "diff": "^9.0.0",
19
+ "docx": "^9.7.1",
20
+ "exceljs": "^4.4.0",
19
21
  "ink": "^5.0.1",
20
22
  "ink-spinner": "^5.0.0",
21
23
  "ink-text-input": "^6.0.0",
22
24
  "log-update": "^5.0.1",
25
+ "pdfkit": "^0.19.1",
26
+ "pptxgenjs": "^4.0.1",
23
27
  "react": "^18.3.1",
24
28
  "string-width": "^7.2.0"
25
29
  },