wormclaude 1.0.123 → 1.0.125

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/cli.js CHANGED
@@ -60,6 +60,17 @@ import { shouldAutoCompact, runCompact, isContextError } from './compact.js';
60
60
  import { shouldExtract, triggerMemory, loadMemoryContext } from './memory.js';
61
61
  // --- WORMCLAUDE SUBCOMMANDS (TUI oncesi) ---
62
62
  const _arg = (process.argv[2] || '').toLowerCase();
63
+ // Headless mod: wormclaude -p "<görev>" → TUI'siz çalıştır, stdout'a yaz, çık (scriptlenebilir + test).
64
+ if (_arg === '-p' || _arg === '--print') {
65
+ const _prompt = process.argv.slice(3).join(' ').trim();
66
+ if (!_prompt) {
67
+ console.error('Kullanım: wormclaude -p "<görev>"');
68
+ process.exit(1);
69
+ }
70
+ const { runHeadless } = await import('./headless.js');
71
+ await runHeadless(_prompt);
72
+ process.exit(0);
73
+ }
63
74
  if (_arg === 'login' || _arg === 'logout' || _arg === 'whoami' || _arg === '--version' || _arg === '-v' || _arg === 'update') {
64
75
  const auth = await import('./auth.js');
65
76
  if (_arg === 'login')
@@ -0,0 +1,76 @@
1
+ // Headless (non-interactive) mod: `wormclaude -p "<görev>"` → ajan döngüsünü bir kez çalıştırır,
2
+ // sonucu stdout'a yazar, çıkar. TUI yok. Scriptlenebilir + otomatik test için. Araçlar OTO-onaylı
3
+ // (kullanıcı -p ile bilerek başlattı). Davranış TUI ile aynı: aynı streamChat + executeToolCalls
4
+ // + strip/capOut/devre-kesici.
5
+ import { loadConfig, streamChat } from './api.js';
6
+ import { allToolSchemas, executeToolCalls, toolLabel, setToolConfig } from './tools.js';
7
+ import { stripInlineToolCalls, stripEchoBlocks } from './inlinetools.js';
8
+ import { cleanModelText } from './textclean.js';
9
+ function cap(name, out) {
10
+ const s = out || '';
11
+ const isCmd = name === 'Bash' || name === 'PowerShell';
12
+ const CAP = isCmd ? 2200 : 8000;
13
+ if (s.length <= CAP)
14
+ return s;
15
+ if (isCmd)
16
+ return s.slice(0, 1400) + `\n… [kısaltıldı] …\n` + s.slice(-600);
17
+ return s.slice(0, CAP) + `\n… [kısaltıldı]`;
18
+ }
19
+ export async function runHeadless(prompt) {
20
+ const config = loadConfig();
21
+ if (!config.apiKey) {
22
+ console.error('Giriş gerekli: wormclaude login');
23
+ process.exit(1);
24
+ }
25
+ setToolConfig(config);
26
+ const plat = process.platform === 'win32' ? 'Windows' : process.platform === 'darwin' ? 'macOS' : 'Linux';
27
+ const history = [
28
+ { role: 'system', content: `ENVIRONMENT: User machine = ${plat}. Bash runs via ${plat === 'Windows' ? 'cmd.exe' : 'sh'}. CWD: ${process.cwd()}.` },
29
+ { role: 'user', content: prompt },
30
+ ];
31
+ let consecFail = 0, totalFails = 0;
32
+ for (let iter = 0; iter < 30; iter++) {
33
+ let answer = '';
34
+ let toolCalls = [];
35
+ try {
36
+ for await (const ev of streamChat(history, allToolSchemas(), config)) {
37
+ if (ev.type === 'text') {
38
+ process.stdout.write(ev.text);
39
+ answer += ev.text;
40
+ }
41
+ else if (ev.type === 'done') {
42
+ toolCalls = ev.toolCalls || [];
43
+ }
44
+ else if (ev.type === 'error') {
45
+ process.stderr.write(`\n[hata: ${ev.error}]\n`);
46
+ }
47
+ }
48
+ }
49
+ catch (e) {
50
+ process.stderr.write(`\n[bağlantı hatası: ${e?.message || e}]\n`);
51
+ process.exit(1);
52
+ }
53
+ answer = stripEchoBlocks(stripInlineToolCalls(cleanModelText(answer))).trim();
54
+ const am = { role: 'assistant', content: answer || '' };
55
+ if (toolCalls.length)
56
+ am.tool_calls = toolCalls.map((t) => ({ id: t.id, type: 'function', function: { name: t.name, arguments: t.args || '{}' } }));
57
+ history.push(am);
58
+ if (!toolCalls.length)
59
+ break;
60
+ const results = await executeToolCalls(toolCalls, {
61
+ confirm: () => Promise.resolve('allow'), // headless → oto-onay
62
+ onResult: (c, _i, res) => { process.stdout.write(`\n ⎿ ${toolLabel(c.name, res.args)} → ${res.ok ? 'OK' : '✗ ' + (res.output || '').slice(0, 120)} (${(res.output || '').length} kar)\n`); },
63
+ });
64
+ for (let i = 0; i < toolCalls.length; i++)
65
+ history.push({ role: 'tool', tool_call_id: toolCalls[i].id, content: cap(toolCalls[i].name, results[i].output || '') });
66
+ const _failed = results.filter((r) => !r.ok).length;
67
+ totalFails += _failed;
68
+ consecFail = (results.length > 0 && _failed === results.length) ? consecFail + 1 : 0;
69
+ if (consecFail >= 2 || totalFails >= 4) {
70
+ process.stdout.write('\n[devre-kesici: komutlar başarısız oldu, durduruldu]\n');
71
+ break;
72
+ }
73
+ }
74
+ process.stdout.write('\n');
75
+ process.exit(0);
76
+ }
@@ -7,6 +7,9 @@
7
7
  // Bu modül o gömülü çağrıları kurtarır — upstream yapısal tool_call vermediğinde YEDEK.
8
8
  import { safeJsonParse } from './safejson.js';
9
9
  const ARG_KEYS = ['arguments', 'parameters', 'input', 'args', 'params'];
10
+ // Model araç adını JSON DIŞINA koyabiliyor: `Bash {"command":...}` / `Write {"file_path":...}`.
11
+ const _TOOLS = 'Bash|PowerShell|Read|Write|Edit|Glob|Grep|WebFetch|WebSearch|Sleep|TaskOutput';
12
+ const TOOL_PREFIX_RE = new RegExp('(?:^|[\\n>*`\\s])(' + _TOOLS + ')\\s*\\{');
10
13
  function toToolCall(obj, i) {
11
14
  if (!obj || typeof obj !== 'object')
12
15
  return null;
@@ -73,8 +76,8 @@ function extractTopLevelJsonObjects(text) {
73
76
  * (<tool_call>, ```json) veya mesajın TAMAMI tek JSON çağrısıysa onu alır. */
74
77
  export function recoverInlineToolCalls(text) {
75
78
  const t = (text || '').trim();
76
- // JSON-temelli çağrı yoksa VE prose-AskUserQuestion da yoksa erken çık.
77
- if (!t || (!t.includes('"name"') && !t.includes('"tool"') && !t.includes('"function"') && !/AskUserQuestion/i.test(t)))
79
+ // JSON/prose/ToolName{…} çağrısı yoksa erken çık.
80
+ if (!t || (!t.includes('"name"') && !t.includes('"tool"') && !t.includes('"function"') && !/AskUserQuestion/i.test(t) && !TOOL_PREFIX_RE.test(t)))
78
81
  return [];
79
82
  const out = [];
80
83
  const seen = new Set();
@@ -126,6 +129,20 @@ export function recoverInlineToolCalls(text) {
126
129
  push({ name: 'AskUserQuestion', arguments: { question, options } });
127
130
  }
128
131
  }
132
+ // 5) "ToolName { ...args... }" — model araç adını JSON DIŞINA koyuyor (Bash {"command":...}).
133
+ // Args doğrudan obje (arguments sarmalı yok) → {name: ToolName, arguments: {...}}.
134
+ if (!out.length) {
135
+ const re = new RegExp('(' + _TOOLS + ')\\s*(\\{)', 'g');
136
+ let mm;
137
+ while ((mm = re.exec(t)) !== null) {
138
+ const objs = extractTopLevelJsonObjects(t.slice(mm.index + mm[1].length));
139
+ if (objs.length) {
140
+ const args = safeJsonParse(objs[0], null);
141
+ if (args && typeof args === 'object' && !Array.isArray(args))
142
+ push({ name: mm[1], arguments: args });
143
+ }
144
+ }
145
+ }
129
146
  return out;
130
147
  }
131
148
  /** Modelin komut/çıktıyı TEKRAR yazdığı kod-bloklarını siler (```plaintext/bash/http/console…).
@@ -154,5 +171,41 @@ export function stripInlineToolCalls(text) {
154
171
  }
155
172
  // AskUserQuestion prose biçimi (interaktif seçiciye çevrildi → metni gizle).
156
173
  s = s.replace(/AskUserQuestion[\s\S]*?\[[^\]]*\]\s*/gi, '');
174
+ // ToolName {…} biçimi (Bash {"command":...}) — adı + ardından gelen dengeli {…} bloğunu sil.
175
+ {
176
+ const re = new RegExp('(' + _TOOLS + ')\\s*\\{', 'g');
177
+ let mm;
178
+ const spans = [];
179
+ while ((mm = re.exec(s)) !== null) {
180
+ let depth = 0, inStr = false, esc = false, end = -1;
181
+ for (let i = mm.index + mm[0].length - 1; i < s.length; i++) {
182
+ const c = s[i];
183
+ if (inStr) {
184
+ if (esc)
185
+ esc = false;
186
+ else if (c === '\\')
187
+ esc = true;
188
+ else if (c === '"')
189
+ inStr = false;
190
+ continue;
191
+ }
192
+ if (c === '"')
193
+ inStr = true;
194
+ else if (c === '{')
195
+ depth++;
196
+ else if (c === '}') {
197
+ depth--;
198
+ if (depth === 0) {
199
+ end = i + 1;
200
+ break;
201
+ }
202
+ }
203
+ }
204
+ if (end > 0)
205
+ spans.push([mm.index, end]);
206
+ }
207
+ for (let i = spans.length - 1; i >= 0; i--)
208
+ s = s.slice(0, spans[i][0]) + s.slice(spans[i][1]);
209
+ }
157
210
  return s.trim();
158
211
  }
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.123';
19
+ export const VERSION = '1.0.125';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormclaude",
3
- "version": "1.0.123",
3
+ "version": "1.0.125",
4
4
  "description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
5
5
  "type": "module",
6
6
  "bin": {